Qt Signal Slot Connection Type
QtCore.SIGNAL and QtCore.SLOT macros allow Python to interface with Qt signal and slot delivery mechanisms. This is the old way of using signals and slots. The example below uses the well known clicked signal from a QPushButton. The connect method has a non python-friendly syntax. It is necessary to inform the object, its signal (via macro) and a slot to be connected to. Qt::AutoConnection: 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: This slot is invoked immediately when the signal is emitted. The slot is executed in the signaling thread. Type: Bug Status: Open. Affects Version/s: Qt Creator 4. Currently the only way to still get code completion for the macro-based SIGNAL and SLOT connection.
A new version of the qt-signal-tools library for connecting signals to arbitrary functions is available.
Changes in this release:
- Compatibility with earlier versions of Qt 4. The previous release required Qt 4.8. The current version works with Qt 4.6 and up and possibly older releases as well.
- Compatibility with Qt 5. Though the functionality of QtSignalForwarder can be mostly achieved in Qt 5 using the new signal/slot syntax, this may be useful for creating code which can work with either version or for porting.
- Performance improvements.
- QtSignalForwarder::connectWithSender()utility, this provides a convenient way to connect a signal to a slot which includes the sender as the first argument. eg. connectWithSender(button, SIGNAL(clicked()), form, SLOT(buttonClicked(QPushButton*)))
The performance improvements come from changing the way that the hidden proxy object which forwards the signal determines where the signal came from. The previous implementation worked in the same way as QSignalMapper by using QObject::sender() and QObject::senderSignalIndex() to determine which signal the proxy was handling. These two functions have some overhead though. Both not only lock a mutex but there is also a linear slowdown as the number of senders connected to a given receiver increases. The previous version of QtSignalForwarder therefore created a new proxy object for each sender.
So I looked for an alternative way to identify the caller of the slot. When a signal -> slot connection is established, Qt internally maps the arguments to the SIGNAL() and SLOT() macros to integer method IDs. The details of the connection, including the receiver, connection type and method IDs of the signal/slot are then stored in a connection object and added to a list maintained by the sender. When a signal is emitted, Qt invokes the qt_metacall()function provided by the receiver’s QMetaObject and passes in the kind of action to perform (property read, property write, method call), a method/property ID and a list of arguments. This function then forwards the arguments to actual signal/slot method corresponding to the method ID.
The method IDs are normally assigned by moc when it processes a header file and generates the QMetaObject object that is used for all of Qt’s introspection features. However, it is possible to specify the method IDs directly when creating a connection by using QMetaObject::connect(sender, signalMethodId, receiver, receiverMethodId…). I’m now abusing the receiver method ID by assigning a new ID to each connection. A caveat is that internally method IDs are stored as 16-bit unsigned integers to save space, since a single QObject-based class would normally have tens of methods at most. This means there is an upper limit of ~65K unique tags that can be used to identify the connection being invoked.
After removing the use of sender() and senderSignalIndex() in QtSignalForwarder the same proxy object can be re-used for a larger number of senders/receivers. A caveat is that we now have to be more careful about how this is used in the context of multiple threads. For now I’ve kept things simple by restricting the use of QtSignalForwarder::connect() to objects which live on the main application thread, which is not a problem for many practical purposes. When this does need to be used with an object that lives on a background thread, a new QtSignalForwarder instance can be created and the bind() function used directly.
Author: Cao Qun
Original text: https://mp.weixin.qq.com/s/Mp…
Welcome to the official account of the technical team of the school network.
QT is a cross platform C + + GUI application development framework developed by QT company in 1991. It can be used to develop GUI programs as well as non GUI programs, such as console tools and servers. QT is an object-oriented framework. With special code generation extensions (called meta object compiler) and some macros, QT is easy to extend and allows real component programming. QT is a cross platform development framework, supporting windows, Linux, MacOS and other different platforms; QT has a large number of development documents and rich API, which brings great convenience to developers; QT users are more and more, and many excellent products are developed based on QT, such as WPS offic, opera browser, QT creator, etc. The core mechanism of QT is the signal and slot. Next, we analyze the implementation principle through the source code.
- signalWhen an object changes its state, the signal is emitted by the object, and the object is only responsible for sending the signal, and it does not know who is receiving the signal on the other end.
- groove: used to receive signals, and slots are just ordinary object member functions. A slot does not know if there is any signal connected to it.
- Signal to slot connection: all classes derived from QObject or its subclasses, such as QWidget, can contain signals and slots. It is managed by static method: QObject:: connect (sender, signal (signal), receiver, slot (slot)); where sender and receiver are pointers to objects, and signal() and slot() are macros for converting signals and slots.
- 1. First of all, we set up a good environment, such as installing qt5.7 (including source code) + vs2013 and corresponding plug-ins on Windows system. We mainly compile and debug through vs.
- 2. We write a simple instance, build it, and copy the PDB of qtcore in the QT installation directory to our executable file directory, as shown in the following figure:
Here is the demo code we want to analyze:
We can create a QT project named demo, write the above code and build it. Under vs, we can import the QT project into a vs project, compile and generate it. The running results are as follows:
Click the middle button to see the console print the following information:
Step 1: basic structure:
When we analyze the code, we can see that in the header files test and MainWindow classes, there are Q_ For macro like object, we can see an additional MOC under the executable folder above_ MainWindow.cpp Of course, what we can’t do after we try to build the macro and the signal slot after we try to build the macro and the signal? Let’s take a look at this macro:
It turns out that this macro is some static and virtual methods. But if we add it to a class and do not implement it, it will definitely report an error. Why can it run normally? It turns out that QT helps us to do a lot of things. Before the compiler compiles the QT code, QT first translates the syntax of QT’s own extension. This operation is accomplished through MOC (meta object compiler), also known as “meta object compiler”. First, the MOC will analyze the source code, including Q_ The header file of object is generated as a C + + source file. The name of this file will be the source file name followed by MOC_ After that, it is processed by the compiler together with the original file. Then we think that the CPP at the beginning of MOC must implement the methods in the macro above and the assignment of data. Next, let’s look at the MOC_ MainWindow.cpp This document:
As we can see from the code above, it’s for Q_ The static data in object are assigned values, and those methods are implemented. These are generated by QT’s MOC compiler for us. The code is analyzed, and symbols are generated for signals and slots, as well as specific data structures. The following mainly records the reference count, size and offset of classes, signals and slots, which will be used later.
Through QT_ MOC_ After the macro literal is replaced, the following data is obtained:
Let’s take a look at QT below_ meta_ data_ MainWindow array structure: content has two columns. The first column is the total number, and the second column is the index describing the beginning of the array, such as 1, 14, / / methods, indicating that there is a method. We can see that slots start from index 14.
From the top source code, we can see that signal and slot are used to correlate signals and slots. What are the functions of these two macros? Let’s analyze:
From the above, we can see that these two are actually string concatenation macros, which will splice “2” in front of the signal, such as “2clean()”, and splice “1” in front of slots, such as “1onclean()”. Among them, qflaglocation mainly stores method in const char * locations [count] in flageddebugsignatures in qthreaddata; Table is used to locate the row information corresponding to the code.
Qt Signal Slot Connection Types
After precompiling, it is as follows:
Through the introduction of some basic macros and data structures above, we know that QT has done a lot of work for us, helped us generate MOC code, provided us with some macros, so that we can develop succinctly and conveniently. Then, how does QT associate signals with slots, that is, two different examples, and how to communicate through the signaling slot mechanism? Next, let’s look at the implementation principle of signal and slot correlation
The second step is the correlation between signal and slot
- 1. Check the string of signal and slot first, qsignal_ Code is 1; signal_ Code is 2.
- 2. Get metadata (the same for sender and receiver).
This method is our upper MOC_ MainWindow.cpp Medium.
According to debugging, we can see QObject:: D_ PTR > metaobject is empty, so smeta is the static metaobject variable above.
//First of all, we have to understand the definition of qmetaobject and qmetaobjectprivate
In QT, in order to achieve binary compatibility, a private class is generally defined. Qmetaobjectprivate is the private class of qmetaobject. Qmetaobject is responsible for some interface implementation, and qmetaobjectprivate is specifically implemented. These two classes are generally accessed by P pointer and D pointer. There is a macro:
Qt Signal Slot Connection Type
Let’s see that the static metaobject above is a variable of type qmetaobject, where qmetaobject is assigned a value:
- 1) & QWidget:: staticmetaobject → Superdata
- 2）qt_meta_stringdata_Test.data -> stringdata
- 3）qt_meta_stringdata_Test() -> data
- 4）qt_ static_ Metacall (callback function) → static_ metacall
Among them, qmetaobject is the external structure, and the connection method inside calls or implements the connect in qmetaobjectprivate. The D member in qmetaobject is filled with the static metaobject data above, while the member in qmetaobjectprivate is filled with QT_ meta_ stringdata_ For the data in the test array, we can see that the first 14 data are filled. This is also the reason why MOC takes 14 as the cardinal number when generating methoddata. The conversion method is as follows:
- 3. Get and save the signal parameters and names. As follows, save the signal parameters and return the method name.
- 4. Calculate indexes (including base classes).
The implementation is as follows:
Where int handle = priv (M > D.Data) → methoddata + 5i. We can analyze that, in fact, it is 14 + 5i. So why five? Because:
// signals: name, argc, parameters, tag, flags
1, 0, 24, 2, 0x06 / Public /,
// slots: name, argc, parameters, tag, flags
3, 0, 25, 2, 0x08 / Private /,
We can see that each signal or slot has five plastic representations.
- 5. Check the mask.
//Methodflags is an enumeration type. We can see that methodsignal = 0x04 and methodslot = 0x08;
// slots: name, argc, parameters, tag, flags
3, 0, 25, 2, 0x08 / Private /,
- 6. Judge the link type. The default is QT:: autoconnection.
We introduce some connection types:
- 1. Autoconnection: automatic connection: by default, the thread and bad object sent by the signal are equivalent to directconnection in one thread, and queuedconnection in different threads.
- 2. Directconnection: direct connection: it is equivalent to calling the slot function directly. However, when the signaled thread and the slot object are no longer the same thread, the slot function is executed in the issued signal.
- 3. Queuedconnection: queue connection: implemented internally through postevent. It is not called in real time, and the slot function is always executed in the thread where the slot function object is located. If the signal parameter is a reference type, a separate copy is made. Thread safe.
- 4. Blockingqueuedconnection: blocking connection: this connection method can only be used for the signaled thread and the object of the slot function. It can be used in a thread any more. It is implemented by semaphore + postevent, and is not called in real time. The slot function is always in the slot The function object is executed in the thread where the function object is located. However, the current thread will be blocked after the execution of the slot function is completed.
- 5. Uniqueconnection: prevents duplicate connections. If the current signal and slot are already connected, they are no longer connected.
Finally, it’s where the signal and slot are related to the core:
First, we need to understand the following data structures:
The above three data structures are very important. QObject is our most familiar base class, and qobjectprivate is its private class for specific implementation. Qobjectprivate inherits from qobjectdata and is accessed by P pointer and D pointer in the form of composition in QObject. In the process of signal and slot correlation, the data structure connection is a very important data structure. The following structure is a vector of the connectionlist:
With the above data structure, we can analyze the following link process. We can see that the following is the connection of the called qmetaobjectprivate, and then the pointer wrapping with qmetaobject:: Connection:
QObjectPrivate:: get (s) method is actually getting a QObjectPrivate instance in QObjec, then calling addConnection method to add to the linked list:
The structure is as follows:
- 1. Each QObject object has a QObject connectionlistvector structure, which is a vector container. The basic units in it are data of the connectionlist type. The number of connectionlists is the same as the number of signals of the QObject object. Each connectionlist corresponds to a signal, which records all connections connected to the signal. We have seen that there are two important members in the definition of connectionlist: first and last. They are both pointers of connection type, pointing to the first and last connection connected to this signal respectively. All connections connected to this signal are organized in a one-way linked list. The nextconnectionlist member in the connection structure is used to point to the next connection in the list.
- 2. At the same time, each QObject object also has a senders member. Senders is a pointer of connection type. Senders itself is the head node of a linked list. All nodes in the list are connected to a slot on the QObject object. However, the list mentioned in the following paragraph is not the same, although they may have some common nodes.
- 3. Each connection object is in two linked lists at the same time. One is a one-way linked list organized by nextconnectionlist members of connection. The common point of each node in this single list is that they all rely on the same signal of the same QObject object. The head node of this list is the first in the connectionlist structure corresponding to the signal; the other is organized by the next and prev members of connection Bidirectional linked list. The common feature of each node in this bi-directional linked list is that their slots are on the same QObject object, and the head node of the list is the sender of the QObject object. The two linked lists will have cross (common nodes), but they have different link pointers, so they are not the same list.
- 4. In connect, a new connection object is first created. After setting the connection information, it is added to the two linked lists mentioned above. When disconnecting, it is removed from the two linked lists and then deleted. When a QObject object is destroyed, all connections in the bidirectional linked list pointed to by its sender pointer will be removed one by one!
Step 3: send signal to receive signal
- 1, we click on the button above and then call it into the onDestory slot, which is where we write the signal trigger:
- 2. The next step is the MOC_ MainWindow.cpp The code inside calls the static method activate of qmetaobject
//Then go to the real qmetaobject:: activate
Our example is autocontion mode, so the following code will be executed for callback:
We finally see that the function calls back to the MOC_ MainWindow.cpp Inside, then call the corresponding slot onClean;
Finally, after calling here, print out: “MainWindow:: onclean”
Finally, after the call is finished, it will return to ondestory
Note: if we do the M_ Release operation of testwidget object (delete M_ Testwidget), and then to emit clean() in ondestory(); after accessing members, you must crash, so pay attention.
2. Qt5.7 source code
3. The signal and slot demo implemented in C + + http://note.youdao.com/notesh…