如何使PySide.QtCore.QTimer.singleShot调用其超时方法

时间:2016-08-09 02:50:48

标签: python multithreading qt pyside qtimer

我正在开发一个复杂且评论不佳的基于Qt的Python应用程序。它使用PySide.QtCore.QTimer.singleShot(int,slot)计时器来延迟线程中插槽的执行,我对此计时器的工作原理感到困惑。

这是一个MWE。此示例使用子类化QThread和重新实现run()的方法。我将以下内容放在名为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')

我用来测试它的代码(称之为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_())

python test.py的输出:

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

奇怪的是,传递给QTimer.singleShot的callable似乎永远不会被调用(输出中没有called print_things()!)我将非常感谢您可以清楚地了解这一点。我觉得我错过了Qt框架的一些简单要素。请耐心等待 - 我花了几个小时寻找答案。

2 个答案:

答案 0 :(得分:1)

QThread.run()调用QThread.exec()的默认实现,它启动线程自己的事件循环。 QTimer需要一个正在运行的事件循环,并且它的timeout()信号将在它启动的线程中发出。run()的实现不会启动事件循环,所以计时器什么都不做。

答案 1 :(得分:1)

正如@ekhumoro指出的那样,我重新实现run()无法调用exec_()。这是主要问题。我花了一分钟时间找出exec_()调用的位置以及如何在完成工作时正确退出()线程。这是有效的代码。

班级定义,timertester.py

import PySide

class SubClassThread(PySide.QtCore.QThread):

        def __init__(self,parent=None):
                print('called SubClassThread.__init__()')
                super(SubClassThread,self).__init__(parent)

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

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

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

申请,test.py

import sys

import PySide

from timertester import SubClassThread

print('Test: QThread subclassing')

# instantiate a QApplication
app = PySide.QtCore.QCoreApplication([])

# instantiate a thread
sct = SubClassThread()

# when the thread finishes, make sure the app quits too
sct.finished.connect(app.quit)

# start the thread
# it will do nothing until the app's event loop starts
sct.start()

# app.exec_() starts the app's event loop. 
# app will then wait for signals from QObjects.
status=app.exec_()

# print status code and exit gracefully
print('app finished with exit code {}'.format(status))
sys.exit(status)

最后,python test.py的输出:

Test: QThread subclassing
called SubClassThread.__init__()
called SubClassThread.run()
called SubClassThread.delayed_print()
end of delayed_print()
called print_things
app finished with exit code 0

我学到了关于QTimers的知识:在timer定时器仍在运行时对delayed_print()的调用结束,并且通过在计时器调用的方法中放置quit(),应用程序在调用该方法之后才会退出。

如果对此代码有任何进一步的评论,或者有关此简单应用的Qt方面,请发帖!我在为初学者找到可访问的PyQt / PySide信息时遇到了一些麻烦。