我在Windows上的PyQt中编写了一个GUI程序。我的程序中有一些昂贵的操作。当这些操作正在运行时,程序在程序栏中显示“Not Responding”。
我认为必须将此操作块作为更新UI的主线程,所以我通过QThread编写多线程代码来测试它,它仍然没有意义。
我写了一个小程序来测试它,操作根本没有在新线程中运行,这是我的小测试代码:
from PyQt5.QtCore import QThread, QObject, QCoreApplication, qDebug, QTimer
class Worker(QObject):
def on_timeout(self):
qDebug('Worker.on_timeout get called from: %s' % hex(int(QThread.currentThreadId())))
if __name__ == '__main__':
import sys
app = QCoreApplication(sys.argv)
qDebug('From main thread: %s' % hex(int(QThread.currentThreadId())))
t = QThread()
qDebug(t)
worker = Worker()
timer = QTimer()
timer.timeout.connect(worker.on_timeout)
timer.start(1000)
timer.moveToThread(t)
worker.moveToThread(t)
t.start()
app.exec_()
这是输出:
From main thread: 0x634
Worker.on_timeout get called from: 0x634
答案 0 :(得分:0)
您的程序有多个错误,并且不会产生您显示的输出。
首先,无法将线程对象传递给qDebug
- 参数必须是字符串。如果您想打印对象,请使用qDebug(repr(obj))
- 甚至更好,只需使用print(obj)
。
其次,您无法在创建它的线程之外启动计时器。您的示例在主线程中进行信号连接,并在主线程中启动计时器。所以worker.on_timeout
将在主线程中调用。但是如果在将其移动到工作线程后连接并启动计时器,则会出现此错误:
QObject :: startTimer:定时器只能用于以...开头的线程 的QThread
我认为使用计时器是不必要的,并且会混淆您的示例,因此最好完全不使用它。相反,您应该将工作线程的started
信号连接到工作对象的run
方法。要模拟长时间运行的操作,可以使用QThread.sleep()
:
from PyQt5.QtCore import QThread, QObject, QCoreApplication
class Worker(QObject):
def run(self):
print('Worker called from: %#x' % int(QThread.currentThreadId()))
QThread.sleep(2)
print('Finished')
QCoreApplication.quit()
if __name__ == '__main__':
import sys
app = QCoreApplication(sys.argv)
print('From main thread: %#x' % int(QThread.currentThreadId()))
t = QThread()
worker = Worker()
worker.moveToThread(t)
t.started.connect(worker.run)
t.start()
app.exec_()
最后,请注意,在将一个worker对象移动到一个线程之后,你应该总是进行信号连接。 this answer中解释了原因。