qt introduction 01-signal slot principle

1. What is moc?

The full name of moc in qt is Meta-Object Compiler, which is "meta-object compiler". When we compile a C++ file, if the macro Q_OBJECT is included in the class declaration, another C++ source file will be generated, which is the moc_xxx.cpp file we often see. The execution process is shown in the figure:

Q_OBJECT is a very important macro. It is a key macro for Qt's meta-compilation system. After this macro is expanded, it contains a lot of code that Qt helps us write, including variable definitions, function declarations, and so on.

1.1 Variables

- static const qt_meta_stringdata_completerTst_t qt_meta_stringdata_completerTst:存储函数列表
- static const uint qt_meta_data_completerTst:类文件描述

1.2 Function declaration after expansion of Q_OBJECT

The following 5 functions are automatically generated using the Q_OBJECT macro

- void xxx::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
- const QMetaObject xxx::staticMetaObject
- const QMetaObject *xxx::metaObject()
- void *xxx::qt_metacast(const char *_clname)
- int xxx::qt_metacall(QMetaObject::Call _c, int _id, void **_a)

In order to better understand these five functions, we first need to introduce a Qt meta object, which is QMetaObject, which stores the source object of the parent class, our current class description, function description and qt_static_metacall function address.

1.2.1 qt_static_metacall

To call the slot function according to the function index, a big detail needs to be paid attention to. In this callback, both the signal and the slot can be called back. The automatically generated code is as follows:

 if (_c == QMetaObject::InvokeMetaMethod) {
    completerTst *_t = static_cast<completerTst *>(_o);
    Q_UNUSED(_t)
    switch (_id) {
    case 0: _t->lanuch(); break;
    case 1: _t->test(); break;
    default: ;
    }
}

lanch is a signal declaration, but it can also be called back. This also indirectly explains a problem. The signal can be used as a slot function.

1.2.2 staticMetaObject

Construct a QMetaObject object and pass in the dynamic information of the current moc file.

1.2.3 metaObject

Returns the current QMetaObject. Generally speaking, the virtual function metaObject() only returns the staticMetaObject object of the class.

1.2.4 qt_metacast

Whether type conversion can be performed is directly called by QObject::inherits to determine whether it is inherited from a certain class. When judging, you need to pass in the string name of the parent class.

1.2.5 qt_metacall

Calling the function callback, the qt_static_metacall function is called internally, which is called when the signal is processed asynchronously, or triggered by the slot function (on_xxx_clicked()) with a certain format specified by Qt. The asynchronous calling code is as follows:

void QMetaCallEvent::placeMetaCall(QObject *object)
{
    if (slotObj_) {
        slotObj_->call(object, args_);
    } else if (callFunction_ && method_offset_ <= object->metaObject()->methodOffset()) {
        callFunction_(object, QMetaObject::InvokeMetaMethod, method_relative_, args_);
    } else {
        QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, method_offset_ + method_relative_, args_);
    }
}

1.3 Custom signal

The following function is a signal defined by ourselves. The moc command helps us generate a signal function implementation. It can be seen that the signal is actually a function, but we just write the signal declaration, and the signal implementation Qt will help us generate it automatically; Function We not only need to write function declarations, but also function implementations must be written by ourselves.

void xxx::lanuch():自定义信号

How does Qt know that we have defined a signal here? This is also the second question we asked at the beginning of the article. The answer is signals . When Qt finds this flag, we are defining signals by default. It helps us produce the realization of the signal. The slots flag is the same. The Qt metasystem is used when analyzing slot functions.

We used the define macro definition to define this keyword.

# define signals

2. connect

Above we analyzed the moc file that the moc system helped us generate. It is the basis and the key to realize the signal slot. In this section, let’s understand the connect function that we usually use the most, and see what he did.

When we execute connect, in fact, he may execute the process like this:

From this picture, we can see that connect doesn’t do much. It seems to construct a Connection object and store it in the sender’s memory. For details, see the code below. This is me. Part of the code from the Qt source code.

QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection);
c->sender = s;   //发送者
c->signal_index = signal_index;//信号索引
c->receiver = r;//接收者
c->method_relative = method_index;//槽函数索引
c->method_offset = method_offset;//槽函数偏移 主要是区别于多个信号
c->connectionType = type;//连接类型
c->isSlotObject = false;//是否是槽对象 默认是true
c->argumentTypes.store(types);//参数类型
c->nextConnectionList = 0;//指向下个连接对象
c->callFunction = callFunction;//静态回调函数,也就是qt_static_metacall

QObjectPrivate::get(s)->addConnection(signal_index, c.data());

The storage structure in the sender's memory

class QObjectConnectionListVector : public QVector<QObjectPrivate::ConnectionList>

After the signal slot is connected, the QObjectConnectionListVector object is stored in the memory. This is an array. Qt cleverly borrows the way of quickly accessing the specified element of the array, and uses the index of the signal as a subscript to index the Connection object he connected. It is well known that a signal can Connected by multiple slots, then our array naturally stores a linked list for convenient insertion and removal, which is the CommectionList object.

3. Signal trigger

Qt provides us with 5 types of connection methods, as follows

  • Qt::AutoConnection automatically connects, according to whether the sender and receiver are in the same thread to determine which connection method to use, the same thread uses direct connection, otherwise it uses queue connection
  • Qt::DirectConnection direct connection
  • Qt::QueuedConnection queue connection
  • Qt::BlockingQueuedConnection blocks the queue connection. As the name implies, although it is cross-threaded, it is still hoped that the next code of the signal can be executed after the slot is executed.
  • Qt::UniqueConnection unique connection

Under normal circumstances, we all use the default connection method, unless some special needs, we will actively specify the connection method. When we execute the signal, the function call relationship may be as follows

emit testSignal(); 执行信号

After the signal is triggered, it is equivalent to calling the QMetaObject::activate function. The function body of the signal is automatically generated by moc to help us.

3.1 Direct connection

For most of the development work, we may all be in the same thread, so direct connection is also the way we use the most connection, direct connection is to put it bluntly is the function callback . Remember the connect we talked about in the third section? He constructed a Connection object and stored it in the sender's memory. The direct connection actually called the function address we previously stored in Connection.

As shown in the figure below, when it is a direct connection, it calls back to a memory stack in the slot function:

When talking about the connect function, we analyzed that a Connection object is actually constructed inside the function and stored in the sender's memory. One of the variables is isSlotObject, which is true by default. When we use connect to connect to the signal slot, this parameter is true by default, but Qt also provides another slot function with a prescribed format. At this time, isSlotObject is false.

As shown in the figure below, this is a slot function using the format specified by Qt. Format: on_objectname_clicked()

3.2 Queue connection

When connect connects to the signal slot, when we use Qt::QueuedConnection as the connection type, the slot function is executed by throwing the QMetaCallEvent event, and the asynchronous effect is achieved through the Qt event loop.

As shown in the figure below, it is the callback stack of the slot function when the queue connection is used:

The following code is taken from the Qt source code. The queued_activate function is a function for processing queue requests. When we use automatic connection and the receiver and sender are not in the same thread, we use the queue connection; or when we specify the connection method as the queue, we use the queue connection.

// determine if this connection should be sent immediately or
// put into the event queue
if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
    || (c->connectionType == Qt::QueuedConnection)) {
    queued_activate(sender, signal_index, c, argv ? argv : empty_argv, locker);
    continue;

4. Summary

The realization principle of Qt signal slot is actually function callback. The difference is that direct connection direct callback and queue connection use Qt's event loop to isolate the asynchronous one time, and finally use function callback.

Through the above overview, we summarize as follows:

1) moc precompilation helps us construct the beginning (signal function body) and end (qt_static_metacall callback function) of the signal slot callback, the middle callback process Qt has been implemented in the QOjbect function;

2) signals and slots are for the convenience of moc to parse our C++ files, and parse out signals and slots from them;

3) There are a total of 5 connection modes for signal slots. The first four are mutually exclusive and can be expressed as asynchronous and synchronous. The fifth only connection is used in conjunction with the first 4 methods;

4) The signal and the slot are essentially the same, but for the user, the signal only needs to be declared, moc will help you realize it, and the slot function declaration and implementation need to be written by yourself;

5) The connect method is to store the sender, signal, receiver and slot for subsequent search when the signal is executed;

6) Signal trigger is a series of function callbacks;

Guess you like

Origin blog.csdn.net/www_dong/article/details/114907797