上一章我们掌握了ListView和基础模型的用法,这一章将解锁Qt Quick中更强大的视图组件:GridView网格视图、TableView表格视图和TreeView树形视图,同时学会用JavaScript或C++打造自定义模型,实现更灵活的数据管理。掌握这些技能,复杂高效的结构化数据UI就能轻松构建!
GridView像一个规整的格子架,特别适合展示图片库、图标集这类需要整齐排列的内容。它继承自Flickable,天生支持滚动和轻拂操作,浏览体验顺畅。
核心属性需重点掌握:
以下是一个水果网格示例,直观展示用法:
import QtQuick 2.15
import QtQuick.Controls 2.15
GridView {
width: 400; height: 300
cellWidth: 100; cellHeight: 100
model: ListModel {
ListElement { name: "苹果"; color: "red" }
ListElement { name: "香蕉"; color: "yellow" }
ListElement { name: "葡萄"; color: "purple" }
// 可继续添加更多数据
}
delegate: Rectangle {
width: GridView.view.cellWidth - 5
height: GridView.view.cellHeight - 5
color: model.color
border.color: "gray"
radius: 8
Text {
anchors.centerIn: parent
text: model.name
font.bold: true
}
}
}
TableView专门用于展示二维表格数据,比如报表、统计数据等。它需要配合TableModel或自定义模型使用,还能精细控制行、列标题和单元格的可视化样式。
几个关键概念要理清:
display、用于编辑的edit,方便不同场景调用数据;TableView.selected就能轻松管理单元格的选中状态。很多人会混淆TableView与其他视图,这里帮你区分:
TreeView是展示层次化数据的神器,比如文件系统目录、公司组织架构这类有父子层级的数据。但它对模型有特殊要求,必须实现几个核心接口:
rowCount(parent):返回指定父节点下的子节点数量;index(row, column, parent):创建子节点的索引;parent(index):返回指定索引节点的父索引;hasChildren(parent):判断指定父节点是否包含子节点;data(index, role):返回指定索引和角色对应的数据。TreeView的架构清晰:TreeView负责可视化展示,TreeModel提供层次化数据,Node Delegate定义每个节点的外观,三者配合就能完美呈现树形结构。
当ListModel、XmlListModel等内置模型满足不了需求时,就需要创建自定义模型,这里分JavaScript和C++两种实现方式:
通过继承QtObject并实现get、count等必要接口即可,简单易上手,适合快速原型开发。
以下是一个可管理数据数组的JS模型示例,还能通知视图数据变化:
// MyJsModel.qml
import QtQuick 2.15
QtObject {
id: root
property var dataArray: []
function append(item) {
dataArray.push(item);
// 发送信号通知视图更新
root.dataChanged();
}
function get(index) {
return dataArray[index];
}
function count() {
return dataArray.length;
}
signal dataChanged()
}
使用时直接在ListView中引用并初始化数据:
ListView {
model: MyJsModel {
Component.onCompleted: {
for(var i=0; i<10; i++) append({value: i*10})
}
}
delegate: Text { text: modelData.value }
}
如果追求高性能和强大功能,建议用C++实现,通常继承QAbstractItemModel或其子类(如QAbstractListModel)。
以下是一个简单的列表模型示例:
// mylistmodel.h
#include <QAbstractListModel>
#include <QVector>
class MyListModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Roles { ValueRole = Qt::UserRole + 1 };
explicit MyListModel(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;
void addValue(int value);
private:
QVector<int> m_data;
};
// mylistmodel.cpp
int MyListModel::rowCount(const QModelIndex &parent) const {
// 父节点有效则为子节点,返回0;否则返回数据总数
return parent.isValid() ? 0 : m_data.size();
}
QVariant MyListModel::data(const QModelIndex &index, int role) const {
if (!index.isValid() || index.row() >= m_data.size())
return QVariant();
if (role == ValueRole)
return m_data.at(index.row());
return QVariant();
}
QHash<int, QByteArray> MyListModel::roleNames() const {
// 映射角色名,方便QML调用
return { {ValueRole, "value"} };
}
void MyListModel::addValue(int value) {
// 通知视图即将插入行,确保UI同步
beginInsertRows(QModelIndex(), m_data.size(), m_data.size());
m_data.append(value);
endInsertRows();
}
要在QML中使用该模型,需先在C++主函数中注册:
qmlRegisterType<MyListModel>("CustomModels", 1, 0, "MyListModel");
之后在QML中导入CustomModels模块即可使用。
cacheBuffer属性,预加载部分项目,提升滚动流畅度;数据流转逻辑清晰:数据源(数据库、文件、网络等)→ 模型(ListModel、TableModel、自定义模型)→ 视图(ListView、GridView、TableView),确保数据与UI高效联动。