Запись и воспроизведение событий Qt GUI
Я пытаюсь реализовать простую, легковесную систему для записи событий 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). (Я не могу использовать поток графического интерфейса, потому что я хочу продолжать посылать скриптовые события в приложение, даже если "главный" цикл событий блокируется, пока работает модальный диалог событий.)
Важные вещи происходят в моем 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
"s QAction
обработчики.
[*] Не каждое событие записывается. Я только записываю spontaneous()
события, и я также отфильтровываю несколько других типов (например, Paint
события и обычные движения мыши).
[**] Это важно, потому что следующее событие в скрипте может относиться к виджету, который был создан предыдущим событием.
2 ответа
Я думаю, что вашу проблему лучше всего решить с помощью QFuture и QFutureWatcher (то есть, если вы используете пространство имен QtConcurrent для потоков, а не QThreads). По сути, система обработки событий Qt НЕ обязательно обрабатывает события в порядке их публикации. Если вам нужно заблокировать до завершения определенного действия, и вы выполняете это действие в отдельном потоке, вы можете использовать объект QFuture, возвращенный QtConcurrent::run() с QFutureWatcher, чтобы блокировать, пока этот конкретный поток не завершит свою обработку,
Что-то еще нужно учитывать, как вы обрабатываете события. Когда вы используете QApplication.postEvent(), создаваемое вами событие добавляется в очередь событий получателя для последующей обработки. За кулисами Qt может переупорядочить и сжать эти события, чтобы сэкономить процессорное время. Я подозреваю, что это больше ваша проблема.
В вашей функции, которая обрабатывает воспроизведение, рассмотрите возможность использования QCoreApplication::processEvents(), которая не вернется, пока все события не завершат обработку. Документация для QCoreApplication находится здесь.
Виджеты QMenu и сигналы QAction являются особым случаем. QMenu имеет функцию exec(), обычно используемую для всплывающих окон. Я подозреваю (но не знаю точно), что QMenuBar будет использовать этот механизм, когда он открывает обычное выпадающее меню. Документы не совсем ясны по этому поводу, но меню во многом похожи на диалоговые окна в том, что они блокируют все другие действия пользователя - как бы это сделал Qt, кроме как предоставив меню свой собственный цикл обработки событий? Я не могу заполнить все пробелы из информации в вашем посте, но я не вижу, как ваша ветка воспроизведения справится с новым циклом событий.