在SmallTalk中有一个经典的设计模式-MVC。即模型-视图-控制器,在qml中将control改成了delegate(委托),也就是现在的Model-View-Delegate.换了个说法,Model还是负责数据,View管着视图输出,Delegate呢就是一个介于视图和数据之间的桥梁。
下面先来看个例子,效果图如下:
import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Layouts 1.1 Rectangle{ 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 { 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 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 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 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。另外,在下面放了几个按钮,用以演示对数据的修改和删除。如果要实现插入数据,那么需要在footerView中添加signal insert()
,并添加Button
Button{ id: insertOne anchors.right: addOne.left anchors.leftMargin: 4 anchors.verticalCenter: parent.verticalCenter text: "Insert" onClicked: footerRootItem.insert() }
并且在 listView中实现Insert函数、建立与footerView的信号链接
function addOne() { model.append( { "name": "MX5", "cost": "1899", "manufacture" : "MeiZu" } ) } function insertOne() { model.insert(Math.round(Math.random() * model.count), { "name" : "HTC One E8", "cost" : "2900", "manufacture" : "HTC" } ) } Component.onCompleted: { listView.footerItem.add.connect(listView.addOne) listView.footerItem.insert.connect(listView.insertOne) }
注意:虽然delegate有很多附加属性以及信号等,但是只有顶层的item才能直接使用这些属性,
非顶层的item需要通过顶层item的id来访问这些属性