代码之家  ›  专栏  ›  技术社区  ›  gevirus

QThread窗口没有响应

  •  1
  • gevirus  · 技术社区  · 7 年前

    我在Windows上用PyQt编写了一个GUI程序。我的程序中有一些昂贵的操作。当这些操作正在运行时,程序在程序栏中显示“无响应”。

    我认为一定是这个操作阻塞了主线程来更新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
    
    1 回复  |  直到 7 年前
        1
  •  0
  •   ekhumoro    7 年前

    您的程序有几个错误,无法生成所显示的输出。

    首先,不可能将线程对象传递给 qDebug -参数必须是字符串。如果要打印对象,请使用 qDebug(repr(obj)) print(obj) .

    其次,不能在创建计时器的线程之外启动计时器。您的示例在主线程中建立信号连接,并在主线程中启动计时器。所以 worker.on_timeout 之后 将其移动到工作线程,将出现以下错误:

    计时器只能与以开始的线程一起使用 QThread公司

    我认为使用计时器是不必要的,并且会混淆您的示例,因此最好将其完全忽略。相反,您应该连接 started 工作线程到 run worker对象的方法。要模拟长时间运行的操作,可以使用 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_()
    

    最后,请注意,您应该始终进行信号连接 之后 将辅助对象移动到线程。原因见 this answer .