1)我创建了一个worker.py,该worker.py执行阻塞菜单的方法_search_cast_.此方法完成搜索后,将发出两个信号:a)一个通知他已恢复list的信号,以及b)该方法已完成. #worker.pyfrom PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlotclass 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)在main.py中,我转储了以下内容,并尝试在代码中解释带注释的内容:#main.pyfrom PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlotimport worker # This is to import worker.pyclass 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()这样,在搜索list时菜单不会被阻塞,屏幕上不会显示任何错误,并且在activity monitor中监视它们时threads的数量保持正确.我希望这对人们有帮助.有关更精确的信息(我仍在学习PyQt,并且措辞可能不太好),建议您检查上面发布的链接. 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 having read in many places, I have come to the conclusion that using Qthread should be the way to go (but if only I could understand how that class works...). However, the use of threading wouldn't be that bad either given that my application is very simple. So, I have tried the following code using import threading: from PyQt5 import QtCore, QtGui, QtWidgetsimport threadingclass menubar(object): def __init__(self): signal.signal(signal.SIGINT, signal.SIG_DFL) self.systray = True self.stopped = False def search_menu(self): self.SearchAction = menu.addAction("Search") self.SearchAction.triggered.connect(self.search_cast) def _search_cast_(self): args.select_cc = True self.cc.initialize_cast() self.cast_list() def search_cast(self): threading.Thread(target=self._search_cast_).start()#some more methods here...def main(): menubar() app = QtWidgets.QApplication(sys.argv) tray = QtWidgets.QSystemTrayIcon(icon) menu = QtWidgets.QMenu() start = menubar() start.search_menu() start.separator_menu() start.populating_menu() start.separator_menu() start.stop_menu() start.resetaudio_menu() start.about_menu() start.exit_menu() tray.setContextMenu(menu) tray.show() app.exec_()if __name__ == '__main__': main()When I start my menu, everything is in place as I expect it. Then, when I click on the menu Search the action triggers the self.search_cast method, and my menu gets populated with the list it finds. I can also see my application doing the searching without getting blocked but when it finishes I get the following errors:QObject: Cannot create children for a parent that is in a different thread.(Parent is QMenu(0x7fcef497c160), parent's thread is QThread(0x7fcef2603d10), current thread is QThread(0x7fcef4a89360)QObject: Cannot create children for a parent that is in a different thread.(Parent is QMenu(0x7fcef497c160), parent's thread is QThread(0x7fcef2603d10), current thread is QThread(0x7fcef4a89360)QObject: Cannot create children for a parent that is in a different thread.After this, the menu is still "functional" in the sense that it is responsive but no more action can be triggered. Additionally, it seems that no more threads are created. I would be glad if somebody could explain me why is this happening?. I don't see the light...Update:I have created now a worker.py that contains:from PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlot#some other importsclass Worker(QObject): finished = pyqtSignal()@pyqtSlot()def _search_cast_(self): self.cc = casting() self.cc.initialize_cast() self.finished.emit()Then I have added in the class menubar the following:class menubar(object): def __init__(self): self.cc = casting() signal.signal(signal.SIGINT, signal.SIG_DFL) self.cc.cast = None self.systray = True self.stopped = False self.obj = worker.Worker() # no parent! self.thread = QThread() # no parent! self.obj.moveToThread(self.thread) self.obj.finished.connect(self.thread.quit) self.thread.started.connect(self.obj._search_cast_) def search_menu(self): self.SearchAction = menu.addAction("Search") self.SearchAction.triggered.connect(self.search_cast) def search_cast(self): self.thread.start() self.cast_list() def cast_list(self): if len(self.cc.availablecc) == 0: # some actions here.And now I get the following error: AttributeError: 'casting' object has no attribute 'availablecc'I make sure that actually the worker is recovering availablecc from an external class that I called cc. But for some reason is not being received by the menubar class. I am working based on this https://stackoverflow.com/a/33453124/1995261 解决方案 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.pyfrom PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlotclass 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.pyfrom PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlotimport worker # This is to import worker.pyclass 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. 这篇关于PyQt5 QObject:无法为处于不同线程中的父级创建子级的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
09-01 18:46