Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-57093

QML: forceActiveFocus() call for disabled Item in FocusScope must be ignored

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Invalid
    • Icon: P2: Important 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.

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

            wearyinside Oleg Yadrov
            wearyinside Oleg Yadrov
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved:

                There are no open Gerrit changes