Pregunta

Issue

I have a PyQt GUI where the user presses a button to start a background thread (workerThread, which is subclassed from QThread). I would like to have a timer display (in the form of a QLabel) to show how much time has elapsed since workerThread started, and I would like this timer to stop as soon as the workerThread exits.

Possible solution

I've thought about creating another independent thread (timerThread) that uses a QTimer to send a signal to a slot to update the QLabel in the main GUI thread with the elapsed time every 1 second. This timerThread will exit as soon as it receives a terminate signal from workerThread.

However, I'd have to start timerThread at the same time as WorkerThread, and I'm not sure how to this.

Question

Is there an easier way to do this? Is QTimer even the right approach to start with?

¿Fue útil?

Solución

Here is one way of doing this. In this example, myThread starts the timerThread as a child process when it's run method is called. It's timeElapsed signal is connected to the timerThreads timeElapsed signal. The timerThread will check each second while the parent isRunning and emit a timeElapsed signal if True:

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import time

from PyQt4 import QtCore, QtGui

class timerThread(QtCore.QThread):
    timeElapsed = QtCore.pyqtSignal(int)

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

    def start(self, timeStart):
        self.timeStart = timeStart

        return super(timerThread, self).start()

    def run(self):
        while self.parent().isRunning():
            self.timeElapsed.emit(time.time() - self.timeStart)
            time.sleep(1)


class myThread(QtCore.QThread):
    timeElapsed = QtCore.pyqtSignal(int)
    def __init__(self, parent=None):
        super(myThread, self).__init__(parent)

        self.timerThread = timerThread(self)
        self.timerThread.timeElapsed.connect(self.timeElapsed.emit)

    def run(self):
        self.timerThread.start(time.time())

        iterations = 3
        while iterations:
            print "Running {0}".format(self.__class__.__name__)
            iterations -= 1
            time.sleep(2)        


class myWindow(QtGui.QWidget):    
    def __init__(self):
        super(myWindow, self).__init__() 

        self.button = QtGui.QPushButton(self)
        self.button.setText("Start Threading!")
        self.button.clicked.connect(self.on_button_clicked)

        self.label = QtGui.QLabel(self)

        self.layout = QtGui.QVBoxLayout(self)
        self.layout.addWidget(self.button)
        self.layout.addWidget(self.label)

        self.myThread = myThread(self)
        self.myThread.timeElapsed.connect(self.on_myThread_timeElapsed)
        self.myThread.finished.connect(self.on_myThread_finished)

    @QtCore.pyqtSlot()
    def on_button_clicked(self):
        self.myThread.start()

    @QtCore.pyqtSlot(int)
    def on_myThread_timeElapsed(self, seconds):
        self.label.setText("Time Elapsed: {0}".format(seconds))

    @QtCore.pyqtSlot()
    def on_myThread_finished(self):
        print "Done"

if __name__ == "__main__":
    import sys

    app = QtGui.QApplication(sys.argv)
    app.setApplicationName('myWindow')

    main = myWindow()
    main.show()

    sys.exit(app.exec_())
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top