爲了不鎖定我的GUI,同時在後臺執行可能較長的線程,我正在抓緊QThread。我正在嘗試編寫一個簡單的應用程序:一個倒計時器,我可以通過點擊「開始」按鈕來啓動,從而啓動一個倒計時循環,通過點擊「暫停」按鈕可以暫停。QThread的簡單應用
我想用「合適的方式」使用QThread(解釋爲over here),即子類化QObject,然後通過moveToThread將此子類的實例附加到QThread。我做了GUI與QTDesigner,這就是我修改到目前爲止(從網絡中其他的例子)在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()中暫停循環?
Thx提前!
更新:
隨着史蒂夫的和three_pineapples的言論的幫助下,我想出了使用objThread的內部事件循環以下解決方案:
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import QThread, SIGNAL, QTimer
import time, sys, mydesign
class SomeObject(QtCore.QObject):
def __init__(self):
super(self.__class__, self).__init__()
self.looping = True
self.count = 10
self.timer = QTimer(self)
self.timer.start(1000)
self.connect(self.timer, SIGNAL("timeout()"), self.longRunning)
finished = QtCore.pyqtSignal()
iterated = QtCore.pyqtSignal()
def pauseLoop(self):
self.looping = False
def longRunning(self):
if self.count > 0 and self.looping:
self.count -= 1
self.iterated.emit()
else:
self.finished.emit()# sends signal for stopping event loop
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.display(self.obj.count)
self.obj.moveToThread(self.objThread)
#connect all the signals
self.obj.finished.connect(self.objThread.quit)
self.obj.iterated.connect(lambda: self.lcdNumber.display(self.obj.count))
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對象從另一個線程。你也不能將GUI對象移動到另一個線程。你將最終與隨機應用程序崩潰(segfaults)。我是你的上面的例子,你仍然可以從次線程訪問LCD小部件,這是不好的!您應該在每次要更新小部件時向主線程發出信號,以便您可以安全地與GUI進行實際交互。 –
我修改了我的答案來說明three_pineapples的評論。 – Steve
謝謝你的好處。我會牢記這一規則。我也會修改我對這條規則的解決方案。 – user2949762