by admin

Qt Slot Function Thread

QtUtils provides convenience functions for accessing Qt objects in a thread safe way.Qt requires that all GUI objects exist in the MainThread and that access to these objects is only made from the MainThread (see Qt documentation).This, while understandable, imposes significant limits on Python applications where threading is easy.While there are solutions using Qt signals, slots and a QThread, these require significant boiler plate code that we believe is unnecessary.

In the function FunctionPointer::call, the args0 is meant to receive the return value of the slot. If the signal returns a value, it is a pointer to an object of the return type of the signal, else, it is 0. If the slot returns a value, we need to copy it in arg0. If it returns void, we do nothing. Qt provides the signals and slots framework which allows you to do just that and is thread-safe, allowing safe communication directly from running threads to your GUI frontend. Signals allow you to.emit values, which are then picked up elsewhere in your code by slot functions which have been linked with.connect. The slot is executed in the thread that emitted the signal (which is not necessarily the thread where the receiver object lives).With queued connections, the slot is invoked when control returns to the event loop of the thread to which the object belongs.

Qt Slot Function Thread Tool

Note

There is some debate as to whether using Python threads with any part of the Qt library is safe, however this has been recently challenged. The QtUtils library only instantiates a QEvent and calls QCoreApplication.postEvent() from a Python thread. It seems likely that as long as the underlying Python threading implementation matches the underlying Qt threading implementation for your particular platform, that there is no issue with how we have written this library. While we have not observed any issues with our library (and we have used it extensively on Windows, OSX and Ubuntu), this does not mean all platforms will behave in the same way. If this matters to you, we suggest you confirm the underlying thread implementation for your build of Python and Qt.

Examples¶

We utilise the Qt event loop to execute arbitrary methods in the MainThread by posting a Qt event to the MainThread from a secondary thread.QtUtils provides a function called inmain which takes a reference to a method to execute in the MainThread, followed by any arguments to be passed to the method.

A call to inmain blocks the calling thread until the Qt event loop can process our message, execute the specified method and return the result.For situations where you don’t wait to wait for the result, or you wish to do some other processing while waiting for the result, QtUtils provides the inmain_later function.This works in the same way as inmain, but returns a reference to a Python Queue object immediately.The result can be retrieved from this queue at any time, as shown in the following example:

This of course works directly with Qt methods as well as user defined functions/methods.For example:

As you can see, the change between a direct call to a Qt method, and doing it in a thread safe way, is very simple:

We also provide decorators so that you can ensure the decorated method always runs in the MainThread regardless of the calling thread.This is particularly useful when combined with Python properties.

QtUtils also provides a convenience function for launching a Python thread in daemon mode.inthread(target_method,arg1,arg2,...kwarg1=False,kwargs2=7,...)

Thread

Exception handling¶

Typically, exceptions are raised in the calling thread.However, inmain_later and the associated decorator will also raise the exception in the MainThread as there is no guarantee that the results will ever be read from the calling thread.

Using QtUtils from the MainThread¶

When using inmain, or the associated decorator, QtUtils will bypass the Qt Event loop as just immediately execute the specified method.This avoids the obvious deadlock where the calling code is being executed by the Qt event loop, and is now waiting for the Qt event loop to execute the next event (which won’t ever happen because it is blocked waiting for the next event by the calling code).inmain_later still posts an event to the Qt event loop when used from the MainThread.This is useful if you want to execute something asynchronously from the MainThread (for example, asynchronously update the text of a label) but we recommend you do not attempt to read the result of such a call as you risk creating a deadlock.

What if I want to wait for user input in a thread?¶

If you want your thread to wait for user input, then this is not the library for you!We suggest you check out how to Wait in thread for user input from GUI for a Qt solution and/or Python threading events for a Python solution.

API reference¶

class qtutils.invoke_in_main.CallEvent(queue, exceptions_in_main, fn, *args, **kwargs)[source]

An event containing a request for a function call.

class qtutils.invoke_in_main.Caller[source]

An event handler which calls the function held within a CallEvent.

event(self, QEvent) → bool[source]
qtutils.invoke_in_main.get_inmain_result(queue)[source]

Processes the result of qtutils.invoke_in_main.inmain_later().

This function takes the queue returned by inmain_later and blocksuntil a result is obtained. If an exception occurred when executing thefunction in the MainThread, it is raised again here (it is also raised in theMainThread). If no exception was raised, the result from the execution of thefunction is returned.

Parameters
Qt slot function threaded

queue – The Python Queue object returned by inmain_later

Returns
Qt slot thread

The result from executing the function specified in the call toinmain_later

qtutils.invoke_in_main.inmain(fn, *args, **kwargs)[source]

Execute a function in the main thread. Wait for it to completeand return its return value.

This function queues up a custom QEvent to the Qt event loop.This event executes the specified function fn in the PythonMainThread with the specified arguments and keyword arguments, and returns the result to the calling thread.

This function can be used from the MainThread, but such use will just directly call the function, bypassing the Qt event loop.

Parameters
  • fn – A reference to the function or method to run in the MainThread.

  • *args – Any arguments to pass to fn when it is called from theMainThread.

  • **kwargs – Any keyword arguments to pass to fn when it is calledfrom the MainThread

Qt public slots
Returns

Qt Slot Parameter

The result of executing fn(*args,**kwargs)

qtutils.invoke_in_main.inmain_decorator(wait_for_return=True, exceptions_in_main=True)[source]

A decorator which enforces the execution of the decorated thread to occur in the MainThread.

This decorator wraps the decorated function or method in eitherqtutils.invoke_in_main.inmain() orqtutils.invoke_in_main.inmain_later().

Keyword Arguments
  • wait_for_return – Specifies whether to use inmain (ifTrue) or inmain_later (ifFalse).

  • exceptions_in_main – Specifies whether the exceptions should be raisedin the main thread or not. This is ignored ifwait_for_return=True. If this isFalse, then exceptions may be silenced ifyou do not explicitly useqtutils.invoke_in_main.get_inmain_result().

Returns

The decorator returns a function that has wrapped the decorated functionin the appropriate call to inmain or inmain_later (ifyou are unfamiliar with how decorators work, please see the Pythondocumentation).

When calling the decorated function, the result is either the result ofthe function executed in the MainThread (if wait_for_return=True)or a Python Queue to be used withqtutils.invoke_in_main.get_inmain_result() at a later time.

qtutils.invoke_in_main.inmain_later(fn, *args, **kwargs)[source]

Queue up the executing of a function in the main thread and return immediately.

This function queues up a custom QEvent to the Qt event loop.This event executes the specified function fn in the PythonMainThread with the specified arguments and keyword arguments, and returnsa Python Queue which will eventually hold the result from the executing offn. To access the result, use qtutils.invoke_in_main.get_inmain_result().

This function can be used from the MainThread, but such use will just directly call the function, bypassing the Qt event loop.

Parameters
Qt signals and slots threads
  • fn – A reference to the function or method to run in the MainThread.

  • *args – Any arguments to pass to fn when it is called from theMainThread.

  • **kwargs – Any keyword arguments to pass to fn when it is calledfrom the MainThread

Returns

A Python Queue which will eventually hold the result(fn(*args,**kwargs),exception) whereexception=[type,value,traceback].

qtutils.invoke_in_main.inthread(f, *args, **kwargs)[source]

Qt Start Thread

A convenience function for starting a Python thread.

This function launches a Python thread in Daemon mode, and returns areference to the running thread object.

Parameters
  • f – A reference to the target function to be executed in the Python thread.

  • *args – Any arguments to pass to f when it is executed in thenew thread.

  • **kwargs – Any keyword arguments to pass to f when it is executedin the new thread.

Returns

A reference to the (already running) Python thread object