QQuickView: No keyboard focus after switching windows
-
My cpp application has a QML view. Inside the view are a number of QML items which accept keyboard input. When an item is clicked, I call forceActiveFocus() on the clicked item. It all works from the time I launch the application, until the time I switch to another window.
If I switch to another application and back, or switch to another window within my application and back, calling forceActiveFocus() has no effect. The items are of a few different types, but here is a sample item:
TextInput { id: textInput anchors.fill: parent inputMethodHints: Qt.ImhFormattedNumbersOnly onActiveFocusChanged: console.log(activeFocus) onEditingFinished: { } MouseArea { anchors.fill: textInput onClicked: { textInput.forceActiveFocus() console.log("clicked") } } }
When switching away I see activeFocus logged to the console as false. When I switch back again and click on the item, "clicked" is logged to the console, so the mouse event is being handled. However, onActiveFocusChanged is never called again.
I also tried an implementation with a FocusScope as the parent of the item, got the same behavior, with focus following my click until the point I switch away to some other window and back again.
-
Okay, this is only a problem when I use a QQuickView.
I've built two minimal examples. In a QML application
Window
with the followingmain.qrc
, focus works just fine:import QtQuick 2.7 import QtQuick.Window 2.2 Window { color: "lightblue" Rectangle { id: textInputRect color: "white" height: 50 width: 150 anchors.centerIn: parent TextInput { id: textInput anchors.fill: parent inputMethodHints: Qt.ImhFormattedNumbersOnly onActiveFocusChanged: console.log(activeFocus) onEditingFinished: { } } } }
In a
QMainWindow
derived class that has aQQuickView
widget in the ui, I lose keyboard focus and can't get it back, any time I switch away from the window. Here is the (as identical as I could make it)main.qrc
loaded into theQQuickView
:import QtQuick 2.7 import QtQuick.Window 2.2 Rectangle { anchors.fill: parent color: "lightblue" Rectangle { id: textInputRect color: "white" height: 50 width: 150 anchors.centerIn: parent TextInput { id: textInput anchors.fill: parent inputMethodHints: Qt.ImhFormattedNumbersOnly onActiveFocusChanged: console.log(activeFocus) onEditingFinished: { } } } }
From the
QQuickView
version, here ismain
:int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QLatin1String("qrc:/main.qml"))); MainWindow window; QQuickView* view = new QQuickView; window.setView(view); window.show(); return app.exec(); }
And here is how I set the
QQuickView
in theMainWindow
:void MainWindow::setView(QQuickView *value) { view = value; QWidget *container = QWidget::createWindowContainer(view, this); view->setSource(QUrl("qrc:/main.qml")); ui->verticalLayout->addWidget(container); }
-
More information. Once I tracked it to the use of QQuickView, I found this bug report:
https://bugreports.qt.io/browse/QTBUG-34414
I happen to be on OS X, so I tried the workaround suggested in the comments there. It amounted to overriding
event(QEvent *event)
in myQMainWindow
derived class. I haven't seen any negative side-effects yet (EDIT: see below), but I would really love for someone more experienced to weigh in on this solution if you've got time.Here is the override:
bool MyWindow::event(QEvent *event) { if (event->type() == QEvent::ActivationChange || event->type() == QEvent::WindowUnblocked) { //edited to add WindowUnblocked if(view->isActive()) { //view is pointer to my QQuickView window()->activateWindow(); return true; } } // handle events that don't match return QWidget::event(event); }
EDIT:
This works when switching to another application, or between my two main application windows, but it does not return focus (activate the window), after opening/closing a dialog. So I also call
window()-activateWindow()
whenevent->type() == QEvent::WindowUnblocked
. Hopefully this is all a safe way to deal with this.