信号与槽
信号与槽机制是Qt的一个主要特征,是Qt与其它工具包最不相同的部分。通过反馈的方式动态地或松散地将事件和状态变化联系起来。
Qt工作的原理:事件驱动,信号槽机制。
回调(callback)。
是一个函数指针,当一个事件发生时被 调用,任何函数都可以被安排作为回调。
- 没有类型安全
- 总是以直接调用方式工作
信号和槽的方式更加动态
- 一个更通用的机制
- 更容易互连两个已存在的类
- 相关类之间涉及更少的知识共享
Qt采用信号和槽实现对象部件之间的通信。
- 能携带任意数量和任意类型的参数,取代原始的回调和消息映射机制
- 面向对象,独立于标准C/C++,必须借助QT工具moc(Meta Object Compiler),C++预处理程序,为高层次事件处理自动生成所需要附加代码
- 必须把事件和相关代码联系起来,才能对事件做出响应。才能使不同类型的对象之间能够进行通信
信号
当信号被发射时,QT代码将回调与其相连接的槽函数
信号将由元对象处理moc自动翻译成C++代码
信号的声明不在.cpp文件中,而在头文件中
Q_OBJECT
......
signals:
void mySignal();
void mySignal(int x);
void mySignalParam(int x,int y);槽
槽函数是普通的C++成员函数,可以被正常调用
槽函数可以有返回值,也可以没有。
槽函数的访问权限三种:public slots、private slots和protected slots。槽函数的存取权限决定了谁能够与其相关联。
普通的 C++ 成员函数一样,槽函数也分为三种类型,即 public slots、private slots 和 protected slots。
- public slots:在这个区内声明的槽意味着任何对象都可将信号与之相连接。这对于组件编程非常有用,你可以创建彼此互不了解的对象,将它们的信号与槽进行连接以便信息能够正确的传递。
- protected slots:在这个区内声明的槽意味着当前类及其子类可以将信号与之相连接。这适用于那些槽,它们是类实现的一部分,但是其界面接口却面向外部。
- private slots:在这个区内声明的槽意味着只有类自己可以将信号与之相连接。这适用于联系非常紧密的类。
槽也能够声明为虚函数,这也是非常有用的。
头文件中中声明
Q_OBJECT
......
public slots:
void mySlot();
void mySlot(int x);
void mySignalParam(int x,int y);连接方式
原型:
QMetaObject::Connection QObject::connect(const QObject * sender, const char * signal, const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoConnection);槽函数执行方式分为:自动、直接、队列、阻塞队列等等。
Qt::AutoConnection:
Qt::DirectConnection
Qt::QueuedConnection:
Qt::BlockingQueuedConnection:
Qt::UniqueConnection可参考:Assist : Qt::ConnectionType
连接
信号与槽关联
QObject::connect( sender, SIGNAL(signal),receiver, SLOT(method) );信号与信号相连
QObject::connect( sender, SIGNAL(signal), receiver, SIGNAL(signal) );同一个信号连接到多个槽
QObject::connect( sender, SIGNAL(signal),receiver, SLOT(method1) );
QObject::connect( sender, SIGNAL(signal),receiver, SLOT(method2) );
......多个信号连接到同一个槽
QObject::connect( sender, SIGNAL(signal1),receiver, SLOT(method) );
QObject::connect( sender, SIGNAL(signal2),receiver, SLOT(method) );
......Qt5: 新语法:
connect(sender, &Sender::valueChanged, receiver, &Receiver::updateValue);TEST
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QLabel>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
signals:
void clicked();
public slots:
void ToCalculate();
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
QPushButton *pushButton;
QLineEdit *lineEdit;
QLineEdit *lineEdit_2;
QLineEdit *lineEdit_3;
QVBoxLayout *layout;
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_Hmainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
lineEdit = new QLineEdit();
lineEdit_2 = new QLineEdit();
lineEdit_3 = new QLineEdit();
pushButton = new QPushButton("计算");
layout = new QVBoxLayout();
layout->addWidget(lineEdit);
layout->addWidget(lineEdit_2);
layout->addWidget(lineEdit_3);
layout->addWidget(pushButton);
QWidget *centerWindow = new QWidget;
this->setCentralWidget(centerWindow);
centerWindow->setLayout(layout);
connect(pushButton, SIGNAL(clicked()),this, SLOT(ToCalculate()) );
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::ToCalculate()
{
int a = lineEdit->text().toInt();
int b = lineEdit_2->text().toInt();
lineEdit_3->setText(QString::number(a+b));
}发送信号
signal一般是在事件处理时候Qt发出,如果需要程序自己触发信号,则使用emit。 使用语法如下:
emit signal如果不需要连接信号槽的时候,可以取消连接。
函数原型(有多个版本,函数重载):
bool QObject::disconnect(const QObject * sender, const char * signal, const QObject *receiver,const char * method);- 取消一个连接不是很常用,因为Qt会在一个对象被删除后自动取消这个对象所包含的所有连接
Q_Object宏
只有继承了QObject类的类,才具有信号槽的能力。凡是QObject类(不管是直接子类还是间接子类),都应该在第一行代码写上Q_OBJECT。不管是不是使用信号槽,都应该添加这个宏。这个宏的展开将为我们的类提供信号槽机制、国际化机制以及 Qt 提供的不基于 C++ RTTI 的反射能力。
moc 只处理头文件中的标记了Q_OBJECT的类声明
#define Q_OBJECT \
public: \
Q_OBJECT_CHECK \
static const QMetaObject staticMetaObject; \
Q_OBJECT_GETSTATICMETAOBJECT \
virtual const QMetaObject *metaObject() const; \
virtual void *qt_metacast(const char *); \
QT_TR_FUNCTIONS \
virtual int qt_metacall(QMetaObject::Call, int, void **); \
private:
Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);