Search code examples
pythonpyqtpyqt5qtimer

Is there a way to make qtimer wait until a function is done?


I have an application in which I would like to do the following thing:

  1. optimize a problem
  2. wait for a certain amount of time, e.g. one minute
  3. measure a certain property
  4. repeat steps two and three several times
  5. start again at 1.)

I want to start the entire process when clicking on a QPushButton. It is necessary that the step 2.) only starts when step 1.) is completely terminated. I dont know how long the optimzation process takes, therefre I cant just use QTimer.sleep().

I have solved this problem the following way:

from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication, QDialog
from PyQt5 import QtWidgets
import sys



class MyForm():
    def __init__(self):
        self.ui = QDialog()
        self.button = QtWidgets.QPushButton(self.ui)
        self.button.clicked.connect(self.start_timer)
        self.waiting_interval = 10000
        self.ui.show()

    def start_timer(self):
        self.optimize()
        self.counter = 0
        self.timer = QTimer()
        self.timer.timeout.connect(self.tick)
        self.timer.setSingleShot(True)
        self.timer.start(self.waiting_interval)



    def tick(self):


        self.timer = QTimer()
        if self.counter == 9:
            self.timer.timeout.connect(self.start_timer)
        else:
            self.measure_property()
            self.timer.timeout.connect(self.tick)
        self.timer.setSingleShot(True)
        self.timer.start(self.waiting_interval)
        self.counter += 1


    def optimize(self):
        pass


    def measure_property(self):
        pass



if __name__ == '__main__':
    app = QApplication(sys.argv)
    w=MyForm()
    app.exec_()

It produces the results that I want but I am looking for a smarter way to do this, maybe using signals and slots. Any help would be appreciated!


Solution

  • The tasks that take a long time are heavy and tend to freeze the GUI giving a bad experience to the user, in these cases those tasks must be executed in another thread:

    import sys
    from PyQt5 import QtCore, QtWidgets
    
    
    class ProcessThread(QtCore.QThread):
        def run(self):
            while True:
                self.optimize()
                for _ in range(3):
                    QtCore.QThread.sleep(60)
                    self.measure_property()
    
        def optimize(self):
            print("optimize")
    
        def measure_property(self):
            print("measure_property")
    
    
    class MyForm():
        def __init__(self):
            self.ui = QtWidgets.QDialog()
            self.thread = ProcessThread(self.ui)
            self.button = QtWidgets.QPushButton("Press me")
            self.button.clicked.connect(self.thread.start)
            self.waiting_interval = 10000
            lay = QtWidgets.QVBoxLayout(self.ui)
            lay.addWidget(self.button)
            self.ui.show()
    
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        w=MyForm()
        sys.exit(app.exec_())