简体   繁体   中英

PyQt5 chang Label text using Loop

code it's clean from bugs but when is running program will freezing the program its countdown using button to start the countdown the picture below discripe the layout enter image description here

the probelm is im using loop to changing label text and that make program freezed

from time import sleep
import PyQt5.QtWidgets as Qtw


class MainWindow(Qtw.QWidget):

    def __init__(self):
        super().__init__()

        self.setLayout(Qtw.QVBoxLayout())
        
        pushButton = Qtw.QPushButton("start",clicked = lambda: setting_label())
        self.layout().addWidget(pushButton)


        my_label = Qtw.QLabel("00:00:00")
        self.layout().addWidget(my_label)
        

        self.show()
        def setting_label():
            t = 1200
            while t:
            
                h  = t // 3600
                m  = t // 60
                s  = t % 60
                timer = "{:02d}:{:02d}:{:02d}".format(h,m,s)
                my_label.setText(timer)
                sleep(1)
                t -= 1


   

app = Qtw.QApplication([])
window = MainWindow()
    
app.exec_()

The way the code is written in the OP, it doesn't really get stuck or frozen. But rather, the display fails to update. You can get around this by trying to force Qt to update the GUI with app.processEvents() . Put it in your setting_label function after the setText():

self.my_label.setText(timer)
app.processEvents()

The Preferred Way

Using app.processEvents() a lot is usually discouraged. Another way to make a countdown timer is to use a QTimer . There is a little more overhead in setting up all of the signals and slots. But it can be very powerful. Here is an example

from time import sleep
import PyQt5.QtWidgets as Qtw
from PyQt5.QtCore import QTimer

class MainWindow(Qtw.QWidget):

    def __init__(self):
        super().__init__()

        self.setLayout(Qtw.QVBoxLayout())

        pushButton = Qtw.QPushButton("start",clicked = self.start_countdown)
        self.layout().addWidget(pushButton)

        self.my_label = Qtw.QLabel("00:00:00")
        self.layout().addWidget(self.my_label)

        self.timer = QTimer()        # create a new QTimer instance
        self.timer.setInterval(1000) # make it fire every 1000 msec
        self.t = 1200
        self.timer.timeout.connect(self.setting_label) # connect the timeout signal to self.setting_label

        self.show()

    def start_countdown(self):
        self.t = 1200
        self.timer.start()

    def setting_label(self):

        if self.t == 0:
            self.timer.stop()
            print('timer stopped')

        h  = self.t // 3600
        m  = self.t // 60
        s  = self.t % 60
        timer = "{:02d}:{:02d}:{:02d}".format(h,m,s)
        self.my_label.setText(timer)
        self.t -= 1

app = Qtw.QApplication([])
window = MainWindow()

app.exec_()

Edit: This solution works for the OP, but others have pointed out that doing this using threading can cause unexpected behavior, crashes, etc. so it's better to do this using other methods (for example: this answer )

The interface freezes because the while loop you use to change the label blocks the event loop of the app (ie receiving inputs). You can fix this by moving the function to a thread like this:

import threading
from time import sleep

import PyQt5.QtWidgets as Qtw


class MainWindow(Qtw.QWidget):
    def __init__(self):
        super().__init__()

        self.setLayout(Qtw.QVBoxLayout())

        def setting_label():
            t = 1200
            while t:
                h  = t // 3600
                m  = t // 60
                s  = t % 60
                timer = "{:02d}:{:02d}:{:02d}".format(h,m,s)
                my_label.setText(timer)
                sleep(1)
                t -= 1
        
        pushButton = Qtw.QPushButton(
            "start",
            clicked=lambda: thread.Thread(target=setting_label).start()
        )
        self.layout().addWidget(pushButton)

        my_label = Qtw.QLabel("00:00:00")
        self.layout().addWidget(my_label)

        self.show()


app = Qtw.QApplication([])
window = MainWindow()
    
app.exec_()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM