【问题标题】:Cancel all outstanding QTimer events取消所有未完成的 QTimer 事件
【发布时间】:2011-02-21 21:19:44
【问题描述】:

我正在寻找一种在 pyqt 中设置多个定时函数调用的方法,并在需要时取消所有挂起的调用。

我正在考虑使用QtCore.QTimer 来设置函数调用,但我不知道有什么好的方法可以取消这些调用。有什么想法吗?



使用QtCore.QTimer.singleShot(1000, self.function) 后,我似乎找不到任何取消的方法。相反,如果我创建一个 QTimer 对象列表,我可以停止它们,但是我不得不管理一个计时器对象列表(创建、删除、活动等),我想避免这种情况。

# Setup a timer object.
timer = QtCore.QTimer(self)
timer.timeout.connect(self.function)
timer.setSingleShot(True)
timer.start(1000)

# To stop the timer object at some later point.
timer.stop()

我还可以管理自己的待处理函数调用队列,如果可能的话,我也想避免这种情况(为了简单起见)。



这是一些虚拟代码,显示了我正在尝试做的事情:

import sys
from PyQt4 import QtCore

class Test(QtCore.QObject):

    def __init__(self, parent=None):
        QtCore.QObject.__init__(self, parent)
        

    def addDelayedCall(self, time, function):
        # Do something here.
        pass


    def clearPendingCalls(self):
        print('  Clearing pending function calls.')
        # Do something here.


    def setupCalls(self):
        self.addDelayedCall(500, self.dummy)
        self.addDelayedCall(1000, self.dummy)
        self.addDelayedCall(1500, self.dummy)
        self.addDelayedCall(2000, self.dummy)


    def dummy(self):
        print('dummy just got called.')


if __name__ == '__main__':
    app = QtCore.QCoreApplication(sys.argv)
    test = Test(app)

    QtCore.QTimer.singleShot(0, test.setupCalls)
    QtCore.QTimer.singleShot(1250, test.clearPendingCalls)
                   
    QtCore.QTimer.singleShot(5000, app.quit)            
    sys.exit(app.exec_())

【问题讨论】:

    标签: qt pyqt


    【解决方案1】:

    我想出了一个解决方案,直接使用QObject 提供的计时器功能。我怀疑有一个更优雅的解决方案,但这可能会满足我的需要。

    import sys
    from PyQt4 import QtCore
    
    
    class Test(QtCore.QObject):
    
        def __init__(self, parent=None):
            QtCore.QObject.__init__(self, parent)
    
            self.timers = {}
    
    
        def timerEvent(self, event):
            function = self.timers.pop(event.timerId())
            self.killTimer(event.timerId())
            function()
    
    
        def addDelayedCall(self, time, function):
            timer_id = self.startTimer(time)
    
            self.timers[timer_id] = function
    
    
        def clearPendingCalls(self):
            print('  Clearing pending function calls.')
    
            while self.timers:
                timer_id, function = self.timers.popitem()
                self.killTimer(timer_id)
    
    
        def setupCalls(self):
            self.addDelayedCall(500, self.dummy)
            self.addDelayedCall(1000, self.dummy)
            self.addDelayedCall(1500, self.dummy)
            self.addDelayedCall(2000, self.dummy)
    
    
        def dummy(self):
            print('dummy just got called.')
    
    
    
    
    if __name__ == '__main__':
        app = QtCore.QCoreApplication(sys.argv)
        test = Test(app)
    
        QtCore.QTimer.singleShot(0, test.setupCalls)
        QtCore.QTimer.singleShot(1250, test.clearPendingCalls)
    
        QtCore.QTimer.singleShot(5000, app.quit)            
        sys.exit(app.exec_())
    

    【讨论】:

    • 一个更简单的方法是像以前一样使用QTimer,但放弃方便的setSingleShot,而不是显式地创建和配置QTimers。 但是,您不需要手动维护一个列表,您需要做的就是在某处维护一个普通的QObject,然后使用该 QObject 作为您创建的 QTimer 实例的父级 (例如QtCore.QTimer(cancellerObject) - 之后您不需要自己持有 QTimer 实例。然后取消所有挂起的计时器,只需销毁该对象,它会立即销毁其所有子 QTimer 作为副作用。
    • @JasonC,这听起来不错,而且确实比我的解决方案简单得多。我将不得不解决这个问题并考虑将其用于未来的项目。
    【解决方案2】:

    您可以通过计时器的超时信号disconnect 并在需要时重新连接。一旦断开连接,您将停止接收来自计时器的任何呼叫,即使它仍然处于活动状态。下面是一个小例子:

    import sys
    from PyQt4 import QtGui, QtCore
    
    class MainForm(QtGui.QMainWindow):
        def __init__(self, parent=None):
            super(MainForm, self).__init__(parent)
    
            self.button = QtGui.QPushButton("button", self)       
            self.button.resize(100, 30)
    
            self.connect(self.button, QtCore.SIGNAL('clicked()'), self.on_button_click)
    
            self.connected = True
            self.timer = QtCore.QTimer(self)
            self.connect(self.timer, QtCore.SIGNAL('timeout()'), self.on_timeout)
            self.connect(self.timer, QtCore.SIGNAL('timeout()'), self.on_timeout_test)
            self.timer.start(1000)
    
        def on_button_click(self):
            if self.connected:
                self.disconnect(self.timer, QtCore.SIGNAL('timeout()'), self.on_timeout_test)
            else:
                self.connect(self.timer, QtCore.SIGNAL('timeout()'), self.on_timeout_test)
            self.connected = not self.connected
    
        def on_timeout(self):
            print 'on_timeout'
    
        def on_timeout_test(self):
            print 'on_timeout_test'
    
    def main():
        app = QtGui.QApplication(sys.argv)
        form = MainForm()
        form.show()
        app.exec_()
    
    if __name__ == '__main__':
        main()
    

    一旦计时器启动,两个插槽 on_timeouton_timeout_test 都会被调用,当您单击 按钮时,on_timeout_test 插槽会断开连接,然后如果 按钮重新连接再次点击。

    希望这有帮助,问候

    【讨论】:

    • 不幸的是,这对我想要做的事情没有帮助。 (尽管它是一个很好的解决方案。)我在我的问题中添加了一些虚拟代码,希望能更清楚地解释我的目标。
    猜你喜欢
    • 2020-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-30
    • 2015-11-23
    相关资源
    最近更新 更多