In .qml I'm generating the Listview based on the .json file below. I'm able to filter the list bases on the "PinName" alone via TextField of the Frame QML type. I also need to be able to use CheckBox type to filter the "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"
}
]
}
I have implemented the Listview model as follows:
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
In .qml I'm generating the Listview based on the .json file below. I'm able to filter the list bases on the "PinName" alone via TextField of the Frame QML type. I also need to be able to use CheckBox type to filter the "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"
}
]
}
I have implemented the Listview model as follows:
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
As of Qt6.4+ with the QML list
type, in particularly, list<var>
behaves similarly to Javascript arrays and supports the filter which is good for search.
To get this to work:
property var raw_data
property list<var> pin_data
pin_data.filter()
to switch between PinName/Functon to Make search based on the Search textfield and Make checkboxPage {
property var raw_data: ({
"Toyota" :
[
/* ... */
],
"Volkswagen" :
[
/* ... */
],
})
property list<var> pin_data: {
var result = [ ];
for (let brand in raw_data) {
for (let pin of raw_data[brand]) {
pin.Brand = brand;
result.push(pin);
}
}
return result;
}
header: RowLayout {
TextField {
id: search
Layout.fillWidth: true
placeholderText: make.checked ? "Make Search" : "PinData/Function Search"
}
CheckBox { id: make; text: "Make" }
}
ListView {
anchors.fill: parent
model: pin_data.filter(
m => !search.text
|| (make.checked ? m.Make : m.PinName + " " + m["Function Name"])
.toLowerCase()
.indexOf(search.text.toLowerCase()) != -1)
delegate: Frame {
width: ListView.view.width
ColumnLayout {
Label { text: `Brand: ${modelData["Brand"]}` }
Label { text: `Make: ${modelData["Make"]}` }
Label { text: `Function Name: ${modelData["Function Name"]}` }
Label { text: `PinDirection: ${modelData["PinDirection"]}` }
Label { text: `PinName: ${modelData["PinName"]}` }
Label { text: `PinType: ${modelData["PinType"]}` }
}
}
}
}
You can Try it Online!
For Qt 5 compatibility, we can declare the array inline with the ListView.model as follows:
model: {
var result = [ ];
for (var brand in raw_data) {
for (var pin of raw_data[brand]) {
pin.Brand = brand;
result.push(pin);
}
}
return result.filter(
m => !search.text
|| (make.checked ? m.Make : m.PinName + " " + m["Function Name"])
.toLowerCase()
.indexOf(search.text.toLowerCase()) != -1);
}
You can Try this Qt5 compatible version online