So, in my application, I create a single QtCore.QTimer
object and then call the singleShot
method on it to evoke a function after say 60 secs. Now, at any given point in time, if I would need to call the singleShot
method on it again and prevent the previous singleShot
method from taking effect (that is preventing it from calling the caller passed to it, if the second time the singleShot
is invoked before the first 60 seconds), what do I need to do? How can I 'kill' the previous QTimer
and completely forget about it and work only with the current QTimer
?
Can someone help me out with this?
Here's just a sample code:
def main():
q = QtCore.QTimer()
q.singleShot(4000, print_hello)
q.killTimer(id) ##how can I get the value of 'id' so that print_hello() is not called before the end of the 4 seconds?
def print_hello():
print 'hello'
Thanks
The problem is that QTimer.singleShot()
does not return a reference to the QTimer
. I don't know of anyway to get the Timer ID so you can kill it using that method. However, you can instantiate a normal QTimer
and make it a single-shot timer (this is not what you have done in your code provided, calling singleShot
on an instance of QTimer
creates a new QTimer
which you do not have access to.)
However, all is not lost. You can create a normal QTimer
and convert it to a single shot timer using setSingleShot(True)
. This allows you to call the stop()
method if you wish to abort the timer. See the code example below which does what you require, on a 3 second timeout. You can push the button as many times as you like in rapid succession, and it will print "hello" once, 3 seconds after you stop. If you push it once, wait 4 seconds, and push it again, it will of course print out twice!
Hope that helps!
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class MyApp(QWidget):
def __init__(self,*args,**kwargs):
QWidget.__init__(self,*args,**kwargs)
self.current_timer = None
self.layout = QVBoxLayout(self)
self.button = QPushButton('start timer')
self.button.clicked.connect(self.start_timer)
self.layout.addWidget(self.button)
def start_timer(self):
if self.current_timer:
self.current_timer.stop()
self.current_timer.deleteLater()
self.current_timer = QTimer()
self.current_timer.timeout.connect(self.print_hello)
self.current_timer.setSingleShot(True)
self.current_timer.start(3000)
def print_hello(self):
print 'hello'
# Create QApplication and QWidget
qapp = QApplication(sys.argv)
app = MyApp()
app.show()
qapp.exec_()
Building on @three_pineapples's answer, and simplifying the code some.
There is no need to create a new QTimer
on every button click, you only need to call .start()
on the existing timer, and it will be stopped and started again.
See the PyQt4 documentation for QTimer.start()
.
import sys
from PyQt4.QtCore import QTimer
from PyQt4.QtGui import (
QApplication,
QWidget,
QVBoxLayout,
QPushButton,
)
class MyApp(QWidget):
def __init__(self,*args,**kwargs):
QWidget.__init__(self,*args,**kwargs)
self.layout = QVBoxLayout(self)
self.button = QPushButton('Start timer')
self.button.clicked.connect(self.start_timer)
self.layout.addWidget(self.button)
self.timer = QTimer()
self.timer.timeout.connect(self.hello)
self.timer.setSingleShot(True)
def start_timer(self):
self.timer.start(3000)
def hello(self):
print('Hello!')
# Create QApplication and QWidget
qapp = QApplication(sys.argv)
app = MyApp()
app.show()
qapp.exec_()
If the creation of a second QTimer
is entirely necessary then your approach is decent enough. What you could do it create a function or class that would such bookkeeping.
You could use the QBasicTimer
. The doc:
The QTimer class provides a high-level programming interface with single-shot timers and timer signals instead of events. There is also a QBasicTimer class that is more lightweight than QTimer and less clumsy than using timer IDs directly.
If you want to get rid of the current_timer
entirely then I would suggest you call the current_timer.deleteLater
function. Make sure you assign a new QTimer
to it as soon as you call this function or del
/delete it by del current_timer
or else if you reference any it's attributes later it will raise an error saying something like C++ object not found
.
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