Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Enter key to accept dialog



  • It's a fairly standard paradigm to be able to accept dialogs via enter/return and reject via escape, but QML does not offer any inbuilt support for this. I would like to get this working generally in my application but I am not sure what is the best/correct way to achieve it. I find the documentation discussion of keyboard focus to be a bit confusing so a big part of the problem I am sure is that I do not have a good mental model of how it works.

    As for what I have tried, most of my dialogs have an explicit DialogButtonBox assigned to the footer and I have been able to make some progress by:

    • calling forceActiveFocus() on the button box
    • adding key handlers (e.g. Keys.onEnterPressed: dlg.accept()) in the DialogButtonBox

    This works to an extent but the issue is how to ensure that forceActiveFocus is called whenever it needs to be. For example, with a simple message dialog, I can do it in onOpened, but once controls are added to the dialog that the user might start interacting with, focus is easily lost from the button box. For example, the second simplest dialog I have tried with has a single combo box. I got this to work by calling forceActiveFocus on the button box in the onClosed event for the combo popup, but this is all a bit ad hoc and doesn't scale to more complex situations.

    Is there a more generic solution to this?



  • Hi @Bob64 , there are a few ways to do this with focus scopes and the like, but simply put I think you are missing setting focus:true on the dialog itself (But without your code I can't be sure)
    As for navigation you can specify this with KeyNavigation.tab/backtab

    Here is an example dialog (Note I am using Qt6.2)

    Dialog {
        id: dialog
        title: "My Dialog"
        anchors.centerIn: parent
        focus: true
    
        Column {
            anchors.fill: parent
            Text {
                text: "Here is my Dialog"
            }
            TextField {
                id: textInput
                placeholderText: "Input some text"
                KeyNavigation.tab: textInput2
            }
            TextField {
                id: textInput2
                placeholderText: "Input some text"
                KeyNavigation.backtab: textInput
                KeyNavigation.tab: textInput3
            }
            TextField {
                id: textInput3
                placeholderText: "Input some text"
                KeyNavigation.backtab: textInput2
                KeyNavigation.tab: textInput
                Keys.onReturnPressed: dialog.accept()
            }
    
            Row {
                Button {
                    id: cancelButton
                    text: "Cancel"
                    onClicked: dialog.reject()
                }
                Button {
                    id: okButton
                    text: "Ok"
                    onClicked: dialog.accept()
                }
            }
        }
    
        onAccepted: {
            console.log("Accepted")
        }
    
        onRejected: {
            console.log("Rejected")
        }
        onOpened: {
            textInput.focus = true
        }
    }
    

    If that doesn't explain what you want perhaps you could share your code that is not working.



  • Thank you @Mr-MinimalEffort. I am going to take another look today. I will try out your example and try to share a simple version of what I have.



  • @Mr-MinimalEffort I tried out your example. It is a good example of implementing keyboard navigation between fields but I don't think I explained very well because, whereas in a sense it goes further than what I was asking about, it does not do the main thing I am interested in which is how to implement behaviour such that dialogs may be accepted (i.e. equivalent of pressing "Ok") by pressing return/enter on keyboard. This is supported out of the box in QtWidgets by the concept of a 'default' button.

    Here's an example from Visual Studio on Windows, the Tools...|Options dialog:

    c4538310-002e-4a63-a8e8-67146649ee72-image.png

    As you can see, the OK button is highlighted here to indicate that it is the default button. No matter how much I click around in the dialog, I can at any point press my return key to accept the dialog.

    Here's some example code with three dialogs: the one you provided, a simple message dialog with the most basic out of the box implementation, and a modified version of the latter that does what I want it to but I don't know if this is the right way to do it. I haven't posted it yet, but the next one would have a single combo widget which causes more complication because it can take focus away from the buttons. However, it would be good to understand the options for the most basic case before getting into that.

    (BTW I am, for work reasons, unfortunately still on 5.9.6.)

    import QtQuick 2.9
    import QtQuick.Window 2.2
    import QtQuick.Controls 2.2
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        Dialog {
            id: dialog1
            title: "My Dialog"
    
            x: (parent.width - width)/2
            y: (parent.height - height)/2
    
            focus: true
    
            Column {
                anchors.fill: parent
                Text {
                    text: "Here is my Dialog"
                }
                TextField {
                    id: textInput
                    placeholderText: "Input some text"
                    KeyNavigation.tab: textInput2
                }
                TextField {
                    id: textInput2
                    placeholderText: "Input some text"
                    KeyNavigation.backtab: textInput
                    KeyNavigation.tab: textInput3
                }
                TextField {
                    id: textInput3
                    placeholderText: "Input some text"
                    KeyNavigation.backtab: textInput2
                    KeyNavigation.tab: textInput
                    Keys.onReturnPressed: dialog.accept()
                }
    
                Row {
                    Button {
                        id: cancelButton
                        text: "Cancel"
                        onClicked: dialog.reject()
                    }
                    Button {
                        id: okButton
                        text: "Ok"
                        onClicked: dialog.accept()
                    }
                }
            }
    
            onAccepted: {
                console.log("Accepted")
            }
    
            onRejected: {
                console.log("Rejected")
            }
            onOpened: {
                textInput.focus = true
            }
        }
    
        Dialog {
            id: dialog2
    
            height: 150; width: 150
            x: (parent.width - width) / 2
            y: (parent.height - height) / 2
    
            focus: true
            modal: true
    
            Label {
                verticalAlignment: Text.AlignVCenter
                horizontalAlignment: Text.AlignHCenter
                anchors.centerIn: parent
                text: "Hello"
            }
    
            standardButtons: Dialog.Ok
        }
    
        Dialog {
            id: dialog3
    
            height: 150; width: 150
            x: (parent.width - width) / 2
            y: (parent.height - height) / 2
    
            focus: true
            modal: true
    
            Label {
                verticalAlignment: Text.AlignVCenter
                horizontalAlignment: Text.AlignHCenter
                anchors.centerIn: parent
                text: "Hello"
            }
    
            standardButtons: Dialog.Ok
    
            footer: DialogButtonBox {
                id: buttons
                standardButtons: Dialog.Ok
                alignment: Qt.AlignHCenter
                Keys.onEnterPressed: dialog3.accept()
                Keys.onReturnPressed: dialog3.accept()
    
                onVisibleChanged: if (visible) forceActiveFocus()
            }
        }
    
        Column {
            anchors.top: parent.top
            anchors.left: parent.left
            anchors.margins: 5
    
            spacing: 5
    
            Button {
                text: "Open dialog 1"
                onClicked: dialog1.open()
            }
            Button {
                text: "Open dialog 2"
                onClicked: dialog2.open()
            }
            Button {
                text: "Open dialog 3"
                onClicked: dialog3.open()
            }
        }
    }
    
    

Log in to reply