4

I am trying to make an app that monitors hardware, I would like to use Qthreadpool instead of having a thread for each widget and I am having trouble connecting signals to display the output. I am also getting no errors.

My old code runs fine and displays what it should using QThread:

import sys
from PyQt4 import QtCore, QtGuiimport ui
import time
import mem_stats


class MainClass(QtGui.QMainWindow, ui.Ui_MainWindow):
        def __init__(self, parent= None):
        super(MainClass, self).__init__(parent)
        self.setupUi(self)
        self.mem_worker = MemWorker()
        self.mem_worker.start()
        self.connect(self.mem_worker, QtCore.SIGNAL('MEM_STATS'),self.show_mem_stats)

    def show_mem_stats(self, free_mem):
        self.free_memory_lcd.display(free_mem)


class MemWorker(QtCore.QThread):
    def __init__(self):
    super(MemWorker, self).__init__()

    def run(self):
        while True:
            free_mem = mem_stats.free_mem()
            self.emit(QtCore.SIGNAL('MEM_STATS'), free_mem)
            time.sleep(1)


if __name__ == '__main__':
    a = QtGui.QApplication(sys.argv)
    app = MainClass()
    app.show()
    sys.exit(a.exec_())

But when i change MemWorker class to QRunnable the code runs with no errors but the QlcdNumber doesn't display anyting.

Here's my new code:

import sys
from PyQt4 import QtCore, QtGui
import ui
import time
import mem_stats


class WorkerSignals(QtCore.QObject):
    mem_signal = QtCore.pyqtSignal(int)


class MainClass(QtGui.QMainWindow, ui.Ui_MainWindow):
    def __init__(self, parent= None):
        super(MainClass, self).__init__(parent)
        self.setupUi(self)
        self.mem_worker = MemWorker()
        self.thread_pool = QtCore.QThreadPool()
        self.thread_pool.setMaxThreadCount(2)
        self.connect(self.mem_worker.signal, QtCore.SIGNAL('MEM_STATS'), self.show_mem_stats)

    def show_mem_stats(self, free_mem):
        self.free_memory_lcd.display(free_mem)
        self.thread_pool.start(self.mem_worker)


class MemWorker(QtCore.QRunnable):
    def __init__(self):
        super(MemWorker, self).__init__()
        self.signal = WorkerSignals()

    def run(self):
        while True:
            free_mem = mem_stats.free_mem()
            self.signal.mem_signal.emit(QtCore.SIGNAL('MEM_STATS'), free_mem)
            time.sleep(1)


if __name__ == '__main__':
    a = QtGui.QApplication(sys.argv)
    app = MainClass()
    app.show()
    sys.exit(a.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
fredwntr1
  • 58
  • 1
  • 6

1 Answers1

5

The problem is that you are not starting the QRunnable, you want to start it in the slot and it will never be called if the QRunnable is not started. On the other hand, it is currently recommended to use the new connection syntax, and finally it is recommended to use the @pyqtSlot decorator that makes the connection from the C++ side, making it faster with fewer resources.

from PyQt4 import QtCore, QtGui
import ui
import time
import mem_stats

class WorkerSignals(QtCore.QObject):
    mem_signal = QtCore.pyqtSignal(int)


class MainClass(QtGui.QMainWindow, ui.Ui_MainWindow):
    def __init__(self, parent= None):
        super(MainClass, self).__init__(parent)
        self.setupUi(self)
        self.mem_worker = MemWorker()
        self.thread_pool = QtCore.QThreadPool()
        self.thread_pool.setMaxThreadCount(2)
        self.mem_worker.signal.mem_signal.connect(self.show_mem_stats)
        self.thread_pool.start(self.mem_worker)

    @QtCore.pyqtSlot(int)
    def show_mem_stats(self, free_mem):
        self.free_memory_lcd.display(free_mem)


class MemWorker(QtCore.QRunnable):
    def __init__(self):
        super(MemWorker, self).__init__()
        self.signal = WorkerSignals()

    def run(self):
        while True:
            ree_mem = mem_stats.free_mem()
            self.signal.mem_signal.emit(free_mem)
            time.sleep(1)


if __name__ == '__main__':
    import sys
    a = QtGui.QApplication(sys.argv)
    app = MainClass()
    app.show()
    sys.exit(a.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Although the code runs now i get an issue here in the terminal when the script is run. "Qt Concurrent has caught an exception thrown from a worker thread. This is not supported, exceptions thrown in worker threads must be caught before control returns to Qt Concurrent." – fredwntr1 Oct 30 '18 at 05:01