Search code examples
pythonpyqt4signals-slotsqtimerqprogressbar

PyQt4: use a QTimer to continually update progress bars


I have a simple dialog with three progress bars that I want to continually update (displaying system resource usage). From reading around the docs, QTimer is the right way to fire a function every x milliseconds (which would update the progress bars). However, I am not able to get it to work and I don't quite know why. It seems relatively simple to connect up the timer timeout signal to an update function, but it never seems to fire.

Here's my code:

import sys
from PyQt4 import QtGui, QtCore
import psutil

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

    def initUI(self):
        mainLayout = QtGui.QHBoxLayout()

        self.cpu_progressBar = QtGui.QProgressBar()
        self.cpu_progressBar.setTextVisible(False)
        self.cpu_progressBar.setOrientation(QtCore.Qt.Vertical)
        mainLayout.addWidget(self.cpu_progressBar)

        self.vm_progressBar = QtGui.QProgressBar()
        self.vm_progressBar.setOrientation(QtCore.Qt.Vertical)
        mainLayout.addWidget(self.vm_progressBar)

        self.swap_progressBar = QtGui.QProgressBar()
        self.swap_progressBar.setOrientation(QtCore.Qt.Vertical)
        mainLayout.addWidget(self.swap_progressBar)

        self.setLayout(mainLayout)

        timer = QtCore.QTimer()
        timer.timeout.connect(self.updateMeters)
        timer.start(1000)

    def updateMeters(self):
        cpuPercent = psutil.cpu_percent()
        vmPercent = getattr(psutil.virtual_memory(), "percent")
        swapPercent = getattr(psutil.swap_memory(), "percent")

        self.cpu_progressBar.setValue(cpuPercent)
        self.vm_progressBar.setValue(vmPercent)
        self.swap_progressBar.setValue(swapPercent)
        print "updated meters"

def main():
    app = QtGui.QApplication(sys.argv)
    ex = Tiny_System_Monitor()

    ex.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

Solution

  • You must keep a reference to the timer object, otherwise it will be immediately garbage-collected when initUI returns:

    class Tiny_System_Monitor(QtGui.QWidget):
        ...
        def initUI(self):
            ...    
            self.timer = QtCore.QTimer()
            self.timer.timeout.connect(self.updateMeters)
            self.timer.start(1000)