Pyqt Signals And Slots Across Threads
Graphical applications (GUI) are event-driven, unlike console or terminal applications. A users action like clicks a button or selecting an item in a list is called an event.
PyQt5 signals and slots Graphical applications (GUI) are event-driven, unlike console or terminal applications. A users action like clicks a button or selecting an item in a list is called an event. If an event takes place, each PyQt5 widget can emit a signal. The receivers of signals are called Slots in Qt terminology. A number of standard slots are provided on Qt classes to allow you to wire together different parts of your application. However, you can also use any Python function as a slot, and therefore receive the message yourself. In this example I can show you how you can implement a custom signal (MySignal) together with the usage of threads with QThread. The following code creates a window with two buttons: the first starts and stop a thread (MyThread) that runs a batch that prints a point in the stdout every seconds continuously.
If an event takes place, each PyQt5 widget can emit a signal. A signal does not execute any action, that is done by a slot.
Signals and Slots. PySide and PyQt are Python bindings to the Qt GUI and application framework. One killer feature of Qt is the signal & slot system, which is a way for widgets and objects to communicate events to one another. An object in Qt can send a signal to other subscribed objects. Signals are used to inform other objects that an event.
Related course:
Create GUI Apps with PyQt5
Signals and slot introduction
Consider this example:
The button click (signal) is connected to the action (slot). In this example, the method slot_method will be called if the signal emits.
This principle of connecting slots methods or function to a widget, applies to all widgets,
or we can explicitly define the signal:
PyQt supports many type of signals, not just clicks.
Example
We can create a method (slot) that is connected to a widget. A slot is any callable function or method.
On running the application, we can click the button to execute the action (slot).
If you are new to programming Python PyQt, I highly recommend this book.
If your program has long running computations running in other threads orprocesses, you can use qtbot.waitSignal
to block a test until a signal is emitted (such as QThread.finished
) or atimeout is reached. This makes it easy to write tests that wait until acomputation running in another thread or process is completed beforeensuring the results are correct:
raising parameter¶
Changed in version 2.0.
You can pass raising=False
to avoid raising aqtbot.TimeoutError
if the timeout isreached before the signal is triggered:
qt_default_raising ini option¶
Changed in version 2.0.
The qt_default_raising
ini option can be used to override the defaultvalue of the raising
parameter of the qtbot.waitSignal
andqtbot.waitSignals
functions when omitted:
Calls which explicitly pass the raising
parameter are not affected.
This option was called qt_wait_signal_raising
before 3.1.0.
Pyqt Signals And Slots Across Threads Game
check_params_cb parameter¶
If the signal has parameters you want to compare with expected values, you can passcheck_params_cb=some_callable
that compares the provided signal parameters to some expected parameters.It has to match the signature of signal
(just like a slot function would) and return True
ifparameters match, False
otherwise.
timeout parameter¶
The timeout
parameter specifies how long waitSignal
should wait for asignal to arrive. If the timeout is None
, there won’t be any timeout, i.e.it’ll wait indefinitely.
If the timeout is set to 0
, it’s expected that the signal arrives directlyin the code inside the withqtbot.waitSignal(...):
block.
Pyqt Signals And Slots Across Threads Free
Getting arguments of the emitted signal¶
The arguments emitted with the signal are available as the args
attributeof the blocker:
Signals without arguments will set args
to an empty list. If the time outis reached instead, args
will be None
.
Getting all arguments of non-matching arguments¶
When using the check_params_cb
parameter, it may happen that the provided signal is received multiple times withdifferent parameter values, which may or may not match the requirements of the callback.all_args
then contains the list of signal parameters (as tuple) in the order they were received.
waitSignals¶
If you have to wait until all signals in a list are triggered, useqtbot.waitSignals
, which receivesa list of signals instead of a single signal. As withqtbot.waitSignal
, it also supportsthe raising
parameter:
check_params_cbs parameter¶
Corresponding to the check_params_cb
parameter of waitSignal
you can use the check_params_cbs
parameter to check whether one or more of the provided signals are emitted with expected parameters.Provide a list of callables, each matching the signature of the corresponding signalin signals
(just like a slot function would). Like for waitSignal
, each callable has toreturn True
if parameters match, False
otherwise.Instead of a specific callable, None
can be provided, to disable parameter checking for thecorresponding signal.If the number of callbacks doesn’t match the number of signals ValueError
will be raised.
The following example shows that the app.worker.status
signal has to be emitted with values 50 and100, and the app.worker.finished
signal has to be emitted too (for which no signal parameterevaluation takes place).
order parameter¶
By default a test using qtbot.waitSignals
completes successfully if all signals in signals
are emitted, irrespective of their exact order. The order
parameter can be set to 'strict'
to enforce strict signal order.Exemplary, this means that blocker.signal_triggered
will be False
if waitSignals
expectsthe signals [a,b]
but the sender emitted signals [a,a,b]
.
Note
The tested component can still emit signals unknown to the blocker. E.g.blocker.waitSignals([a,b],raising=True,order='strict')
won’t raise if the signal-senderemits signals [a,c,b]
, as c
is not part of the observed signals.
A third option is to set order='simple'
which is like “strict”, but signals may be emittedin-between the provided ones, e.g. if the expected signals are [a,b,c]
and the senderactually emits [a,a,b,a,c]
, the test completes successfully (it would fail with order='strict'
).
Getting emitted signals and arguments¶
To determine which of the expected signals were emitted during a wait()
you can useblocker.all_signals_and_args
which contains a list ofwait_signal.SignalAndArgs
objects, indicating the signals (and their arguments)in the order they were received.
Pyqt Signals And Slots Across Threads Onto
Making sure a given signal is not emitted¶
If you want to ensure a signal is not emitted in a given block of code, usethe qtbot.assertNotEmitted
context manager:
By default, this only catches signals emitted directly inside the block.You can pass wait=...
to wait for a given duration (in milliseconds) forasynchronous signals to (not) arrive: