qml model view使用

Model-View

Qt 中的 Model-View 编程框架Model-View-Delegate,Model负责数据,View管着视图输出,Delegate呢就是一个介于视图和数据之间的桥梁。

listview

ListView 用来显示一个条目列表,条目对应的数据来自于Model,而每个条目的外观则由 Delegate 决定。

import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1

Rectangle{
    width: 360
    height: 300
    color: "#EEEEEE"

    Component{
        id: phoneModel

        ListModel{
            ListElement{
                name: "iphone 3GS"
                cost: "1000"
                manufacturer: "Apple"
            }

            ListElement{
                name: "iphone 4"
                cost: "1800"
                manufacturer: "Apple"
            }

            ListElement{
                name: "iphone 4s"
                cost: "2300"
                manufacturer: "Apple"
            }

            ListElement{
                name: "iphne 5"
                cost: "1590"
                manufacturer: "Apple"
            }

            ListElement{
                name: "iphone B199"
                cost: "1590"
                manufacturer: "HuaWei"
            }

            ListElement{
                name: "MI 25"
                cost: "1999"
                manufacturer: "XiaoMi"
            }

            ListElement{
                name: "GALAXY s5"
                cost: "4698"
                manufacturer: "Samsung"
            }
        }
    }//phoneModel is end(视图数据)

    Component{
        id: headView
        Item {
            width: parent.width
            height: 30
            RowLayout{
                anchors.left: parent.left
                anchors.verticalCenter: parent.verticalCenter
                spacing: 8
                Text{
                    text: "name"
                    font.bold: true
                    font.pixelSize: 20
                    Layout.preferredWidth: 120
                }

                Text{
                    text: "cost"
                    font.bold: true
                    font.pixelSize: 20
                    Layout.preferredWidth: 80
                }

                Text{
                    text: "manufacturer"
                    font.bold: true
                    font.pixelSize: 20
                    Layout.fillWidth: true
                }
            }
        }
    }//headview is end(定义的表头)

    Component{
        id: footerView

        Item{
            id: footerRootItem
            width: parent.width
            height: 30
            property alias text: txt.text
            signal clean()
            signal change()
            signal replace()

            Text{
                id: txt
                anchors.left: parent.left
                anchors.top: parent.top
                anchors.bottom: parent.bottom
                width: parent.width/4
                font.italic: true
                color: "blue"
                verticalAlignment: Text.AlignVCenter
            }

            Button{
                id: cleanBtn
                anchors.right: parent.right
                anchors.verticalCenter: parent.verticalCenter
                text: "clear"
                onClicked: footerRootItem.clean()
            }//清空视图数据的按钮

            Button{
                id: changeBtn
                anchors.right: cleanBtn.left
                anchors.rightMargin:  5
                anchors.verticalCenter: parent.verticalCenter
                text: "change data"
                onClicked: footerRootItem.change()
            }//改变选中行数据

            Button{
                id: replaceBtn
                anchors.right: changeBtn.left
                anchors.rightMargin: 5
                anchors.verticalCenter: parent.verticalCenter
                text: "replace data"
                onClicked: footerRootItem.replace()
            }//替换选中行的数据
        }

    }//footer属性允许我们制定listview的页脚,footerItem保存了footer组件创建出来的item对象,这个item会被
    //添加到listview的末尾,在所有可见的item之后

    Component{
        id: phoneDelegate
        Item {
            id: wrapper
            width: parent.width
            height: 30

            MouseArea{
                anchors.fill: parent
                onClicked: wrapper.ListView.view.currentIndex = index
                onDoubleClicked: wrapper.ListView.view.model.remove(index)
            }

            RowLayout{
                anchors.left: parent.left
                anchors.verticalCenter: parent.verticalCenter
                spacing: 8
                Text{
                    id: coll
                    text: name
                    color: wrapper.ListView.isCurrentItem ? "red" : "black"
                    font.pixelSize: wrapper.ListView.isCurrentItem ? 22 : 18
                    Layout.preferredWidth: 120
                }//coll text is end

                Text{
                    text: cost
                    color: wrapper.ListView.isCurrentItem ? "red" : "black"
                    font.pixelSize: wrapper.ListView.isCurrentItem ? 22 : 18
                    Layout.preferredWidth: 80
                }//cost text is end

                Text{
                    text: manufacturer
                    color: wrapper.ListView.isCurrentItem ? "red" : "black"
                    font.pixelSize: wrapper.ListView.isCurrentItem ? 22 : 18
                    Layout.fillWidth: true
                }//manufacturer is end
            }
        }
    }//delegate is end(视图的委托)

    ListView{
        id: listView
        anchors.fill: parent
        focus: trues
        delegate: phoneDelegate
        model: phoneModel.createObject(listView)
        header: headView
        footer: footerView
        highlight: Rectangle{
            color: "lightblue"
        }

        onCurrentIndexChanged: {
            if(listView.currentIndex >= 0){
                var data = listView.model.get(listView.currentIndex)
                listView.footerItem.text = data.name + "," + data.cost + "," + data.manufacturer
            }
            else
                listView.footerItem.text = " "
        }

        function changeItem()//修改模型数据
        {
            listView.model.setProperty(listView.currentIndex, "manufacturer", "China")
        }

        function replaceItem()//替换模型数据
        {
            listView.model.set(listView.currentIndex, {"name": "234 ninbi",                                                    "cost": 1999, "manufacturer": "ZhongXing"})
        }

        Component.onCompleted: {
            listView.footerItem.clean.connect(listView.model.clear)//关联信号
            listView.footerItem.change.connect(listView.changeItem)//关联改变信号
            listView.footerItem.replace.connect(listView.replaceItem)
        }
    }//定义listview
}

效果图:

这个例子比较简单,增加了头和footer。另外,在下面放了几个按钮,用以演示对数据的修改和删除。

TableView

tableview与Listview相似,只不过是多了滚动条、挑选以及可调节尺寸等功能,它的数据也是通过Model来实现的。

import QtQuick 2.2
import QtQuick.Controls 1.2

Rectangle{
    id: root
    width: 360
    height: 300

    property var background: "#d7e3bc"
    property var alterBackground: "white"
    property var highlight: "#e4f7d6"
    property var headerBkg: "#F0F0F0"
    property var normalG: Gradient{
        GradientStop{position: 0.0; color: "#c7d3ac"}
        GradientStop{position: 1.0; color: "#F0F0F0"}
    }
    property var hoverG: Gradient{
        GradientStop{position: 0.0; color: "white"}
        GradientStop{position: 1.0; color: "#d7e3bc"}
    }
    property var pressG: Gradient{
        GradientStop{position: 0.0; color: "#d7e3bc"}
        GradientStop{position: 1.0; color: "white"}
    }

    TableView{  //定义table的显示,包括定制外观
        id: phoneTable
        anchors.fill: parent
        focus: true
        TableViewColumn{role: "name"; title: "Name"; width: 100; elideMode: Text.ElideRight;}
        TableViewColumn{role: "cost"; title: "Cost"; width: 100; elideMode: Text.ElideRight;}
        TableViewColumn{role: "manufacture";title: "Manufacture"; width: 100; elideMode: Text.ElideRight;}

        itemDelegate: Text{
            text: styleData.value
            color: styleData.selected ? "red" : "black"
            elide: Text.ElideRight
        }

        rowDelegate: Rectangle{
            color: styleData.selected? root.highlight :
                         (styleData.alternate ? root.alterBackground : root.background)
        }

        headerDelegate: Rectangle{
            implicitWidth: 10
            implicitHeight: 24
            border.color: "gray"
            border.width: 1
            Text{
                anchors.verticalCenter: parent.verticalCenter
                anchors.left: parent.left
                anchors.leftMargin: 4
                anchors.right: parent.right
                anchors.rightMargin: 4
                text: styleData.value
                color: styleData.pressed ?"red" : "blue"
                font.bold: true
            }
        }//header delegate is end

        model: ListModel{
            id: phoneModel
            ListElement{
                name: "iphone5"
                cost: "4900"
                manufacture: "apple"
            }
            ListElement{
                name: "b199"
                cost: "1590"
                manufacture: "huawei"
            }
            ListElement{
                name: "MI25"
                cost: "1999"
                manufacture: "xiaomi"
            }
            ListElement{
                name: "galaxy s6"
                cost: "3900"
                manufacture: "samsung"
            }
        }//listmodel is end
    }
}

GridView

gridview和listview相似,只不过是呈现的方式不同,可以把grideview理解成 IconMode的呈现方式

import QtQuick 2.0
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.XmlListModel 2.0

Rectangle {
    width: 400
    height: 400

    Component{
        id: videoModel
        XmlListModel{
            id: xmlModel
            source: "videos.xml"
            query: "/videos/video"
            XmlRole{name: "name"; query: "@name/string()"}
            XmlRole{name: "img"; query: "poster/@img/string()"}
            XmlRole{name: "rating"; query: "attr[3]/number()"}
        }
    }//video model is end

    Component{
        id: videoDelegate
        Item{
            id: wrapper
            width: videoView.cellWidth
            height: videoView.cellHeight
            MouseArea{
                anchors.fill: parent
                onClicked: wrapper.GridView.view.currentIndex = index
            }

            Image {
                id: poster
                width: 100
                height: 150
                anchors.horizontalCenter: parent.horizontalCenter
                anchors.top: parent.top
                anchors.topMargin: 3
                fillMode: Image.PreserveAspectFit
                source: img
            }

            Text{
                anchors.top: poster.bottom
                anchors.topMargin: 4
                width: parent.width

                text: name
                color: wrapper.GridView.isCurrentItem ? "blue" : "black"
                font.pixelSize: 18
                horizontalAlignment: Text.AlignHCenter
                elide: Text.ElideMiddle
            }

        }
    }//video model is end

    GridView{
        id: videoView
        anchors.fill: parent
        cellWidth: 120
        cellHeight: 190

        delegate: videoDelegate
        model: videoModel.createObject(videoView)
        focus: true
        highlight: Rectangle{
            color: "lightblue"
        }
    }
}

效果图如下:

PathView

pathview由model 、delegate、path三部分组成。Path的startX、startY用于描述路径的起点,而pathElements是个路径元素的列表,常见的路径元素有PathLine(直线)athQuad(赛贝尔二次曲线)、 PathCubic(赛贝尔三次曲线)、PathArc(椭圆上的一段弧)、PathCurve、PathSvg等。路径元素的终点就是整个路径的终点,终点可以和起点重合,如果重合那就表形成闭环。

import QtQuick 2.2

Rectangle {
    id: root
    width: 480
    height: 320
    color: "black"

    Component{
        id: rectDelegate

        Item{
            id: wrapper
            z: PathView.zOrder
            opacity: PathView.itemAlpha
            scale: PathView.itemScale
            Rectangle{
                width: 100
                height: 60
                color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
                border.width: 2
                border.color: wrapper.PathView.isCurrentItem ? "red" : "lightgray"
                Text{
                    anchors.centerIn: parent
                    font.pixelSize: 28
                    text: index
                    color: Qt.lighter(parent.color, 2)
                }
            }
        }
    }//rectDelegate is end

    PathView{
        id: pathView
        anchors.fill: parent
        interactive: true
        pathItemCount: 7
        preferredHighlightBegin: 0.5
        preferredHighlightEnd: 0.5
        highlightRangeMode: PathView.StrictlyEnforceRange

        delegate: rectDelegate
        model: 15
        focus: true
        Keys.onLeftPressed: decrementCurrentIndex()
        Keys.onRightPressed: incrementCurrentIndex()

        path:Path{
            startX: 10
            startY: 100
            PathAttribute{name: "zOrder"; value: 0;}
            PathAttribute{name: "itemAlpha"; value: 0.1;}
            PathAttribute{name: "itemScale"; value: 0.6}
            PathLine{
                x: root.width/2 - 40
                y: 100
            }

            PathAttribute{name: "zOrder"; value: 10;}
            PathAttribute{name: "itemAlpha"; value: 0.8;}
            PathAttribute{name: "itemScale"; value: 1.2}
            PathLine{
                x: root.width/2 - 60
                y: 0
            }

            PathAttribute{name: "zOrder"; value: 0;}
            PathAttribute{name: "itemAlpha"; value: 0.1;}
            PathAttribute{name: "itemScale"; value: 0.6}
        }

      MouseArea{
            anchors.fill: parent
            onWheel: {                
                if(wheel.angleDelta.y > 0)
                    pathView.decrementCurrentIndex()
                else
                    pathView.incrementCurrentIndex()
            }
        }
    }
}

repeater

repeater,用于创建多个基于item的组件,通常会用到三个属性,count-创建item的数量,model-指定数据,delegate-待实例化的模型,一般在创建repeater时不显示初始化。另外,还有其它常用属性:
  itemAt(index) 根据索引返回对应的delegate实例
  model 可以取数字(表示创建的数量)、字符串列表、对象列表、ListModel
虽然repeater可以一次性创建大量的同一类型的Item,但是当量大时,效率就会低下;而listview呢它会创建少部分item,直到用户需要看到它时才会再创建。

import QtQuick 2.2
import QtQuick.Layouts 1.1

Rectangle {
    id: root
    width: 320
    height: 480
    color: "#EEEEEE"

    Grid{
        anchors.left: parent.left
        anchors.leftMargin: 4
        anchors.top: parent.top
        anchors.topMargin: 4
        rows: 3
        spacing: 5

        Repeater{
            //model: 8 //数字模式
            model: ["A", "B", "C", "D", "E", "F", "G", "H"]   //字符串模式

            Rectangle{
                width: root.width / 3 - 7
                height: width
                color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)

                Text{
                    anchors.centerIn: parent
                    font.pixelSize: 15
                    font.bold: true
                    color: "red"
                    text: modelData //modelData.name 或者modelData.text
                }
            }
        }
    }
}

XmlListModel

除了常规的从代码中交互数据外,还有一种直接从XML文件中读取数据的方式,那就是XmlListModel。它从XML数据中创建一个只读的model

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×