Skip to content
Advertisement

How to call a function periodically while my MainWindow is active?

I have tried doing it with multiprocessing module to no avail. I get the following error:

TypeError: cannot pickle ‘MainWindow’ object

import time, multiprocessing
from PyQt5 import QtWidgets, QtGui


class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        self.initializeUI()
        self.show()


    def initializeUI(self):
        # UI stuff

        self.setLayout(QtWidgets.QGridLayout())

        dummy_btn = QtWidgets.QPushButton("Ok")
        self.layout().addWidget(dummy_btn)

        updater = multiprocessing.Process(target=self.update_function, args=[])
        updater.start()

    def update_function(self):
        time.sleep(2)
        print("This text, again!")
        self.update_function()



app = QtWidgets.QApplication([])
mw = MainWindow()
app.exec_()

Advertisement

Answer

the proper way to do this is to not use any sort of parallel mechanism, instead use QTimer.singleshot, as QT doesn’t work well with multiprocessing or threading, and if you want to repeat it then you can just connect the function to a Qtimer.timeout signal and set the timer on repeat using Qtimer.start() as in this tutorial

import time, multiprocessing
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtCore import QTimer


class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        self.initializeUI()
        self.show()


    def initializeUI(self):
        # UI stuff

        self.setLayout(QtWidgets.QGridLayout())

        dummy_btn = QtWidgets.QPushButton("Ok")
        self.layout().addWidget(dummy_btn)
        self.timer = QTimer(self)
        # self.timer.singleShot(2000,self.update_function)  # for one time call only
        self.timer.timeout.connect(self.update_function)
        self.timer.start(2000) # time in milliseconds.

    def update_function(self):
        # time.sleep(2) this is not needed
        print("This text, again!")
        self.update()  # this had a typo



app = QtWidgets.QApplication([])
mw = MainWindow()
app.exec_()

Edit: to clarify on working with threads and multiprocessing, if you use multiprocessing for example there are many precautions, such as putting an if __name__ == "__main__": guard on your code, and not use anything that belong to QT inside the subprocesses, and just use it for running things that don’t need QT, like reading files and doing calculations.

as for threading, using any QWidget object in another thread other than your main application thread is going to crash your application, you can emit signals from child threads for signaling, but you cannot update the GUI on another thread, so only use QT objects that don’t touch the GUI inside threads. (like networking, reading files, and sharing the CPU for extra calculations)

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement