Search code examples
pythonpyqtpyqt5lagqprogressbar

QtWidgets.QProgressBar.setTextVisible(False) causes lag


I have a QProgressBar that gets updated every second. The percentage text wasn't needed on it, so I added progressBar.setTextVisible(False) when it was created. However, this made it extremely slow to respond and laggy, so that it takes longer than a second to update. In addition, other code would wait for the progress bar to update to execute, making the entire program slow. This happens both on macOS, where progress bars don't show text anyways, and other OSes, like Ubuntu, that does show it.

Why does making the progress text not being visible cause this, and how can I solve this (while still removing the progress text)?


Solution

  • It is not that there is a lag. For you to understand it well use the following metaphor: let's say that there are 2 people, both must advance 1m in 1 second, but the first only performs jumps every second, while the second performs several continuous steps, so the first person is similar at the progressbar without text and in the second with text.

    When the value of the progressbar is changed, it is evaluated if it is necessary to repaint it, and in the case that there is visible text, it is done anyway, although it does not need if the value has changed, on the other hand if there is no text other than the changed value it is required that the step is appropriate I think that for reasons of performance.

    That part of the code can be found in the following link

    The solution is to force the painting every time there is a change.

    progressBar.valueChanged.connect(progressBar.repaint)
    

    Example:

    import sys
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    def create_progressBar(timeLine, isTextVisible, workaround=False):
        progressBar = QtWidgets.QProgressBar()
        progressBar.setTextVisible(isTextVisible)
        timeLine.frameChanged.connect(progressBar.setValue)
        if workaround:
            progressBar.valueChanged.connect(progressBar.repaint)
        progressBar.setRange(0, 100)
        return progressBar
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
    
        widget = QtWidgets.QWidget()
        lay = QtWidgets.QFormLayout(widget)
        timeLine = QtCore.QTimeLine(1000*10)
        timeLine.setFrameRange(0, 100)
    
        normal_with_text = create_progressBar(timeLine, True)
        normal_without_text = create_progressBar(timeLine, False)
        workaround_without_text = create_progressBar(timeLine, False, True)
        lay.addRow("normal_with_text", normal_with_text)
        lay.addRow("normal_without_text", normal_without_text)
        lay.addRow("workaround_without_text", workaround_without_text)
    
        timeLine.start()
        widget.show()
        sys.exit(app.exec_())