QThread的简单应用

2024-05-20 19:53:35 发布

您现在位置:Python中文网/ 问答频道 /正文

在后台执行可能更长的线程时,为了不锁定GUI,我对QThread进行了控制。我试着练习写一个简单的应用程序:一个倒计时计时器,我可以通过点击“开始”按钮启动,从而启动倒计时循环,我可以通过单击“暂停”按钮暂停。在

我想用QThread(解释了over here)的“正确方式”来实现,即子类化QObject,然后通过moveToThread将这个子类的一个实例附加到QThread。我用QTDesigner做了GUI,这是到目前为止我在Python中修改的内容(来自网络上的其他示例):

from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import QThread, SIGNAL

import time, sys, mydesign

class SomeObject(QtCore.QObject):

    def __init__(self, lcd):
        super(self.__class__, self).__init__()
        self.lcd = lcd
        self.looping = True
    finished = QtCore.pyqtSignal()
    def pauseLoop(self):
        print "Hello?"
        self.looping = False

    def longRunning(self):
        count = 10
        self.lcd.display(count)
        while count > 0 and self.looping:
            time.sleep(1)
            count -= 1
            self.lcd.display(count)
        self.finished.emit()

class ThreadingTutorial(QtGui.QMainWindow, mydesign.Ui_MainWindow):
    def __init__(self):
        super(self.__class__, self).__init__()
        self.setupUi(self)

        #an instance of SomeObject gets attached to
        #an instance of wrapper class QThread()

        #objThread is a wrapper object for an instance of
        # self-defined class SomeObject
        self.objThread = QtCore.QThread()
        self.obj = SomeObject(self.lcdNumber)
        self.obj.moveToThread(self.objThread)
        #connect all the signals
        self.obj.finished.connect(self.objThread.quit)
        self.objThread.started.connect(self.obj.longRunning)
        self.startCountdown.clicked.connect(self.objThread.start)
        self.pauseButton.clicked.connect(self.obj.pauseLoop)


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    form = ThreadingTutorial()
    form.show()
    app.exec_()

GUI没有被锁定,但是pauseLoop()函数只在循环完成后执行。如何才能实现在longRunning()中暂停循环的目标?在

提前通知!在

更新:

在Steve和three_npenapples的评论的帮助下,我使用objThread的内部事件循环提出了以下解决方案:

^{pr2}$

Tags: importselfobjlcdinitdefcountconnect
1条回答
网友
1楼 · 发布于 2024-05-20 19:53:35

之所以发生这种情况,是因为您告诉Qt在一个线程中运行SomeObject对象的代码。在代码中,有两个线程,主GUI线程和self.objThread。在与longRunning()相同的线程中调用pauseLoop(),这意味着{}必须在pauseLoop()运行之前完成。相反,您需要从另一个线程调用pauseLoop(),而不是self.objThread。在

请注意,当您开始更改来自两个不同线程(主线程和新线程)的数据时,您可能会开始遇到争用条件。既然你只设置了一个布尔变量,你会很好,但这是需要记住的。在

编辑:正如three_pineapples的评论所指出的,访问GUI对象(例如:QWidget)应该只在主GUI线程中完成。为了说明这是如何工作的,我更新了这个答案,以使用信号更新GUI线程中的LCD,而不是仅仅将值打印到stdout。我还添加了一些代码来打印不同部分的当前线程。在

from PySide import QtGui, QtCore
from PySide.QtCore import QThread, SIGNAL

import time, sys

class SomeObject(QtCore.QObject):
    updateCounter = QtCore.Signal(int)
    finished = QtCore.Signal()
    def __init__(self):
        super(self.__class__, self).__init__()
        self.looping = True
    def pauseLoop(self):
        self.looping = False
        print 'Pause Loop: '+str(QThread.currentThreadId())
    def longRunning(self):
        print 'Long Running: '+str(QThread.currentThreadId())
        count = 10
        while count > 0 and self.looping:
            count -= 1
            self.updateCounter.emit(count)
            time.sleep(1)
        self.finished.emit()

class ThreadingTutorial(QtGui.QWidget):
    def __init__(self):
        super(self.__class__, self).__init__()
        #
        self.thisLayout = QtGui.QVBoxLayout(self)
        self.startCountdown = QtGui.QPushButton('Start', self)
        self.pauseButton = QtGui.QPushButton('Stop', self)
        self.lcd = QtGui.QLabel('', self)
        self.thisLayout.addWidget(self.startCountdown)
        self.thisLayout.addWidget(self.pauseButton)
        self.thisLayout.addWidget(self.lcd)
        #
        print 'Main GUI Thread: '+str(QThread.currentThreadId())
        self.objThread = QtCore.QThread()
        self.obj = SomeObject()
        self.obj.moveToThread(self.objThread)
        self.obj.updateCounter.connect(self._updateTimer)
        #
        self.obj.finished.connect(self.objThread.quit)
        self.objThread.started.connect(self.obj.longRunning)
        self.startCountdown.clicked.connect(self.objThread.start)
        self.pauseButton.clicked.connect(self._stopTimer)
    def _stopTimer(self):
        self.obj.pauseLoop()
    def _updateTimer(self, num):
        self.lcd.setText(str(num))
        print 'Update Timer: '+str(QThread.currentThreadId())


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    form = ThreadingTutorial()
    form.show()
    app.exec_()

输出示例:

^{pr2}$

相关问题 更多 >