Search code examples
pythonmultithreadingqtpysideqtimer

How to make a PySide.QtCore.QTimer.singleShot call its timeout method


I am working on a complex and poorly commented Qt-based Python application. It employs a PySide.QtCore.QTimer.singleShot(int,slot) timer to delay the execution of a slot within a thread, and I am confused about how this timer works.

Here is a MWE. This example uses the approach of subclassing QThread and reimplementing run(). I put the following in a file called timertester.py:

import PySide
import time

class SubClassThread(PySide.QtCore.QThread):

        def run(self):
                print('called SubClassThread.run()')
                self.delayed_print()

        def delayed_print(self):
                print('called SubClassThread.delayed_print()')
                PySide.QtCore.QTimer.singleShot(1000, self.print_things)
                time.sleep(2)
                print('end of delayed_print()')

        def print_things(self):
                print('called print_things')

The code I am using to test this (call it test.py):

import sys
import time

import PySide

from timertester import SubClassThread

print('Test: QThread subclassing')
app = PySide.QtCore.QCoreApplication([])
sct = SubClassThread()
sct.finished.connect(app.exit)
sct.start()
sys.exit(app.exec_())

The output of python test.py:

Test: QThread subclassing
called SubClassThread.run()
called SubClassThread.delayed_print()
end of delayed_print()

The curious part is that the callable passed to QTimer.singleShot never seems to get called (there is no called print_things() in the output!) I would greatly appreciate any clarity that you can shed on this. I feel that I am missing some simple ingredient of the Qt framework. Please bear with me- I did spend some hours searching for answers to this.


Solution

  • The default implementaion of QThread.run() calls QThread.exec(), which starts the thread's own event-loop. A QTimer requires a running event-loop, and its timeout() signal will be emitted in the thread it is started in. Your implementation of run() does not start an event-loop, so the timer will do nothing.