-
Bug
-
Resolution: Invalid
-
P2: Important
-
None
-
5.7.0, 5.8.0 Beta
-
None
Recently there was a discussion about focus/forceActiveFocus behavior in case if Item is disabled (QTBUG-55937), but what I'm suggesting here is only about one specific case that needs to be covered. I'll explain it on examples, consequentially making small changes and going from simple to more complex cases.
Case 1: Enabled Item in Window.
---------------------------------------------------
Window { onActiveFocusItemChanged: console.log("Window: activeFocusItem changed to", activeFocusItem) Item { id: testItem objectName: "TestItem" enabled: true onActiveFocusChanged: { console.log(objectName, "activeFocus changed to", activeFocus) } } Component.onCompleted: { testItem.forceActiveFocus() } }
---------------------------------------------------
Case 1 output:
---------------------------------------------------
qml: Window: activeFocusItem changed to QQuickItem(0x7fb5054dc740, "TestItem")
qml: TestItem activeFocus changed to true
---------------------------------------------------
This code is simple and works as expected.
Case 2: Disabled Item in Window.
---------------------------------------------------
Window { onActiveFocusItemChanged: console.log("Window: activeFocusItem changed to", activeFocusItem) Item { id: testItem objectName: "TestItem" enabled: false onActiveFocusChanged: { console.log(objectName, "activeFocus changed to", activeFocus) } } Component.onCompleted: { testItem.forceActiveFocus() } }
---------------------------------------------------
Case 2 output:
---------------------------------------------------
qml: Window: activeFocusItem changed to QQuickRootItem(0x7fa58c535d10)
---------------------------------------------------
So far so good - forceActiveFocus() call is just ignored, and I'd get the same output even if I removed testItem.forceActiveFocus() call
Case 3: Enabled Item in FocusScope.
---------------------------------------------------
Window { onActiveFocusItemChanged: console.log("Window: activeFocusItem changed to", activeFocusItem) FocusScope { id: focusScope objectName: "FocusScope" onActiveFocusChanged: { console.log(objectName, "activeFocus changed to", activeFocus) } Item { id: testItem objectName: "TestItem" enabled: true onActiveFocusChanged: { console.log(objectName, "activeFocus changed to", activeFocus) } } } Component.onCompleted: { testItem.forceActiveFocus() } }
---------------------------------------------------
Case 3 output:
---------------------------------------------------
qml: Window: activeFocusItem changed to QQuickItem(0x7ff9a0c28b10, "TestItem")
qml: FocusScope activeFocus changed to true
qml: TestItem activeFocus changed to true
---------------------------------------------------
Absolutely no difference with Case 1 - as expected. I know that it's not how FocusScope are supposed to be used, and I'm explicitly calling forceActiveFocus in this example just for demonstration.
Case 4: Disabled Item in FocusScope.
---------------------------------------------------
Window { onActiveFocusItemChanged: console.log("Window: activeFocusItem changed to", activeFocusItem) FocusScope { id: focusScope objectName: "FocusScope" onActiveFocusChanged: { console.log(objectName, "activeFocus changed to", activeFocus) } Item { id: testItem objectName: "TestItem" enabled: false onActiveFocusChanged: { console.log(objectName, "activeFocus changed to", activeFocus) } } } Component.onCompleted: { testItem.forceActiveFocus() } }
---------------------------------------------------
Case 4 output:
---------------------------------------------------
qml: Window: activeFocusItem changed to QQuickFocusScope(0x7fcbcc14e740, "FocusScope")
qml: FocusScope activeFocus changed to true
---------------------------------------------------
Surprise! Move focus to FocusScope item is not what I meant to do. Even though this is OK when a few Items have active focus at the same time (item and all its parent focus scopes), in this case it is not correct logic, the focus scope should not receive the focus.
Imagine that you have 3 buttons in one FocusScope, and moving of focus is implemented by handling Keys.onPressed signals and making targetButtonId.forceActiveFocus() calls. Now for whatever reason you need to disable one of those buttons. When you try to move focus to the disabled button focus will be lost - it will go to the FocusScope object.
The possible solution (I haven't checked it yet, though) would be to run while loop in QQuickItem::forceActiveFocus(Qt::FocusReason) https://github.com/qt/qtdeclarative/blob/dev/src/quick/items/qquickitem.cpp#L4572 only if item is enabled.
It might be hard to understand what the issue is if you haven't intensively worked with QML (especially taking into account the fact that a lot of people are confused by difference of "focus" property and "forceActiveFocus" function), so if my explanation is not clear - please ask me, I'll be glad to answer.