I have a TableView that I want to fill dynamically after it is created - i.e. I read a list of strings from my c++ app that I want to set as the model of the TableView. I use a ListModel for that, I fill it with no problems from the Component.onCompleted of the TableView. However, after it is loaded, I also want to select certain item from the list as the default option. The problem is that even though the ListModel contains all the data, the rowCount property of the TableView is not updated, so when I call tableView.selection.select(indexOfTheDefaultItem)
, I get a warning "TableViewSelection: index out of range".
I have tried emiting the ListModel.dataChanged()
signal and handle the initial selection there, but that does not help, I also tried to do it on all other signals (onLayoutChanged, onModelChanged...) I could find but with no results. If I reload my data after the first failed attempt, it works, because there are already some rows from the first attempt, so the selection does not go out of range. So it seems the only problem is that the rowCount is not updated until it is too late for me (maybe it is after the component is rendered?).
So ultimately the question is - is there some signal that is emmitted AFTER the rowCount has been updated to which I could react? I have seen some solutions that involve creating the list on the c++ side of the app and using the beginInsertRows() and endInsertRows(), but these are apparently not a function of ListView and I would prefer to keep the code in the qml. Here is what my solution looks right now:
ListModel
{
id:listModel
}
TableView
{
id: tableView
selectionMode:SelectionMode.SingleSelection
model: listModel
TableViewColumn
{
role: "myRole"
title: "myTitle"
}
onModelChanged // or Connections{target:listModel onDataChanged .... } or onAnythingThatWillWorkPlease:
{
if (tableView.rowCount > 0) // this prevents the "index out of range" warning, but does not really solve the problem
{
var defaultEntityIndex = 5;
tableView.currentRow = defaultEntityIndex; // when I don't call this, the code in the onSelectionChanged below has "null pointer" exception, i.e. I presume the currentRow stays at the initial -1 - hence this "hack"
tableView.selection.select(defaultEntityIndex);
}
}
Connections
{
target: tableView.selection
onSelectionChanged :
{
if (tableView.currentRow >= 0)
myC++Class.selectedThing = listModel.get(tableView.currentRow).role;
}
}
}
function initList()
{
var vals = myC++Class.getTheListWithData();
for(var i =0; i<vals.length; i++)
{
listModel.append({role: vals[i]});
}
tableView.model = listModel // I just tried to do this to trigger the modelChanged signal
listModel.dataChanged(0, vals.length - 1);
}
Component.onCompleted:
{
initList();
}
Connections // this is to re-fresh the tableView when my data changes
{
target: myC++class
onDataChanged: // my custom signal
{
initList();
}
}
The current behavior is: I open the window with this code, the listView is filled with my strings read from the getTheListWithData method, but nothing is selected. When I then reload the data (have a button for that), the initList is called again from thanks to the connections in the end of the code example and this time it selects the desired row.
property int defaultEntityIndex
and using it in theonRowCountChanged
? – Velkan