pixelgrease
pixelgrease

Reputation: 2118

How to remove active focus from QML Loader item?

I have a UI where clicking on a control selects it and deselects any other control that is currently selected. It worked great until I loaded part of the UI into a Loader.

Now if I select an element on the loader while something outside the loader is selected, focus is correctly taken away from the outside control and given to the control on the Loader. But re-selecting the outside control does not take focus away from the control on the loader like it should.

I use forceActiveFocus() to set focus where it is supposed to be. Only one item can have active focus so when you call forceActiveFocus() on an element, it gets focus and whatever had focus loses it.

I wrote a small sample project that shows this behavior. When it opens, you see a Windows split into to two halves; the yellow half is a component in a Loader. Nothing is selected. Clicking a side will set focus to that side, either the parent Item or the Item in the Loader.

No focus on startup

If you click the left half, it shows focused. This is exactly as expected.

Click left half and it receives focus

If you click the right half, it shows focus and removes focus from the left half, again, this is exactly as expected.

Click right half and it receives focus

But now if you click the exposed parent Item's side, it gets focus as expected, but the component in the Loader still shows that it has focus!

Click left half and it is focused, but right half remains focused too!

Clicking into the right half will correctly force focus to it and remove focus from the left half, but how to remove focus from the right half when clicking on the left half?

This Qt 5.6 code will reproduce the behavior:

import QtQuick 2.6
import QtQuick.Window 2.2

Window {
    visible: true

    Item {
        id: item
        anchors.fill: parent

        Text {
            text: 'Focused'
            font.bold: true
            visible: parent.focus // incorrect; must use parent.activeFocus
        }
        MouseArea {
            anchors.fill: parent
            onClicked: item.forceActiveFocus()
        }
        Text {
            text: 'Parent Item'
            anchors.centerIn: parent
        }
        Loader {
            id: loader
            anchors {
                left: parent.horizontalCenter; right: parent.right
                top: parent.top; bottom: parent.bottom
            }
            sourceComponent: rect
            opacity: .8
        }
        Text {
            anchors.centerIn: loader
            text: 'The\nLoader'
        }
    }

    Component {
        id: rect

        Rectangle {
            color: 'yellow'

            Text {
                text: 'Focused'
                font.bold: true
                visible: parent.focus // incorrect; must use parent.activeFocus
            }
            MouseArea {
                anchors.fill: parent
                onClicked: parent.forceActiveFocus()
            }
        }
    }
}

Upvotes: 1

Views: 5201

Answers (1)

pixelgrease
pixelgrease

Reputation: 2118

Use the activeFocus property instead of the focus property to determine whether or not an element has active focus. I am not sure why focus worked so well before, but using it to detect active focus was a defective approach and destined to fail.

Upvotes: 4

Related Questions