有没有一种方法可以让QTimer等待函数执行完毕?

3

我有一个应用程序,希望实现以下功能:

  1. 优化问题
  2. 等待一段时间,比如一分钟
  3. 测量某个属性
  4. 重复执行步骤二和三多次
  5. 重新开始从1)开始

我希望在单击QPushButton时启动整个过程。需要确保当步骤1)完全终止后才开始步骤2)。由于我不知道优化过程需要多长时间,因此不能只使用QTimer.sleep()。

我通过以下方式解决了这个问题:

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_()

它能够产生我想要的结果,但是我正在寻找一种更智能的方法来实现这一点,也许可以使用信号和槽。任何帮助都将不胜感激!


到目前为止,我看到您正在使用信号,因此假设 optimize() 和 measure_property() 任务需要少于10毫秒是可以的。如果任务需要更长时间,则必须在另一个线程中执行,以防止阻塞GUI。 - eyllanesc
任务需要更长时间,measure() 需要几秒钟,而 optimize() 则需要 20 到 80 秒不等。 - anonymous
如果不是在主线程中完成任务,那么这项任务就不应该被执行。另一方面,在界面上是否显示了优化或测量属性的结果呢? - eyllanesc
1个回答

3

执行时间长的任务比较繁重,往往会导致 GUI 崩溃,给用户带来不好的体验。在这种情况下,这些任务必须在另一个线程中执行:

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_())

谢谢你的帮助!不过仍有两个问题我没有理解。首先,线程从未停止。即使我关闭了GUI,它仍在继续运行。如何停止它?其次,我不懂这个结构。为什么在构造函数中要将self.ui作为参数传递?而为什么self.thread.start实际上启动了ProcessThread中定义的线程呢?你只是创建了一个ProcesThread的实例,但并未调用此实例上的run方法? - anonymous
1)在我的测试中,当GUI关闭时线程会结束,你修改了我的测试代码吗? 2)我将GUI设置为线程的父级,这样当GUI被销毁时线程也会被销毁。如果你了解QThread的继承,那么就已经有一些定义好的行为来自于QThread(它们已经完成了我们的工作,这就是继承的魔力 :-)),所以你不应该直接调用run方法,而是在调用start时QThread会创建一个线程并调用run方法。 - eyllanesc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接