我正在尝试实现一个简单、轻量级的系统来记录 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)
播放:
我只是在工作线程(非 GUI)中执行上面的脚本。 (我不能使用 GUI 线程,因为我想继续向应用程序发送脚本事件,即使在模式对话框事件循环运行时“主”事件循环被阻塞。)
重要的事情发生在我的 post_event()
函数中,它需要做两件事:
- 首先,调用
QApplication.postEvent(obj, recorded_event)
- 等待所有事件完成处理:**
- 将一个特殊事件发布到
obj
正在运行的同一事件循环中。 - 处理特殊事件时:
- 调用
QApplication.processEvents()
- 设置一个标志,告诉播放线程可以继续
- 调用
- 将一个特殊事件发布到
第二部分完成后,我的预期是第一部分(记录的事件)的所有效果都已完成,因为特殊事件在记录的事件。
整个系统大部分似乎都能很好地处理鼠标事件、按键事件等。但是当我尝试播放时,QAction
处理程序出现了问题我的主要 QMenuBar
的事件。
无论我尝试什么,似乎我无法强制我的播放线程阻塞以完成所有 QAction.triggered
处理程序我的 QMenu
项。据我所知,QApplication.processEvents()
在 QAction
处理程序完成之前返回。
QMenu
小部件或 QAction
信号是否有一些特殊之处打破了 QApplication.postEvent()
和/或 的正常规则>QApplication.processEvents()
? 我需要一种方法来阻止完成我的 QMenu
的 QAction
处理程序。
[*] 并非每个事件都被记录下来。我只记录 spontaneous()
事件,我还过滤掉了一些其他类型(例如 Paint
事件和普通鼠标移动)。
[**] 这很重要,因为脚本中的下一个事件可能引用由上一个事件创建的小部件。
最佳答案
我认为您的问题可能最好通过使用 QFuture 和 QFutureWatcher 来解决(也就是说,如果您对线程使用 QtConcurrent 命名空间,而不是 QThreads)。基本上,Qt 事件处理系统不一定按事件发布的顺序处理事件。如果您需要阻塞直到某个 Action 完成,并且您在单独的线程中执行该 Action ,您可以使用 QtConcurrent::run() 返回的 QFuture 对象和 QFutureWatcher 来阻塞直到该特定线程完成其处理.
还有一点需要考虑的是您处理事件的方式。当您使用 QApplication.postEvent() 时,您创建的事件会添加到接收者的事件队列中,以便稍后处理。在幕后,Qt 可以重新排序和压缩这些事件以节省处理器时间。我怀疑这更多是你的问题。
在处理播放的函数中,考虑使用 QCoreApplication::processEvents(),它在所有事件处理完成之前不会返回。 QCoreApplication 的文档是 here.
关于c++ - Qt GUI事件记录和回放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15784719/