user3696412 user3696412 - 1 year ago 243
Python Question

Simplest way for PyQT Threading

I have a GUI in PyQt with a function

. Easy to imagine, it is called when a new image should be added into a QListWidget. For the detection of new images in a folder, I use a
to detect file changes in the folder, and this thread then calls

This yields the warning that
shouldn't be called outside the gui thread, for reasons of thread safety.

What is the best and most simple way to make this threadsafe? QThread? Signal / Slot? QMetaObject.invokeMethod? I only need to pass a string from the thread to

Answer Source

I believe the best approach is using the signal/slot mechanism. Here is an example.

from PyQt4 import QtGui
from PyQt4 import QtCore

# Create the class 'Communicate'. The instance
# from this class shall be used later on for the
# signal/slot mechanism.

class Communicate(QtCore.QObject):
    myGUI_signal = QtCore.pyqtSignal(str)

''' End class '''

# Define the function 'myThread'. This function is the so-called
# 'target function' when you create and start your new Thread.
# In other words, this is the function that will run in your new thread.
# 'myThread' expects one argument: the callback function name. That should
# be a function inside your GUI.

def myThread(callbackFunc):
    # Setup the signal-slot mechanism.
    mySrc = Communicate()

    # Endless loop. You typically want the thread
    # to run forever.
        # Do something useful here.
        msgForGui = 'This is a message to send to the GUI'
        # So now the 'callbackFunc' is called, and is fed with 'msgForGui'
        # as parameter. That is what you want. You just sent a message to
        # your GUI application! - Note: I suppose here that 'callbackFunc'
        # is one of the functions in your GUI.
        # This procedure is thread safe.

    ''' End while '''

''' End myThread '''

In your GUI application code, you should create the new Thread, give it the right callback function, and make it run.

from PyQt4 import QtGui
from PyQt4 import QtCore
import sys
import os

# This is the main window from my GUI

class CustomMainWindow(QtGui.QMainWindow):

    def __init__(self):
        super(CustomMainWindow, self).__init__()
        self.setGeometry(300, 300, 2500, 1500)
        self.setWindowTitle("my first window")
        # ...


    def theCallbackFunc(self, msg):
        print('the thread has sent this message to the GUI:')


    def startTheThread(self):
        # Create the new thread. The target function is 'myThread'. The
        # function we created in the beginning.
        t = threading.Thread(name = 'myThread', target = myThread, args = (self.theCallbackFunc))


''' End CustomMainWindow '''

# This is the startup code.

if __name__== '__main__':
    app = QtGui.QApplication(sys.argv)
    myGUI = CustomMainWindow()

''' End Main '''

I really hope this was helpful. Please let me know if it worked for you.