Table of contents
Four signal slot writing methods:
Common errors and corrections:
Mistake 1: Unconnected signal and slot
Mistake 2: Mismatch of signal and slot parameters
Mistake 3: Not using the Q_OBJECT macro
Error 4: Unhandled cross-thread connection
In Qt, signals (Signal) and slots (Slot) are a mechanism for communication between objects, used to achieve a loosely coupled approach. When a signal is sent, its associated slot is called. The following are four common signal slot writing methods and five connection methods:
Four signal slot writing methods:
-
Direct function linkage :
QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
This is Qt's early connection syntax, using strings to represent signals and slots. Type checking cannot be done at compile time.
-
Function pointer connection :
QObject::connect(sender, &SenderClass::signal, receiver, &ReceiverClass::slot);
This type of connection is type-checked at compile time, but may not be flexible enough in some cases, such as connecting to a base class slot.
-
Lambda expression concatenation (C++11 and later):
QObject::connect(sender, &SenderClass::signal, [=]() { /* slot implementation */ });
This method can use Lambda expression as the implementation of the slot, which is very convenient.
-
Qt5 new syntax connection :
QObject::connect(sender, &SenderClass::signal, receiver, &ReceiverClass::slot, Qt::ConnectionType);
This syntax was introduced in Qt5 and allows specifying the connection type, eg
Qt::AutoConnection
, ,Qt::DirectConnection
etc.
Five connection methods:
-
AutoConnection : Automatically select the connection method according to the thread where the signal and slot are located. If on the same thread, use
DirectConnection
otherwiseQueuedConnection
. -
DirectConnection : When the signal is sent, the slot function is called directly. Applies to the situation where signals and slots are in the same thread.
-
QueuedConnection : Put the signal into the event queue of the receiver thread, which will be processed by the receiver thread at an appropriate time. Suitable for cross-thread communication.
-
BlockingQueuedConnection :
QueuedConnection
Similar, but the thread that sends the signal is blocked until the receiver thread has processed the signal. -
UniqueConnection : Ensure that the connection is unique, preventing multiple connections to the same signal and slot. If the same connection already exists, the new connection will not be created.
Example:
A simple Qt application that contains a button and a textbox. When the button is clicked, the textbox displays a message. We will show how to use Qt's signal-slot mechanism in this case, covering four ways of writing and five ways of connecting.
#include <QtWidgets>
class MyWidget : public QWidget {
Q_OBJECT
public:
MyWidget(QWidget *parent = nullptr) : QWidget(parent) {
QVBoxLayout *layout = new QVBoxLayout(this);
button = new QPushButton("Click Me", this);
textEdit = new QTextEdit(this);
textEdit->setReadOnly(true);
layout->addWidget(button);
layout->addWidget(textEdit);
connectUsingDirectFunction();
connectUsingFunctionPointer();
connectUsingLambda();
connectUsingQt5Syntax();
}
private slots:
void showMessage() {
textEdit->append("Button clicked!");
}
private:
QPushButton *button;
QTextEdit *textEdit;
void connectUsingDirectFunction() {
QObject::connect(button, SIGNAL(clicked()), this, SLOT(showMessage()));
}
void connectUsingFunctionPointer() {
QObject::connect(button, &QPushButton::clicked, this, &MyWidget::showMessage);
}
void connectUsingLambda() {
QObject::connect(button, &QPushButton::clicked, [=]() {
textEdit->append("Button clicked using lambda!");
});
}
void connectUsingQt5Syntax() {
QObject::connect(button, &QPushButton::clicked, this, &MyWidget::showMessage, Qt::AutoConnection);
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyWidget widget;
widget.show();
return app.exec();
}
#include "main.moc"
In this case, we created a simple window containing a button and a read-only text field. We connected the button's clicked
signal to the slot that displays the message in four different ways showMessage
.
Common errors and corrections:
Let's illustrate some common mistakes when it comes to Qt's signals and slots, and show how to fix them:
Mistake 1: Unconnected signal and slot
// 错误示例 QObject::connect(button, SIGNAL(clicked()), this, SLOT(showMessage())); // 没有连接按钮的clicked信号与槽函数
Correction method:
// 正确示例 QObject::connect(button, &QPushButton::clicked, this, &MyWidget::showMessage);
Mistake 2: Mismatch of signal and slot parameters
// 错误示例 class MyWidget : public QWidget { Q_OBJECT public slots: void slotWithInt(int value); }; // ... QObject::connect(sender, SIGNAL(someSignal()), this, SLOT(slotWithInt(QString))); // 参数不匹配
Correction method:
// 正确示例 class MyWidget : public QWidget { Q_OBJECT public slots: void slotWithInt(int value); }; // ... QObject::connect(sender, SIGNAL(someSignal(int)), this, SLOT(slotWithInt(int))); // 参数匹配
Mistake 3: Not using Q_OBJECT
macros
// 错误示例 class MyWidget : public QWidget { public: MyWidget(QWidget *parent = nullptr) : QWidget(parent) {} public slots: void showMessage() { /* ... */ } };
Correction method:
// 正确示例 class MyWidget : public QWidget { Q_OBJECT public: MyWidget(QWidget *parent = nullptr) : QWidget(parent) {} public slots: void showMessage() { /* ... */ } };
Error 4: Unhandled cross-thread connection
// 错误示例 QObject::connect(sender, SIGNAL(someSignal()), receiver, SLOT(slotInDifferentThread())); // 未处理跨线程连接
Correction method:
// 正确示例 QObject::connect(sender, SIGNAL(someSignal()), receiver, SLOT(slotInDifferentThread()), Qt::QueuedConnection); // 使用Qt::QueuedConnection来处理跨线程连接