【发布时间】:2017-10-09 19:55:24
【问题描述】:
尝试使用 QThread 和 PyQt5 的插槽/信号在后台线程中处理多个文件。
我正在使用 Python 3.5.2 和 PyQt5.8.2。 PyCharm 2017.1 向我发出警告:
-
# FAILS HERE行Unresolved attribute reference的connect部分w.done.connect(..) - 和
Cannot find reference 'connect' in 'function'为thread.started.connect(...)。
当我尝试在 PyCharm 之外运行时,我得到 TypeError: decorated slot has no signature compatible with Worker.done[]。
在 PyCharm 中查看选项卡完成时,没有显示 connect() 或 disconnect() 方法,但 emit() 显示。
SO上的所有教程和问题都说以下内容应该有效。
简化代码为:
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QThread
from PyQt5.QtWidgets import QMainWindow
class MyApp(QMainWindow, myUiMainWindow):
def __init__(self):
super(self.__class__, self).__init()
self.setupUI(self)
@pyqtSlot()
def update_this(self):
<update things>
def doMyStuff(self):
<get a file_list>
for f in file_list:
w = Worker(f)
thread = QThread()
w.moveToThread(thread)
w.done.connect(self.update_this) # FAILS HERE
thread.started.connect(w.process) # FAILS HERE
thread.start()
class Worker(QObject):
done = pyqtSignal()
def __init__(self, file_path):
super(Worker, self).__init__(parent=None)
self.f = file_path
@pyqtSlot()
def process(self):
<do stuff>
self.done.emit()
更新:我终于能够通过卸载 pyqt5 并从此处重新安装 (anaconda.org/bpentz/pyqt5) 来解决这个问题。我不知道这是如何解决问题的,但确实如此。但是,此代码不起作用,它几乎立即关闭 QThread()。我更新了以下相关代码(如下),现在我在终端或 PyCharm 中遇到了没有 Traceback 的 python 崩溃(奇怪的是,这在调试器中工作得很好)。目标是遍历文件并在多个 QThreads() 中处理它们,更新进度条 (update_this),然后在处理完所有文件时提醒用户。
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QThread
from PyQt5.QtWidgets import QMainWindow
class MyApp(QMainWindow, myUiMainWindow):
def __init__(self):
super(self.__class__, self).__init()
self.setupUI(self)
self.pushButton.clicked.connect(self.doMyStuff)
@pyqtSlot()
def thread_complete(self):
self.num_completed += 1
if self.num_completed == len(self.file_list):
<reset things>
def doMyStuff(self):
<get a self.file_list>
self.num_completed = 0
self.threads = []
for f in self.file_list:
w = Worker(f)
self.threads.append(QThread())
w.moveToThread(threads[-1])
self.threads[-1].started.connect(w.process)
self.threads[-1].finished.connect(self.thread_complete)
self.threads[-1].start()
class Worker(QObject):
def __init__(self, file_path):
super(Worker, self).__init__(parent=None)
self.f = file_path
@pyqtSlot()
def process(self):
<do stuff with self.f>
附加更新:如前所述,问题不在于将工作人员保留在内存中。完成此操作后,线程场景就起作用了。然而,同样如前所述,使用 QThread() 并没有实现我一直在寻找并认为 QThreading 可能实现的多处理效率的想法,并且比仅在单个 QThread() 中串行处理文件更糟糕。尝试使用多重处理会导致其他问题here。
工作 QThread() 代码(虽然很慢!):
def doMyStuff(self):
<get a self.file_list>
self.num_completed = 0
self.threads = []
self.workers = []
for f in self.file_list:
w = Worker(f)
w.done.connect(self.update_this)
thread = QThread()
w.moveToThread(thread)
thread.started.connect(w.process)
thread.finished.connect(self.thread_complete)
self.threads.append(thread)
self.workers.append(worker)
【问题讨论】:
-
MyApp 类的构造函数?
-
将
@pyqtSlot(object)更改为@pyqtSlot() -
@eyllanesc - 谢谢。我早些时候改变了它,它没有工作。我可以通过卸载 pyqt5 并从这里重新安装 (anaconda.org/bpentz/pyqt5) 来解决这个问题。我不知道这是如何解决问题的,但确实如此。但是,此代码不起作用,它几乎立即关闭 QThread()。我已将代码更新为上面的编辑和新问题。
-
请显示完整代码。
-
@launchpadmcquack 你需要保留对工作人员的引用,否则当
doMyStuff返回时它们会被删除(在你的线程有机会运行之前)。像处理线程一样将它们添加到列表中。
标签: python python-3.x pyqt pyqt5 qthread