如何在QML中使用CheckBox过滤ListView?
QML实现ListView多条件过滤(TextField+CheckBox)
我在QML中基于以下JSON数据生成了ListView,目前已实现通过TextField对PinName字段进行过滤,现在需要额外添加用CheckBox对Make字段的过滤功能。
{ "Toyota" : [ { "Make": "RAV4", "PinName": "J1-A3/A4", "PinType": "Digital", "PinDirection": "Output", "Function Name": "Reverse Output" }, { "Make": "RAV4", "PinName":"J1-C1", "PinType": "Analogue", "PinDirection": "Input", "Function Name": "Fuel Sensor Signal" }, { "Make": "Fortuner", "PinName": "J1-C2", "PinType": "Tristate", "PinDirection": "Input", "Function Name": "Generic Spare" }, { "Make": "Fortuner", "PinName": "J1-C3/C4", "PinType": "Digital", "PinDirection": "Output", "Function Name": "Bin Marker Lights" }, { "Make": "Corolla", "PinName": "J1-D1", "PinType": "Tristate", "PinDirection": "Input", "Function Name": "DiffLock Switch (CTD)" }, { "Make": "Corolla", "PinName": "J1-D2", "PinType": "Tristate", "PinDirection": "Output", "Function Name": "Park Brake Press Switch" } ], "Volkswagen": [ { "Make": "Polo", "PinName": "J1-A3/A4", "PinType": "Digital", "PinDirection": "Output", "Function Name": "Reverse Output" }, { "Make": "Polo", "PinName": "J1-C1", "PinType": "Analogue", "PinDirection": "Input", "Function Name": "Fuel Sensor Signal" }, { "Make": "Taigo", "PinName": "J1-C2", "PinType": "Tristate", "PinDirection": "Input", "Function Name": "Generic Spare" }, { "Make": "Taigo", "PinName": "J1-C3/C4", "PinType": "Digital", "PinDirection": "Output", "Function Name": "Bin Marker Lights" }, { "Make": "Tiguan", "PinName": "J1-D1", "PinType": "Tristate", "PinDirection": "Input", "Function Name": "DiffLock Switch (CTD)" }, { "Make": "Tiguan", "PinName": "J1-D2", "PinType": "Tristate", "PinDirection": "Output", "Function Name": "Park Brake Press Switch" } ] }
我当前实现的ListView代码如下:
ListView { id: pinListView Layout.fillWidth: true Layout.fillHeight: true clip: true model: FilterDelegateModel { id: filterDelegateModel model: pinModel filter: search ? function(model){ var isFound = false ; var i = 0 ; //=================================================== const pattern = search.trim() ; if(pattern.length > 0){ var regex = new RegExp(pattern,'i' /*ignore case*/); //What does this do???? isFound = (regex.test(model.Make+ model.FunctionName )) ; } return isFound ; } : null property string search: searchTextEdit.text.trim().toLowerCase() onSearchChanged: Qt.callLater(update) delegate: Frame { id: frame property int visibleIndex: DelegateModel.visibleIndex width: ListView.view.width background: Rectangle { color: visibleIndex & 1 ? "#404040" : "#343434" border.color: "#7D7D7D" border.width: 1 } RowLayout { id: layout anchors.fill: parent spacing: 6 Text { text: (visibleIndex + 1) color: "#fdbb30" font.bold: true font.pointSize: 9 } Text { Layout.fillWidth: true text: model.functionName+" - "+"["+model.make+"]" color: "white" //"#fdbb30" font.bold: true font.pointSize: 9 } Rectangle { color: 'transparent'//'transparent'//'plum' Layout.alignment: Qt.AlignLeft //Layout.fillWidth: true Layout.minimumWidth: 50 Layout.preferredWidth: layout.width*0.5 Layout.maximumWidth: layout.width*0.5 Layout.minimumHeight: 40 Loader { id: controlLoader // sourceComponent: pinListView.getPinControl(model.direction, model.type) anchors.centerIn: parent } } } //RowLayout }//Frame }//FilterDelegateModel } //ListView
实现步骤
提取唯一Make值并生成CheckBox组
从JSON数据中提取所有不重复的Make名称,动态生成对应的CheckBox供用户选择过滤车型。维护选中的Make集合
创建列表存储用户选中的Make值,CheckBox状态变化时同步更新该集合。修改过滤逻辑
在原有TextField过滤基础上,加入CheckBox的选中条件:若选中特定Make则只显示对应条目;若未选中任何CheckBox则不对Make做过滤。
修改后的完整代码
// 顶部添加CheckBox过滤栏 RowLayout { id: makeFilterLayout Layout.fillWidth: true spacing: 10 padding: 5 // 提取所有唯一的Make值 property var uniqueMakes: (function() { var makes = []; for (var brand in pinModel) { pinModel[brand].forEach(item => { if (!makes.includes(item.Make)) { makes.push(item.Make); } }); } return makes; })() // 存储选中的Make值 property var selectedMakes: [] // 动态生成CheckBox Repeater { model: makeFilterLayout.uniqueMakes delegate: CheckBox { text: modelData checked: true // 默认全选 onCheckedChanged: { if (checked) { if (!makeFilterLayout.selectedMakes.includes(modelData)) { makeFilterLayout.selectedMakes.push(modelData); } } else { const index = makeFilterLayout.selectedMakes.indexOf(modelData); if (index !== -1) { makeFilterLayout.selectedMakes.splice(index, 1); } } filterDelegateModel.update(); } } } } // 修改后的ListView及过滤逻辑 ListView { id: pinListView Layout.fillWidth: true Layout.fillHeight: true clip: true model: FilterDelegateModel { id: filterDelegateModel model: pinModel filter: function(model) { // 1. TextField搜索过滤(针对PinName) let matchesSearch = true; const pattern = search.trim(); if (pattern.length > 0) { const regex = new RegExp(pattern, 'i'); // 'i'表示忽略大小写 matchesSearch = regex.test(model.PinName); } // 2. CheckBox的Make过滤 let matchesMake = true; if (makeFilterLayout.selectedMakes.length > 0) { matchesMake = makeFilterLayout.selectedMakes.includes(model.Make); } // 需同时满足两个过滤条件 return matchesSearch && matchesMake; } property string search: searchTextEdit.text.trim().toLowerCase() onSearchChanged: Qt.callLater(update) delegate: Frame { id: frame property int visibleIndex: DelegateModel.visibleIndex width: ListView.view.width background: Rectangle { color: visibleIndex & 1 ? "#404040" : "#343434" border.color: "#7D7D7D" border.width: 1 } RowLayout { id: layout anchors.fill: parent spacing: 6 Text { text: (visibleIndex + 1) color: "#fdbb30" font.bold: true font.pointSize: 9 } Text { Layout.fillWidth: true text: model["Function Name"]+" - "+"["+model.Make+"]" color: "white" font.bold: true font.pointSize: 9 } Rectangle { color: 'transparent' Layout.alignment: Qt.AlignLeft Layout.minimumWidth: 50 Layout.preferredWidth: layout.width*0.5 Layout.maximumWidth: layout.width*0.5 Layout.minimumHeight: 40 Loader { id: controlLoader // sourceComponent: pinListView.getPinControl(model.PinDirection, model.PinType) anchors.centerIn: parent } } } //RowLayout }//Frame }//FilterDelegateModel } //ListView
关键修正说明
- 原代码过滤逻辑误写为
model.Make+ model.FunctionName,已修正为针对PinName的过滤,符合需求描述。 - 修复了JSON字段名
Function Name(带空格)的读取问题,改为model["Function Name"]。 - CheckBox默认全选,用户可自由取消不需要的车型选项,状态变化时自动触发过滤更新。
内容的提问来源于stack exchange,提问作者Clive N




