I'm using lot's of TextInputs within ListViews in my QML-Application. To modify the value I'm providing a virtual QML-Keyboard, that also contains a TextInput.
When I click on a TextInput in the ListView, the TextInput within the QML-Keyboard get's focus and the user can start editing. When finished the text should be sent to the TextInput within the ListView.
The problem I have is, that I don't know how to copy the text of the keyboard's TextInput to the ListView's-TextInput because the focus is lost when starting my virtual keyboard.
Each delegate item in a ListView
is univocally identified by its index
attached property. The first delegate in the list has index 0, then 1 and so on.
A ListView
has a property currentIndex
referring to the currently selected item delegate. When the currentIndex
is set to a specific delegate also the currentItem
property is set to the corresponding delegate object.
Given these properties, you can exploit them to obtain the desired behaviour. When you select a TextInput
to edit it, you can set the currentIndex
of the list to the index of the TextInput
delegate. In this way also currentItem
is set and it can later be used to refer the delegate (and the TextInput
inside) when the editing in the virtual keyboard is finished.
Here is an example that better explains my point:
import QtQuick 2.3
import QtQuick.Window 2.0
import QtQuick.Layouts 1.1
Window {
width: 200
height: 300
visible: true
Component {
id: myDelegate
Rectangle {
width: myList.width; height: 20
color: myList.currentIndex === index ? "lightgreen" : "lightgray" // distinguish the selecte delegate
onFocusChanged: textInput.forceActiveFocus()
property alias textInput: textInput // alias the textInput // (1)
TextInput {
id: textInput
anchors.fill: parent
onCursorVisibleChanged: {
if(cursorVisible)
{
myList.currentIndex = index // (2)
keyboardInput.text = textInput.getText(0, textInput.text.length) // (3)
keyboardInput.forceActiveFocus()
}
}
}
}
}
ColumnLayout {
anchors.fill: parent
ListView {
id: myList
model: 5
delegate: myDelegate
spacing: 10
Layout.fillWidth: true
Layout.fillHeight: true
}
Rectangle {
Layout.alignment: Qt.AlignBottom
color: "steelblue"
Layout.preferredWidth: parent.width
Layout.preferredHeight: 40
TextInput {
anchors.centerIn: parent // simulate the keyboard
id: keyboardInput
width: parent.width
font.pixelSize: parent.height
onEditingFinished: {
myList.currentItem.textInput.text = getText(0, text.length) //(4)
}
}
}
}
}
This is a simplified example in which your virtual keyboard is substituted by a blue TextInput
with id keyboardInput
. Each time a TextInput
in the list is focused, the focus is passed to keyboardInput
for editing text.
First of all the TextInput
in the delegate is aliased (1) to be accessible from outside the delegate. When a TextInput
in the list get focused for editing (in my case I consider the CursorVisibleChanged
event), the list currentIndex
is set to the index
of the delegate (2) and also the current text in the TextInput
is copied inside keyboardInput
(3). When the editing is finished, the text inside keyboardInput
is copied back to the currently selected TextInput
via currentitem
(4).
This approach applies even with more than one ListView
: simply store the current list in a variable at an higher scope and refer that variable in (4) to set the text in the correct delegate.