Forwarding keys to a Listview delegate inside a Popup
-
I'm trying to implement an autocomplete box similar to this https://material.angularjs.org/latest/demo/autocomplete.
I'm using a TextField and a Popup with a listview to show the suggestions, but I'm having trouble forwarding keys from TextField to the listview delegate.What I'm doing now is opening the popup on the textfield onTextChanged event and then query the database for suggestions and populate the suggestions model. I'm using Keys.forwardTo to forward key events from the textfield to the listview in the popup, and it works fine, for navigation. But I can't figure out select an element from the list using 'return' key.
This is main.qml
TextField { id: searchBar placeholderText: "Search..." focus: true property string searched_text: searchBar.text onTextChanged: { qmlComm.autoCompleteSearch(searchBar.text) autocomplete.open() } Keys.forwardTo: [autocomplete.autocompleteListViewAlias] } AutoCompletePopup{ id: autocomplete x:searchBar.x y:searchBar.y - 10 height: mainAppPage.height / 2 width: searchBar.width }
This is popup.qml:
Popup { id: autoCompletePopup property alias autocompleteListViewAlias: autoCompleteListView x: 200 y: 200 width: 200 height: 400 modal: false focus: false clip: true closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside Component { id: highlightBar Rectangle { width: autoCompleteListView.width height: 60 color: Material.color(Material.Pink) opacity: 0.7 y: autoCompleteListView.currentItem.y } } Rectangle { id: autoCompleteRect color: "transparent" height: autoCompletePopup.height width: autoCompletePopup.width ListView { id: autoCompleteListView anchors.fill: parent model: autoCompleteModel delegate: Item { id: autoCompleteDelegate height: 60 Rectangle { id: autoCompleteDelegateBackground width: autoCompleteListView.width height: 60 focus: true color: "transparent" Text { id: autoCompleteItemName text: name font.capitalization: Font.Capitalize anchors.left: autoCompleteDelegateBackground.left anchors.leftMargin: 10 anchors.verticalCenter: autoCompleteDelegateBackground.verticalCenter } MouseArea { id: autoCompleteMouseArea anchors.fill: autoCompleteDelegateBackground onClicked: { console.log("You clicked " + tableName + " " + name + " " + id) //tableName,name and id are model role names autoCompleteListView.currentIndex = index } } // this is the problem, this event does not trigger Keys.onReturnPressed: { console.log("Pressed Enter on " + name) } } } // successfully triggered when keys are forwarded Keys.onPressed: { if (event.key === Qt.Key_Down) { console.log("AUTOCOMPLETE : Pressed down") } else if (event.key === Qt.Key_Up) { console.log("AUTOCOMPLETE : Pressed up") } else if (event.key === Qt.Key_Return) { console.log("AUTOCOMPLETE : Pressed enter") } } highlight: highlightBar highlightFollowsCurrentItem: false ScrollBar.vertical: ScrollBar { } focus: false clip: true } } }
I managed to get the navigation and selection behavior I want if I force the focus on the delegate on a mouse click like so : (in the mousearea on click event)
autoCompleteListView.forceActiveFocus();
But then the textbox looses focus and the user can no longer type.
I'm looking for a way to react to aKeys.onReturnPressed
event inside the delegate, or some other solution that would help me select an item from a listview while maintaining the focus on the textedit.Thank You!
P.S, I'm new to QML and Qt, so I'm also open to any suggestions that would help me build an autocomplete box that use completely different approach from what I have taken.
-
Does this do more or less what you want (besides that it's using a dummy model instead of doing any actual filtering)?
import QtQuick 2.6 import QtQuick.Controls 2.0 ApplicationWindow { width: 640 height: 480 visible: true TextField { id: textField focus: true anchors.centerIn: parent onTextChanged: popup.open() Keys.forwardTo: [listView.currentItem, listView] Popup { id: popup padding: 1 y: parent.height width: parent.width contentHeight: listView.contentHeight ListView { id: listView currentIndex: 0 anchors.fill: parent model: ["foo", "bar", "baz"] delegate: ItemDelegate { text: modelData width: parent.width highlighted: index === listView.currentIndex Keys.onReturnPressed: { textField.text += text popup.close() } } } } } }
-
Yes! Adding forwarding to
listview.currentItem
does exactly what I want. Thank You!