在 PyQt 中使用 QThread 的正确方法示例? [英] Example of the right way to use QThread in PyQt?

查看:60
本文介绍了在 PyQt 中使用 QThread 的正确方法示例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试学习如何在 PyQt Gui 应用程序中使用 QThreads.我有一些可以运行一段时间的东西,(通常)有我可以更新 Gui 的点,但我想将主要工作拆分到它自己的线程中(有时东西会卡住,最终有一个很好的取消/重试按钮,如果 Gui 因 Main Loop 被阻塞而被冻结,这显然不起作用).

I'm trying to learn how to use QThreads in a PyQt Gui application. I have stuff that runs for a while, with (usually) points where I could update a Gui, but I would like to split the main work out to its own thread (sometimes stuff gets stuck, and it would be nice to eventually have a cancel/try again button, which obviously doesn't work if the Gui is frozen because the Main Loop is blocked).

我已阅读https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/.该页面说重新实现 run 方法不是这样做的方法.我遇到的问题是找到一个 PyQt 示例,它有一个主线程执行 Gui 和一个不这样做的工作线程.这篇博文是针对 C++ 的,所以虽然它的例子确实有帮助,但我还是有点迷茫.有人可以指出我在 Python 中正确执行此操作的示例吗?

I've read https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/. That page says that re-implementing the run method is not the way to do it. The problem I am having is finding a PyQt example that has a main thread doing the Gui and a worker thread that does not do it that way. The blog post is for C++, so while it's examples do help, I'm still a little lost. Can someone please point me to an example of the right way to do it in Python?

推荐答案

这里是一个单独的工作线程的工作示例,它可以发送和接收信号以允许它与 GUI 通信.

Here is a working example of a separate worker thread which can send and receive signals to allow it to communicate with a GUI.

我制作了两个简单的按钮,一个在单独的线程中开始长时间的计算,一个立即终止计算并重置工作线程.

I made two simple buttons, one which starts a long calculation in a separate thread, and one which immediately terminates the calculation and resets the worker thread.

像这里那样强行终止线程通常不是最好的做事方式,但在某些情况下,总是优雅地退出不是一种选择.

Forcibly terminating a thread as is done here is not generally the best way to do things, but there are situations in which always gracefully exiting is not an option.

from PyQt4 import QtGui, QtCore
import sys
import random

class Example(QtCore.QObject):

    signalStatus = QtCore.pyqtSignal(str)

    def __init__(self, parent=None):
        super(self.__class__, self).__init__(parent)

        # Create a gui object.
        self.gui = Window()

        # Create a new worker thread.
        self.createWorkerThread()

        # Make any cross object connections.
        self._connectSignals()

        self.gui.show()


    def _connectSignals(self):
        self.gui.button_cancel.clicked.connect(self.forceWorkerReset)
        self.signalStatus.connect(self.gui.updateStatus)
        self.parent().aboutToQuit.connect(self.forceWorkerQuit)


    def createWorkerThread(self):

        # Setup the worker object and the worker_thread.
        self.worker = WorkerObject()
        self.worker_thread = QtCore.QThread()
        self.worker.moveToThread(self.worker_thread)
        self.worker_thread.start()

        # Connect any worker signals
        self.worker.signalStatus.connect(self.gui.updateStatus)
        self.gui.button_start.clicked.connect(self.worker.startWork)


    def forceWorkerReset(self):      
        if self.worker_thread.isRunning():
            print('Terminating thread.')
            self.worker_thread.terminate()

            print('Waiting for thread termination.')
            self.worker_thread.wait()

            self.signalStatus.emit('Idle.')

            print('building new working object.')
            self.createWorkerThread()


    def forceWorkerQuit(self):
        if self.worker_thread.isRunning():
            self.worker_thread.terminate()
            self.worker_thread.wait()


class WorkerObject(QtCore.QObject):

    signalStatus = QtCore.pyqtSignal(str)

    def __init__(self, parent=None):
        super(self.__class__, self).__init__(parent)

    @QtCore.pyqtSlot()        
    def startWork(self):
        for ii in range(7):
            number = random.randint(0,5000**ii)
            self.signalStatus.emit('Iteration: {}, Factoring: {}'.format(ii, number))
            factors = self.primeFactors(number)
            print('Number: ', number, 'Factors: ', factors)
        self.signalStatus.emit('Idle.')

    def primeFactors(self, n):
        i = 2
        factors = []
        while i * i <= n:
            if n % i:
                i += 1
            else:
                n //= i
                factors.append(i)
        if n > 1:
            factors.append(n)
        return factors


class Window(QtGui.QWidget):

    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.button_start = QtGui.QPushButton('Start', self)
        self.button_cancel = QtGui.QPushButton('Cancel', self)
        self.label_status = QtGui.QLabel('', self)

        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.button_start)
        layout.addWidget(self.button_cancel)
        layout.addWidget(self.label_status)

        self.setFixedSize(400, 200)

    @QtCore.pyqtSlot(str)
    def updateStatus(self, status):
        self.label_status.setText(status)


if __name__=='__main__':
    app = QtGui.QApplication(sys.argv)
    example = Example(app)
    sys.exit(app.exec_())

这篇关于在 PyQt 中使用 QThread 的正确方法示例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆