QML中的Model View——一个ListView实例

QML中的Model View——一个ListView实例

(2011-11-14 15:14:09)
标签:

杂谈

 

引言

Qt 中的 Model View 大家已经比较熟悉了(详情请参阅model view programming)。在QML中也有类似的模式。本文就向大家初步讲解一下 QML 中的 Model View 的用法,并提供一个 ListView 的例子程序供大家参考。


Model

Models 是用来提供数据的,它既可以以 QML 的形式出现也可以是 C++的类。QML中的Model有 ListModelXmlListModelVisualItemModel;C++中的 Model 有 QAbstractItemModel、QStringList、 QList<QObject*>等。


View

View 是用来显示 Model 中的数据的,如果有 Delegates,则 View 会通过 Delegates 的帮助来显示 Model 中的每一个 Item。

QML 中有ListView, GridView, PathView, Repeater 这几种,当然大家也可以在这几种View的基础上扩展写出来自己的View。这些View都自动实现了动力滚动和弹簧效果。


Delegates

Delegates 是用来为 Model 中的每一个 Item 创建其对应的实例,并被 View 拿来做显示用的。

这里再补充一点,在大家在看诸如 ListView、GridView、PathView 这些 QML Element 的时候会发现它们都有一个叫 Highlight 的属性,它定义的是怎样对 Item 进行高亮突出显示。

其实 Highlight 和 Delegates 都是一个QML Component。我们通常会把一个 Component 写到一个 .qml 文件里(文件名第一个字母大写),从而利于程序其他地方以及日后的复用。 Highlight 和 Delegates 的作用本质都是相同的,都是为了描述如何显示 Model 中的每一块数据的,只是 Highlight 只会在 Item 在选中的情况下起作用。


例程主要代码分析

首先我们来到 main.qml 文件,这是 qml 入口文件( ”m“是小写的,与其他大写字母开头的Component有区别)。

ListView {
id: listView
z:0
anchors.fill: parent
model: MyModel {}
delegate: myDelegate
 } 

”ListView“ :我们这里直接使用了QML ListView Element。给它一个id,为了在其他地方可以引用到它。

”model: MyModel {}“:我们用了一个 model,叫做 MyModel,它是写在一个叫 MyModel.qml 文件中的,model 的名字是由文件名决定的,model名首字母要大写 。 我们这里直接写“MyModel {} “,只要有MyModel.qml这个文件,QML engine 就会认识的。其实我们也可以不这样写,如果这个 Model 有个 id,我们直接在这里写它的 id 也可以。

“delegate: myDelegate”:myDelegate是 我们自定义的一个 Delegate 的 id。



下面我们看下 myDelegate 是如何定义的:

Component {
id: myDelegate
 //以下全部省略 



然后我们继续看 myDelegate 里面还有什么:

states: [
State {
name: "Details"
PropertyChanges { target: listView; z:2}
PropertyChanges { target: background; color: "ivory" }
PropertyChanges { target: myImage; width: 180; height: 180 } // Make picture bigger
PropertyChanges { target: myContainer; detailsOpacity: 1; } // Make details visible
PropertyChanges { target: myContainer; height: listView.height } // Fill the entire list area with the detailed view
PropertyChanges { target: idTitle; color: "black" }
PropertyChanges { target: idTitle; font.pointSize: 11 }
PropertyChanges { target: topLayout; x: 10; }
PropertyChanges { target: myContainer.ListView.view; explicit: true; contentY: myContainer.y }
PropertyChanges { target:             ListView.view; interactive: false }
 },
State {
name: ""
PropertyChanges { target: listView; z:0}
PropertyChanges { target: background; color : "black"}
PropertyChanges { target: myImage; width: 47; height: 47 }
PropertyChanges { target: myContainer; detailsOpacity: 0; }
PropertyChanges { target: myContainer; height: 65 }
PropertyChanges { target: idTitle; color: "white" }
PropertyChanges { target: idTitle; font.pointSize: 9 }
PropertyChanges { target: topLayout; x: 50; }
PropertyChanges { target: myContainer.ListView.view; interactive: true }
 }]
 
transitions: Transition {
ParallelAnimation {
ColorAnimation { property: "color"; duration: 400 }
NumberAnimation { duration: 400; properties: "detailsOpacity,x,contentY,height,width" }
 } 

以上这部分代码也出现在 myDelegate 中。

它定义的是两种状态,一个叫 "Details" (自己起的名字),另一个叫 ""也就是一个空的字符串,这是这个 Item 的默认状态。在这两种不同状态下,delegate 中不同对象所对应的属性值都是不同的。

当发生状态切换的时候,就会触发动画效果(由 transitions 定义),其中 contentY 的变化会使得原本列表中的一个小 Item 伸展充满整个屏幕。



最后我们来到 MyModel.qml 文件,看 model 是如何定义的:

ListModel {
ListElement {
title: "Qt"
picture: "content/pics/Qt.png"
detailstr: "<html>
<ol>
<li> Intuitive C++ class library
<li> cross-platform
<li> Integrated development tools
<li> High runtime performance
</ol>
</html>"
method: "<html> 
<ul>
<li> Qt is a cross-platform application and UI framework. Using Qt, you can write web-enabled applications once and deploy them across desktop, mobile and embedded operating systems without rewriting the source code.
<li> Intuitive C++ class library
<li> Portability across desktop and embedded operating systems
<li> Integrated development tools with cross-platform IDE
<li> High runtime performance and small footprint on embedded
</ul>
</html>"
 }
 
ListElement {
...
 //以下省略 

我们这里使用了 ListModel,里面包含着一个又一个的 ListElement 作为数据 Item。这里要注意的是,我们在 Model 里面定义的属性,在 Delegate 中是可以直接访问的到的。比如在 myDelegate 中有:

Text {
text: detailstr
 //以下省略 

于是这个文本就会显示 Model 中 detailstr 的具体内容。

此外,我们还可以使用 Javascript 对 Model 进行 append(), insert(), move(), remove() 等动态操作,从而实现对 Model 数据的增加删除和修改。

使用数据库存储Model数据

上面的Model数据是直接写到代码里的,但是在实际应用中我们通常会从某个地方读取数据,而不是直接写到代码里。比如我们可以把数据存到数据库里,程序启动的时候从数据库中读取数据,退出的时候把Model中的数据存放回数据库中。主要代码如下所示:

ListModel {
id: mymodel
Component.onCompleted: loadImageData()
Component.onDestruction: saveImageData()
 function loadImageData() {
 var db = openDatabaseSync("MyDB", "1.0", "My model SQL", 50000);
db.transaction(
 function(tx) {
 // Create the database if it doesn't already exist
tx.executeSql('CREATE TABLE IF NOT EXISTS Images(id INTEGER primary key, title TEXT, picture TEXT)');
 
 var rs = tx.executeSql('SELECT * FROM Images');
 var index = 0;
 if (rs.rows.length > 0) {
 var index = 0;
 while (index < rs.rows.length) {
 var myItem = rs.rows.item(index);
mymodel.append( {
 "id": myItem.id,
 "title": myItem.title ,
 "picture": myItem.picture });
index++;
 }
 } else {
mymodel.append( {
 "id": 1,
 "title": 'apple' ,
 "picture": 'content/pics/apple.png' });
mymodel.append( {
 "id": 2,
 "title": 'Qt Quick!' ,
 "picture": 'content/pics/Qt.png' });
 }
 }
 )
 }
 
 function saveImageData() {
 var db = openDatabaseSync("MyDB", "1.0", "My model SQL", 50000);
db.transaction(
 function(tx) {
tx.executeSql('DROP TABLE Images');
tx.executeSql('CREATE TABLE IF NOT EXISTS Images(id INTEGER primary key, title TEXT, picture TEXT)');
 var index = 0;
 while (index < mymodel.count) {
 var myItem = mymodel.get(index);
tx.executeSql('INSERT INTO Images VALUES(?,?,?)', [myItem.id, myItem.title, myItem.picture]);
index++;
 }
 }
 )
 }
 } 

动态添加数据是非常简单的,比如我们在 onClicked 事件中可以这样做:

onClicked: mymodel.append( { "title": 'Qt', "picture": 'content/pics/Qt.png' }) 

删除数据:

onClicked: mymodel.remove(listView.currentIndex) 

例程:Media:ListModelViewWithDatabase.zip

应用程序截图

下面是程序在N8上面的运行效果:

QMLListView1.JPG

QMLListView2.JPG

QMLListView3.JPG

QMLListView4.JPG

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值