Recording, saving, loading and replaying of Qt input events could come in handy in numerous situations. For example, in automatic GUI testing or when implementing a macro system (like the one in Microsoft Office or Adobe Photoshop), in interactive help systems, demos of all sorts etc.
Input events in Qt are nicely grouped by inheritance of QInputEvent class and there are just 6 classes describing specific events, namely QContextMenuEvent, QKeyEvent, QMouseEvent, QTabletEvent, QTouchEvent and QWheelEvent. All of them are pretty straightforward to serialize, deserialize and clone. Combined with Qt’s ability to install a global event filter (using qApp) it made implementing QIERAP (Qt Input Events Recorder And Player 😉 ) demo possible.
So… today, I give you QInputEventRecorder class, BSD-licensed as always. It facilitates four functions: recording of input events, storing them in binary files (created using QDataStream), loading them back and replaying them with given speed factor. QInputEventRecorder captures events targeted at specified widget and all of its children. It assumes that all widgets have names. In case they don’t you can use QInputEventRecorder::nameAllWidgets(QWidget*) static method which gives unique names to all unnamed children of the specified widget. This method could be further enhanced to generate names in a more reproducible manner, to preserve validity of recordings after GUI modifications, particularly after reordering or insertion of new elements. This is one of the items on my hobby TODO list 😉 In general, event designates are remembered not only by their name but also by their relation to other widgets, e.g. if we have widget_2 which is a child of widget_1 (which has no parent) it’s going to be recorded as widget_1/widget_2, while widget_1 will be recorded simply as widget_1. As an extra precaution, class name of the target widget is also stored, which might be good or bad depending on if you plan to eventually swap classes of some widgets on your form.
I guess that’s pretty much all there is to it, you will learn rest of the story from code itself. I’m also attaching a Win32 binary and a sample recording so that everyone can see it in action 🙂
And this is what you should see when the demo stops running:
Thx. I plan to use the idea for Qt recorder in StoryText test tool.
Fantastic! I hoped it could be used for GUI testing one day. Let me know if you need any assistance. Cheers!
Cool. I’m going to integrate this into our app and see if it can output QTest-code (in C++ and/or python).
You should put this on github or bitbucket if you want to get some contributions!
Good idea! But for now let’s start with patches. If anybody really starts contributing then creating repository will be justified : ) Good luck with your project!
This is great but there is one issue: I allocate a QFileDialog (as a child of MainWindow, which is the widget being recorded). When fileDialog->show() is called I can capture the click on the file name, but the lineEdit with the file name does not get updated and the click on the “Open” button does not get captured.
BTW, you have to allocate the QFileDialog before the call to nameAllWidgets() so that it is a child of the MainWindow. You can’t call the static method QFilDialog::getOpenFileName().
Thanks for this. It was a while ago, I appreciate that. In addition to the issue with QFileDialog that Lee mentions, it doesn’t seem able to capture context menu events. Have you any ideas on how to address this? If I could get context menu events to work this would be just what I need.
I have a question:when the object has no parent ,something looks wrong. It means that the objects must have parents,but sometimes in my software some objects have no parent.Do you have good idea ? many thanks.