QtQuick - 让 TableView 在其模型更改后更新其 rowCount
QtQuick - make TableView update its rowCount after its model has changed
我有一个 TableView,我想在创建后动态填充它 - 即,我从我的 C++ 应用程序中读取了一个字符串列表,我想将其设置为 TableView 的模型。我为此使用了 ListModel,我从 TableView 的 Component.onCompleted 中填充它没有任何问题。但是,加载后,我还想 select 列表中的某些项目作为默认选项。问题是即使 ListModel 包含所有数据,TableView 的 rowCount 属性 没有更新,所以当我调用 tableView.selection.select(indexOfTheDefaultItem)
时,我收到警告 "TableViewSelection: index out of range"。
我尝试发出 ListModel.dataChanged()
信号并在那里处理初始 selection,但这没有帮助,我还尝试对所有其他信号(onLayoutChanged、onModelChanged...)执行此操作我能找到但没有结果。如果我在第一次尝试失败后重新加载我的数据,它会起作用,因为第一次尝试已经有一些行,所以 selection 不会超出范围。所以似乎唯一的问题是 rowCount 直到对我来说为时已晚才更新(也许是在呈现组件之后?)。
所以最终的问题是 - 在 rowCount 更新后是否发出了一些我可以做出反应的信号?
我见过一些涉及在应用程序的 c++ 端创建列表并使用 beginInsertRows() 和 endInsertRows() 的解决方案,但这些显然不是 ListView 的功能,我更愿意将代码保留在 qml 中。
这是我的解决方案现在的样子:
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();
}
}
当前行为是:我用这段代码打开 window,listView 中填充了我从 getTheListWithData 方法读取的字符串,但没有 selected。然后当我重新加载数据时(有一个按钮),由于代码示例末尾的连接再次调用 initList,这次它 selects 所需的行。
正如 Velkan 在评论中指出的那样,解决方案是简单地使用 onRowCountChanged 信号,然后它会按预期工作。下面是我的完整代码。
ListModel
{
id:listModel
}
TableView
{
id: tableView
selectionMode:SelectionMode.SingleSelection
model: listModel
TableViewColumn
{
role: "myRole"
title: "myTitle"
}
onRowCountChanged:
{
if (rowCount > 0)
{
var defaultEntityIndex = 0;
for (var i = 0; i < rowCount; i++)
{
if (model.get(i).role == qsTr("NameOfTheDefaultItem"))
defaultEntityIndex = i;
}
// select the default item and also set it as current so that it is highlighted
currentRow = defaultEntityIndex
selection.select(defaultEntityIndex)
// move the view to the item so that the user knows that something got selected without his input....though this function actually does not seem to be working
positionViewAtRow(defaultEntityIndex, ListView.Beginning)
focus = true
}
}
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]});
}
// the lines that were here in the original post are (as expected) not needed
}
Component.onCompleted:
{
initList();
}
Connections // this is to re-fresh the tableView when my data changes
{
target: myC++class
onDataChanged: initList();
}
再次感谢 Velkan。
唯一的问题是,我希望 TableView 在自动选择默认元素时向下滚动到默认元素,以便用户知道发生了此默认选择。 positionViewAtRow 函数应该做到这一点,但实际上并没有。我发现其他人的一些帖子也有同样的问题,但到目前为止 none 他们的解决方案对我有用。但这对我来说是一个需要更多研究的问题,或者在最坏的情况下是另一个 SO 问题 :) 如果我找到解决方案,我会更新这个答案。
我有一个 TableView,我想在创建后动态填充它 - 即,我从我的 C++ 应用程序中读取了一个字符串列表,我想将其设置为 TableView 的模型。我为此使用了 ListModel,我从 TableView 的 Component.onCompleted 中填充它没有任何问题。但是,加载后,我还想 select 列表中的某些项目作为默认选项。问题是即使 ListModel 包含所有数据,TableView 的 rowCount 属性 没有更新,所以当我调用 tableView.selection.select(indexOfTheDefaultItem)
时,我收到警告 "TableViewSelection: index out of range"。
我尝试发出 ListModel.dataChanged()
信号并在那里处理初始 selection,但这没有帮助,我还尝试对所有其他信号(onLayoutChanged、onModelChanged...)执行此操作我能找到但没有结果。如果我在第一次尝试失败后重新加载我的数据,它会起作用,因为第一次尝试已经有一些行,所以 selection 不会超出范围。所以似乎唯一的问题是 rowCount 直到对我来说为时已晚才更新(也许是在呈现组件之后?)。
所以最终的问题是 - 在 rowCount 更新后是否发出了一些我可以做出反应的信号? 我见过一些涉及在应用程序的 c++ 端创建列表并使用 beginInsertRows() 和 endInsertRows() 的解决方案,但这些显然不是 ListView 的功能,我更愿意将代码保留在 qml 中。 这是我的解决方案现在的样子:
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();
}
}
当前行为是:我用这段代码打开 window,listView 中填充了我从 getTheListWithData 方法读取的字符串,但没有 selected。然后当我重新加载数据时(有一个按钮),由于代码示例末尾的连接再次调用 initList,这次它 selects 所需的行。
正如 Velkan 在评论中指出的那样,解决方案是简单地使用 onRowCountChanged 信号,然后它会按预期工作。下面是我的完整代码。
ListModel
{
id:listModel
}
TableView
{
id: tableView
selectionMode:SelectionMode.SingleSelection
model: listModel
TableViewColumn
{
role: "myRole"
title: "myTitle"
}
onRowCountChanged:
{
if (rowCount > 0)
{
var defaultEntityIndex = 0;
for (var i = 0; i < rowCount; i++)
{
if (model.get(i).role == qsTr("NameOfTheDefaultItem"))
defaultEntityIndex = i;
}
// select the default item and also set it as current so that it is highlighted
currentRow = defaultEntityIndex
selection.select(defaultEntityIndex)
// move the view to the item so that the user knows that something got selected without his input....though this function actually does not seem to be working
positionViewAtRow(defaultEntityIndex, ListView.Beginning)
focus = true
}
}
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]});
}
// the lines that were here in the original post are (as expected) not needed
}
Component.onCompleted:
{
initList();
}
Connections // this is to re-fresh the tableView when my data changes
{
target: myC++class
onDataChanged: initList();
}
再次感谢 Velkan。
唯一的问题是,我希望 TableView 在自动选择默认元素时向下滚动到默认元素,以便用户知道发生了此默认选择。 positionViewAtRow 函数应该做到这一点,但实际上并没有。我发现其他人的一些帖子也有同样的问题,但到目前为止 none 他们的解决方案对我有用。但这对我来说是一个需要更多研究的问题,或者在最坏的情况下是另一个 SO 问题 :) 如果我找到解决方案,我会更新这个答案。