I am getting a grip on QThread in order to not lock my GUI, while performing possibly longer threads in the background. I am trying for practice to write a simple application: A countdown timer which I can start by clicking on a button "Start", thereby initiating a countdown loop, which I can pause by clicking on a button "Pause".
I want to do it in the "proper way" of using QThread (explained over here), i.e. subclassing QObject and then attach an instance of this subclass to a QThread via moveToThread. I did the GUI with QTDesigner and this is what I modified so far (from other examples on the Net) in 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_()
The GUI is not locked but the function pauseLoop() only gets executed after the loop is finished. How do I have to do it in order to accomplish my goal to be able to pause the loop in longRunning()?
Thx in advance!
update:
With the help of Steve's and three_pineapples's remarks, I come up with following solution using the inner event loop of 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_()