QT信号槽使用
信号和槽的声明
在qt中,信号槽机制是用于qt对象间通信的机制。一个类要能构使用信号槽,必须继承子QObject类并添加Q_OBJECT宏:
#include <QObject>
class qt_demo : public QObject
{
Q_OBJECT
public:
explicit qt_demo(QObject *parent = nullptr);
public slots:
void slot_recv_code(int code);
signals:
void signal_recv_code(int code);
};
声明信号的关键字为signals,声明槽函数的关键字为slots,这些都是qt独有的关键字,这些关键字会被Qt的moc转换为标准的C++语句。
信号和槽的关系
- 槽的参数的类型需要与信号参数的类型相对应,
- 槽的参数不能多余信号的参数,因为若槽的参数更多,则多余的参数不能接收到信号传递过来的值,若在槽中使用了这些多余的无值的参数,就会产生错误。
- 若信号的参数多余槽的参数,则多余的参数将被忽略。
- 一个信号可以与多个槽关联,多个信号也可以与同一个槽关联,信号也可以关联到另一个信号上。
- 若一个信号关联到多个槽时,则发射信号时,槽函数按照关联的顺序依次执行。
- 若信号连接到另一个信号,则当第一个信号发射时,会立即发射第二个信号。
信号和槽的关联(连接)
信号和槽使用QObject类中的成员函数connect进行关联,该函数有多个重载版本,如下所示。
版本1
QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)
其中sender为信号发送对象,receiver为信号接收对象,signal和method为信号和槽的签名字符串,一般用SIGNAL和SLOT宏来转换,type为连接类型。
QLabel *label = new QLabel;
QScrollBar *scrollBar = new QScrollBar;
QObject::connect(scrollBar, SIGNAL(valueChanged(int)),
label, SLOT(setNum(int)));
版本2
QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method, Qt::ConnectionType type = Qt::AutoConnection)
其中sender为信号发送对象,receiver为信号接收对象,signal和method为通过QMetaMethod获取到的元信息,type为连接类型。QMetaMethod是Qt提供的一个专门类型,可以用来获取一个对象成员函数的元数据。
QMetaMethod signalMethod = QMetaMethod::fromSignal(&MyWgtA::signalA);
int methodIndex = m_wgtB->metaObject()->indexOfMethod("onSlotB()");
// 防止找不到;
if (methodIndex != -1)
{
QMetaMethod slotMethod = m_wgtB->metaObject()->method(methodIndex);
connect(m_wgtA, signalMethod, m_wgtB, slotMethod);
}
版本3
QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const char *method, Qt::ConnectionType type = Qt::AutoConnection) const
重载版本,等价与connect(sender, signal, this, method, type).
,就是将sender本身的信号和槽绑定。
版本4
template <typename PointerToMemberFunction> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection)
其中sender为信号发送对象,receiver为信号接收对象,signal为slot为成员函数指针,分别指向信号和槽函数,type为连接类型。
QLabel *label = new QLabel;
QLineEdit *lineEdit = new QLineEdit;
QObject::connect(lineEdit, &QLineEdit::textChanged,
label, &QLabel::setText);
版本5
template <typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
sender为信号发送者,signal为成员信号指针,functor为函数或者仿函数。同时这里没有连接type参数,相当于信号发送后直接调用functor。
The signal must be a function declared as a signal in the header. The slot function can be any function or functor that can be connected to the signal. A function can be connected to a given signal if the signal has at least as many argument as the slot. A functor can be connected to a signal if they have exactly the same number of arguments. There must exist implicit conversion between the types of the corresponding arguments in the signal and the slot.
例子
void someFunction();
QPushButton *button = new QPushButton;
QObject::connect(button, &QPushButton::clicked, someFunction);
QByteArray page = ...;
QTcpSocket *socket = new QTcpSocket;
socket->connectToHost("qt-project.org", 80);
QObject::connect(socket, &QTcpSocket::connected, [=] () {
socket->write("GET " + page + "\r\n");
});
版本6
template <typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)
对于版本5多了context和type连接类型,这里context对象可以理解为代替reveicer对象的作用。
void someFunction();
QPushButton *button = new QPushButton;
QObject::connect(button, &QPushButton::clicked, this, someFunction, Qt::QueuedConnection);
QByteArray page = ...;
QTcpSocket *socket = new QTcpSocket;
socket->connectToHost("qt-project.org", 80);
QObject::connect(socket, &QTcpSocket::connected, this, [=] () {
socket->write("GET " + page + "\r\n");
}, Qt::AutoConnection);
connect的连接类型
Qt::ConnectionType定义了信号和槽之间的连接类型:
Constant | Value | Description |
---|---|---|
Qt::AutoConnection | 0 | (Default) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted. |
Qt::DirectConnection | 1 | The slot is invoked immediately when the signal is emitted. The slot is executed in the signalling thread. |
Qt::QueuedConnection | 2 | The slot is invoked when control returns to the event loop of the receiver’s thread. The slot is executed in the receiver’s thread. |
Qt::BlockingQueuedConnection | 3 | Same as Qt::QueuedConnection, except that the signalling thread blocks until the slot returns. This connection must not be used if the receiver lives in the signalling thread, or else the application will deadlock. |
Qt::UniqueConnection | 0x80 | This is a flag that can be combined with any one of the above connection types, using a bitwise OR. When Qt::UniqueConnection is set, QObject::connect() will fail if the connection already exists (i.e. if the same signal is already connected to the same slot for the same pair of objects). This flag was introduced in Qt 4.6. |
信号和槽的断开
静态方式1
bool QObject::disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
Disconnects signal in object sender from method in object receiver. Returns true if the connection is successfully broken; otherwise returns false.
- 断开对象的信号所连接的所有东西
disconnect(myObject, nullptr, nullptr, nullptr);
// 等价
myObject->disconnect();
- 断开对象指定信号连接的所有东西
disconnect(myObject, SIGNAL(mySignal()), nullptr, nullptr);
// 等价
myObject->disconnect(SIGNAL(mySignal()));
- 和指定接收者断连
disconnect(myObject, nullptr, myReceiver, nullptr);
// 等价
myObject->disconnect(myReceiver);
If signal is nullptr, it disconnects receiver and method from any signal. If not, only the specified signal is disconnected.
If receiver is nullptr, it disconnects anything connected to signal. If not, slots in objects other than receiver are not disconnected.
If method is nullptr, it disconnects anything that is connected to receiver. If not, only slots named method will be disconnected, and all other slots are left alone. The method must be nullptr if receiver is left out, so you cannot disconnect a specifically-named slot on all objects.
静态方式2
bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method)
等价方式1
成员方式3
bool QObject::disconnect(const char *signal = nullptr, const QObject *receiver = nullptr, const char *method = nullptr) const
断开本对象的信号连接
// a、断开对象A所有信号的连接:
myObjectA->disconnect();
// b、断开对象A的信号signalA()所有的连接:
myObjectA->disconnect(SIGNAL(mySignal()));
// c、对象A与对象B断开所有信号连接:
myObjectA->disconnect(nullptr, myReceiverB, nullptr);
// d、对象A与对象B断开槽函数onSlotB()所有相关信号的连接::
myObjectA->disconnect(nullptr, myReceiverB, SLOT(onSlotB()));
成员方式4
bool QObject::disconnect(const QObject *receiver, const char *method = nullptr) const
断开本对象和reciever连接的信号
// a、对象A与对象B断开所有信号连接:
myObjectA->disconnect(myReceiverB)
// b、对象A与对象B断开槽函数onSlotB()所有相关信号的连接::
myObjectA->disconnect(myReceiverB, SLOT(onSlotB()));
静态方式5
bool QObject::disconnect(const QMetaObject::Connection &connection)
断开一个connection,该connection是之前connect的返回。
静态方式6
template <typename PointerToMemberFunction> bool QObject::disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method)
与静态方法1类似
QObject::disconnect(lineEdit, &QLineEdit::textChanged,
label, &QLabel::setText);
注意点
- 信号之间可以相互连接
- 一个信号可以连接多个信号/槽
- 一个槽可以被多个信号连接
- 如果一个信号连接多个信号/槽,那么绑定的信号/槽的触发顺序和连接建立顺序一致
- disconnect会断开所有符合的连接
- sender或者receiver一旦销毁,连接自动断开
- 信号和槽存在自动绑定,参考Qt 源码剖析 - 信号槽自动连接机制
参考
QObject::connect
QObject::disconnect
QMetaobject