Home > Enterprise >  Update progress bar from thread monitoring CPU activity
Update progress bar from thread monitoring CPU activity

Time:05-30

I am getting this error from my code:

RuntimeWarning: MetaObjectBuilder::addMethod: Invalid method signature provided for "CPU_VALUE"
  self.threadclass.CPU_VALUE.connect(SIGNAL('CPU_VALUE'), self.UpdateProgressBar)
from PySide2 import QtWidgets, QtCore
from PySide2.QtCore import SIGNAL, Signal
import main
import sysinfo


class MainUiClass(main.Ui_MainWindow, QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainUiClass, self).__init__(parent)
        self.setupUi(self)
        self.threadclass = ThreadClass()
        self.threadclass.start()
        self.threadclass.CPU_VALUE.connect(SIGNAL('CPU_VALUE'), self.UpdateProgressBar)
        # self.UpdateProgressBar()

    def UpdateProgressBar(self):
        val = sysinfo.getCPU()
        self.progressBar.setValue(val)


class CpuClass(QtCore.QObject):
    cpu = Signal()


class ThreadClass(QtCore.QThread):
    CPU_VALUE = CpuClass()
    cpu = Signal()

    def __init__(self, parent=None):
        super(ThreadClass, self).__init__(parent)

    def run(self):
        while 1:
            # val = sysinfo.getCPU()
            self.CPU_VALUE.emit(SIGNAL('CPU_VALUE'), sysinfo.getCPU())
            # print(val)


if __name__ == '__main__':
    app = QtWidgets.QApplication([])
    a = MainUiClass()
    a.show()
    app.exec_()

sysinfo file:

import psutil

def getCPU():
    return psutil.cpu_percent(interval=1)

CodePudding user response:

Your example has several problems. Firstly, you are mixing old-style and new-style signals, which is confusing and unnecessary. Old-style signals should never be used in new applications. Secondly, you are using a signal object (CpuSignal), which is unnecessary since signals can be directly defined on the QThread class. Thirdly, you aren't emitting the value of the cpu percent in the signal, so the progress bar will never be updated. Finally, you haven't provided a mechanism for shutting down your thread cleanly.

In the demo script below, all the above issues have been fixed and I have also added a Simulator class to generate cpu-activity for testing. Clicking the Test button will produce about twenty seconds of activity and the progress-bar will then be updated accordingly:

screenshot

import psutil
from PySide2 import QtWidgets, QtCore
from PySide2.QtCore import Signal

class MainUiClass(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.progress = QtWidgets.QProgressBar()
        self.button = QtWidgets.QPushButton('Test')
        self.button.clicked.connect(self.handleButton)
        layout = QtWidgets.QHBoxLayout(self)
        layout.addWidget(self.progress)
        layout.addWidget(self.button)
        self.monitor = CpuMonitor()
        self.monitor.cpuPercent.connect(self.progress.setValue)
        self.monitor.start()
        self.simulator = Simulator()

    def handleButton(self):
        if not self.simulator.isRunning():
            self.simulator.start()

    def closeEvent(self, event):
        for thread in self.simulator, self.monitor:
            thread.stop()
            thread.quit()
            thread.wait()

class CpuMonitor(QtCore.QThread):
    cpuPercent = Signal(int)

    def run(self):
        self._stopped = False
        while not self._stopped:
            value = int(psutil.cpu_percent(interval=1))
            self.cpuPercent.emit(value)

    def stop(self):
        self._stopped = True

class Simulator(QtCore.QThread):
    def run(self):
        self._stopped = False
        random = QtCore.QRandomGenerator.system()
        timer1 = QtCore.QDeadlineTimer(20000)
        while not self._stopped and not timer1.hasExpired():
            duration = random.bounded(400, 800)
            self.msleep(duration)
            timer2 = QtCore.QDeadlineTimer(duration)
            while not self._stopped and not timer2.hasExpired():
                pass

    def stop(self):
        self._stopped = True

if __name__ == '__main__':

    app = QtWidgets.QApplication(['CPU Monitor'])
    a = MainUiClass()
    a.show()
    app.exec_()
  • Related