I'm attempting to implement a simple, lightweight system for recording Qt GUI events and playing them back from a script. I thought this would be fairly straightforward using the magic of Qt's event system, but I'm running into a problem I don't understand.
Here's quick summary of what I'm doing:
RECORDING:
I use QApplication.instance().eventFilter()
to capture all GUI events I'm interested in* and save them to a Python script, in which each step looks something like this:
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:
I simply execute the script above, in a worker (non-GUI) thread. (I can't use the GUI thread because I want to keep sending scripted events to the application, even if the 'main' eventloop is blocked while a modal dialog eventloop is running.)
The important stuff happens in my post_event()
function, which needs to do two things:
- First, call
QApplication.postEvent(obj, recorded_event)
- Wait for all events to finish processing:**
- Post a special event to the same eventloop that
obj
is running in. - When the special event is handled:
- Call
QApplication.processEvents()
- Set a flag that tells the playback thread it's okay to continue
- Call
- Post a special event to the same eventloop that
After the second part is complete, my expectation is that all effects of the first part (the recorded event) have completed, since the special event was queued after the recorded event.
The whole system mostly seems to work just fine for mouse events, key events, etc. But I'm having a problem with QAction
handlers when I attempt to playback events for my main QMenuBar
.
No matter what I try, it seems that I can't force my playback thread to block for the completion of all QAction.triggered
handlers that result from clicking on my QMenu
items. As far as I can tell, QApplication.processEvents()
is returning before the QAction
handler is complete.
Is there something special about QMenu
widgets or QAction
signals that breaks the normal rules for QApplication.postEvent()
and/or QApplication.processEvents()
? I need a way to block for the completion of my QMenu
's QAction
handlers.
[*] Not every event is recorded. I only record spontaneous()
events, and I also filter out a few other types (e.g. Paint
events and ordinary mouse movements).
[**] This is important because the next event in the script might refer to a widget that was created by the previous event.