《Qt MOOC系列教程》第四章第二节:模型视图框架

除了ListModel之外,还有其他几种QML模型类型。如XmlistModel,使用它可以从XML数据源构造模型,
它提供了一种非常方便的方法来解析XML数据。ObjectModel附带了要在视图中使用的可视项,它不需要委托,因为模型本身已经包含了可视项。DelegateModel在使用QAbstractItemModel索引访问数据项的情况下非常有用,典型的用例是层次树模型,用户可以在子树上下导航。

您甚至可以把对象实例当作model。在这种情况下,对象属性就是角色名称,如以下示例所示。

Text {
    id: myText
    text: "Hello"
    visible: false 
}

Component {
    id: myDelegate
    Text { text: model.text } 
}

ListView {
    anchors.fill: parent
    model: myText
    delegate: myDelegate
}    

1. XmlListModel

XmlListModel用于从XML数据创建只读模型。这是一种从类似RSS Feeds读取数据并从相关XML元素创建数据模型的非常方便的方法。

一个简单的XML结构可能如下:

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
    <channel>
        <item>
            <title>A blog post</title>
            <pubDate>Sat, 07 Sep 2010 10:00:01 GMT</pubDate>
        </item>
        <item>
            <title>Another blog post</title>
            <pubDate>Sat, 07 Sep 2010 15:35:01 GMT</pubDate>
        </item>
    </channel>
</rss>

这个XML文档包含了标签<rss>)和属性version="2.0")。开始标签<item>和结束标签</item>形成了一个元素,元素还可以具有子元素。这意味着它是一棵节点树,需要遍历该树以提取数据。

以下示例显示了如何从XML数据创建模型。

import QtQuick 2.0
import QtQuick.XmlListModel 2.0

XmlListModel {
    id: xmlModel
    source: "http://www.mysite.com/feed.xml"
    query: "/rss/channel/item"

    XmlRole { name: "title"; query: "title/string()" }
    XmlRole { name: "pubDate"; query: "pubDate/string()" }
}

source属性用于定义XML文档的位置,可以是本地资源或远程资源。

query属性值应该是一个有效的XPath (XML Path Language) 选择器。除此之外,XPath用于从XML文档树中选择与给定路径表达式匹配的节点。

通过查询/rss/channel/item,我们选择了所有的<item>,该<item><channel>的子元素,而<channel>是文档的根元素<rss>的子元素。有关更多详细用法,请参阅XPath使用示例

角色是使用XmlRoles来定义的。注意,这些<item>元素包含了其他所有元素,因此我们需要一个查询来绑定特定数据。在示例中,我们查询了<item>元素的<title><pubDate>,然后使用string()函数来获取它们的值,然后将该值绑定到对应命名的角色titlepubDate。有关更多示例,请参见XmlRole::query

ListView中使用上面生成的模型是完全正常的。我们可以把委托绑定到模型的角色:

ListView {
    width: 180; height: 300
    model: xmlModel
    delegate: Text { text: title + ": " + pubDate }
}

2. ObjectModel

ObjectModel可以用于定义一组可视项目,这样我们就不必使用委托。

ObjectModel {
    id: itemModel
    Text { color: "red"; text: "Hello " }
    Text { color: "green"; text: "World " }
    Text { color: "blue"; text: "again" }
}

ListView {
    anchors.fill: parent
    model: itemModel
    orientation: Qt.Horizontal
}

3. DelegateModel

在某种意义上,DelegateModelObjectModel类似,它也将模型和委托封装在一起。此外,它被用于层次模型。注意,其实所有QML模型类型实际上都是一个列表。您可以通过对QAbstractItemModel进行子类化来创建表、树和层次模型。DelegateModel有一个rootIndex属性,它是一种QModelIndex类型。使用模型索引可以在树结构的子项和父项之间进行导航。我们后面会介绍它。

DelegateModel对于在多个视图中共享委托数据项或对项进行排序和筛选也很有用。

3.1 共享数据项

DelegateModel使用Package类型可以将具有共享上下文的委托提供给多个视图。Package中的所有项都可以通过Package.name附加属性分配一个名称。类似下面的示例,它具有两个不同的Package.name项目。实际内容Text是基于对包含奇数索引的Package委托索引或对包含偶数索引的Package委托索引。模型myModel仅包含具有display角色的列表元素。

DelegateModel {
    id: visualModel
    delegate: Package {
        Item { id: odd; height: childrenRect.height; Package.name: "oddIndex" }
        Item { id: even; height: childrenRect.height; Package.name: "evenIndex" }
        Text {
            parent: (index % 2) ? even : odd
            text: display
        }
    }
    model: myModel
}

这样就可以在不同的视图中使用程序的包名称。DelegateModel的属性parts选择了一个DelegateModel从指定的部分创建委托。

ListView {
    height: parent.height/2
    width: parent.width
    model: visualModel.parts.oddIndex
}

ListView {
    y: parent.height/2
    height: parent.height/2
    width: parent.width
    model: visualModel.parts.evenIndex
}

3.2 对数据项进行排序和过滤

您可以使用DelegateModel中的组对委托进行排序和筛选。默认情况下,每个委托都有一个组。也可以使用DelegateModelGroup类型定义其他组。它提供了创建和删除组中的项目或将项目移动到组内其他索引位置的方法。

使用组的第一步是向DelegateModel添加一个或多个组。在下面示例中有两个组,默认情况下,所有委托项都添加到group1组中。请注意,项目也会添加到默认items组中,因此任何委托都可能同时属于几个组。DelegateModelfilterOnGroup属性确定了我们只对group1中的委托感兴趣。

DelegateModel {
    id: visualModel
    model: myModel // contains ListElements with the display role 
    filterOnGroup: "group1"

    groups: [
        DelegateModelGroup { name: "group1"; includeByDefault: true },
        DelegateModelGroup { name: "group2" }
     ]

DelegateModel中定义的组都会向每个委托项添加两个附加属性。其中DelegateModel.inGroupName用于表示该项目是否属于该组,DelegateModel.groupNameIndex则保存了该组中项的索引。

附加属性在检查和更改委托所属的组或更改项目在该组中的位置时非常有用。下面的示例展示了如何通过按下鼠标来更改组:

delegate: Text {
    id: item
    text: display
    MouseArea {
        anchors.fill: parent
        onClicked: {
            if (item.DelegateModel.inGroup1) {
                item.DelegateModel.inGroup1 = false;
                item.DelegateModel.inGroup2 = true;
            }
            else {
                item.DelegateModel.inGroup1 = true;
                item.DelegateModel.inGroup2 = false;
            }
      }
   }
}

您也可以将组筛选器赋值为要显示的组,这样一次只能显示一个组。

ListView {
    anchors.fill: parent
    model: visualModel
    focus: true
    Keys.onReturnPressed: {
        visualModel.filterOnGroup = (visualModel.filterOnGroup === "group1") ? "group2" : "group1";
    }
}

3.3 本节涉及的参考资料

https://doc.qt.io/qt-5/qtquick-modelviewsdata-modelview.html#xml-model
http://doc.qt.io/qt-5/qml-qtquick-xmllistmodel-xmllistmodel.html
https://qmlbook.github.io/en/ch06/index.html#a-model-from-xml
http://doc.qt.io/qt-5/xquery-introduction.html
http://doc.qt.io/qt-5/qml-qtqml-models-objectmodel.html
http://doc.qt.io/qt-5/qml-qtqml-models-delegatemodel.html

Source

获取更多信息,请关注作者公众号:程序员练兵场
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值