在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{ 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。另外,在下面放了幾個按鈕,用以演示對數據的修改和刪除。如果要實現插入數據,那么需要在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來訪問這些屬性