Simon Warta
Simon Warta

Reputation: 11408

Getting focus/activeFocus status from QML ListView

I've a two column layout with a ListView in the left column. With the Left/Right Keys I can change focus between the two parts of the app.

The active focus of the left column is delegated to the ListView and from there straight to one of it's rows.

How can I check whether the ListView or one of it's children has focus?

import QtQuick 1.1

FocusScope {
    width: 960
    height: 540
    id: app
    focus: true

    FocusScope {
        id: leftColumn
        KeyNavigation.right: rightColumn
        anchors.bottom: parent.bottom
        anchors.left: parent.left
        anchors.top: parent.top
        width: 250
        focus: true

        Rectangle {
            id: leftBackgroundColor
            anchors.fill: parent
            color: contactsList.activeFocus ? "red" : "#E6E6E6"

            ListView {
                id: contactsList
                interactive: true
                anchors.fill: parent
                focus: true

                delegate: Text {
                    text: name
                    font.bold: activeFocus
                }
                model: ListModel {
                    ListElement { name: "Simon" }
                    ListElement { name: "Mary" }
                    ListElement { name: "Jack" }
                    ListElement { name: "Frank" }
                }

            }
        }
     }


    FocusScope {
        id: rightColumn
        KeyNavigation.left: leftColumn

        anchors.left: leftColumn.right
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        anchors.top: parent.top
        onFocusChanged: console.log("Right focus changed: " + focus + "/" + activeFocus)

        Rectangle {
            id: rightBackgroundColor
            anchors.fill: parent
            focus: true
            color: activeFocus ? "red" : "#b3b3b3"            
        }
    }
}

Upvotes: 2

Views: 14161

Answers (3)

Robin Burchell
Robin Burchell

Reputation: 881

I know that this is an old question, but I think it still deserves a proper explanation, as the same model of focus is still used in QtQuick 2.

How can I check whether the ListView or one of it's children has focus?

The central problem here is that you appear to be a little confused about the meanings of the two focus properties (and that's understandable, it's a bit non-obvious).

To see if a FocusScope (or any of its children) has focus right now, you want to check the Item::activeFocus property on it. This means "either I, or one of my children has focus right now", and it's recursively cleared from a FocusScope when focus is moved to another FocusScope.

On the other hand, Item::focus is a request for focus, not information about the current state, so you should not be binding other values on it (e.g. color: foo.focus ? "black" : "red") to it, unless you want to check whether or not the item is capable of gaining focus at some point in the future, not whether it has focus right now.

That explains why you can have something with Item::focus true, while it doesn't actually have focus -- it's not that the signal is missing, it's that you were misusing the property to mean something it isn't.

So, you want something like this:

Rectangle {
        id: leftBackgroundColor
        anchors.fill: parent
        color: leftColumn.activeFocus ? "red" : "#E6E6E6"
}

...

Rectangle {
    id: rightBackgroundColor
    anchors.fill: parent
    focus: true
    color: rightColumn.activeFocus ? "red" : "#b3b3b3"
}

Upvotes: 2

Simon Warta
Simon Warta

Reputation: 11408

I think I found a workaround:

onActiveFocusChanged: { focusChanged(focus) }

This emits the focusChanged signal whenever the active focus changes. Using this, the property bindings (like color: parent.focus ? "red" : "#E6E6E6") work as well.

Full test code:

import QtQuick 1.1

FocusScope {
    width: 960
    height: 540
    id: app
    focus: true

    FocusScope {
        id: leftColumn
        KeyNavigation.right: rightColumn
        anchors.bottom: parent.bottom
        anchors.left: parent.left
        anchors.top: parent.top
        width: 250

        onActiveFocusChanged: { focusChanged(focus) }

        Rectangle {
            id: leftBackgroundColor
            anchors.fill: parent
            color: parent.focus ? "red" : "#E6E6E6"

            ListView {
                id: contactsList
                interactive: true
                anchors.fill: parent
                focus: true

                delegate: Text {
                    text: name
                    font.bold: activeFocus
                }
                model: ListModel {
                    ListElement { name: "Simon" }
                    ListElement { name: "Mary" }
                    ListElement { name: "Jack" }
                    ListElement { name: "Frank" }
                }

            }
        }
     }


    FocusScope {
        id: rightColumn
        focus: true
        KeyNavigation.left: leftColumn

        anchors.left: leftColumn.right
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        anchors.top: parent.top

        onActiveFocusChanged: { focusChanged(focus) }

        Rectangle {
            id: rightBackgroundColor
            anchors.fill: parent
            focus: true
            color: activeFocus ? "red" : "#b3b3b3"            
        }
    }
}

Upvotes: 3

Deadron
Deadron

Reputation: 5289

You are creating trouble for yourself in this code. Only one element can have focus at any given time so if you have every element's focus property set to true its not especially clear which element has focus when it is rendered(I believe its the last element rendered that has focus set). As to figuring out which element has focus you can't request the current focused element. What you can do is hookup a listener to the onFocusChanged event that exists on the elements to perform actions when that object gains/loses focus. A better question might be why do you care who has focus?

Upvotes: 0

Related Questions