[英]Qt GUI event recording and playback
我正在尝试实现一个简单,轻量级的系统来记录Qt GUI事件并从脚本中播放它们。 我认为使用Qt事件系统的魔力会相当简单,但我遇到了一个我不明白的问题。
以下是我正在做的事情的快速摘要:
记录:
我使用QApplication.instance().eventFilter()
捕获我感兴趣的所有GUI事件*并将它们保存到Python脚本中,其中每个步骤看起来像这样:
obj = get_named_object('MainWindow.my_menubar')
recorded_event = QMouseEvent(2, PyQt4.QtCore.QPoint(45, 8), 1, Qt.MouseButtons(0x1), Qt.KeyboardModifiers(0x0))
post_event(obj, recorded_event)
回放:
我只是在一个worker( 非GUI )线程中执行上面的脚本。 (我不能使用GUI线程,因为我想继续向应用程序发送脚本事件,即使在模式对话框eventloop运行时'main'eventloop被阻止。)
重要的东西发生在我的post_event()
函数中,它需要做两件事:
QApplication.postEvent(obj, recorded_event)
obj
的同一事件循环中。 QApplication.processEvents()
第二部分完成后,我的期望是第一部分(记录的事件)的所有效果都已完成 ,因为特殊事件在记录的事件之后排队。
整个系统主要是似乎只是正常工作的鼠标事件,重要事件等,但我有一个问题QAction
处理程序,当我试图播放我的主要活动QMenuBar
。
无论我尝试什么,似乎我都不能强制我的回放线程阻止完成因点击我的QMenu
项而产生的所有QAction.triggered
处理程序 。 据我所知, QApplication.processEvents()
在QAction
处理程序完成之前返回。
有关QMenu
小部件或QAction
信号的特殊内容QMenu
违反了QApplication.postEvent()
和/或QApplication.processEvents()
的常规规则? 我需要一种方法来阻止我的QMenu
的QAction
处理程序的完成。
[*]并非每个事件都被记录下来。 我只记录spontaneous()
事件,我还过滤掉了一些其他类型(例如Paint
事件和普通鼠标移动)。
[**]这很重要,因为脚本中的下一个事件可能引用上一个事件创建的窗口小部件。
我认为你的问题可能最好通过使用QFuture和QFutureWatcher来实现(也就是说,如果你为线程使用QtConcurrent命名空间而不是QThreads)。 基本上,Qt事件处理系统不一定按照发布的顺序处理事件。 如果需要阻塞直到某个操作完成,并且您在单独的线程中执行该操作,则可以使用QtConcurrent :: run()返回的QFuture对象与QFutureWatcher一起阻塞,直到该特定线程完成其处理。
还需要考虑的是处理事件的方式。 使用QApplication.postEvent()时,您创建的事件将添加到接收方的事件队列中,以便稍后处理。 在幕后,Qt可以重新排序和压缩这些事件以节省处理器时间。 我怀疑这更像是你的问题。
在处理回放的函数中,请考虑使用QCoreApplication :: processEvents(),它将在所有事件处理完毕后才返回。 QCoreApplication的文档就在这里。
QMenu小部件和QAction信号是一个特例。 QMenu有一个exec()函数,通常用于弹出窗口。 我怀疑(但我不确定)QMenuBar在打开常规下拉菜单时会使用此机制。 文档对此并不清楚,但Menus的行为很像对话框,因为它们阻止了所有其他用户活动 - 除了通过给菜单提供自己的事件循环之外,Qt将如何做到这一点? 我无法填写你帖子中信息的所有空白,但我看不到你的播放线程如何应对新的事件循环。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.