QML ListModel

1.简单model

mport QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    width: 400
    height: 500
    visible: true

    // 方法2:在数据项中包含选中状态
    ListModel {
        id: fruitModel2

        Component.onCompleted: {
            append({name: "Apple", cost: 2.45, isSelected: false})
            append({name: "Orange", cost: 3.25, isSelected: false})
            append({name: "Banana", cost: 1.95, isSelected: false})
            append({name: "Grape", cost: 4.50, isSelected: false})
            append({name: "Peach", cost: 3.75, isSelected: false})
        }

        function setSelectedIndex(index) {
            for (var i = 0; i < count; i++) {
                setProperty(i, "isSelected", i === index)
            }
        }

        function getSelectedIndex() {
            for (var i = 0; i < count; i++) {
                if (get(i).isSelected) return i
            }
            return -1
        }
    }

    Column {
        spacing: 20
        anchors.fill: parent
        anchors.margins: 20

        Label {
            text: "方法2:数据项包含选中状态"
            font.bold: true
        }

        ListView {
            id: listView2
            width: parent.width
            height: 200
            model: fruitModel2
            currentIndex: fruitModel2.getSelectedIndex()  // 从Model获取选中索引
            clip: true

            delegate: Rectangle {
                width: listView2.width
                height: 40
                color: isSelected ? "lightgreen" : "white"
                border.color: "lightgray"

                Text {
                    text: name + " - $" + cost.toFixed(2)
                    anchors.verticalCenter: parent.verticalCenter
                    x: 10
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                        fruitModel2.setSelectedIndex(index)
                    }
                }
            }
        }

        Row {
            spacing: 10
            Button {
                text: "选中Orange(index=1)"
                onClicked: fruitModel2.setSelectedIndex(1)
            }
            Button {
                text: "选中Grape(index=3)"
                onClicked: fruitModel2.setSelectedIndex(3)
            }
            Button {
                text: "清除选中"
                onClicked: fruitModel2.setSelectedIndex(-1)
            }
        }

        Label {
            text: "当前选中: " + (fruitModel2.getSelectedIndex() >= 0
                ? fruitModel2.get(fruitModel2.getSelectedIndex()).name
                : "无")
        }
    }
}

 

2.给model指定一个属性

import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    width: 400
    height: 500
    visible: true

    // 方法1:使用Model的curIndex属性
    ListModel {
        id: fruitModel1
        property int curIndex: -1  // 当前选中索引

        ListElement { name: "Apple"; cost: 2.45 }
        ListElement { name: "Orange"; cost: 3.25 }
        ListElement { name: "Banana"; cost: 1.95 }
        ListElement { name: "Grape"; cost: 4.50 }
        ListElement { name: "Peach"; cost: 3.75 }
    }

    Column {
        spacing: 20
        anchors.fill: parent
        anchors.margins: 20

        Label {
            text: "方法1:使用Model的curIndex属性"
            font.bold: true
        }

        ListView {
            id: listView1
            width: parent.width
            height: 200
            model: fruitModel1
            currentIndex: fruitModel1.curIndex  // 绑定到Model的curIndex
            clip: true

            delegate: Rectangle {
                width: listView1.width
                height: 40
                color: ListView.isCurrentItem ? "lightblue" : "white"
                border.color: "lightgray"

                Text {
                    text: name + " - $" + cost.toFixed(2)
                    anchors.verticalCenter: parent.verticalCenter
                    x: 10
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                        fruitModel1.curIndex = index  // 点击时更新Model的curIndex
                    }
                }
            }
        }

        Row {
            spacing: 10
            Button {
                text: "选中Apple(index=0)"
                onClicked: fruitModel1.curIndex = 0
            }
            Button {
                text: "选中Banana(index=2)"
                onClicked: fruitModel1.curIndex = 2
            }
            Button {
                text: "清除选中"
                onClicked: fruitModel1.curIndex = -1
            }
        }
    }
}

 

 

3.嵌套model代码

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

ApplicationWindow {
    width: 600
    height: 800
    visible: true
    title: "动态嵌套列表示例"

    // 主数据模型
    property var mainData: [
        {
            groupName: "默认组",
            items: [
                { name: "项目1", color: "lightblue" },
                { name: "项目2", color: "lightgreen" }
            ]
        }
    ]

    // 颜色选项
    property var colorOptions: ["#FF9999", "#99FF99", "#9999FF", "#FFFF99", "#FF99FF", "#99FFFF"]

    // 主ListView
    ListView {
        id: listView
        anchors.fill: parent
        spacing: 20
        model: mainData
        delegate: listDelegate
    }

    // ListView的委托组件
    Component {
        id: listDelegate

        Column {
            id: listColumn
            width: listView.width
            spacing: 10
            property int groupIndex: index  // 保存当前组的索引

            // 组标题行
            RowLayout {
                width: parent.width
                spacing: 10

                Text {
                    text: modelData.groupName
                    font.bold: true
                    font.pixelSize: 16
                    Layout.fillWidth: true
                }

                Button {
                    text: "删除组"
                    onClicked: removeGroup(groupIndex)
                }
            }

            // 内嵌的GridView
            GridView {
                id: gridView
                width: parent.width
                height: Math.ceil(modelData.items.length / 3) * 100
                cellWidth: 100
                cellHeight: 100
                model: modelData.items
                delegate: gridDelegate

                Label {
                    visible: parent.count === 0
                    anchors.centerIn: parent
                    text: "点击下方按钮添加项目"
                }
            }

            // 添加项目按钮
            Button {
                width: parent.width
                text: "添加项目到本组"
                onClicked: addItemToGroup(groupIndex)
            }
        }
    }

    // GridView的委托组件
    Component {
        id: gridDelegate

        Rectangle {
            width: 90
            height: 90
            color: modelData.color
            border.color: "black"
            radius: 5

            Column {
                anchors.centerIn: parent
                spacing: 5

                Text {
                    text: modelData.name
                    font.pixelSize: 12
                    anchors.horizontalCenter: parent.horizontalCenter
                }

                Button {
                    text: "删除"
                    anchors.horizontalCenter: parent.horizontalCenter
                    onClicked: {
                        // 通过parent层级访问外部委托的groupIndex
                        var outerDelegate = parent.parent.parent.parent.parent
                        removeItemFromGroup(outerDelegate.groupIndex, index)
                    }
                }
            }
        }
    }

    // 底部控制面板
    footer: Row {
        spacing: 10
        padding: 10

        Button {
            text: "添加新组"
            onClicked: addNewGroup()
        }

        Button {
            text: "清空所有"
            onClicked: clearAll()
        }
    }

    // === 功能函数 ===

    function addNewGroup() {
        var groupCount = mainData.length + 1;
        mainData.push({
            groupName: "新组 " + groupCount,
            items: []
        });
        mainData = mainData.slice();
    }

    function removeGroup(groupIndex) {
        mainData.splice(groupIndex, 1);
        mainData = mainData.slice();
    }

    function addItemToGroup(groupIndex) {
        var itemCount = mainData[groupIndex].items.length + 1;
        mainData[groupIndex].items.push({
            name: "项目 " + itemCount,
            color: colorOptions[Math.floor(Math.random() * colorOptions.length)]
        });
        mainData = mainData.slice();
    }

    function removeItemFromGroup(groupIndex, itemIndex) {
        mainData[groupIndex].items.splice(itemIndex, 1);
        mainData = mainData.slice();
    }

    function clearAll() {
        mainData = [];
        mainData = mainData.slice();
    }


//    // 修改指定ID项的颜色
//    function changeItemColor(itemId, newColor) {
//        if (itemReferences[itemId]) {
//            itemReferences[itemId].color = newColor
//        }
//    }


}

2.结果

 4.嵌套例子

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

ApplicationWindow {
    width: 600
    height: 400
    visible: true
    title: "ListModel 选择示例"

    ListModel {
        id: categoryModel

        Component.onCompleted: {
            append({
                categoryName: "水果",
                items: [
                    {name: "苹果", price: 5.2, isSelected: true},
                    {name: "香蕉", price: 3.5, isSelected: false},
                    {name: "橙子", price: 4.8, isSelected: false},
                    {name: "葡萄", price: 8.0, isSelected: false}
                ],
                isSelected: true
            });

            append({
                categoryName: "蔬菜",
                items: [
                    {name: "胡萝卜", price: 2.3, isSelected: false},
                    {name: "西红柿", price: 3.8, isSelected: false},
                    {name: "黄瓜", price: 2.5, isSelected: false}
                ],
                isSelected: false
            });

            append({
                categoryName: "零食",
                items: [
                    {name: "薯片", price: 6.5, isSelected: false},
                    {name: "巧克力", price: 12.0, isSelected: false},
                    {name: "饼干", price: 5.5, isSelected: false},
                    {name: "坚果", price: 15.0, isSelected: false},
                    {name: "糖果", price: 8.5, isSelected: false}
                ],
                isSelected: false
            });
        }
    }

    ColumnLayout {
        anchors.fill: parent
        spacing: 10

        // 显示当前模型状态
        ListView {
            Layout.fillWidth: true
            Layout.fillHeight: true
            model: categoryModel
            delegate: Column {
                width: parent.width
                spacing: 5

                Text {
                    text: categoryName + (isSelected ? " (选中)" : "")
                    font.bold: true
                    color: isSelected ? "blue" : "black"
                }

                Repeater {
                    model: items
                    delegate: Text {
                        text: "  - " + name + ": " + price + (isSelected ? " (选中)" : "")
                        color: isSelected ? "green" : "black"
                    }
                }
            }
        }

        // 按钮区域
        RowLayout {
            Layout.fillWidth: true
            spacing: 10

            TextField {
                id: id_txt1
                width: 50
            }

            Button {
                text: "选中大分类"
                onClicked: {
                    // 遍历所有分类
                    for (var i = 0; i < categoryModel.count; i++) {
                        // 设置第2个分类(索引1)为true,其他为false
                        categoryModel.setProperty(i, "isSelected", i === parseInt(id_txt1.text));
                    }
                }
            }

            TextField {
                id: id_txt2
                width: 50
            }

            Button {
                text: "选中小分类"
                onClicked: {
                    // 获取第3个分类(索引2)
                    var category = categoryModel.get(parseInt(id_txt1.text));
                    var subModelSize = category.items.count
                    var subModel = category.items

                    for (var j = 0; j < subModelSize; j++) {
                        subModel.setProperty(j, "isSelected", (j === parseInt(id_txt2.text)))
                    }
                }
            }
        }
    }
}

 5.例子

import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    id: root

    visible: true
    width: 400
    height: 600
    title: "使用isSelect属性的ListView"

    property int sIndex: -1
    // 数据模型 - 包含isSelect属性
    ListModel {
        id: listModel
        ListElement { name: "项目1"; isSelect: true }
        ListElement { name: "项目2"; isSelect: false }
        ListElement { name: "项目3"; isSelect: false }
        ListElement { name: "项目4"; isSelect: false }
        ListElement { name: "项目5"; isSelect: false }
    }


    ListView {
        id: listView
//        anchors.fill: parent
        width: parent.width
        height: 800
        model: listModel
        spacing: 2
        currentIndex: sIndex


        delegate: Rectangle {
            id: delegateItem
            width: listView.width
            height: 50
            color: index === root.sIndex ? "lightblue" : "white"  // 选中时变浅蓝色

            border.color: "lightgray"
            border.width: 1

            property int selected: isSelect
            onSelectedChanged: {
                if(isSelect && -1!==index) {
                    root.sIndex = index
                    console.log("listView.currentIndex", listView.currentIndex)
                }
            }

            Text {
                text: name
                anchors.centerIn: parent
                font.pixelSize: 16
            }

            MouseArea {
                anchors.fill: parent
                onClicked: {
                    // 切换当前项的isSelect状态
//                    listModel.setProperty(index, "isSelect", true)
//                    console.log("点击了:", name, "选中状态:", !isSelect)
//                    console.log(listView.currentIndex)
                    root.sIndex = index
                }
            }


        }
    }

    Row {
        anchors.bottom: parent.bottom
        TextArea {
            id: id_txt
            width: 80
        }

        Button {
            text: "test"
            onClicked: {
//                for(var i=0; i<listModel.count; ++i) {
//                    listModel.setProperty(i, "isSelect", false)
//                }
//                listModel.setProperty(parseInt(id_txt.text), "isSelect", true)
//                console.log(listView.currentIndex)
                root.sIndex = parseInt(id_txt.text)
            }
        }
    }


}

或者

import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    id: root

    visible: true
    width: 400
    height: 600
    title: "使用isSelect属性的ListView"

    // 数据模型 - 包含isSelect属性
    ListModel {
        id: listModel
        ListElement { name: "项目1"; isSelect: true }
        ListElement { name: "项目2"; isSelect: false }
        ListElement { name: "项目3"; isSelect: false }
        ListElement { name: "项目4"; isSelect: false }
        ListElement { name: "项目5"; isSelect: false }
    }


    ListView {
        id: listView
        width: parent.width
        height: 800
        model: listModel
        spacing: 2
        delegate: Rectangle {
            id: delegateItem
            width: listView.width
            height: 50
            color: index === ListView.view.currentIndex ? "lightblue" : "white"  // 选中时变浅蓝色

            border.color: "lightgray"
            border.width: 1

            property int selected: isSelect
            onSelectedChanged: {
                if(isSelect && -1!==index) {
                    ListView.view.currentIndex = index
                    console.log("listView.currentIndex", listView.currentIndex)
                }
            }

            Text {
                text: name
                anchors.centerIn: parent
                font.pixelSize: 16
            }

            MouseArea {
                anchors.fill: parent
                onClicked: {
                    for(var i=0; i<listModel.count; ++i) {
                        listModel.setProperty(i, "isSelect", false)
                    }
                    listModel.setProperty(index, "isSelect", true)
                    console.log(listView.currentIndex)
                }
            }
        }
    }

    Row {
        anchors.bottom: parent.bottom
        TextArea {
            id: id_txt
            width: 80
        }

        Button {
            id: id_btn
            text: "test"
            onClicked: {
                for(var i=0; i<listModel.count; ++i) {
                    listModel.setProperty(i, "isSelect", false)
                }
                listModel.setProperty(parseInt(id_txt.text), "isSelect", true)
                console.log(listView.currentIndex)
            }
        }
    }
}

 

 6.嵌套设置选中

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

ApplicationWindow {
    width: 600
    height: 400
    visible: true
    title: "ListModel 选择示例"

    ListModel {
        id: id_categoryModel

        Component.onCompleted: {
            append({
                categoryName: "水果",
                items: [
                    {name: "苹果", price: 5.2, isSelected: true},
                    {name: "香蕉", price: 3.5, isSelected: false},
                    {name: "橙子", price: 4.8, isSelected: false},
                    {name: "葡萄", price: 8.0, isSelected: false}
                ],
                isSelected: true
            });

            append({
                categoryName: "蔬菜",
                items: [
                    {name: "胡萝卜", price: 2.3, isSelected: false},
                    {name: "西红柿", price: 3.8, isSelected: false},
                    {name: "黄瓜", price: 2.5, isSelected: false}
                ],
                isSelected: false
            });

            append({
                categoryName: "零食",
                items: [
                    {name: "薯片", price: 6.5, isSelected: false},
                    {name: "巧克力", price: 12.0, isSelected: false},
                    {name: "饼干", price: 5.5, isSelected: false},
                    {name: "坚果", price: 15.0, isSelected: false},
                    {name: "糖果", price: 8.5, isSelected: false}
                ],
                isSelected: false
            });
        }
    }

    function notifyCppCurSheet(name) {
        console.log("c++ record sheet name", name)
    }
    function notifyCppCurDiagram(name) {
        console.log("c++ record diagram name", name)
    }


    ListView {
        id: id_listview
        width: parent.width
        height: 40
        model: id_categoryModel
        orientation: ListView.Horizontal
        spacing: 3
        delegate: Rectangle {
            width: 100
            height: ListView.view.height
            color: model.isSelected?"lightblue":"gray"
            Text {
                anchors.centerIn: parent
                text: categoryName
            }
            MouseArea {
                anchors.fill: parent
                onClicked: {
                    for(var i=0; i<id_categoryModel.count; ++i) {
                        id_categoryModel.setProperty(i, "isSelected", false)
                    }
                    model.isSelected = true
                    notifyCppCurSheet(categoryName)
                }
            }
        }
    }

    Item {
        width: parent.width
        height: parent.height-id_listview.height
        anchors.top: id_listview.bottom
        anchors.topMargin: 5

        Repeater {
            model: id_categoryModel
            Loader {
                anchors.fill: parent
                visible: isSelected
                sourceComponent: GridView {
                    cellWidth: 80
                    cellHeight: 80
                    anchors.fill: parent
                    model: items
                    delegate: Rectangle {
                        width: 80
                        height: 80
                        Text {
                            anchors.centerIn: parent
                            text: name
                        }
                        color: isSelected?"green":"gray"
                        MouseArea {
                            anchors.fill: parent
                            onClicked: {
                                for(var i=0; i<items.count; ++i) {
                                    items.setProperty(i, "isSelected", false)
                                }
                                model.isSelected = true
                                notifyCppCurDiagram(name)
                            }
                        }
                    }
                }
            }
        }
    }
}

 

posted @ 2025-07-14 23:34  朱小勇  阅读(136)  评论(0)    收藏  举报