Qt QML Focus an Item (TextField) when showing a StackView Page
Asked Answered
M

2

5

I want to enable TextField focus when QML file is loaded. But, it is not working. After loading TestUi.qml file I put some button and its onClick() method I did _recipientView.focus = true_, it works fine. The problem is that default focus is not enabled when view is loaded first time.

TestUi.qml

import QtQuick 2.0
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.0


Page {

    function init() {
        recipientView.focus = true;
    }

    TextField {
       id: recipientView
        Layout.fillWidth: true
        font.pixelSize: 18
        inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhEmailCharactersOnly
        focus: true
        placeholderText: "Email"
    
    }
}

main.qml

onComposeBtnClicked: {
    rootStackView.push(test)
    test.init()
}

TestUi {
    id: test
    visible: false
}
Menton answered 17/2, 2017 at 13:24 Comment(2)
Did you try to set it via Component.onCompleted: recipientView.focus = true; ?Buitenzorg
When app is starting to load, Component.onCompleted is running no matter which page is. I did it no helpMenton
H
9

Edit

The Page component already acts as a FocusScope, so only forcing the active focus is necessary. Thanks for the comments.

StackView {
    id: stackView
    initialItem: firstPage

    // Ensures the focus changes to your page whenever
    // you show a different page
    onCurrentItemChanged: {
        currentItem.forceActiveFocus()
    }
}

Page {
    id: firstPage
    visible: false

    TextField {
        // Explicitly set the focus where needed
        focus: true
    }
}

Original answer

This is simply because you are pushing TestUi into your stack with rootStackView.push(test). When you do so, the focus is reset. This is typically handled with a QFocusScope, which role is to remember the focused Item, and give the focus back to it when the QFocusScope regains focus.

In your case, adding a QFocusScope to your base page would enable restoring the focus correctly when the page is shown:

StackView {
    id: stackView
    initialItem: firstPage
    onCurrentItemChanged: {
        currentItem.forceActiveFocus()
    }
}

Page {
    id: firstPage
    visible: false
    onFocusChanged: {
        scope.focus = true
    }
    FocusScope {
        id: scope
        TextField {
            focus: true
            // ...
        }
    }
}

You can then use your page handler onVisibleChanged if you want to reset to focus when the user comes back to it (after a pop for instance), instead of memorizing it where the focus is. But in that case the FocusScope might be overkill.

For information, you can also use the StackView property initialItem in order to set the first page.

It is also kind of unrelated, but prefer importing the most recent version of the QtQuick components available. QtQuick version will be 2.12 for Qt 5.12. A bit less trivial for QtQtcuik.Controls version, but they are getting in line with that versioning scheme.

Haversack answered 17/2, 2017 at 13:56 Comment(3)
I have to set focus not to the main Page. For me worked just adding onCurrentItemChanged: { currentItem.forceActiveFocus() } To main.qml. And adding Focus.scope to my target file caused an error.Juncture
For me adding onCurrentItemChanged was enough aswell. There are some QML items like Page that act as focus scopes themselves. (a list of those items can be found here: doc.qt.io/qt-5/qtquickcontrols2-focus.html)Dietitian
Thanks for the feedbacks. I don't remember if at the time, it was necessary, I will edit the answer regardless.Haversack
M
0

The actual/non-trick way for Qt 5.8+ is using the activated attached signal as follows:

StackView {
    id: stackView
    initialItem: firstPage
}

// As already mentioned by another answer, the Page acts like FocusScope
Page {
    id: firstPage
    visible: false
    
    // *** The Key! ***
    // Force to be active focus whenever this item is active. 
    // You need this on every loadable item with `FocusScope` behaviour.
    // So, it is a good idea to create a new component based on a `Page` 
    // that has the following signal handler
    StackView.onActivated: {
        forceActiveFocus()
    }

    TextField {
        id: txt1
        // Explicitly set the focus where needed
        focus: true
        // An example to show how you can control the focus chain
        KeyNavigation.tab: txt2
    }
    TextField {
        id: txt2
        // Previous focus item
        KeyNavigation.backtab: txt1
    }
}
Melon answered 21/3, 2024 at 17:45 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.