I am working in a menu system tray with PyQt5. I am very new with PyQt5, and what I want to do is to trigger an action without the menu being blocked (multithreading). After
I will proceed to answer myself. Inspired by https://stackoverflow.com/a/33453124/1995261, I solved this by implementing the following:
1) I created a worker.py that executes the method _search_cast_ that was blocking the menu. When this method finishes searching, it emits two signals: a) one informing that he recovered the list, and b) that the method has finished.
#worker.py
from PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlot
class Worker(QObject):
finished = pyqtSignal()
intReady = pyqtSignal(list)
def __init__(self):
QObject.__init__(self)
@pyqtSlot()
def _search_cast_(self):
self.cc = casting()
self.cc.initialize_cast()
availablecc = self.cc.availablecc
self.intReady.emit(availablecc)
self.finished.emit()
2) In the main.py I dumped the following and I try to explain inside the code with comments:
#main.py
from PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlot
import worker # This is to import worker.py
class menubar(object):
def __init__(self):
signal.signal(signal.SIGINT, signal.SIG_DFL)
self.cc.cast = None
self.systray = True
self.stopped = False
self.obj = worker.Worker() # The worker is started with no parent!
self.thread = QThread() # We initialise the Qthread class with no parent!
self.obj.intReady.connect(self.onIntReady) # We receive the signal that the list is ready
self.obj.moveToThread(self.thread) # Moving the object to the thread
self.obj.finished.connect(self.thread.quit) # When the method is finished we receive the signal that it is finished
self.thread.started.connect(self.obj._search_cast_) # We need to connect the above with the desired method inside the work.py
self.app = QtWidgets.QApplication(sys.argv)
def search_menu(self):
self.SearchAction = self.menu.addAction("Search")
self.SearchAction.triggered.connect(self.search_cast)
def onIntReady(self, availablecc): # This method receives the list from the worker
print ('availablecc', availablecc) # This is for debugging reasons to verify that I receive the list with the correct content
self.availablecc = availablecc
def search_cast(self): #This method starts the thread when self.SearchAction is triggered
args.select_cc = True
self.thread.start()
In this way, when searching for the list the menu does not get blocked, no errors are shown on the screen and the number of threads when monitoring them in activity monitor stay correct.
I hope this helps people. For more precise information (I am still learning PyQt and my wording may not be very good), I suggest you to check the link that I posted above.