PyQt5 QObject: Cannot create children for a parent that is in a different thread

后端 未结 2 1979
轮回少年
轮回少年 2021-01-07 04:29

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

2条回答
  •  情歌与酒
    2021-01-07 05:31

    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.

提交回复
热议问题