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 thefooter
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 theDialogButtonBox
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 inonOpened
, 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 callingforceActiveFocus
on the button box in theonClosed
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?
- calling
-
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/backtabHere 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:
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() } } }