QML ListView筛选项目。

8
我有一个ListView表格。我想要添加一些筛选按钮来根据项目类型隐藏/显示该表格的项目。最简单的方法是设置项委托的可见属性。然而,隐藏的项目仍然计入listView.contentHeight或listView.visibleArea.heightRatio。因此,在滚动时这些值会发生变化,并影响滚动条的高度和位置,导致它在没有顺序的情况下折叠、扩展和跳动。
另一个问题是,在listView中,如果选中一个项目,就无法知道它的索引,例如,它看起来像是表格中的第二个位置,但实际上它的索引更高,因为有不可见的项目。如果不计算不可见的项目,那将非常好。
请帮助解决这个问题。谢谢大家。
ListView{
  id: listView
  delegate: itemdelegate
}

Component{
  id: itemdelegate
  Item{
    visible: model.type === filteredType ? true: false
  }
}

对于任何来到这个问题的人,一种非常好的在 QML ListView 中过滤项目的方法是使用 DelegateModel 作为 ListView 模型,如此处所指定的。 - Eduardo
5个回答

3
动态向您的显示模型添加项目,例如。
filterButton.onClicked:{
    for(var i = 0; i < myListModel.count;i++)
    {
        if(myListModel.get(i).desiredProperty == "desiredValue")
            myDisplayModel.append("prop1":"val1");
    }
}

4
谢谢您的帮助。我之前也有一个解决方案,但是就性能而言,您的方式需要更多时间来清除和填充列表视图模型(以及表项),导致GUI冻结。我进行了性能测试,发现我的方法所需的时间显着更短。 - Maluvel

3

可能会起作用,但由于数据来自QML,您的建议不适用。谢谢。 - Maluvel

2

我找到了使用VisualDataModel QML项进行ListView过滤的方法,它非常好用。


1
有任何例子吗? - Ivan Fateev
你可以搜索VisualDataModel示例。这是一个旧的线程,但我会尝试在某个时候更新代码并提供示例。 - Maluvel

0

使用DelegateModel,我们可以利用DelegateModelGroup来过滤并显示ListModel的子集。在下面的示例中,我实现了FilterDelegateModel,基于将DelegateModel与类似数组的过滤属性组合起来,以便我们可以轻松定义一个过滤器:

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Page {
    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 10
        Label { text: qsTr("Search") }
        Frame {
            Layout.fillWidth: true
            TextEdit {
                id: searchTextEdit
                width: parent.width
            }
        }
        Label { text: qsTr("States (count:%1)").arg(filterDelegateModel.count) }
        ListView {
            Layout.fillWidth: true
            Layout.fillHeight: true
            clip: true
            model: FilterDelegateModel {
                id: filterDelegateModel
                model: states
                filter: search ? model =>  model.state.toLowerCase().indexOf(search) !== -1 : null
                property string search: searchTextEdit.text.toLowerCase()
                onSearchChanged: Qt.callLater(update)
                delegate: Frame {
                    id: frame
                    property int visibleIndex: DelegateModel.visibleIndex
                    width: ListView.view.width
                    background: Rectangle {
                        color: visibleIndex & 1 ? "#e0e0e0" : "#d0d0d0"
                        border.color: "#c0c0c0"
                    }
                    RowLayout {
                        width: parent.width
                        Text {
                            text: (visibleIndex + 1)
                            color: "grey"
                        }
                        Text {
                            Layout.fillWidth: true
                            text: model.state
                        }
                    }
                }
            }
        }
    }
    ListModel {
        id: states
        ListElement { state:"California" }
        ListElement { state:"New York" }
        ListElement { state:"Las Vegas" }
        ListElement { state:"Seattle" }
        ListElement { state:"Texas" }
    }
}

//FilterDelegateModel.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQml.Models 2.15
DelegateModel {
    property var filter: null
    onFilterChanged: Qt.callLater(update)
    groups: [
        DelegateModelGroup {
            id: allItems
            name: "all"
            includeByDefault: true
            onCountChanged: Qt.callLater(update)
        },
        DelegateModelGroup {
            id: visibleItems
            name: "visible"
        }
    ]
    filterOnGroup: "visible"
    function update() {
        allItems.setGroups(0, allItems.count, [ "all" ] );
        for (let index = 0; index < allItems.count; index++) {
            let visible = !filter || filter(allItems.get(index).model);
            if (!visible) continue;
            allItems.setGroups(index, 1, [ "all", "visible" ]);
        }
    }
    Component.onCompleted: Qt.callLater(update)
}

你可以在线尝试!

上述实现存在性能问题,每次更改筛选器、向源ListModel添加新记录都会导致所有记录再次进行扫描。如果您的ListModel中有大量记录(比如超过1000条),这将成为一个问题。为了解决这些问题,我有一个更全面的FilterDelegateModel实现,支持增量更新https://github.com/stephenquan/qt5-qml-toolkit/blob/main/FilterDelegateModel.qml


-2
您可以根据过滤条件设置宽度/高度。 例如:
Rectangle {
    width: condition?100:0
    height: condition?100:0
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接