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.

Signals and slots is a language construct introduced in Qt for communication between objects which makes it easy to implement the observer pattern while avoiding boilerplate code.The concept is that GUI widgets can send signals containing event information which can be received by other widgets / controls using special functions known as slots. This is similar to C/C function pointers, but.

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.

For any C developer who's used Qt, we've grown to love the Signals/Slots idiom it presents for creating clean Observer code. However, it relied on the Qt Moc pre-compiler tool, which meant any project that wanted to use this feature had to use follow along with the Qt idiom, which really made Qt applications look potentially foreign despite being written in C. Free Spins: Available after deposit bonus is redeemed/lost, credited as Qt Signals And Slots Thread Safe £2 bonus. MONOPOLY Live only. 1x wagering and Max bonus bet of £5 applies to winnings, 7 days to accept & Qt Signals And Slots Thread Safe 7 days to complete wagering, maximum withdrawal from winnings is £200. Qt - SigSlot - Boost Libraries Qt was the original signal/slots implementation, but it Sigslot and Boost on the other hand are pure ISO C, but both have some disadvantages. None of these are thread-safe and it can be somewhat inconvenient manually Qt documentation states that signals and slots can be direct, queued and auto.

  • 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:
// MainWindow.h

// MainWindow.cpp

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:

analysis:

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 Signals And Slots Thread Safety

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:

Let’s see that the static metaobject above is a variable of type qmetaobject, where qmetaobject is assigned a value:

Qt Signals And Slots Thread Safe
  • 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).
Qt Signals And Slots Thread Safe

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:

analysis:

  • 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:

Qt Signal Slot Not Working

  • 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;

Qt Signals And Slots Thread Safe

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.

1、https://woboq.com/blog/how-qt…

2. Qt5.7 source code

Working

3. The signal and slot demo implemented in C + + http://note.youdao.com/notesh…

Meeting C++

published at 20.08.2015 15:28 by Jens Weller

This is the 7th blog post in my series about writing applications with C++ using Qt and boost. This time it is about how to notify one part of our application that something has happened somewhere else. I will start with Qt, as it brings with signals and slots a mechanism to do exactly that. But, as I have the goal not to use Qt mainly in the UI Layer, I will also look on how to notify other parts of the application, when things are changing. The last episode was about QWidgets and data.

The video for this episode:

Signals and Events in Qt

Qt Signal Thread

But lets start with Qt. Qt offers two different systems for our needs, Qt signal/slot and QEvents. While Qt signal/slot is the moc driven signaling system of Qt (which you can connect to via QObject::connect), there is a second Event interface informing you about certain system-like events, such as QMouseEvent, QKeyEvent or QFocusEvent. Usually you have to overwrite a method to receive such events, or use an event filter, like I showed in my last post for QFocusEvents. Some classes translate QEvents to signals, such as the TreeView, which has a signal for displaying context menus. But as this blog post is more on signaling then system events...

Qt has had its own signaling mechanism for a long time now, so when you use Qt, you also will use QSignals. Qt also uses its own keywords for this: signals, slots and emit. There is an option to turn this of, and use the macros Q_SIGNAL/S,Q_SLOT/S and Q_EMIT instead: CONFIG += no_keywords. This allows to use 3rd party libraries which use these terms, e.g. boost::signal. Qt signal/slot implementation is thread safe, so that you can use it to send messages between different QThreads, this is especially important, as anything UI related should run in the main thread of Qt, anything that could block your UI should not run in this thread, so running jobs in a QThreadPool and emitting the finished result as a signal is a common pattern. Maybe I will touch this in a later post...

For now, lets see the basics of using signals and slots in Qt. This is the code from my MainWindow class constructor, connecting several signals to slots:

So, the traditional, moc driven connect method is QObject* derived sender, the SIGNAL macro defining the signal to connect to, followed by the QObject* derived receiver, then SLOT(...) is the last argument, naming the slot to connect to. There is a fifth defaultet parameter: the ConnectionType. The last line contains the new, lambda based connection option, where you again have the sender and its slot, this time as a method-pointer, and then followed by a lambda acting as the receiving slot.

This syntax can lead to a rare error, when ever a signal is overloaded, like QComboBox::currentIndexChanged, which is available with an int or QString parameter. Then you'll need an ugly static_cast to tell the compiler which version you'd like:

In this case I didn't even needed the argument from the slot. It is fairly easy to use your own signals and slots, all you need is a QObject derived class, which is processed by the moc. Mostly of course you already have classes derived from QObject indirectly, which then use signals and slots, like the page panel class:

So, slots and signals are normal member functions, declared after the qt-specific keyword signals/slots. When you want to emit a signal, its enough to just write 'emit my_signal();', and all observers on this signal will get notified. Slots are often used to react to certain events in the UI, like the currentIndexChanged signal in this case. In the widget editor of QtCreator you get an overview of available signals when right clicking and selecting 'go to slot...', this will create a slot for this signal in your QWidget derived class.

There is also the option to map certain widgets to certain values when a signal fires, this is done via QSignalMapper. I use this in a different program to have one widget for editing flag like settings, where each flag is a bit in a settings value:

The constructor only takes a QStringList for the option names, and an int for how many columns of check boxes the current use case should have. The QSignalMapper is a member variable, and each QCheckBox connects its clicked signal to the map() slot of QSignalMapper. With setMapping the connection between the sender and the value is set up. QSignalMapper offers int, QObject*, QWidget* and QString as mapping values. QVariant or a generic interface is not provided by Qt. In the clicked slot I simply toggle the bit for the corresponding flag.

When working in Qt, most of it types provide support for signals and slots through deriving from QObject, which offers connect/disconnect methods to manage your slot connections. This brings again the disadvantages of QObject and the moc, as templates can't be used in this context, all classes using signal/slot must be concrete classes. Deriving your classes from templates (CRTP e.g.) can help here to mix in a generic layer.

While Qt is fairly well prepared to manage its own messaging needs, what alternatives exist, that could be used in the non Qt related code? The C++ standard offers currently only std::function, which can be used to implement a callback mechanism. But this has its limitations, of a 1:1 or 1:many connection this is a viable option. I use it to notify my MainWindow class that a node in the tree has changed its name. Also its useful to implement classes which execute a callback in a certain context, like EventFilter in the last blog post in this series. But std::function is not an implementation of the observer pattern, and implementing your own with it would be reinventing the wheel. Boost has had for a long time a signal library, which now is available as version 2: boost::signals2.

Using boost::signals2

Honestly, if I could avoid using signals2, I would, as it has one certain disadvantage: build times increase. So far my project is kind of small, has only a few classes, which most of are less then 100 loc. Adding boost::signals2 to a class makes it hard to build a project quickly for debugging or just seeing if the work of the past hour still compiles.

The need for signals2 came in my application, when I began to understand, that there are some events, which go from the Qt layer into the boost/standard C++ layer, and then need to travel back into the Qt layer. Each Page has a shared_ptr to a layout object, which is part of a LayoutItem holding the list of layouts for a document. There is one LayoutPanel to edit, create and delete layouts in LayoutItem, and each PagePanel has a QComboBox, so that the user can select the layout for the page. Now, when a user creates/renames a layout, each PagePanel needs to be notified, but when it gets deleted, also page needs to change. This could be implemented in the Qt layer, each Qt class involved has access to the boost/C++ layer, and can make the necessary changes. But then, this important business logic of removing a layout will only work through the UI. When I use boost::signals2, it can be done in the boost/standard C++ layer.

boost::signals2 has a signal template, which has the signature as the argument, this signal type also then has the typedef for the slot type, signal::connect returns a connection object:

When ever an object subscribes to the layout signals, it must to so for all three, the vector should invoke RVO. Currently, PagePanel is the only subscriber, it simply connects to the signals using boost::bind:

Qt Signals And Slots Thread Safe

One detail here is, that I do use scoped_connection, which will call disconnect() on its destruction, while the default boost::signals2::connection class does not. scoped_connection can be moved, but not copied. But once it is in the vector, it will stay there. Also, you should forward declare the connection classes, so that you don't have to include the boost/signals2.hpp headers, this prevents leaking into other sources.

But boost::signals2 can do far more. I have no use for code that depends on the order of slots called, but you can specify this with signal::contect(int group, slot):

In some context it is interesting to handle the return value of a signal, for this boost::signal2 offers a combiner, which is the second template parameter to signal: signal<float(float,float), aggregate_combiner<std::vector<float> > >. This combiner then also overwrites the return value of the signal, which is now std::vector instead of float. Another feature is that you can block a connection with shared_connection_block.

boost::signal2 is currently header only, thread safe and offers a few more customization points, for example you can change the mutex, but also the signature type, which currently is boost::function.

Qt Signal And Slots

Alternatives to boost::signals2

If you know very well what you are doing, you could use boost::signal instead of its new version, signals2. This might improve your compile times, but boost::signals is not any more maintained. Also, while signals2 is header-only, signals is not. The thread safety is a key feature of signals2, which at some time sooner or later will come into play in your code base. I don't want to introduce a 3rd party library into my project just to have signaling/observer pattern, but you should know, that there are a few alternatives (I googled that too):

  • libsigslot
    • has open bugs from 2003 - 2011, memory leaks and other issues. But seems to do the job.
  • libsigc++
    • a standard C++ implementation, inspired by Qt, you (might) have to derive your objects from a base class. Virtual function calls are the base of this library it seems, at least for method slots, which the call has to be derived from sigc::trackable.
    • gtkmm and glibmm seem to use this for their signaling needs.
    • the 5 open bugs seem to be feature requests mostly (and nil is a keyword in Object-C, well...)
    • the library has been rewritten using modern C++ idioms (claims the site)
  • This codeproject article from 2005 gives some insights, but C++11 changes some of them I think.
  • slimsig
    • seems to be a header only alternative to boost::signals2
    • 2 open bugs, no change in one year
  • boost::synapse
    • this library is proposed for boost, but has not yet been reviewed.
    • I think it could be a more lightweight alternative to signals2
    • Currently its not threadsafe.

Qt Signals And Slots Thread Safety

The only disadvantage of boost::signal2 is really its impact on compile and link time, which can be reduced through pimple and other isolation techniques, so that a recompilation is only triggered when really needed. One idea which came in my mind during this blog post is a std_signal2 header, which replaces the boost types (function, mutex etc.) with the corresponding std types. I'm not sure how this would work out, but boost::signals2 seems to be pretty well build to do this, a lot of template parameters have default values which then configure the library, and are hidden from the day to day usage.

Qt Signals And Slots Tutorial

Join the Meeting C++ patreon community!
This and other posts on Meeting C++ are enabled by my supporters on patreon!

Copyright Meetingcpp GmbH 2020 ImprintPiwik Opt outPrivacy Policy