The Qt Object Model: Signals and Slots

1. Overview of the signal and slot mechanism

Signals and slots are one of the proud mechanisms of the Qt framework. The so-called signal slot is actually the observer mode. When an event occurs, for example, a button detects that it has been clicked, it sends a signal. This emission is purposeless, similar to broadcasting. If an object is interested in this signal, it will use the connect function, which means, bind the signal it wants to process to a function (called a slot) of its own to process this signal. That is to say, when the signal is sent, the connected slot function will be called back automatically.

The essence of a slot is a member function of a class, and its parameters can be of any type. It is almost the same as an ordinary C++ member function. It can be a virtual function; it can also be overloaded; it can be public, protected, private, or called by other C++ member functions. The only difference is that a slot can be connected to a signal, and the slot will be called whenever the signal connected to the slot is emitted.

In the early days, communication between objects was implemented using callbacks. Callbacks are actually implemented using function pointers. When we want the processing function to be notified when something happens, we need to pass the pointer of the callback function to the processing function, so that the processing function will call the callback function at an appropriate time. Callbacks have two distinct disadvantages:

  • They are not type-safe, and we cannot guarantee that the parameters passed to the callback function by the handler are correct.
  • The callback function and the handler function are tightly coupled, because the handler function must know which function is called back.

The benefits of this article, free to receive Qt development learning materials package, technical video, including (C++ language foundation, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project combat, QSS, OpenCV, Quick module, interview questions, etc.) ↓↓↓↓↓↓See below↓↓Click on the bottom of the article to receive the fee↓↓

2. Typical application examples

Let's use a simple example to further explain the relevant knowledge of signals and slots. Create a new Qt Gui application, the project name is mySignalSlot, the base class is QWidget, and the class name remains Widget. After completion, first declare the signal and slot in the widget.h file:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QDebug>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT //必须包含的宏

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

public slots:
    void testSolts(); //测试槽函数

signals:
    void testSignals(); //测试信号

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

To use signals and slots, you must add the Q_OBJECT macro at the very beginning of the class declaration. In this program, the class declaration is automatically generated, and this macro has been added.

The signal code will be automatically generated by moc, and developers cannot implement it in their own C++ code. Instead, slots should be implemented by the developer. Modify the widget.cpp file as follows:

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //连接信号槽
    connect(this,SIGNAL(testSignals()),this,SLOT(testSolts()));
    //发射信号
    emit testSignals();
}

Widget::~Widget()
{
    delete ui;
}

//测试槽函数
void Widget::testSolts()
{
    qDebug() << "调用了测试槽函数";
}

The effect achieved in this example is: after the signal is emitted, the testSolts() slot function will be called, and the "Application Output" window will print "The test slot function was called".

3. Precautions for using signals and slots

Here is a list of precautions that should be paid attention to when using signals and slots:

  • Both the sender and receiver need to inherit from QObject or its subclasses;
  • The Q_OBJECT macro must be added at the beginning of the class declaration;
  • The parameter type in the slot should correspond to the signal parameter type, and cannot be more than the signal parameter;
  • Use signals to mark the signal function, the signal is a function declaration, return void, no need to implement the function code;
  • Use emit to send signals at appropriate locations;
  • Slot function is an ordinary member function, as a member function, it will be affected by public, private and protected;
  • Any member function, static function, global function, and lambda expression can be used as a slot function.

Fourth, the association between signals and slots

Signals and slots are associated using the connect() function of the QObject class. The prototype of this function in Qt4 is as follows:

static QMetaObject::Connection QObject::connect(const QObject *sender, 
										const char *signal,
                        				const QObject *receiver, 
                        				const char *member, 
                        		Qt::ConnectionType = Qt::AutoConnection);

The first parameter sender is the object that sends the signal, the second parameter signal is the signal to be sent, the third parameter receiver is the object that receives the signal, and the fourth parameter slot is what the receiving object needs to call after receiving the signal slot function. The last parameter of the connect() function indicates the connection method, and the default value is Qt::AutoConnection. For signals and slots, you must use the SIGNAL() and SLOT() macros, which convert their arguments to const char* types. The return value of the connect() function is bool type, and returns true when the connection is successful.

For the parameters of signals and slots, the basic principle is that the parameter types in the signal should correspond to the parameter types in the slot, and the parameters in the signal can be more than the parameters in the slot, but not the other way around; if there are redundant parameters in the signal parameters, they will be ignored.

The newly added overloaded form of the connect() function in Qt5 is as follows:

static QMetaObject::Connection QObject::connect(const QObject *sender, 
										PointerToMemberFunction signal,
                        				const QObject *receiver, 
                        				PointerToMemberFunction member, 
                        		Qt::ConnectionType type = Qt::AutoConnection);

The biggest difference from Qt4 is that you don’t need to use the SIGNAL() and SLOT() macros when specifying the signal and slot parameters, and the slot function no longer has to be a function declared with the slots keyword, but can be any function and signal Associated member functions. To enable a member function to be associated with a signal, the number of parameters of this function cannot exceed the number of parameters of the signal, but it is not required that the parameter types of the function are exactly the same as the corresponding parameter types in the signal, only that implicit conversion can be performed That's it. Using this overloaded form, the association in the previous program can be replaced by the following code:

connect(this,&Widget::testSignals,this,&Widget::testSolts);

Compared with the previous one, using this method has another advantage that it can be checked at compile time. Errors such as typos of signals and slots, and the number of parameters of function parameters are more than the number of parameters of signals can be found at compile time. So it is recommended to use this association form when writing Qt5 code.

There is also an automatic association method between signals and slots. For example, the slot of the button click signal generated directly in the design mode is used in this way: on_pushButton_clicked() consists of three parts: the string on, the objectName of the component, and the signal name , separated by underscores. A slot named in this form can be directly associated with a signal without using the connect() function, but other settings need to be made in this way.

5. Disconnect the association between signal and slot

The connection between signal and slot can be disconnected through the disconnect() function, whose prototype is as follows:

static bool QObject::disconnect(const QObject *sender, const char *signal,
                           const QObject *receiver, const char *member);

(1) Disconnect all associations with all signals of a sending object

disconnect(myObject, nullptr, nullptr, nullptr);

Equivalent to

myObject->disconnect();

(2) Disconnect all associations with a specified signal

disconnect(myObject, SIGNAL(mySignal()), nullptr, nullptr);

Equivalent to

myObject->disconnect(SIGNAL(mySignal()));

(3) Disconnect all associations with a specified accepting object

disconnect(myObject, nullptr, myReceiver, nullptr);

Equivalent to

myObject->disconnect(myReceiver);

(4) Disconnect the association between a specified signal and slot

disconnect(myObject, SIGNAL(mySignal()), myReceiver, SLOT(mySlot()));

Equivalent to

myObject->disconnect(SIGNAL(mySignal()), myReceiver, SLOT(mySlot()));

is also equivalent to

disconnect(myConnection); //myConnection是进行关联时connect()的返回值

Its usage is similar, except that its signal and slot parameters need to use the form of function pointer &MyObject::mySignal(), &MyReceiver::mySlot(), etc. This function cannot disconnect the signal from general functions or lambda expressions. If necessary, you can use the return value of connect() to disconnect. In fact, when an object is deleted, all its associated links will become invalid, and QT will automatically remove all links to this object.

Six, more usage of signals and slots

(1) A signal can connect to multiple slots

Use QObject::connect to connect a signal to multiple slots, and when the signal is emitted, the slots will be called sequentially in the order in which they were declared.

MyStr  a;
MyStr  b;
MyStr  c;
//信号连接到两个槽
QObject::connect(&a,SIGNAL(valueChanged(QString)),&b,SLOT(setValue(QString)));
QObject::connect(&a,SIGNAL(valueChanged(QString)),&c,SLOT(setValue(QString)));
a.setValue("this is A");
//依次调用b.setValue()、c.setValue()

(2) Multiple signals can be connected to the same slot

Similarly, multiple signals can be connected to the same slot, and the sending of each signal will call that slot.

MyStr  a;
MyStr  b;
MyStr  c;
//两个信号连接到同一个槽
QObject::connect(&a,SIGNAL(valueChanged(QString)),&c,SLOT(setValue(QString)));
QObject::connect(&b,SIGNAL(valueChanged(QString)),&c,SLOT(setValue(QString)));
//下面的操作皆会调用到槽c.setValue()
a.setValue("this is A");
b.setValue("this is B");

(3) A signal can be connected to another signal

When the first signal is transmitted, the second signal is also sent out one by one.

MyStr  a;
MyStr  b;
MyStr  c;
//两个信号相连接
QObject::connect(&a,SIGNAL(valueChanged(QString)),&b,SIGNAL(valueChanged(QString)));
//再建立b与c的连接
QObject::connect(&b,SIGNAL(valueChanged(QString)),&c,SLOT(setValue(QString)));
//下面的操作同时发送了信号a.valueChanged与b.valueChanged
a.setValue("this is A");
//从而信号b.valueChanged被槽c.setValue所接收

Seven, extension: Qt object model overview

The standard C++ object model can support the object paradigm (object paradigm) very efficiently at runtime, but its static nature is not flexible enough in some problem domains. Graphical user interface programming requires not only high efficiency at runtime, but also high flexibility. To this end, Qt adds some features to the standard C++ object model to form its own object model. These properties are:

  • A powerful seamless object communication mechanism - signals and slots (signals and slots);
  • Queryable and designable object properties system (object properties);
  • Powerful events and event filters (events and event filters);
  • string translation for internationalization by context;
  • Perfect timer (timers) driver, making it possible to handle multiple tasks in an event-driven GUI;
  • Hierarchical, queryable object trees that organize object ownership in a natural way;
  • The guard pointer is QPointer, which automatically sets it to 0 when the referenced object is destroyed;
  • Dynamic object conversion mechanism (dynamic cast).

These features of Qt are implemented in accordance with the standard C + + specification, and the use of these features must inherit from the QObject class. Among them, the object communication mechanism and the dynamic attribute system also need the support of the meta-object system (Meta-Object System). Regarding the object model, you can view the Object Model keyword in the help.

The benefits of this article, free to receive Qt development learning materials package, technical video, including (C++ language foundation, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project combat, QSS, OpenCV, Quick module, interview questions, etc.) ↓↓↓↓↓↓See below↓↓Click on the bottom of the article to receive the fee↓↓

Guess you like

Origin blog.csdn.net/QtCompany/article/details/131773806