Looks like Qt Quick tests require the test window to have a focus in order to send itself mouse and keyboard events. It's Ok, when I run only one test. But when I try to run multiple instances of Qt Quick tests, they fight for the window focus and this cause tests failures.
How can I perform Qt Quick tests without focusing the test window? Is there any option to force Qt Quick to use fake mouse and keyboard events instead of working with real window system? How can I run multiple instances of Qt Quick tests without focus problems?
OK, I will bite.
You could use some C++ event posting to redirect a single event to multiple QML windows:
class Dispatcher : public QObject {
Q_OBJECT
public slots:
void click(qreal x, qreal y) {
foreach (QObject * o, objects) {
QMouseEvent * e1 = new QMouseEvent(QEvent::MouseButtonPress, QPointF(x, y), Qt::MouseButton::LeftButton, Qt::MouseButton::LeftButton, Qt::KeyboardModifier::NoModifier);
QCoreApplication::postEvent(o, e1);
QMouseEvent * e2 = new QMouseEvent(QEvent::MouseButtonRelease, QPointF(x, y), Qt::MouseButton::LeftButton, Qt::MouseButton::LeftButton, Qt::KeyboardModifier::NoModifier);
QCoreApplication::postEvent(o, e2);
}
}
void addTarget(QObject * obj) {
objects.append(obj);
}
private:
QObjectList objects;
};
Then you create a dispatcher and register it as a context property, or register it as a QML type and instantiate it in QML if you will, and use it to register all objects that should be receiving events.
Here is the quick QML test I wrote to test if it works:
The main window contains a MouseArea
which simply redirects the click event to the dispatcher. Each extra window contains a mouse area and text to output the click coordinate, and registers itself in the dispatcher. When the mouse area in the main window is clicked, a click event is simulated by the dispatcher for the two windows, and as a result the text in them confirms that the event was indeed dispatched to the window and processed by the underlying mouse area.
Window {
id: main
visible: true
width: 300
height: 300
x: 100
y: 100
MouseArea {
anchors.fill: parent
onClicked: Dispatcher.click(mouseX, mouseY)
}
Component {
id: comp
Item {
anchors.fill: parent
Text {
id: txt
}
MouseArea {
id: ma
anchors.fill: parent
onClicked: txt.text = "clicked at " + mouseX + ", " + mouseY
}
}
}
Window {
id: w1
visible: true
width: 300
height: 300
x: 420
y: 100
Loader {
anchors.fill: parent
sourceComponent: comp
}
Component.onCompleted: Dispatcher.addTarget(w1)
}
Window {
id: w2
visible: true
width: 300
height: 300
x: 740
y: 100
Loader {
anchors.fill: parent
sourceComponent: comp
}
Component.onCompleted: Dispatcher.addTarget(w2)
}
}
You can use a similar approach to either redirect events from one to multiple windows, or to generate completely independent event sequences for every window, you can also write an event logger, then save events you manually trigger and play those back on at item at variable speed. You can do pretty much anything. The same approach should also work for keyboard events. Also, you can enable focus for each window at a time from the C++ side when you are posting the events.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With