取消所有未完成的 QTimer 事件
Posted
技术标签:
【中文标题】取消所有未完成的 QTimer 事件【英文标题】:Cancel all outstanding QTimer events 【发布时间】: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_())
【问题讨论】:
【参考方案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_timeout
和 on_timeout_test
都会被调用,当您单击 按钮时,on_timeout_test
插槽会断开连接,然后如果 按钮重新连接再次点击。
希望这有帮助,问候
【讨论】:
不幸的是,这对我想要做的事情没有帮助。 (尽管它是一个很好的解决方案。)我在我的问题中添加了一些虚拟代码,希望能更清楚地解释我的目标。以上是关于取消所有未完成的 QTimer 事件的主要内容,如果未能解决你的问题,请参考以下文章
在 WooCommerce 3+ 中将已付款订单标记为“已完成”,将未付款订单标记为“已取消”[重复]