Search code examples
python-3.xpyqtpyqt5

PyQt5 does not redrawing widget


Force repainting does not repaint PyQt5 widget (Qlabel, QTextEdit, even QProgressBar and etc)

Tested platforms: Linux, MacOS

PyQt5 version: 5.15.7
Installed from pip

As example I created simple app that updating text in QLabel widget in for loop. Force repainting doesnt working

import sys
from time import sleep
from PyQt5.QtWidgets import (QWidget, QApplication, QPushButton, QLabel)

class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.text = QLabel('Test', self)
        self.text.move(10, 10)
        self.text.resize(60,20)

        self.button =  QPushButton('Run', self)
        self.button.move(17,40)
        self.button.clicked.connect(self.some_activity)

        self.setGeometry(300, 300, 100, 80)
        self.show()

    def some_activity(self):
        for i in range(100):
            text = f'i = {i}'
            self.text.setText(text)
            # self.text.update() -> Nothing happens (it shouldnt: https://doc.qt.io/qt-5/qwidget.html#update)
            self.text.repaint() # -> Nothing happens
            self.repaint() # -> Nothing happens
            print(f'Text updated: {text}')
            sleep(0.03)

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

Video demonstration: link


Solution

  • Just needed to use QThread to use for loop in my program
    Thanks @musicamante for helping.

    import sys
    from time import sleep
    from PyQt5 import QtCore
    from PyQt5.QtWidgets import (QWidget, QApplication, QPushButton, QLabel)
    
    class Thread(QtCore.QThread):
        signal = QtCore.pyqtSignal(str)
        def __init__(self, parent=None): QtCore.QThread.__init__(self, parent)
    
        def run(self): 
            for i in range(100):
                text = f'i = {i}'
                print(f'Text updated: {text}')
                self.signal.emit(text)
                sleep(.3)
    
    class Example(QWidget):
        def __init__(self):
            super().__init__()
            self.text = QLabel('Test', self)
            self.text.move(10, 10)
            self.text.resize(60,20)
    
            self.thread = Thread()
            self.thread.signal.connect(self.signal, QtCore.Qt.QueuedConnection)
    
            self.button =  QPushButton('Run', self)
            self.button.move(17,40)
            self.button.clicked.connect(self.thread.start)
    
            self.setGeometry(300, 300, 100, 80)
            self.show()
        
        def signal(self, text): self.text.setText(text)
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        ex = Example()
        sys.exit(app.exec_())