QtQuick - 让 TableView 在其模型更改后更新其 rowCount

Posted

技术标签:

【中文标题】QtQuick - 让 TableView 在其模型更改后更新其 rowCount【英文标题】:QtQuick - make TableView update its rowCount after its model has changed 【发布时间】:2016-07-08 10:04:39 【问题描述】:

我有一个 TableView,我想在创建后动态填充它 - 即,我从我的 c++ 应用程序中读取了一个字符串列表,我想将其设置为 TableView 的模型。我为此使用了一个 ListModel,我从 TableView 的 Component.onCompleted 中填充它没有任何问题。但是,加载后,我还想从列表中选择某些项目作为默认选项。问题是即使 ListModel 包含所有数据,TableView 的 rowCount 属性也没有更新,所以当我调用tableView.selection.select(indexOfTheDefaultItem) 时,我收到警告“TableViewSelection: index out of range”。 我曾尝试发出ListModel.dataChanged() 信号并在那里处理初始选择,但这无济于事,我还尝试对所有其他信号(onLayoutChanged,onModelChanged ...)执行此操作,但没有结果。如果我在第一次尝试失败后重新加载我的数据,它会起作用,因为第一次尝试已经有一些行,所以选择不会超出范围。所以似乎唯一的问题是 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 Connectionstarget: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();
    

当前的行为是:我用这段代码打开窗口,listView 被我从 getTheListWithData 方法读取的字符串填充,但没有选择任何内容。然后当我重新加载数据(有一个按钮)时,由于代码示例末尾的连接再次调用了 initList,这一次它选择了所需的行。

【问题讨论】:

添加property int defaultEntityIndex并在onRowCountChanged中使用呢? 这正是我想要的,我发誓我之前尝试过但它没有用....但我一定在代码中有其他错误或拼写错误(很可能是因为我有qml 没有代码自动完成)....无论如何我又试了一次,它可以工作,谢谢。如果你把它作为答案,我会接受它......虽然它可能是一个可以删除的无用问题,但我会让你决定:) 用一些代码自己回答。提升 *** 上 qt5 的统计数据。 【参考方案1】:

正如 Velkan 在 cmets 中指出的那样,解决方案是简单地使用 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 函数应该做到这一点,但没有。我发现了一些其他人有同样问题的帖子,但到目前为止,他们的解决方案都没有对我有用。但这对我来说是一个需要进行更多研究的问题,或者在最坏的情况下是另一个 SO 问题 :) 如果我找到解决方案,我会更新这个答案。

【讨论】:

以上是关于QtQuick - 让 TableView 在其模型更改后更新其 rowCount的主要内容,如果未能解决你的问题,请参考以下文章

来自 C++ 的 QStandardItemModel 在 QtQuick / QML TableView 中不可见

QtQuick Controls 2 中的新 TableView 是不是支持不同的“角色”

QtQuick TableView CheckBox 委托调用 QAbstractTableModel 的 setData 函数

将 QStandardItemModel 从 C++ 传递到 QtQuick / QML TableView 并显示它

如何使用基于字段值选择的异构委托制作 QtQuick TableView / TreeView

QtQuick 2.0 下拉按钮