当前位置: 首页 > news >正文

10. 模型与视图

一、模型与视图

  模型/视图架构包含三部分:模型(Model)是应用对象,用来表示数据;视图(View)是模型的用户界面,用来显示数据;委托(Delegate,也被称为 代理)可以定制数据的渲染和编辑方式。通过数据和界面进行分离,使得相同的数据在多个不同的视图中进行显示成为可能,而且还可以创建新的视图,而不需要改变底层的数据框架。

模型与视图机制

  我们可以在终端中使用 pip 安装 PySide6 模块。默认是从国外的主站上下载,因此,我们可能会遇到网络不好的情况导致下载失败。我们可以在 pip 指令后通过 -i 指定国内镜像源下载

pip install pyside6 -i https://mirrors.aliyun.com/pypi/simple

  国内常用的 pip 下载源列表:

  • 阿里云 https://mirrors.aliyun.com/pypi/simple
  • 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple
  • 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple
  • 中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple

二、数据模型

  Qt Quick 提供的模型类型主要包含在 QtQml.Models 模块中,另外还有一个基于 XML 的 QtQml.XmlListModel 模型。

2.1、列表模型

  ListModel 可以包含 ListElement 类型来存储数据。ListModel 的数据项的数量可以使用 count 属性获得。为了维护模型中的数据,该类型还提供了一系列方法:

object get(int index)                                                           // 获取模型中的指定索引的项
set(int index, jsobject dict)                                                   // 设置模型中指定索引的项为新值
append(jsobject dict)                                                           // 将新项添加到列表模型的末尾
insert(int index, jsobject dict)                                                // 在指定索引处插入新项
move(int from, int to, int n)                                                   // 将从索引“from”开始的“n”项移动到索引“to”
remove(int index, int count = 1)                                                // 从模型中删除从索引“index”开始的“count”项
clear()                                                                         // 从模型中删除所有内容

  其中一些方法需要接受字典类型作为其参数,这种字典类型会被模型自动转换成 ListElement 对象。如果需要通过模型修改 ListElement 中的内容,可以使用 setProperty() 方法,这个方法可以修改给定索引位置的 ListElement 的属性值。

  ListElement 需要在 ListModel 中定义,使用方法同其它 QML 类型基本没有区别,不同之处在于,ListElement 没有固定的属性,而是包含一系列自定义的键值。我们可以把 ListElement 看作一个 键值对 组成的 集合,其中 被称为 角色(role),它使用与属性相同的语法进行定义。

  角色 既定义了如何访问数据,也定义了数据本身。角色的名字以小写字母开始,并且应当是给定模型中所有 ListElement 通用的名字。角色的值必须是简单的常量,例如:字符串布尔类型数字枚举类型。角色的名字供委托获取数据使用,每一个角色的名字都可以在委托的作用域内访问,并且指向当前 ListElement 中对应的值。另外,角色还可以包含列表数据,例如包含多个 ListElement

2.2、 XML文档模型

  XmlListModel 可以从 XML 数据创建只读的模型,既可以作为视图的数据源,也可以为 Repeater 等能够和模型数据进行交互的类型提供数据。要使用 XmlListModel,需要使用 import QtQuick.XmlListModel 语句引入相关的模块。

  XmlListModelsource 属性 指定 XmlListModel 使用的 XML 文档的位置,可以是一个 网络地址,也可以是 本地地址XmlListModelxml 属性 保存用于当前 Model的 XML 字符串,应当是 UTF-8 编码的。当同时指定 xml 属性和 source 属性时,xml 属性优先生效。

  XmlListModelprogress 属性 表示 XML 文档的下载进度,取值范围从 0 到 1,取值为 1表示下载完成。如果是本地 XML,progress 属性会在读取数据时立即变成 1。当下载完成后,XmlListModel 开始加载数据,此时可以通过 status 获知数据加载状态。

由于 XmlListModel 的数据是异步加载的,因此当程序启动、数据尚未加载的时候,界面会显示一段时间的空白。可以使用 XmlListModelstatus 属性 获取模型加载的状态。该属性可取的值如下:

  • XmlListModel.Null:模型中没有 XML 数据。
  • XmlListModel.Ready:XML 数据已经加载到模型。
  • XmlListModel.Loading:模型正在读取和加载 XML 数据。
  • XmlListModel.Error:加载数据出错,详细出错信息可以使用 errorString() 获得。

  XmlListModelcount 表示 当前 Model 内数据的个数。我们可以通过 get() 方法可以 得到指定索引位置的数据对象,然后可以根据属性名的方式来访问数据。

   XmlListModelquery 属性,它是一个 XPath 表达式,表示从该模型的 XmlListModelRole 对象创建模型项的基本路径的字符串。

  XmlListModelRole 类型用来 定义模型中每一个数据项的角色,它包含 3 个属性:name 属性用于 指定角色的名称,可以在委托中直接访问该名称;elementName 属性用于 指定 XML 元素的名称或 XML 元素的路径attributeName 属性用于 指定 XML 元素的属性

  在 XmlListModel 使用 XPath 表达式来提取 XML 文档中的数据。XPath 使用 路径表达式 来选取 XML 文档中的 节点 或者 节点集。在 XPath 中,有 7 种类型的节点:元素属性文本命名空间处理指令注释 以及 文档节点(或称为 根节点)。XML 文档是被作为 节点树 来对待的。树的根 被称为 文档节点 或者 根节点

  在 XPath 语言中,节点是沿着路径选择的。我们常用的 路径表达式 如下:

  • 标签名:选取此节点的所有子节点。
  • /:从根节点选取。
  • //:选取文档中与标签名匹配的所有节点,而不考虑这些节点的位置。
  • .:选取当前节点。
  • ..:选取当前节点的父节点。
  • @:选取属性。

XmlListModel 是只读模型,当原始XML数据发生改变时,可以通过调用 reload() 刷新模型数据。

2.3、表格模型

  TableModel 从 Qt 5.14 引入,在现在的版本中依然需要通过实验模块 Qt.labs.qmlmodels 来提供。在该类型出现以前,要想创建具有多个列的模型,需要通过 Python 中自定义 QAbstractTableModel 子类来实现。而 TableModel 的目的就是实现一个简单的模型,可以将 JavaScript/JSON对象存储为能与 TableView 一起使用的表格模型的数据,而不再需要子类化 QAbstractTableModel

  模型中的每个列 都是通过声明 TableModelColumn 实例来指定的,其中每个实例的顺序决定了其列索引。使用 rows 属性或通过调用 appendRow()设置模型的初始行数据TableModel 设计用于 JavaScript/JSON 数据,其中每一行都是一些简单的 键值对

  如果我们要访问特定行,可以使用 getRow() 方法,也可以通过 rows 属性直接访问模型的 JavaScript 数据,但不能以这种方式修改模型数据。要添加新行,可以使用 appendRow() 方法和 insertRow() 方法;要 修改现有行,可以使用 setRow() 方法;要 移动行 可以使用 moveRow() 方法、要 删除行 可以使用 removeRow() 方法;要 清除数据 可以使用 clear() 等方法。

object getRow(int rowIndex)                                                     // 获取指定行的数据      
QModelIndex index(int row, int column)                                          // 获取指定索引的模型索引
setRow(int rowIndex, object row)                                                // 设置指定行的数据
appendRow(object row)                                                           // 追加一行数据
insertRow(int rowIndex, object row)                                             // 在指定索引插入一行数据
moveRow(int fromRowIndex, int toRowIndex, int rows)                             // 移动指定范围内的行
removeRow(int rowIndex, int rows)                                               // 删除指定范围内的行
bool setData(QModelIndex index, variant value, string role)                     // 设置指定索引的数据
clear()                                                                         // 清空所有行

三、视图类型

  视图作为数据项集合的容器,不仅提供了强大的功能,还可以进行定制来满足样式或行为上的特殊需求。视图类型主要是 Flickable 的几个子类型,包括 列表视图ListView)、网格视图GridView)、表格视图TableView) 及其子类型 树视图TreeView)。作为 Flickable 的子类型,这几个视图在数据量超出窗口范围时,可以进行拖动以显示更多的数据。

3.1、列表视图

  ListView 用来显示一个条目列表,条目对应的数据来自于 Model,而每个条目的外观则由 Delegate 决定。要使用 ListView,必须为其指定一个 Model、一个 Delegate。其中,Model 可以是 QML 内建类型,如 ListModelXmlListModel,也可以是在 Python 中实现的 QAbstractItemModelQAbstractListModel 的派生类。

3.1.1、 ListView的简单使用

  我们新建一个 template.py 文件。

import sysfrom PySide6.QtWidgets import QApplication
from PySide6.QtQml import QQmlApplicationEngineif __name__ == "__main__":app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例engine = QQmlApplicationEngine()                                            # 2.创建QML引擎对象engine.load("template.qml")                                                 # 3.加载QML文件sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

  我们新建一个 template.qml 文件。

import QtQuick.Window// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色// 列表视图ListView {id: listViewIdanchors.fill: parent// 模型model: ["木之本樱", "御坂美琴", "夏娜"]// 委托delegate: Rectangle {width: listViewId.widthheight: 50color: "#99CCFF"border.color: "#333333"border.width: 1radius: 10Text {anchors.centerIn: parentfont.pointSize: 14font.bold: truecolor: "#FF6666"// 如果模型中没有包含任何命名的角色,那么可以通过modelData角色来提供数据// 对于只有一个角色的模型,也可以使用modelDatatext: modelData}}}
}

3.1.2、页眉与页脚

  我们可以通过为 ListViewheader 属性设置 页眉页眉 将放在 ListView 的最开始,所有的 Item 之前。当你使用方向键浏览 Item 或者用鼠标在 ListView 内拖动时,页眉随着拖动可能会变得不可见。ListViewheaderItem 属性保存了本 ListView 使用的、由 header 组件创建出来的 Item

  我们还可以通过 footer 属性允许指定 ListView 的页脚,footerItem 保存了 footer 组件创建出来的 Item 对象,这个 Item 会被添加到 ListView 的末尾,在所有可见的 Item 之后。

  修改 template.qml 文件的内容。

import QtQuick.Window// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色// 列表视图ListView {id: listViewIdanchors.fill: parentmodel: listModelId                                                      // 模型delegate: delegateId                                                    // 委托header: headerId                                                        // 页眉footer: footerId                                                        // 页脚}// 模型ListModel {id: listModelIdListElement {name: "木之本樱"; age: 10}ListElement {name: "御坂美琴"; age: 14}ListElement {name: "夏娜"; age: 15}}// 委托Component {id: delegateIdRectangle {width: listViewId.widthheight: 50color: "#99CCFF"border.color: "#333333"border.width: 1radius: 10Text {anchors.centerIn: parentfont.pointSize: 14font.bold: truecolor: "#FF6666"text: "我是" + name + ",我今年" + age + "岁。"}}}// 页眉Component {id: headerIdRectangle {width: listViewId.widthheight: 50color: "#0066CC"border.color: "#333333"border.width: 1radius: 10Text {anchors.centerIn: parentfont.pointSize: 14font.bold: truecolor: "#FF6666"text: "个人信息"}}}// 页脚Component {id: footerIdRectangle {width: listViewId.widthheight: 50color: "#0066CC"border.color: "#333333"border.width: 1radius: 10Text {anchors.centerIn: parentfont.pointSize: 16font.bold: truecolor: "#FF6666"text: "很高兴遇到你,今后请多多指教。"}}}
}

3.1.3、高亮显示与键盘导航

  我们可以通过 highlight 属性 保存要用作高亮显示的组件。高亮项的默认 z 属性为 0 。如果我们还想使用 键盘控制视图,需要设置 focus 属性为 true,以便 ListView 能够接收键盘事件。如果不想视图具有交互性,可以设置 interactive 属性为 false,这样视图将无法通过鼠标或键盘进行操作。我们还可以设置 keyNavigationWraps 属性为 true,这样当使用键盘导航时,如果到达列表的最后一个数据项,会自动跳转到列表的第一个数据项。

  修改 template.qml 文件的内容。

import QtQuick.Window// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色// 列表视图ListView {id: listViewIdanchors.fill: parentfocus: true                                                             // 列表视图获取焦点keyNavigationWraps: true                                                // 键盘导航是否循环// 模型model: ListModel {ListElement {name: "木之本樱"; age: 10}ListElement {name: "御坂美琴"; age: 14}ListElement {name: "夏娜"; age: 15}}// 委托delegate: Rectangle {width: listViewId.widthheight: 50color: "#99CCFF"border.color: "#333333"border.width: 1radius: 10Text {anchors.centerIn: parentfont.pointSize: 14font.bold: truecolor: "#FF6666"text: "我是" + name + ",我今年" + age + "岁。"}MouseArea {anchors.fill: parentonClicked: {listViewId.currentIndex = index}}}// 页眉header: Rectangle{width: listViewId.widthheight: 50color: "#0066CC"border.color: "#333333"border.width: 1radius: 10Text {anchors.centerIn: parentfont.pointSize: 14font.bold: truecolor: "#FF6666"text: "个人信息"}}// 页脚footer: Rectangle {width: listViewId.widthheight: 50color: "#0066CC"border.color: "#333333"border.width: 1radius: 10Text {anchors.centerIn: parentfont.pointSize: 16font.bold: truecolor: "#FF6666"text: "很高兴遇到你,今后请多多指教。"}}// 高亮highlight: Rectangle {width: listViewId.widthheight: 50z: 3color: "#0000FF"opacity: 0.6border.color: "#333333"border.width: 1radius: 10}}
}

ListViewkeyNavigationEnabled 属性可以 设置是否启用键盘导航,该属性值默认与 interactive 属性进行了绑定,如果明确指定了该属性的值,那么会解除绑定。

3.1.4、数据分组

  ListView 支持数据的分组显示,相关数据可以出现在一个分组中。每个分组还可以使用委托定义其显示的样式。ListView 定义了一个 section 附加属性,用于将相关数据显示在一个分组中,section 是一个属性组,其属性如下:

  • section.property定义分组的依据,也就是根据数据模型的哪一个 角色 进行分组。
  • section.criteria定义如何创建分组名字,可选值如下:
    • ViewSection.FullString:默认,依照 section.property 定义的 创建分组。
    • ViewSection.FirstCharacter:依照 section.property 值的 首字母 创建分组。
  • section.delegate:与 ListView 的委托类似,用于 提供每一个分组的委托组件,其 z 属性值为 2
  • section.labelPositioning定义当前或下一个分组标签的位置,可选值如下:
    • ViewSection.InlineLabels:默认,分组标签出现在 数据项之间
    • ViewSection.CurrentLabelAtStart:在列表滚动时,当前分组的标签 始终出现在列表视图开始的位置
    • ViewSection.NextLabelAtEnd:在列表滚动时,下一分组的标签 始终出现在列表视图末尾。该选项要求系统预先找到下一个分组的位置,因此可能会有一定的性能问题。

  修改 template.qml 文件的内容。

import QtQuick.Window// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色// 列表视图ListView {id: listViewIdanchors.fill: parentfocus: true                                                             // 列表视图获取焦点keyNavigationWraps: true                                                // 键盘导航是否循环// 模型model: ListModel {ListElement {name: "木之本樱"; age: 10; department: "魔法部"}ListElement {name: "夏娜"; age: 15; department: "魔法部"}ListElement {name: "御坂美琴"; age: 14; department: "科学部"}}// 委托delegate: Rectangle {width: listViewId.widthheight: 50color: "#99CCFF"border.color: "#333333"border.width: 1radius: 10Text {anchors.centerIn: parentfont.pointSize: 14font.bold: truecolor: "#FF6666"text: "我是" + name + ",我今年" + age + "岁,我是" + department + "的。"}MouseArea {anchors.fill: parentonClicked: {listViewId.currentIndex = index}}}// 分组section {property: "department"                                              // 分组的属性criteria: ViewSection.FullString                                    // 分组的标准// 分组的委托组件delegate: Rectangle {width: listViewId.widthheight: 50color: "#CCCCFF"border.color: "#333333"border.width: 1radius: 10Text {anchors.centerIn: parentfont.pointSize: 24font.bold: truecolor: "#FF6666"text: section                                               // 获取分组属性的名称}}}// 高亮highlight: Rectangle {width: listViewId.widthheight: 50z: 3color: "#0000FF"opacity: 0.6border.color: "#333333"border.width: 1radius: 10}}
}

ListView 中的每一个数据项都有 ListView.sectionListView.previousSectionListView.nextSection 等附加属性。

3.1.5、动态修改模型

  我们可以使用 ListModelappend() 方法 追加数据insert() 方法 插入数据move() 方法 移动数据remove() 方法 移除数据get() 方法 获取数据set() 方法 设置数据clear() 方法 清空数据 等。

  修改 template.qml 文件的内容。

import QtQuick.Window
import QtQuick.Controls// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色// 列表视图ListView {id: listViewIdanchors.fill: parentfocus: true                                                             // 列表视图获取焦点keyNavigationWraps: true                                                // 键盘导航是否循环// 模型model: ListModel {ListElement {name: "木之本樱"; age: 10}ListElement {name: "御坂美琴"; age: 14}ListElement {name: "夏娜"; age: 15}}// 委托delegate: Rectangle {width: listViewId.widthheight: 50color: "#99CCFF"border.color: "#333333"border.width: 1radius: 10Text {anchors.centerIn: parentfont.pointSize: 14font.bold: truecolor: "#FF6666"text: "我是" + name + ",我今年" + age + "岁。"}MouseArea {anchors.fill: parentonClicked: {listViewId.currentIndex = index}}}// 页眉header: Rectangle{width: listViewId.widthheight: 50color: "#0066CC"border.color: "#333333"border.width: 1radius: 10Text {anchors.centerIn: parentfont.pointSize: 14font.bold: truecolor: "#FF6666"text: "个人信息"}}// 高亮highlight: Rectangle {width: listViewId.widthheight: 50z: 3color: "#0000FF"opacity: 0.6border.color: "#333333"border.width: 1radius: 10}}// 页脚Component {id: listViewFooterIdRectangle {width: listViewId.widthheight: 50color: "#0066CC"border.color: "#333333"border.width: 1radius: 10Row {anchors.centerIn: parentspacing: 10Button {width: 100font.pointSize: 16font.bold: truetext: "添加"onClicked: {listViewId.model.append({"name": "白钰袖", "age": 16})}}Button {width: 100font.pointSize: 16font.bold: truetext: "插入"onClicked: {listViewId.model.insert(listViewId.currentIndex + 1, {"name": "纳西妲", "age": 500})}}Button {width: 100font.pointSize: 16font.bold: truetext: "删除"onClicked: {if (listViewId.currentIndex >= 0){listViewId.model.remove(listViewId.currentIndex)}}}Button {width: 100font.pointSize: 16font.bold: truetext: "清空"onClicked: {listViewId.model.clear()}}}}}// 当组件完成加载时,将列表视图的footer设置为listViewFooterId// 否则可能会报如下错误(不影响使用):// QQmlComponent: Cannot create new component instance before completing the previous// "There are still \"-1\" items in the process of being created at engine destruction."Component.onCompleted: {listViewId.footer = listViewFooterId}
}

3.1.6、加载XML文件

  我们用 XmlListModelsource 属性 指定 XmlListModel 使用的 XML 文档的位置。然后,我们使用 query 属性用于从 XML 中提取数据。

  XmlListModelRole 类型用来 定义模型中每一个数据项的角色,它包含 3 个属性:name 属性用于 指定角色的名称,可以在委托中直接访问该名称;elementName 属性用于 指定 XML 元素的名称或 XML 元素的路径attributeName 属性用于 指定 XML 元素的属性

  我们新建一个 template.xml 文件。

<?xml version="1.0" encoding="utf-8"?>
<persons><person><name>木之本樱</name><age>10</age></person><person><name>御坂美琴</name><age>14</age></person><person><name>夏娜</name><age>15</age></person>
</persons>

  修改 template.qml 文件的内容。

import QtQuick.Window
import QtQml.XmlListModel// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色// 列表视图ListView {id: listViewIdanchors.fill: parentmodel: xmlListModelId                                                   // 模型delegate: delegateId                                                    // 委托}// 定义一个XmlListModel模型,用于从XML文件中提取数据XmlListModel {id: xmlListModelIdsource: "template.xml"                                                  // XML文件的路径query: "/persons/person"                                                // XPath查询,用于从XML中提取数据// 定义模型中每一个数据项的角色XmlListModelRole {name: "name"                                                        // 角色名称,用于在委托中访问数据elementName: "name"                                                 // 元素名称,用于从XML中提取数据}XmlListModelRole {name: "age"elementName: "age"}}// 委托Component {id: delegateIdRectangle {width: parent.widthheight: 50color: "#99CCFF"border.color: "#333333"border.width: 1radius: 10Text {anchors.centerIn: parentfont.pointSize: 14font.bold: truecolor: "#FF6666"text: "我是" + name + ",我今年" + age + "岁。"}}}
}

3.2、网格视图

  网格视图 GridView 在一块可用的空间中以方格形式显示数据列表。GridViewListView 非常类似,实质的区别在于,GridView 需要 在一个二维表格视图中使用委托,而不是线性列表中。相对于 ListViewGridView 使用 cellWidthcellHeight 属性 控制单元格的大小,每一个委托所渲染的数据项都会出现在这样一个单元格的左上角。

  GridView 有一个 flow 属性,用于 指定 Item 的流模式,可以取值如下:

  • GridView.FlowLeftToRight:默认值,表格从左向右开始填充,按照从上向下的顺序添加行。此时,表格是 纵向滚动 的。
  • GridView.FlowTopToBottom表格从上向下开始填充,按照从左向右的顺序添加列。此时,表格是 横向滚动 的。

  如果我们还想使用 键盘控制视图,需要设置 focus 属性为 true,以便 GridView 能够接收键盘事件。当 keyNavigationWraps 属性为 true 时,可以使用左右按键循环浏览 GridView 内的 Item,连续按右键抵达列表末尾,再按右键则跳转到列表开始;左键逻辑与右键相反;上下键则只在某列内循环。keyNavigationWraps 的默认值为 false,按左右键,焦点到达列表的头、尾时不进行跳转,按上下键到达一列的头尾时也不跳转。

  修改 template.qml 文件的内容。

import QtQuick.Window
import QtQuick.Controls// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色GridView {id: gridViewIdanchors.fill: parentflow: Qt.FlowLeftToRight                                                // 列表项的流动方向focus: true                                                             // 列表视图获取焦点keyNavigationWraps: true                                                // 键盘导航是否循环// 整数作为模型。在这种情况下,模型不包含任何数据角色,表示创建了一个包含n个数据项的model: 10// 委托delegate: Rectangle {width: 100height: 100color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)border.color: "#333333"border.width: 1radius: 10Text {anchors.centerIn: parentfont.pointSize: 32font.bold: truecolor: "#FF6666"text: index}MouseArea {anchors.fill: parentonClicked: {gridViewId.currentIndex = index}}}highlight: Rectangle {width: gridViewId.delegate.widthheight: gridViewId.delegate.heightz: 3color: "#0000FF"opacity: 0.6border.color: "#333333"border.width: 1radius: 10}}
}

3.3、表格视图

  TableView 就是 Qt Quick 为表格式呈现数据提供的组件。TableViewListView 类似,相比之下多了滚动条、挑选、可调整尺寸的表头等特性。它的数据也通过 Model 来提供,你可以使用 ListModelXmlListModel,也可以使用 Python 中从 QAbstractItemModelQAbstractTableModel 等继承而实现的 Model。

  修改 template.qml 文件的内容。

import QtQuick.Window
import QtQuick.Controls
import Qt.labs.qmlmodels// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色// 添加水平表头HorizontalHeaderView {id: horizontalHeaderViewIdanchors.top: parent.topanchors.left: tableViewId.leftsyncView: tableViewIdmodel: ["姓名", "年龄"]}// 添加垂直表头VerticalHeaderView {id: verticalHeaderViewIdanchors.top: tableViewId.topanchors.left: parent.leftsyncView: tableViewId}// 表格视图TableView {id: tableViewIdanchors.top: horizontalHeaderViewId.bottomanchors.bottom: parent.bottomanchors.left: verticalHeaderViewId.rightanchors.right: parent.rightrowSpacing: 2columnSpacing: 2// 模型model: TableModel {TableModelColumn {display: "name"}TableModelColumn {display: "age"}rows: [{name: "木之本樱", age: 10},{name: "御坂美琴", age: 14},{name: "夏娜", age: 15}]}// 委托delegate: DelegateChooser {DelegateChoice {column: 1delegate: SpinBox {editable: truevalue: model.displayRectangle {z: -1anchors.fill: parentcolor: "#99CCFF"}onValueModified: {model.display = value}}}// 默认委托DelegateChoice {delegate: TextInput {font.pointSize: 24font.family: "楷体"color: "#FF6666"text: model.displayRectangle {z: -1anchors.fill: parentcolor: "#99CCFF"}onEditingFinished: {model.display = text}}}}}
}

3.4、路径视图

  PathView 沿着特定的路径显示 Model 内的数据。Model 可以是 QML 内建的 ListModelXmlListModel,也可以是在 Python 中实现的 QAbstractListModel 的派生类。要使用 PathView,至少需要设置 modeldelegatepath 三个属性。path 属性是 PathView 的专有特性,它指定 PathView 用来放置 Item 的路径。

  Path 的属性 startXstartY 用于 描述路径起点pathElements 属性是个 列表,是默认属性,它 保存组成路径的多个路径元素,常见的路径元素有 PathLinePathQuadPathCubicPathArcPathCurvePathSvg。路径上最后一个路径元素的终点就是整个路径的终点,如果终点与起点重合,那么 Pathclosed 属性就为 true

  路径元素除 PathSvg 外,都有 xy 属性,以绝对坐标的形式指定本段路径的终点,而起点呢,就是前一个路径段的终点。第一个路径段的起点,就是 PathstartXstartY 所描述的整个路径的起点。另外还有 relativeXrelativeY 两个属性,以相对于起点的相对坐标的形式来指定终点。你还可以混合使用绝对坐标与相对坐标,比如使用 xrelativeY 来决定路径段的终点。

  PathLine 是最简单的路径元素,在 Path 的起点或者上一段路径的终点,与本元素定义的终点之间绘制 一条直线

  PathQuad 元素定义一条 二次方贝塞尔曲线 作为路径段。它的 起点上一个路径元素的终点(或者路径的起点),终点xyrelativeXrelativeY 定义,控制点controlXcontrolYrelativeControlXrelativeControlY 来定义。

  PathCubic 定义 一条三次方贝塞尔曲线,它有 两个控制点

  PathArc 路径元素定义 椭圆上的一条弧线,它的 起点上一个路径元素的终点(或者路径的起点),终点xyrelativeXrelativeY 定义。椭圆的 两个半轴 分别由 radiusXradiusY 定义。direction 属性 定义绘制弧线的方向,默认取值 PathArc.Clockwise顺时针绘制弧线;要想 逆时针绘制弧线,需要设置 direction 的值设置为 PathArc.Counterclockwise。当我们指定了弧线的起点、终点、半径、绘制方向后,还是可能存在两条弧线都能满足给定的参数,此时 useLargeArc 属性设置为 false(默认值),取 较小的弧线,设置为 true 后,取 较大的弧线

  PathCurve 定义一条 Catmull-Rom 曲线。

  修改 template.qml 文件的内容。

import QtQuick.Window
import QtQml.XmlListModel// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {id: windowIdwidth: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色PathView {anchors.fill: parentfocus: true                                                             // 获取焦点model: 10delegate: delegateIdpath: pathIdKeys.onLeftPressed: {decrementCurrentIndex();}Keys.onRightPressed: {incrementCurrentIndex();}}Path {id: pathId// 起始点startX: windowId.width / 2startY: windowId.height - 50// 路径属性PathAttribute {name: "scale"value: 1}// 三次方贝塞尔曲线PathCubic {x: 50y: windowId.height / 2control1X: windowId.width / 2 - windowId.width / 8control1Y: windowId.heightcontrol2X: 0control2Y: windowId.height / 2 + windowId.height / 8}PathAttribute {name: "scale"value: 0.5}PathCubic {x: windowId.width / 2y: 50control1X: 0control1Y: windowId.height / 2 - windowId.height / 8control2X: windowId.width / 2 - windowId.width / 8control2Y: 0}PathAttribute {name: "scale"value: 0.3}PathCubic {x: windowId.width - 50y: windowId.height / 2control1X: windowId.width / 2 + windowId.width / 8control1Y: 0control2X: windowId.widthcontrol2Y: windowId.height / 2 - windowId.height / 8}PathAttribute {name: "scale"value: 0.5}PathCubic {x: windowId.width / 2y: windowId.height - 50control1X: windowId.widthcontrol1Y: windowId.height / 2 + windowId.height / 8control2X: windowId.width / 2 + windowId.width / 8control2Y: windowId.height}PathAttribute {name: "scale"value: 1}}Component {id: delegateIdRectangle {width: 64height: 64color: Qt.rgba(Math.random(), Math.random() ,Math.random(), 1)opacity: PathView.isCurrentItem ? 1 : 0.3border.width: 2border.color: "#333333"radius: 10scale: PathView.scale}}
}
http://www.hskmm.com/?act=detail&tid=26991

相关文章:

  • [KaibaMath]1004 关于f(x,y) = [x]+[y] - [x+y]的平移稳定性
  • Mac OS 问题与技巧
  • 《算法设计与分析》第一章学习记录
  • nestjs 和 nextjs 分别是做啥的
  • 定时收集TCM数据并生成Excel报表并上传
  • 2025.10 国庆集训模拟赛总结
  • 详细介绍:https和http有什么区别-http各个版本有什么区别
  • CF2150F Cycle Closing
  • Easysearch 字段隐身之谜:source_reuse 与 ignore_above 的陷阱解析
  • QOJ856 Cactus 广义串并联图
  • CF2152 订题
  • 静态路由
  • Kruskal 重构树学习笔记
  • GJ Round 2025赛季
  • ASP.NET Core 中读取 UserAgent 的正确姿势
  • vLLM推理加速指南:7个技巧让QPS提升30-60%
  • Git学习记录(二):代码patch
  • 2025年10月化妆品代工厂最新推荐排行榜:聚焦 OEM/ODM/ 网红爆款需求,精选优质企业助品牌高效合作
  • Exchange安全漏洞分析:ProxyOracle攻击链详解
  • 牛客 周赛111 20251008
  • 本人于2025上半学期编码需要遵守的规范(参考腾讯内部编码规范)
  • 10.8 CSP-JS 模拟赛 T5. xor
  • 防抖 解释
  • 从零到一搭建:vue3+vite7+antfu+stylelint+githooks,全流程配置,附带源码,集成css变量使用,下载即用
  • bat批处理脚本文件-获取当前时间的几种方法
  • 二分图最大权完美匹配 KM算法
  • 2025.10.8模拟赛
  • Python 中的排序排序函数及区别
  • RL | 速读 IJCAI 2025 的强化学习论文
  • IDM弹窗解决 - -一叶知秋