如何在进入Qt事件循环后自动执行方法?

5 投票
3 回答
5278 浏览
提问于 2025-04-16 18:50

我想执行一个方法,这个方法只能在我的 QApplication 显示出来后才能调用,也就是说,只有在它进入主事件循环 exec_() 的时候才能执行。我刚开始接触 Qt4(使用 PyQt4):我希望能有一个类似 on_start() 的回调函数,但我没有找到这样的东西。

我需要创建一个线程或者定时器吗?还是说在这个 API 里已经有现成的回调可以用呢?

3 个回答

0

我之前没用过Qt,所以可能说得不太对,但我想你可以把你的 on_start() 方法和 ApplicationActivate 事件绑定在一起。这样的话,你可以在 on_start() 方法里设置一个标志,这样代码就只会在第一次运行的时候执行,而在程序运行过程中触发 ApplicationActivate 事件时就不会再执行了。

另一方面,如果 on_start() 方法是被多个线程调用的,你可能需要使用线程特定的标志。我自己没做过太多多线程的事情,所以不太清楚具体该怎么做,或者说这会有多简单或复杂。

7

你可以用一个一次性定时器来实现这个功能,就像下面这个简单的脚本:

import sys
from PyQt4 import QtGui, QtCore

app = QtGui.QApplication(sys.argv)

def on_start():
    print(' in event loop!')
    print(' telling app to exit ...')
    app.exit(123)

QtCore.QTimer.singleShot(0, on_start)
print('About to enter event loop')
rc = app.exec_()
print('All done - returned %d' % rc)

当你运行这个脚本时,你应该能看到

About to enter event loop
 in event loop!
 telling app to exit ...
All done - returned 123
0

目前我选择用 QThread 这样来实现:

class MyThread(QtCore.QThread):
    def run(self):
    ''' reinplemented from parent '''
        # make thread sleep to make sure
        # QApplication is running before doing something
        self.sleep(2)
        do_something()

class MyWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.attr = 'foo'
        self.thread = MyThread(self)
        self.thread.start()

def main():
    app = QtGui.QApplication(sys.argv)
    w = MyWidget()
    w.show()
    sys.exit(app.exec_())

这样做对我来说是有效的,因为我在(真实的)代码中,线程实际上是在 X 显示中寻找应用程序窗口,并会一直尝试直到找到它。不过,这并不是解决问题的优雅方式。如果 QApplication 在进入事件循环时能发出一个信号,那就更好了。JAB 提出了 Qt.ApplicationActivate,但似乎 QApplication 并没有发出这个信号。即使它发出了,由于 MyWidget() 不是作为 QApplication 的子对象实例化的,我也不知道怎么把信号从 app 传递到 w

在接受我的答案作为最终解决方案之前,我会等一个更好的答案,如果有的话。

撰写回答