Stop a QTimer.singleShot() timer

3.4k views Asked by At
  1. Is it possible to stop a QTimer.singleShot() timer? (Please don't tell me to use the stop() function of a QTimer object - I really want to know if the static function QTimer.singleShot() can be stopped before its time has elapsed)

  2. What happens if a second QTimer.singleShot() is launched before the first one has elapsed? Is the first one killed, or is a second one started instead?

1

There are 1 answers

0
ekhumoro On

Q. What happens if a second QTimer.singleShot() is launched before the first one has elapsed? Is the first one killed or is a second one started instead?

  • All timers work independently, so if two are started in succession, both will run until completion.

Q. Is it possible to stop a QTimer.singleShot() timer? (Please don't tell me to use the stop() function of a QTimer object - I really want to know if the static function QTimer.singleShot() can be stopped before its time has elapsed)

  • The static function creates an internal object that handles the timer, so there is no public API available to stop it. However, there is a hack involving QAbstractEventDispatcher which can work around this restriction. It relies on an implementation detail, so it is not recommended that this is used in production code. But you asked whether it was possible, so here is a demo:

    from PyQt4 import QtCore, QtGui
    
    class Window(QtGui.QWidget):
        def __init__(self):
            super(Window, self).__init__()
            self.button = QtGui.QPushButton('Start', self)
            self.button.clicked.connect(self.handleTimer)
            self.edit = QtGui.QLineEdit(self)
            self.edit.setReadOnly(True)
            layout = QtGui.QVBoxLayout(self)
            layout.addWidget(self.button)
            layout.addWidget(self.edit)
            self._timer = None
    
        def handleTimer(self):
            dispatcher = QtCore.QAbstractEventDispatcher.instance()
            if self._timer is None:
                self.edit.clear()
                self.button.setText('Stop')
                QtCore.QTimer.singleShot(3000, self.handleTimeout)
                self._timer = dispatcher.children()[-1]
            else:
                dispatcher = QtCore.QAbstractEventDispatcher.instance()
                dispatcher.unregisterTimers(self._timer)
                self.button.setText('Start')
                self._timer = None
    
        def handleTimeout(self):
            self._timer = None
            self.button.setText('Start')
            self.edit.setText('timeout')
    
    if __name__ == '__main__':
    
        import sys
        app = QtGui.QApplication(sys.argv)
        window = Window()
        window.setGeometry(500, 150, 300, 100)
        window.show()
        sys.exit(app.exec_())