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

Posted

技术标签:

【中文标题】进入Qt事件循环后如何自动执行方法?【英文标题】:How to execute a method automatically after entering Qt event loop? 【发布时间】:2011-06-02 14:11:12 【问题描述】:

我想执行一个方法,该方法只能在我的QApplication 显示后调用,即当它进入其主事件循环exec_() 时。我是 Qt4 的新手(使用 PyQt4):我希望有一个类似 on_start() 的回调,但没有找到。 我需要创建线程或计时器吗?还是 API 中已经包含一些回调?

【问题讨论】:

【参考方案1】:

您可以为此使用单次计时器,如以下简单脚本所示:

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

【讨论】:

谢谢,我也想过使用 QTimer。我最终选择了QThread,我认为它更易于使用。但是您的示例比文档更清楚:)【参考方案2】:

我以前没有使用过 Qt,所以我可能错了,但我想你可以将你的 on_start() 方法绑定到 ApplicationActivate 事件,并从你的 on_start() 方法中设置一个标志,以便代码只会在第一次运行,而不会在其他任何时候在程序执行期间触发ApplicationActivate 事件。

另一方面,如果on_start() 方法将被多个线程调用,您可能希望使用特定于线程的标志。我自己没有做过太多的多线程,所以我不确定具体是什么,或者它有多简单/复杂。

【讨论】:

嘿,谢谢。我见过Qt.ApplicationActivate,但我仍然感到困惑,因为QApplication 没有实现该信号。如果我必须将此信号绑定到QApplication,它也必须在事件循环开始之后发生,这让我回到了最初的问题。但也许我只是不明白信号在 Qt 中是如何工作的 :) “但我仍然感到困惑,因为 QApplication 没有实现该信号。”这就是子类化的目的。 @JAB:是的,我在我的评论和你的评论之间想到了这一点。但是QApplication 的事件是否可以传递给QWidget,即使后者不是前者的孩子?我只见过最顶层小部件的子级之间的事件处理。 我认为这应该是可能的,但正如我所说,我没有任何实际使用 Qt 的经验。 riverbankcomputing.co.uk/static/Docs/PyQt4/html/… @JAB:哈!也许我可以将Widget() 实例连接到 Widget() 类定义之外的QApplication,即在main() 函数中。我会尝试让你知道它是如何工作的。谢谢。【参考方案3】:

现在我选择这样使用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 的子代,我不知道如何通过从appw 的信号

我会等待更好的答案(如果有的话),然后再接受我的答案作为选择的解决方案。

【讨论】:

以上是关于进入Qt事件循环后如何自动执行方法?的主要内容,如果未能解决你的问题,请参考以下文章

QT事件循环

qt源码解析1--事件循环原理(重写事件函数,事件过滤器等)

WPF中想要让一个按钮单击事件结束后自动再单击这个按钮,也就是让单机事件连续反复执行,应该如何实现?

QT事件循环与QThread类的关闭quit(),wait()

js事件循环

Qt 阻塞事件循环