Qt Events and Signal/Slots

Qt events and signal/slots

The Qt documentation probably explains it best:

In Qt, events are objects, derived
from the abstract QEvent class, that
represent things that have happened
either within an application or as a
result of outside activity that the
application needs to know about.
Events can be received and handled by
any instance of a QObject subclass,
but they are especially relevant to
widgets. This document describes how
events are delivered and handled in a
typical application.

So events and signal/slots are two parallel mechanisms accomplishing the same things. In general, an event will be generated by an outside entity (for example, keyboard or mouse wheel) and will be delivered through the event loop in QApplication. In general, unless you set up the code, you will not be generating events. You might filter them through QObject::installEventFilter() or handle events in subclassed object by overriding the appropriate functions.

Signals and Slots are much easier to generate and receive and you can connect any two QObject subclasses. They are handled through the Metaclass (have a look at your moc_classname.cpp file for more), but most of the interclass communication that you will produce will probably use signals and slots. Signals can get delivered immediately or deferred via a queue (if you are using threads).

A signal can be generated.

Event loops and signal-slot processing when using multithreading in Qt

All results you got are perfectly correct. I'll try to explain how this works.

An event loop is an internal loop in Qt code that processes system and user events. Event loop of main thread is started when you call a.exec(). Event loop of another thread is started by default implementation of QThread::run.

When Qt decides it's time to process an event, it executes its event handler. While event handler is working, Qt has no chance to process any other event (unless given directly by QApplication::processEvents() or some other methods). Once the event handler is finished, control flow returns to the event loop and Qt may execute another handler to process another event.

Signals and slots are not the same as events and event handlers in Qt terminology. But slots are handled by event loops somewhat similarily. If you have control flow in your code(such as in main function) you can execute any slot immediately just as any other C++ function. But when Qt does that it can only do that from an event loop. It should be noted that signals are always sent immediately, while slot execution may be delayed.

Now let's see what happens in each case.

Case 1

WorkerManager::process is executed directly at the program start. New thread is started and Worker::process is executed immediately in the new thread. WorkerManager::process continues execution until Worker is done, freezing all other actions (including slot processing) in main thread. After WorkerManager::process is finished, control flow goes to QApplication::exec. Qt establishes connection to the other thread, receives messages about slot invokation and invokes all of them consequently.

Case 2

Qt by default executes slots of an object in the thread this object belongs to. Main thread will not execute slots of WorkerManager because it belongs to another thread. However this thread is never started. Its event loop is never finished. Invokations of slot1 and slot2 are left forever in Qt's queue waiting for you to start the thread. Sad story.

Case 3

In this case WorkerManager::process is executed in main thread because you invoke it directly from main thread. Meanwhile, WorkerManager's thread is started. Its event loop is launched and waiting for events. WorkerManager::process starts Worker's thread and executes Worker::exec in it. Worker starts sending signals to WorkerManager. WorkerManager's thread almost immediately starts to execute appropriate slots. At this point it seems awkward that WorkerManager::slot2 and WorkerManager::process are executed simultaneously. But it's perfectly fine, at least if WorkerManager is thread-safe. Shortly after Worker is done, WorkerManager::process is finished and a.exec() is executed but has not much to process.

Case 4

Main function just launches WorkerManager's thread and immediately goes to a.exec(), resulting in end as first line in the output. a.exec() processes something and ensures program execution but doesn't execute WorkerManager's slots because it belongs to another thread. WorkerManager::process is executed in WorkerManager's thread from its event loop. Worker's thread is started and Worker::process starts sending signals from Worker's thread to WorkerManager's thread. Unfortunately the latter is busy executing WorkerManager::process. When Worker is done, WorkerManager::process also finishes and WorkerManager's thread immediately executes all queued slots.

The largest problem in your code is usleep and infinite loops. You should almost never use those when working with Qt. I understand that a sleep in Worker::process is just a placeholder for some real calculation. But you should remove sleep and infinite loop from WorkerManager. Use WorkerManager::slot1 to detect Worker's termination. If you develop a GUI application there would be no need to move WorkerManager to another thread. All its methods (without sleep) will be executed fast and will not freeze the GUI.

An event system - like signal / slot in Qt without forking - C++

At a high level, Qt's signal/slots and boost's signal library work like the Observer Pattern (they just avoid needing an Observer base class).

Each "signal" keeps track of what "slots" are observing it, and then iterates over all of them when the signal is emitted.

As for how to specifically implement this, the C++ is pretty similar to the Java code in the Wikipedia article. If you want to avoid using an interface for all observers, boost uses templates and Qt uses macros and a special pre-compiler (called moc).

How do I correctly use the signal/slot system from qt

The macros SIGNAL and SLOT work based on textual comparison of names, and are thus sensitive to correct qualification. The signal/slot name must never be qualified, and any types must be qualified exactly the same as they were in their declaration. So change your code to this:

connect(ui->scrollArea, SIGNAL(sizeChanged(int,int)), ui->scrollAreaWidgetContents, SLOT(setSize(int,int)));


Related Topics



Leave a reply



Submit