C++ Qt-GUI事件记录和回放

C++ Qt-GUI事件记录和回放,c++,python,qt,pyqt,qt-events,C++,Python,Qt,Pyqt,Qt Events,我试图实现一个简单、轻量级的系统,用于记录QtGUI事件并从脚本中回放它们。我认为使用Qt事件系统的魔力,这将是相当简单的,但我遇到了一个我不理解的问题 下面是我所做工作的简要总结: 录音: 我使用QApplication.instance() obj=get\u named\u object('MainWindow.my\u menubar')) 录制的_事件=QMouseEvent(2,PyQt4.QtCore.QPoint(45,8),1,Qt.MouseButtons(0x1),Qt.K

我试图实现一个简单、轻量级的系统,用于记录QtGUI事件并从脚本中回放它们。我认为使用Qt事件系统的魔力,这将是相当简单的,但我遇到了一个我不理解的问题

下面是我所做工作的简要总结:

录音:

我使用
QApplication.instance()

obj=get\u named\u object('MainWindow.my\u menubar'))
录制的_事件=QMouseEvent(2,PyQt4.QtCore.QPoint(45,8),1,Qt.MouseButtons(0x1),Qt.KeyboardModifiers(0x0))
事后事件(obj,记录的事件)
播放:

我只是在工作线程(非GUI)中执行上面的脚本。(我无法使用GUI线程,因为我希望继续向应用程序发送脚本化事件,即使在模式对话框eventloop运行时“main”eventloop被阻止。)

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

  • 首先,调用
    QApplication.postEvent(obj,recorded\u event)
  • 等待所有事件完成处理:**
    • 将特殊事件发布到运行
      obj
      的同一事件循环中
    • 处理特殊事件时:
      • 调用
        QApplication.processEvents()
      • 设置一个标志,告诉播放线程可以继续
第二部分完成后,我的期望是第一部分(记录的事件)的所有效果都已完成,因为特殊事件在记录的事件之后排队

整个系统似乎在鼠标事件、按键事件等方面都能正常工作。但是当我尝试播放主
QMenuBar
的事件时,
QAction
处理程序出现问题

无论我尝试什么,似乎都无法强制播放线程阻止完成所有
QAction。通过单击我的
QMenu
项触发的
处理程序
。据我所知,
QApplication.processEvents()
QAction
处理程序完成之前返回

QMenu
小部件或
QAction
信号是否有什么特殊之处,它们打破了
QApplication.postEvent()和/或
QApplication.processEvents()的正常规则我需要一种方法来阻止完成我的
QMenu
QAction
处理程序。

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


[**]这一点很重要,因为脚本中的下一个事件可能引用由上一个事件创建的小部件。

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

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


在处理回放的函数中,考虑使用QCOReAp::PraceSeVScript(),直到所有事件完成处理,它才会返回。QCoreApplication的文档是QMenu小部件,QAction信号是一个特例。QMenu有一个exec()函数,通常用于弹出窗口。我怀疑(但我不确定)QMenuBar在打开常规下拉菜单时会使用这种机制。文档对此并不清楚,但菜单的作用非常类似于对话框,因为它们阻止了所有其他用户活动——除了给菜单提供自己的事件循环,Qt如何做到这一点?我无法填补您帖子中信息中的所有空白,但我不知道您的播放线程如何处理新的事件循环。

我已经在播放过程中调用了
QApplication.processEvents()
(我的问题中不清楚,所以我对其进行了编辑)。此外,感谢您提供有关Qt并发的提示--我以前从未见过该库。不过,我觉得在这种情况下这对我没什么帮助。除非我遗漏了什么,否则Qt Concurrent不允许我选择在哪个线程中执行我的“工作”。我需要在主gui线程中处理我的“特殊”操作。目前,我通过驻留在GUI线程中的一个信号来实现这一点,我使用
Qt.QueuedConnection
将它连接到
connect()
。然而,当涉及
QMenu
时,它的行为并不像预期的那样。好吧,如果您在单独的线程中执行此处理,QtConcurrent将允许您“选择”要运行它的线程。但是,由于您是在主线程中执行此操作,因此这不起作用。鉴于您正在经历来自QApplication的非标准行为,我怀疑您的线程遇到了某种定时问题。当您认为QMenu操作没有被放入事件队列时,它们可能没有被放入事件队列。我最好的建议是尝试通过将post_event()工作移动到主线程来调试它。如果这样做有效,那么您将知道您有线程计时问题。