模型和视图
# 09.模型和视图
- 9.1 模型/视图架构
- 9.1.1 模型/视图介绍
- 9.1.2 模型(Model)
- 9.1.3 视图(View)
- 9.1.4 委托(Delegate)
- 9.2 数据模型
- 9.2.1 整数作为模型
- 9.2.2 ListModel
- 9.2.3 WorkerScript
- 9.2.4 ObjectModel
- 9.2.5 DelegateModel
- 9.2.6 Package
- 9.2.7 XmlListModel
- 9.2.8 LocalStorage
- 9.3 视图类型
- 9.3.1 ListView
- 9.3.2 GridView
- 9.3.3 视图过渡
- 9.3.4 PathView
- 9.3.5 TableView
- 9.4 C++扩展QML模型
- 9.4.1 C++扩展介绍
- 9.4.2 核心步骤
- 9.4.3 定义C++模型
- 9.4.4 注册C++模型
- 9.4.5 在QML中使用C++模型
- 9.4.6 总结一下
# 9.1 模型/视图架构
# 9.1.1 模型/视图介绍
在 QML 中,模型/视图(Model/View)架构是一种用于管理和显示数据的强大模式。
它将数据(模型)与用户界面(视图)分离,使得数据的管理和显示更加灵活和高效。
# 9.1.2 模型(Model)
模型是数据的来源,负责存储和管理数据。
在 QML 中,模型可以是 ListModel、XmlListModel、JsonListModel 或自定义的 C++ 模型。
# 9.1.3 视图(View)
视图是数据的展示方式,负责将模型中的数据渲染到用户界面。
在 QML 中,视图可以是 ListView、GridView、TableView 等。
# 9.1.4 委托(Delegate)
委托定义了如何渲染模型中的每一项数据。
在 QML 中,委托通常是一个 Component,用于定义每一项的 UI 和行为。
# 9.2 数据模型
# 9.2.1 整数作为模型
- 简单易用:直接使用整数作为模型,无需定义复杂的数据结构。
- 动态生成:可以根据需要动态生成数字序列。
- 与视图组件结合:可以与
ListView、GridView、Repeater等视图组件结合使用。
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
visible: true
width: 800
height: 600
title: "Dynamic Integer Model"
property int itemCount: 5 // 动态模型大小
Column {
anchors.centerIn: parent
spacing: 10
// 动态生成整数模型
Repeater {
model: itemCount // 使用属性动态设置模型大小
delegate: Rectangle {
width: 100
height: 50
color: "lightblue"
border.color: "black"
Text {
text: "Item " + (index + 1) // 使用索引
anchors.centerIn: parent
}
}
}
// 增加模型大小
Button {
text: "Add Item"
onClicked: itemCount++
}
// 减少模型大小
Button {
text: "Remove Item"
onClicked: if (itemCount > 0) itemCount--
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 9.2.2 ListModel
ListModel 是一个简单的列表模型,ListView 是一个用于显示列表数据的视图。案例:ListModel 和 ListView
// 定义模型
ListModel {
id: fruitModel
ListElement { name: "Apple"; color: "red" }
ListElement { name: "Banana"; color: "yellow" }
ListElement { name: "Grape"; color: "purple" }
}
2
3
4
5
6
7
# 9.2.3 WorkerScript
# 9.2.4 ObjectModel
ObjectModel 是一个用于存储 QML 对象的模型。
ObjectModel {
id: objectModel
Rectangle { width: 100; height: 100; color: "red" }
Rectangle { width: 100; height: 100; color: "green" }
Rectangle { width: 100; height: 100; color: "blue" }
}
2
3
4
5
6
# 9.2.5 DelegateModel
# 9.2.6 Package
# 9.2.7 XmlListModel
XmlListModel 是一个用于解析 XML 数据的模型。案例:XmlListModel 和 ListView
// 定义 XML 模型
XmlListModel {
id: xmlModel
source: "data.xml" // XML 文件路径
query: "/items/item" // XPath 查询
XmlRole { name: "name"; query: "name/string()" }
XmlRole { name: "color"; query: "color/string()" }
}
2
3
4
5
6
7
8
# 9.2.8 LocalStorage
# 9.2.9 C++扩展QML模型
如果需要更复杂的数据管理,可以自定义 C++ 模型并集成到 QML 中。
- C++ 模型类:
#include <QAbstractListModel>
#include <QStringList>
class MyModel : public QAbstractListModel {
Q_OBJECT
public:
enum Roles {
NameRole = Qt::UserRole + 1,
ColorRole
};
MyModel(QObject *parent = nullptr) : QAbstractListModel(parent) {
m_data << "Red" << "Green" << "Blue";
}
int rowCount(const QModelIndex &parent = QModelIndex()) const override {
return m_data.size();
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
if (!index.isValid() || index.row() >= m_data.size())
return QVariant();
switch (role) {
case NameRole: return m_data.at(index.row());
case ColorRole: return m_data.at(index.row()).toLower();
default: return QVariant();
}
}
QHash<int, QByteArray> roleNames() const override {
QHash<int, QByteArray> roles;
roles[NameRole] = "name";
roles[ColorRole] = "color";
return roles;
}
private:
QStringList m_data;
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
- 在 QML 中使用:
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
visible: true
width: 800
height: 600
title: "Custom Model Example"
ListView {
anchors.fill: parent
model: MyModel {} // 使用自定义模型
delegate: Rectangle {
width: ListView.view.width
height: 50
color: model.color // 使用模型数据
Text {
text: model.name // 使用模型数据
anchors.centerIn: parent
font.pixelSize: 20
color: "white"
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 9.3 视图类型
# 9.3.1 ListView
# 9.3.2 GridView
GridView 是一个用于显示网格数据的视图。案例:GridView
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
visible: true
width: 800
height: 600
title: "GridView Example"
// 定义模型
ListModel {
id: colorModel
ListElement { color: "red" }
ListElement { color: "green" }
ListElement { color: "blue" }
ListElement { color: "yellow" }
ListElement { color: "purple" }
ListElement { color: "orange" }
}
// 定义视图
GridView {
anchors.fill: parent
model: colorModel // 绑定模型
delegate: colorDelegate // 绑定委托
cellWidth: 100
cellHeight: 100
}
// 定义委托
Component {
id: colorDelegate
Rectangle {
width: GridView.view.cellWidth
height: GridView.view.cellHeight
color: model.color // 使用模型数据
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 9.3.3 视图过渡
# 9.3.4 PathView
# 9.3.5 TableView
TableView 是一个用于显示表格数据的视图。案例:TableView
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
visible: true
width: 800
height: 600
title: "TableView Example"
// 定义模型
ListModel {
id: tableModel
ListElement { name: "Alice"; age: 25; gender: "Female" }
ListElement { name: "Bob"; age: 30; gender: "Male" }
ListElement { name: "Charlie"; age: 35; gender: "Male" }
}
// 定义视图
TableView {
anchors.fill: parent
model: tableModel // 绑定模型
delegate: tableDelegate // 绑定委托
columnWidthProvider: function(column) { return 200; } // 列宽
rowHeightProvider: function(row) { return 50; } // 行高
}
// 定义委托
Component {
id: tableDelegate
Rectangle {
implicitWidth: 200
implicitHeight: 50
border.color: "black"
Text {
text: {
switch (column) {
case 0: return model.name;
case 1: return model.age;
case 2: return model.gender;
default: return "";
}
}
anchors.centerIn: parent
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 9.4 C++扩展QML模型
# 9.4.1 C++扩展介绍
在 QML 中,可以通过 C++ 扩展自定义模型(Model),以便在 QML 中使用复杂的数据结构和逻辑。
C++ 扩展的模型通常继承自 QAbstractItemModel 或其子类(如 QAbstractListModel 或 QAbstractTableModel),并通过 Q_PROPERTY 和 Q_INVOKABLE 暴露接口给 QML。
# 9.4.2 核心步骤
- 定义 C++ 模型类:
- 继承
QAbstractListModel或QAbstractItemModel。 - 实现
rowCount、data和roleNames等虚函数。 - 使用
Q_PROPERTY和Q_INVOKABLE暴露属性和方法。
注册 C++ 模型到 QML: 使用
qmlRegisterType将 C++ 模型注册为 QML 类型。在 QML 中使用模型:实例化 C++ 模型,并与视图组件(如
ListView或GridView)绑定。
# 9.4.3 定义C++模型
1. 头文件(MyModel.h)
- 定义模型类,继承自
QAbstractListModel或QAbstractItemModel。 - 声明角色枚举、数据存储结构和虚函数(如
rowCount、data、roleNames)。 - 使用
Q_PROPERTY和Q_INVOKABLE暴露属性和方法。
#ifndef MYMODEL_H
#define MYMODEL_H
#include <QAbstractListModel>
#include <QStringList>
class MyModel : public QAbstractListModel {
Q_OBJECT
public:
// 角色枚举
enum Roles {
NameRole = Qt::UserRole + 1,
ColorRole
};
// 构造函数
explicit MyModel(QObject *parent = nullptr);
// 虚函数重写
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
// 自定义方法
Q_INVOKABLE void addItem(const QString &item);
Q_INVOKABLE void removeItem(int index);
private:
// 数据存储结构
QStringList m_data;
};
#endif // MYMODEL_H
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2. 实现文件(MyModel.cpp)
- 实现模型类的虚函数和自定义方法。初始化数据存储结构(如
QList或QStringList)。
#include "MyModel.h"
MyModel::MyModel(QObject *parent) : QAbstractListModel(parent) {
// 初始化数据
m_data << "Red" << "Green" << "Blue";
}
int MyModel::rowCount(const QModelIndex &parent) const {
Q_UNUSED(parent);
return m_data.size();
}
QVariant MyModel::data(const QModelIndex &index, int role) const {
if (!index.isValid() || index.row() >= m_data.size())
return QVariant();
switch (role) {
case NameRole: return m_data.at(index.row());
case ColorRole: return m_data.at(index.row()).toLower();
default: return QVariant();
}
}
QHash<int, QByteArray> MyModel::roleNames() const {
QHash<int, QByteArray> roles;
roles[NameRole] = "name";
roles[ColorRole] = "color";
return roles;
}
void MyModel::addItem(const QString &item) {
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_data.append(item);
endInsertRows();
}
void MyModel::removeItem(int index) {
if (index < 0 || index >= m_data.size())
return;
beginRemoveRows(QModelIndex(), index, index);
m_data.removeAt(index);
endRemoveRows();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 9.4.4 注册C++模型
在 main.cpp 中注册模型:
#include "MyModel.h" // 包含模型头文件
int main(int argc, char *argv[]) {
// 注册 C++ 模型到 QML
qmlRegisterType<MyModel>("com.example.mymodel", 1, 0, "MyModel");
return app.exec();
}
2
3
4
5
6
# 9.4.5 在QML中使用C++模型
import QtQuick
import QtQuick.Controls
import com.example.mymodel 1.0 // 导入 C++ 模型
Item {
// 实例化 C++ 模型
MyModel {
id: myModel
}
Column {
anchors.centerIn: parent
spacing: 10
// 显示模型数据
ListView {
width: 200
height: 300
model: myModel
delegate: Rectangle {
width: ListView.view.width
height: 50
color: model.color // 使用模型数据
Text {
text: model.name // 使用模型数据
anchors.centerIn: parent
font.pixelSize: 20
color: "white"
}
}
}
// 添加数据
Button {
text: "Add Item"
onClicked: myModel.addItem("New Color")
}
// 删除数据
Button {
text: "Remove Item"
onClicked: myModel.removeItem(0) // 删除第一个项
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 9.4.6 总结一下
| 步骤 | 描述 |
|---|---|
| 定义 C++ 模型类 | 继承 QAbstractListModel 并实现虚函数 |
| 注册模型到 QML | 使用 qmlRegisterType 注册模型 |
| 在 QML 中使用模型 | 实例化模型并与视图组件绑定 |
通过 C++ 扩展 QML 模型,可以实现复杂的数据管理和逻辑处理,同时保持 QML 的简洁性和灵活性。