Qt Signal Slot Mapper

This blog is part of a series of blogs explaining the internals of signals and slots.

  1. Qt Signal Slot Mapper Usb
  2. Qt Signal Slot Mapper Software
  3. Qt Signal Slot Mapper App
  4. Qt Signal Slot Mapper Tool
  5. Qt Signal Slot Mapper Online

In this article, we will explore the mechanisms powering the Qt queued connections.

I have been trying to implement signal mapper. I have used the example code below. But, this example code from 4.8 doesn't have SLOT getting signal from 'mapped'. So, I added my own SLOT(doThings(int)). But signal mapper doesn't send any signal to the slot. Any help would be really appreciated. ./ #ifndef MYCLASSH #define MYCLASSH #include #include class MyClass: public QObject QOBJECT public: MyClass( const QString &text, QObject.parent = 0 ); const QString& text const; int getLengthOfText const; public slots: void setText( const QString &text ); signals: void textChanged( const QString& ); private. 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.

Summary from Part 1

In the first part, we saw that signalsare just simple functions, whose body is generated by moc. They are just calling QMetaObject::activate, with an array of pointers to arguments on the stack.Here is the code of a signal, as generated by moc: (from part 1)

QMetaObject::activatewill then look in internal data structures to find out what are the slots connected to that signal.As seen in part 1, for each slot, the following code will be executed:

So in this blog post we will see what exactly happens in queued_activateand other parts that were skipped for the BlockingQueuedConnection

Qt Event Loop

A QueuedConnection will post an event to the event loop to eventually be handled.

When posting an event (in QCoreApplication::postEvent),the event will be pushed in a per-thread queue(QThreadData::postEventList).The event queued is protected by a mutex, so there is no race conditions when threadspush events to another thread's event queue.

Once the event has been added to the queue, and if the receiver is living in another thread,we notify the event dispatcher of that thread by calling QAbstractEventDispatcher::wakeUp.This will wake up the dispatcher if it was sleeping while waiting for more events.If the receiver is in the same thread, the event will be processed later, as the event loop iterates.

The event will be deleted right after being processed in the thread that processes it.

An event posted using a QueuedConnection is a QMetaCallEvent. When processed, that event will call the slot the same way we call them for direct connections.All the information (slot to call, parameter values, ...) are stored inside the event.

Copying the parameters

The argv coming from the signal is an array of pointers to the arguments. The problem is that these pointers point to the stack of the signal where the arguments are. Once the signal returns, they will not be valid anymore. So we'll have to copy the parameter values of the function on the heap. In order to do that, we just ask QMetaType. We have seen in the QMetaType article that QMetaType::create has the ability to copy any type knowing it's QMetaType ID and a pointer to the type.

To know the QMetaType ID of a particular parameter, we will look in the QMetaObject, which contains the name of all the types. We will then be able to look up the particular type in the QMetaType database.

queued_activate

We can now put it all together and read through the code ofqueued_activate, which is called by QMetaObject::activate to prepare a Qt::QueuedConnection slot call.The code showed here has been slightly simplified and commented:

Upon reception of this event, QObject::event will set the sender and call QMetaCallEvent::placeMetaCall. That later function will dispatch just the same way asQMetaObject::activate would do it for direct connections, as seen in Part 1

Qt signal slot mapper download

BlockingQueuedConnection

BlockingQueuedConnection is a mix between DirectConnection and QueuedConnection. Like with aDirectConnection, the arguments can stay on the stack since the stack is on the thread thatis blocked. No need to copy the arguments.Like with a QueuedConnection, an event is posted to the other thread's event loop. The event also containsa pointer to a QSemaphore. The thread that delivers the event will release thesemaphore right after the slot has been called. Meanwhile, the thread that called the signal will acquirethe semaphore in order to wait until the event is processed.

It is the destructor of QMetaCallEvent which will release the semaphore. This is good becausethe event will be deleted right after it is delivered (i.e. the slot has been called) but also whenthe event is not delivered (e.g. because the receiving object was deleted).

A BlockingQueuedConnection can be useful to do thread communication when you want to invoke afunction in another thread and wait for the answer before it is finished. However, it must be donewith care.

The dangers of BlockingQueuedConnection

You must be careful in order to avoid deadlocks.

Obviously, if you connect two objects using BlockingQueuedConnection living on the same thread,you will deadlock immediately. You are sending an event to the sender's own thread and then are locking thethread waiting for the event to be processed. Since the thread is blocked, the event will never beprocessed and the thread will be blocked forever. Qt detects this at run time and prints a warning,but does not attempt to fix the problem for you.It has been suggested that Qt could then just do a normal DirectConnection if both objects are inthe same thread. But we choose not to because BlockingQueuedConnection is something that can only beused if you know what you are doing: You must know from which thread to what other thread theevent will be sent.

The real danger is that you must keep your design such that if in your application, you do aBlockingQueuedConnection from thread A to thread B, thread B must never wait for thread A, or you willhave a deadlock again.

When emitting the signal or calling QMetaObject::invokeMethod(), you must not have any mutex lockedthat thread B might also try locking.

A problem will typically appear when you need to terminate a thread using a BlockingQueuedConnection, for example in thispseudo code:

You cannot just call wait here because the child thread might have already emitted, or is about to emitthe signal that will wait for the parent thread, which won't go back to its event loop. All the thread cleanup information transfer must only happen withevents posted between threads, without using wait(). A better way to do it would be:

The downside is that MyOperation::cleanup() is now called asynchronously, which may complicate the design.

Conclusion

This article should conclude the series. I hope these articles have demystified signals and slots,and that knowing a bit how this works under the hood will help you make better use of them in yourapplications.

The QSignalMapper class bundles signals from identifiable senders. More...

Mapper

Public Functions

QSignalMapper(QObject * parent = 0)
~QSignalMapper()
QObject * mapping(int id) const
QObject * mapping(const QString & id) const
QObject * mapping(QWidget * widget) const
QObject * mapping(QObject * object) const
void removeMappings(QObject * sender)
void setMapping(QObject * sender, int id)
void setMapping(QObject * sender, const QString & text)
void setMapping(QObject * sender, QWidget * widget)
void setMapping(QObject * sender, QObject * object)
  • 29 public functions inherited from QObject

Public Slots

  • 1 public slot inherited from QObject

Signals

void mapped(int i)
void mapped(const QString & text)
void mapped(QWidget * widget)
void mapped(QObject * object)
  • 1 signal inherited from QObject

Additional Inherited Members

  • 1 property inherited from QObject
  • 7 static public members inherited from QObject
  • 8 protected functions inherited from QObject

Detailed Description

The QSignalMapper class bundles signals from identifiable senders.

This class collects a set of parameterless signals, and re-emits them with integer, string or widget parameters corresponding to the object that sent the signal.

The class supports the mapping of particular strings or integers with particular objects using setMapping(). The objects' signals can then be connected to the map() slot which will emit the mapped() signal with the string or integer associated with the original signalling object. Mappings can be removed later using removeMappings().

Example: Suppose we want to create a custom widget that contains a group of buttons (like a tool palette). One approach is to connect each button's clicked() signal to its own custom slot; but in this example we want to connect all the buttons to a single slot and parameterize the slot by the button that was clicked.

Here's the definition of a simple custom widget that has a single signal, clicked(), which is emitted with the text of the button that was clicked:

The only function that we need to implement is the constructor:

A list of texts is passed to the constructor. A signal mapper is constructed and for each text in the list a QPushButton is created. We connect each button's clicked() signal to the signal mapper's map() slot, and create a mapping in the signal mapper from each button to the button's text. Finally we connect the signal mapper's mapped() signal to the custom widget's clicked() signal. When the user clicks a button, the custom widget will emit a single clicked() signal whose argument is the text of the button the user clicked.

See also QObject, QButtonGroup, and QActionGroup.

Member Function Documentation

QSignalMapper::QSignalMapper(QObject * parent = 0)

Constructs a QSignalMapper with parent parent.

QSignalMapper::~QSignalMapper()

Destroys the QSignalMapper.

[slot] void QSignalMapper::map()

Qt Signal Slot Mapper Usb

This slot emits signals based on which object sends signals to it.

[slot] void QSignalMapper::map(QObject * sender)

This slot emits signals based on the sender object.

[signal] void QSignalMapper::mapped(int i)

This signal is emitted when map() is signalled from an object that has an integer mapping set. The object's mapped integer is passed in i.

Note:Signal mapped is overloaded in this class. To connect to this one using the function pointer syntax, you must specify the signal type in a static cast, as shown in this example:

See also setMapping().

[signal] void QSignalMapper::mapped(const QString & text)

This signal is emitted when map() is signalled from an object that has a string mapping set. The object's mapped string is passed in text.

Note:Signal mapped is overloaded in this class. To connect to this one using the function pointer syntax, you must specify the signal type in a static cast, as shown in this example:

See also setMapping().

[signal] void QSignalMapper::mapped(QWidget * widget)

This signal is emitted when map() is signalled from an object that has a widget mapping set. The object's mapped widget is passed in widget.

Note:Signal mapped is overloaded in this class. To connect to this one using the function pointer syntax, you must specify the signal type in a static cast, as shown in this example:

See also setMapping().

[signal] void QSignalMapper::mapped(QObject * object)

Qt Signal Slot Mapper Software

This signal is emitted when map() is signalled from an object that has an object mapping set. The object provided by the map is passed in object.

Note:Signal mapped is overloaded in this class. To connect to this one using the function pointer syntax, you must specify the signal type in a static cast, as shown in this example:

See also setMapping().

QObject * QSignalMapper::mapping(int id) const

Returns the sender QObject that is associated with the id.

See also setMapping().

QObject * QSignalMapper::mapping(const QString & id) const

This function overloads mapping().

QObject * QSignalMapper::mapping(QWidget * widget) const

This function overloads mapping().

Returns the sender QObject that is associated with the widget.

QObject * QSignalMapper::mapping(QObject * object) const

This function overloads mapping().

Returns the sender QObject that is associated with the object.

void QSignalMapper::removeMappings(QObject * sender)

Removes all mappings for sender.

This is done automatically when mapped objects are destroyed.

Qt signal slot mapper usb

void QSignalMapper::setMapping(QObject * sender, int id)

Adds a mapping so that when map() is signalled from the given sender, the signal mapped(id) is emitted.

There may be at most one integer ID for each sender.

See also mapping().

void QSignalMapper::setMapping(QObject * sender, const QString & text)

Adds a mapping so that when map() is signalled from the sender, the signal mapped(text ) is emitted.

There may be at most one text for each sender.

void QSignalMapper::setMapping(QObject * sender, QWidget * widget)

Qt Signal Slot Mapper App

Adds a mapping so that when map() is signalled from the sender, the signal mapped(widget ) is emitted.

There may be at most one widget for each sender.

void QSignalMapper::setMapping(QObject * sender, QObject * object)

Qt Signal Slot Mapper Tool

Adds a mapping so that when map() is signalled from the sender, the signal mapped(object ) is emitted.

There may be at most one object for each sender.

Qt Signal Slot Mapper Online

© 2016 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.