I am looking for a way to setup a number of timed function calls in pyqt, with a way to cancel all pending calls when needed.
I was looking at using QtCore.QTimer
to setup the function calls, but I don't know of any good way to cancel these calls. Any ideas?
I can't seem to find any way to cancel after using QtCore.QTimer.singleShot(1000, self.function)
. If instead I create a list of QTimer
objects I can stop them, but then I am forced to manage a list of timer objects (creation, deletion, which are active, etc.), which I would like to avoid.
# 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()
I could also manage my own queue of pending function calls, which I would also like to avoid if possible (for the sake of simplicity).
Here is some dummy code showing the kind of thing I am trying to do:
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_())
I have come up with a solution by directly using the timer functionality provided by QObject
. I suspect that there is a more elegant solution, but this will probably work for what I need.
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_())
you can disconnect from the timer's timeout signal and connect back whenever you need. Once disconnected you stop receiving any calls from the timer even though it still remains active. Below is a small example:
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()
once timer started both slots on_timeout
and on_timeout_test
are getting called, when you click the button on_timeout_test
slot gets disconnected and then connected back if button is clicked again.
hope this helps, regards
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With