QT:模型视图代理
Qt Model/View/Delegate(MVD)框架,它是 Qt 中用于实现数据显示和编辑的一种架构模式,主要由模型(Model)、视图(View)和委托(Delegate)三部分组成,以下是对其概念的详细介绍:
模型(Model)
角色:模型是 MVD 框架的核心部分,主要负责存储和管理数据。它提供了一种统一的接口,用于访问和操作各种类型的数据,如数组、列表、表格数据等,而不依赖于具体的数据存储方式。
功能:模型负责提供数据给视图进行显示,同时也处理来自视图的用户交互操作,如数据的插入、删除、修改等。它通过信号和槽机制与视图和委托进行通信,当数据发生变化时,模型会发出信号通知视图进行更新。
常用类:在 Qt 中,有多种模型类可供使用,如QStandardItemModel用于处理标准的列表和表格数据,QFileSystemModel用于处理文件系统相关的数据,QSqlTableModel用于与数据库表进行交互等。
视图(View)
角色:视图主要负责数据的可视化展示,它从模型中获取数据,并以特定的方式将数据呈现给用户,如以列表、表格、树状等形式显示。
功能:视图负责接收用户的输入操作,如鼠标点击、键盘输入等,并将这些操作转换为对模型的请求。例如,当用户在表格视图中点击某个单元格时,视图会将这个操作传递给模型,以便模型进行相应的处理。同时,视图会根据模型发出的信号来更新自身的显示,以反映数据的变化。
常用类:Qt 提供了多种视图类,如QListView用于显示列表数据,QTableView用于显示表格数据,QTreeView用于显示树状结构数据等。
委托(Delegate)
角色:委托用于控制数据在视图中的编辑和显示方式,它提供了一种自定义数据显示和编辑行为的机制。
功能:在视图中,当用户需要编辑数据时,委托会提供相应的编辑组件,如文本框、下拉列表等,让用户进行编辑。委托还可以对用户输入的数据进行验证和格式化处理,确保数据的合法性和一致性。
常用类:Qt 中常用的委托类是QStyledItemDelegate,它提供了基本的委托功能。用户可以通过继承QStyledItemDelegate类来实现自定义的委托,以满足特定的需求。
QAbstractItemModel
在 Qt 中,QAbstractItemModel 是所有模型类的抽象基类,它为数据模型提供了一个通用的接口,使得数据可以被不同的视图(如 QListView、QTableView、QTreeView 等)显示和操作。从 QAbstractItemModel 派生出了许多具体的模型类
QStandardItemModel
用途:QStandardItemModel 是一个通用的模型类,用于存储标准项(QStandardItem)的数据。它可以处理列表、表格和树状结构的数据,非常适合简单的数据管理和显示。
#include <QApplication>
#include <QStandardItemModel>
#include <QTableView>
#include <QDebug>
// 槽函数,用于处理数据更改信号
void printCellData(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) {
Q_UNUSED(roles);
// 将 model 声明为 const QAbstractItemModel* 类型
const QAbstractItemModel *model = topLeft.model();
// 遍历更改的单元格范围
for (int row = topLeft.row(); row <= bottomRight.row(); ++row) {
for (int col = topLeft.column(); col <= bottomRight.column(); ++col) {
QModelIndex index = model->index(row, col);
QVariant data = model->data(index);
qDebug() << "Row:" << row << "Column:" << col << "Data:" << data.toString();
}
}
}
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
// 创建一个 QStandardItemModel,有 3 行 2 列
QStandardItemModel model(3, 2);
// 设置表头
model.setHorizontalHeaderLabels({"Name", "Age"});
// 设置单元格数据
QStandardItem *item1 = new QStandardItem("Alice");
model.setItem(0, 0, item1);
QStandardItem *item2 = new QStandardItem("25");
model.setItem(0, 1, item2);
// 创建一个表格视图并设置模型
QTableView tableView;
tableView.setModel(&model);
// 连接模型的数据更改信号到槽函数
QObject::connect(&model, &QStandardItemModel::dataChanged, printCellData);
tableView.show();
return a.exec();
}
QFileSystemModel
用途:QFileSystemModel 用于表示文件系统的目录和文件结构。它可以方便地在视图中显示文件系统的内容,支持文件和文件夹的浏览、排序等操作。
#include <QApplication>
#include <QFileSystemModel>
#include <QTreeView>
#include <QDebug>
// 槽函数,用于处理树状视图的点击事件
void printClickedItemInfo(const QModelIndex &index) {
const QFileSystemModel *model = qobject_cast<const QFileSystemModel*>(index.model());
if (model) {
// 获取文件或文件夹的路径
QString filePath = model->filePath(index);
// 获取文件或文件夹的名称
QString fileName = model->fileName(index);
// 判断是文件还是文件夹
bool isDir = model->isDir(index);
qDebug() << "Clicked Item Information:";
qDebug() << "Name:" << fileName;
qDebug() << "Path:" << filePath;
qDebug() << "Is Directory:" << (isDir ? "Yes" : "No");
}
}
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
// 创建一个 QFileSystemModel
QFileSystemModel model;
// 设置根路径
model.setRootPath(QDir::homePath());
// 创建一个树状视图并设置模型
QTreeView treeView;
treeView.setModel(&model);
// 设置显示的根目录
treeView.setRootIndex(model.index(QDir::homePath()));
// 连接树状视图的 clicked 信号到槽函数
QObject::connect(&treeView, &QTreeView::clicked, printClickedItemInfo);
treeView.show();
return a.exec();
}
QSqlTableModel
用途:QSqlTableModel 用于与数据库中的单个表进行交互。它提供了一种简单的方式来显示、编辑和管理数据库表中的数据。
#include <QApplication>
#include <QSqlDatabase>
#include <QSqlTableModel>
#include <QTableView>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>
// 创建表并插入示例数据
void setupDatabase(QSqlDatabase &db) {
QSqlQuery query(db);
// 创建 people 表
if (!query.exec("CREATE TABLE IF NOT EXISTS people ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"name TEXT, "
"age INTEGER)")) {
qDebug() << "Table creation error:" << query.lastError().text();
return;
}
// 插入示例数据
if (!query.exec("INSERT INTO people (name, age) VALUES ('Alice', 25)")) {
qDebug() << "Data insertion error:" << query.lastError().text();
}
if (!query.exec("INSERT INTO people (name, age) VALUES ('Bob', 30)")) {
qDebug() << "Data insertion error:" << query.lastError().text();
}
}
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
// 连接数据库
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("test.db");
if (!db.open()) {
qDebug() << "Database open error:" << db.lastError().text();
return 1;
}
// 设置数据库,创建表并插入数据
setupDatabase(db);
// 创建一个 QSqlTableModel
QSqlTableModel model;
// 设置要操作的表名
model.setTable("people");
// 选择表中的数据
model.select();
// 创建一个表格视图并设置模型
QTableView tableView;
tableView.setModel(&model);
tableView.show();
return a.exec();
}
setupDatabase 函数:
该函数接受一个 QSqlDatabase 引用作为参数,用于在数据库中创建表并插入示例数据。
使用 QSqlQuery 执行 SQL 语句,CREATE TABLE IF NOT EXISTS 用于创建 people 表,如果该表不存在的话。
接着使用 INSERT INTO 语句插入两条示例数据。
main 函数:
连接到 SQLite 数据库 test.db,如果打开失败则输出错误信息并退出程序。
调用 setupDatabase 函数,创建表并插入示例数据。
创建 QSqlTableModel 并设置要操作的表名为 people,然后调用 select() 方法从表中选择数据。
创建 QTableView 并将模型设置给它,最后显示表格视图。
QSqlQueryModel
用途:QSqlQueryModel 用于执行 SQL 查询并显示查询结果。它是一个只读模型,不支持直接编辑数据,但可以方便地显示数据库查询的结果。
#include <QApplication>
#include <QSqlDatabase>
#include <QSqlQueryModel>
#include <QTableView>
#include <QSqlError>
#include <QDebug>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
// 连接数据库
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("test.db");
if (!db.open()) {
qDebug() << "Database open error:" << db.lastError().text();
return 1;
}
// 创建一个 QSqlQueryModel
QSqlQueryModel model;
// 执行 SQL 查询
model.setQuery("SELECT * FROM people");
// 创建一个表格视图并设置模型
QTableView tableView;
tableView.setModel(&model);
tableView.show();
return a.exec();
}
功能特点
- QSqlQueryModel
只读性:QSqlQueryModel 是一个只读模型,它主要用于执行 SQL 查询并显示查询结果,不支持直接对数据进行编辑、插入或删除操作。这是因为它设计的初衷是简单地呈现查询到的数据,不提供修改数据的接口,以保证数据的安全性和一致性。
灵活性:它非常灵活,可以执行任意的 SQL 查询语句,无论是简单的 SELECT 查询,还是复杂的多表连接查询、带有条件和排序的查询等,都能轻松应对。你可以根据自己的需求构造不同的 SQL 查询语句,然后将结果显示在视图中。
数据处理:QSqlQueryModel 只是简单地将查询结果存储在模型中,并提供给视图进行显示,不负责对数据进行额外的处理或维护。例如,它不会跟踪数据的修改状态,也不会自动更新数据库中的数据。 - QSqlTableModel
可编辑性:QSqlTableModel 支持对数据进行编辑、插入和删除操作。它提供了一系列的接口,如 setData() 用于修改数据,insertRows() 用于插入新行,removeRows() 用于删除行等。当你对模型中的数据进行修改后,可以调用 submitAll() 或 revertAll() 方法来提交或撤销这些修改,并且这些修改会自动反映到数据库中。
单表操作:QSqlTableModel 主要用于与数据库中的单个表进行交互,它只能操作一个指定的表。在使用时,你需要通过 setTable() 方法指定要操作的表名,然后可以对该表中的数据进行各种操作。
数据同步:QSqlTableModel 会自动跟踪数据的修改状态,确保模型中的数据与数据库中的数据保持同步。当你对模型中的数据进行修改后,调用 submitAll() 方法时,它会将这些修改应用到数据库中;调用 revertAll() 方法时,会将模型中的数据恢复到上次从数据库中读取的状态。
使用场景
- QSqlQueryModel
当你只需要显示数据库中的数据,而不需要对数据进行编辑时,可以使用 QSqlQueryModel。例如,显示数据库中的统计报表、查询结果列表等。
当你需要执行复杂的 SQL 查询,并且不需要对查询结果进行修改时,QSqlQueryModel 是一个很好的选择。因为它可以执行任意的 SQL 查询,并且能够快速地将查询结果显示在视图中。 - QSqlTableModel
当你需要对数据库中的单个表进行数据的编辑、插入和删除操作时,应该使用 QSqlTableModel。例如,开发一个数据库管理系统,需要对用户信息表进行增删改查操作,就可以使用 QSqlTableModel。
当你需要确保模型中的数据与数据库中的数据保持同步时,QSqlTableModel 能够很好地满足需求。它会自动处理数据的更新和同步,减少了开发者的工作量。