問題描述
我正在使用 PyQt5 在菜單系統托盤中工作.我對 PyQt5 很陌生,我想做的是在不阻塞菜單的情況下觸發一個動作(多線程).在閱讀了很多地方之后,我得出的結論是使用 Qthread
應該是要走的路(但如果我能理解那個類是如何工作的......).但是,考慮到我的應用程序非常簡單,使用 threading
也不會那么糟糕.因此,我使用 import threading
嘗試了以下代碼:
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, QtWidgets
import threading
class 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()
當我開始菜單時,一切都如我所愿.然后,當我單擊菜單 Search
時,該操作會觸發 self.search_cast
方法,并且我的菜單會填充它找到的列表.我還可以看到我的應用程序在沒有被阻止的情況下進行搜索,但是當它完成時出現以下錯誤:
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...
更新:
我現在創建了一個 worker.py
,其中包含:
I have created now a worker.py
that contains:
from PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlot
#some other imports
class Worker(QObject):
finished = pyqtSignal()
@pyqtSlot()
def _search_cast_(self):
self.cc = casting()
self.cc.initialize_cast()
self.finished.emit()
然后我在 class menubar
中添加了以下內容:
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.
現在我收到以下錯誤:
AttributeError: 'casting' object has no attribute 'availablecc'
我確保 worker
實際上正在從我稱為 cc
的外部類中恢復 availablecc
.但由于某種原因,menubar
類沒有接收到.我正在根據這個 https://stackoverflow.com/a/33453124/1995261
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
推薦答案
我會繼續回答自己.受 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) 我創建了一個 worker.py
來執行阻塞菜單的方法 _search_cast_
.當這個方法完成搜索時,它會發出兩個信號:a)一個通知他恢復了 list
,b)這個方法已經完成.
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) 在 main.py
中,我轉儲了以下內容,并嘗試在代碼中用注釋進行解釋:
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()
這樣,當搜索list
時,菜單不會被阻塞,屏幕上不會顯示錯誤,threads
在<代碼>活動監視器代碼>保持正確.
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.
我希望這對人們有所幫助.如需更準確的信息(我還在學習 PyQt,我的措辭可能不是很好),建議您查看我在上面發布的鏈接.
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:無法為不同線程中的父級創建子級的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!