Qt GUI事件录制和播放

时间:2013-04-03 10:19:41

标签: c++ python qt pyqt qt-events

我试图实现一个简单,轻量级的系统来记录Qt GUI事件并从脚本中播放它们。我认为使用Qt的事件系统的魔力会相当简单,但我遇到了一个我不明白的问题。

以下是我正在做的事情的快速摘要:

RECORDING:

我使用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)

PLAYBACK:

我只是在一个worker(非GUI )线程中执行上面的脚本。 (我无法使用GUI线程,因为我想继续向应用程序发送脚本事件,即使在运行模式对话框事件循环时阻止了主要的事件循环。)

重要的事情发生在我的post_event()函数中,它需要做两件事:

  • 首先,致电QApplication.postEvent(obj, recorded_event)
  • 等待所有活动完成处理:**
    • 将特殊事件发布到obj正在运行的同一个事件循环中。
    • 处理特殊事件时:
      • 致电QApplication.processEvents()
      • 设置一个标志,告诉回放线程可以继续

第二部分完成后,我的期望是第一部分(记录的事件)的所有效果都已完成,因为特殊事件在之后排队记录的事件。

整个系统主要是似乎适用于鼠标事件,关键事件等。但是当我尝试播放事件时,我遇到了QAction处理程序的问题我的主要QMenuBar

无论我尝试什么,似乎我无法通过点击{{{ 1}}项目。据我所知,QAction.triggered QMenu处理程序完成之前返回

QApplication.processEvents()小部件或QAction信号是否有特殊内容违反QMenu和/或QAction的正常规则? 我需要一种方法来阻止我的QApplication.postEvent() QApplication.processEvents()处理程序的完成。

[*]并非所有事件都被记录下来。我只记录QMenu个事件,我还会过滤掉其他一些类型(例如QAction事件和普通鼠标移动)。

[**]这很重要,因为脚本中的下一个事件可能是指前一个事件创建的小部件。

2 个答案:

答案 0 :(得分:1)

我认为使用QFuture和QFutureWatcher可以最好地解决您的问题(也就是说,如果您将QtConcurrent命名空间用于线程,而不是QThreads)。基本上,Qt事件处理系统不一定按照发布的顺序处理事件。如果需要阻塞直到某个操作完成,并且您在单独的线程中执行该操作,则可以使用QtConcurrent :: run()返回的QFuture对象与QFutureWatcher一起阻塞,直到该特定线程完成其处理。

要考虑的是处理事件的方式。使用QApplication.postEvent()时,您创建的事件将添加到接收方的事件队列中,以便稍后处理。在幕后,Qt可以重新排序和压缩这些事件以节省处理器时间。我怀疑这更像是你的问题。

在处理播放的函数中,请考虑使用QCoreApplication :: processEvents(),它将在所有事件处理完毕后才会返回。 QCoreApplication的文档是here.

答案 1 :(得分:1)

QMenu小部件和QAction信号是一种特殊情况。 QMenu有一个exec()函数,通常用于弹出窗口。我怀疑(但我不确定)QMenuBar在打开常规下拉菜单时会使用此机制。文档对此并不清楚,但Menus的行为很像对话框,因为它们阻止了所有其他用户活动 - 除了通过给菜单提供自己的事件循环之外,Qt将如何做到这一点?我无法填写你帖子中信息的所有空白,但我看不到你的播放线程如何应对新的事件循环。