aman rawat
aman rawat

Reputation: 13

Timers in PyQt based GUI

I am facing a problem while running the timers simultaneously one by one.The next timer is running and previous one get stopped and after reaching the time the previous one starts. The problematic code is listed below.

import time
from PyQt4 import QtCore, QtGui
import sys


try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)



class Window(QtGui.QMainWindow):

    def __init__(self):

        super(Window, self).__init__()
        self.setGeometry(50, 50, 500, 300)
        self.setWindowTitle("PyQT tuts!")
        self.setWindowIcon(QtGui.QIcon('pythonlogo.png'))
        self.home()


    def home(self):

        self.btn = QtGui.QPushButton(self)
        self.btn.setObjectName(_fromUtf8("pb"))
        self.btn.clicked.connect(self.timer)
        self.btn.setText("Timer1")
        self.btn.resize(65,25)
        self.btn.move(100,100)

        self.btn2 = QtGui.QPushButton(self)
        self.btn2.setObjectName(_fromUtf8("pb2"))
        self.btn2.clicked.connect(self.timer2)
        self.btn2.setText("Timer2")
        self.btn2.resize(65,25)
        self.btn2.move(100,150)

        self.btn3 = QtGui.QPushButton(self)
        self.btn3.setObjectName(_fromUtf8("pb3"))
        self.btn3.clicked.connect(self.timer3)
        self.btn3.setText("Timer3")
        self.btn3.resize(65,25)
        self.btn3.move(100,200)

        self.btn4 = QtGui.QPushButton(self)
        self.btn4.setObjectName(_fromUtf8("pb4"))
        self.btn4.clicked.connect(self.timer4)
        self.btn4.setText("Timer4")
        self.btn4.resize(65,25)
        self.btn4.move(100,250)


        self.show()


    def timer(self):

        # uin = input("enter the time : ")

        when_to_stop = 10 
        # abs(int(uin))

        while when_to_stop > 0:
            m, s = divmod(when_to_stop, 60)
            h, m = divmod(m, 60)
            time_left = str(h).zfill(2) + ":" + str(m).zfill(2) + ":" + str(s).zfill(2)

            # print(time_left+'\r')
            time.sleep(1.0)
            when_to_stop -= 1
            self.btn.setText(str(time_left))
            QtGui.qApp.processEvents()


    def timer2(self):

        # uin = input("enter the time : ")

        when_to_stop = 10 
        # abs(int(uin))

        while when_to_stop > 0:
            m, s = divmod(when_to_stop, 60)
            h, m = divmod(m, 60)
            time_left = str(h).zfill(2) + ":" + str(m).zfill(2) + ":" + str(s).zfill(2)

            # print(time_left+'\r')
            time.sleep(1.0)
            when_to_stop -= 1
            self.btn2.setText(str(time_left))
            QtGui.qApp.processEvents()


    def timer3(self):

        # uin = input("enter the time : ")

        when_to_stop = 10
        # abs(int(uin))

        while when_to_stop > 0:
            m, s = divmod(when_to_stop, 60)
            h, m = divmod(m, 60)
            time_left = str(h).zfill(2) + ":" + str(m).zfill(2) + ":" + str(s).zfill(2)

            # print(time_left+'\r')
            time.sleep(1.0)
            when_to_stop -= 1
            self.btn3.setText(str(time_left))
            QtGui.qApp.processEvents()



     def timer4(self):

        # uin = input("enter the time : ")

        when_to_stop = 10 
        # abs(int(uin))

        while when_to_stop > 0:
            m, s = divmod(when_to_stop, 60)
            h, m = divmod(m, 60)
            time_left = str(h).zfill(2) + ":" + str(m).zfill(2) + ":" + str(s).zfill(2)

            # print(time_left+'\r')
            time.sleep(1.0)
            when_to_stop -= 1
            self.btn4.setText(str(time_left))
            QtGui.qApp.processEvents()




def run():


    app = QtGui.QApplication(sys.argv)
    GUI = Window()
    sys.exit(app.exec_())


run()

Upvotes: 1

Views: 943

Answers (1)

eyllanesc
eyllanesc

Reputation: 243887

time.sleep() should not be used in the GUI because it will block the GUI eventloop causing problems like not updating the GUI, besides using input (), and consider bad practice calling processEvents().

Qt offers QTimer which is a class specialized in calling a specific task every certain interval of time.

In the next part I show an example:

import sys
from PyQt4 import QtCore, QtGui
from functools import partial


class Window(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        centralwidget = QtGui.QWidget()
        self.setCentralWidget(centralwidget)
        layout = QtGui.QVBoxLayout(centralwidget)

        for i in range(4):
            button = QtGui.QPushButton("Timer{}".format(i+1))
            layout.addWidget(button)
            button.clicked.connect(partial(self.onClicked, button))

    def onClicked(self, button):
        sec = 10 # seconds
        timer =  button.property("timer").toPyObject()
        if timer is None:
            timer = QtCore.QTimer(button)
        timer.stop()
        timer.setInterval(1000)
        timer.setProperty("button", button)
        timer.setProperty("endTime", QtCore.QTime.currentTime().addMSecs(sec*1000+10))
        timer.timeout.connect(partial(self.onTimeout, timer))
        self.onTimeout(timer)
        timer.start()
        button.setProperty("timer", timer)

    def onTimeout(self, timer):
        button= timer.property("button")
        if hasattr(button, 'toPyObject'):
            button = button.toPyObject()
        tm = timer.property("endTime").toPyObject()
        if hasattr(tm, 'toPyObject'):
            tm = tm.toPyObject()
        ms = QtCore.QTime.currentTime().msecsTo(tm)
        if ms < 0:
            timer.stop()
        else:
            button.setText(QtCore.QTime().addMSecs(ms).toString())


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    ex = Window()
    ex.show()
    sys.exit(app.exec_())

Upvotes: 1

Related Questions