QT当中model-view-delegate(模型-视图-代理),此结构实现数据和界面的分离。Qt的模型-视图结构分为三部分:模型(model)-视图(view)-代理(Delegate)。其中模型与数据源通信;并为其它部件提供接口;视图从模型中引用数据条目的模型索引(ModelIndex)。在视图当中,代理负责绘制数据条目,比如编辑条目,代理和模型进行直接通信。
关系:
模型、视图、代理是MVC模式中的三个核心组件,各自承担不同的职责。
- 模型(Model):负责存储数据和对数据进行处理,提供访问和修改数据的接口。模型通常是应用程序最底层的部分,与具体业务逻辑有关。
- 视图(View):负责展示数据给用户,并且提供交互操作。视图通常是用户与应用程序交互的主要界面,如Web页面、桌面应用程序的窗口等。
- 代理(Proxy):作为“中间人”,实现模型和视图之间的沟通。代理通常是一些中间件或者控制器,用于管理模型和视图之间的通信流程,以确保它们之间的正确性和可靠性。
在MVC架构中,模型、视图、代理之间的关系如下图所示:
当用户与视图交互时,视图会向代理发送请求,代理会将请求转发给模型进行处理。模型完成数据的处理后,将结果返回给代理,代理再将结果传递给视图,视图最终显示给用户。在这个交互过程中,代理扮演着重要的角色,它不仅负责将请求传递给模型,还需要处理模型返回的数据,以便视图能够正确地显示数据。
1.模型 model
InterView框架中所有模型都基于抽象基类QAbstractItemModel类,InterView框-架中所有模型都基于抽象基类QAbstractltemModel类,此类由:QAbstractListModel ;QAbstractTableModel和QAbstractProxyModel类继承。
用于将数据存储在特定格式中并提供访问和操作这些数据的方法。它们实现了Qt Model/View体系结构的核心,允许在用户界面中呈现数据。Qt提供了多种类型的model,包括列表、表格、树形结构等。通过使用标准接口来访问model,可以轻松地进行数据排序、过滤、插入、修改和删除操作。Model通常与view(视图)搭配使用,以便在GUI中显示数据。常用的model有QStandardItemModel、Q、QSqlQueryModel、QFileSystemModel等。
2.视图 View
InterView框架中的所有视图都基于抽象基类QAbstractltemView类,此类由QColumnView、QHeaderView、QListView、QTableView和QTreeView类继承。
Qt中的View是指数据可视化的组件,用于将model中的数据以某种方式呈现给用户。View通常与model搭配使用,以便在GUI中显示数据。Qt提供了多种类型的view,包括列表、表格、树形结构等。通过使用标准接口来访问view,可以轻松地对其进行设置和定制,如更改列宽度、行高度、排序、过滤等。常用的view有QTableView、QListView、QTreeView等。
对于不同类型的view,Qt还提供了各种内置功能和自定义选项,例如:QTableView提供了单元格编辑、复选框、进度条等;QListView提供了图标、文本、列表、网格等不同的显示方式;QTreeView提供了可展开的树形结构和可收缩的节点等。此外,还可以通过实现自定义view来创建特定需求的数据可视化组件。
3.代理 Delegate
InterView框架中的所有代理都基于抽象基类QAbstractltemDelegate类,
此类由QltemDelegate和QStyledltemDelegate类继承。
Delegate(代理)是Qt中非常重要的一种机制,它提供了灵活的控件定制和事件处理能力。Delegate通常用于为模型提供自定义渲染和编辑,并且可以处理与控件交互相关的事件。
在Qt中,每个控件都有一个默认的delegate,但是这个delegate只提供了基本的呈现和编辑功能。如果需要更多的定制,就需要使用自定义delegate了。
自定义delegate通常继承自QStyledItemDelegate或QAbstractItemDelegate类。QStyledItemDelegate提供了一些方便的函数来绘制和编辑数据项,而QAbstractItemDelegate则提供了更高级的控制能力。
自定义delegate需要实现以下三个函数:
-
paint():用于绘制数据项的外观。
-
createEditor():用于创建编辑器,以便用户编辑数据项。
-
setEditorData()和setModelData():用于将数据从编辑器传输到模型,以及从模型传输到编辑器。
除了这些核心函数外,还可以通过其他一些函数来控制delegate的外观和行为,例如sizeHint()、updateEditorGeometry()等。
举例1:
效果:
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QAbstractItemModel> //模型
#include <QAbstractItemView> //视图
#include <QItemSelectionModel> // 模式
#include <QSplitter> //分割窗口
#include <QDirModel> //用于展示文件系统目录结构。
#include <QListView> //列表视图
#include <QTreeView> //树视图
#include <QTableView> //表视图
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//MainWindow w;
//w.show();
QDirModel model; //专门用于获取磁盘文件目录的数据模型 类似QFileSystemModel类
QTreeView tree; //树形视图
QListView list; //列表视图
QTableView table;//表视图
//设置数据模型
tree.setModel(&model);
list.setModel(&model);
table.setModel(&model);
//设置树形视图的选择模式为多选模式,允许用户通过按住Ctrl键或Shift键来同时选择多个树节点。
tree.setSelectionMode(QAbstractItemView::MultiSelection);
//将树形结构控件(tree)的选择模型(selectionModel)设置为列表控件(list)的选择模型。
//这样做的目的是让两个控件共用同一个选择模型,以便在对它们进行选择操作时能够保持同步。
list.setSelectionModel(tree.selectionModel());
table.setSelectionModel(tree.selectionModel());
//连接槽函数
QObject::connect(&tree,SIGNAL(doubleClicked(QModelIndex)),&list,SLOT(setRootIndex(QModelIndex)));
QObject::connect(&tree,SIGNAL(doubleClicked(QModelIndex)),&table,SLOT(setRootIndex(QModelIndex)));
QSplitter *qslter=new QSplitter(Qt::Horizontal); //水平分割窗口
qslter->addWidget(&tree);
qslter->addWidget(&list);
qslter->addWidget(&table);
qslter->show();
return a.exec();
}
举例2:
效果:
自定义表模型类显示
Modelextended.h
#ifndef MODELEXTENDED_H
#define MODELEXTENDED_H
#include <QAbstractTableModel>
#include <QVector>
#include <QStringList>
#include <QMap>
class ModelExtended : public QAbstractTableModel
{
Q_OBJECT
public:
explicit ModelExtended(QObject *parendt=0);
//系统自带的model相关的函数进行重新定义
virtual int rowCount(const QModelIndex &parent=QModelIndex())const; //行
virtual int columnCount(const QModelIndex &parent=QModelIndex())const; //列
QVariant data(const QModelIndex &index,int role) const; //显示数据
QVariant headerData(int section,Qt::Orientation orientateion,int role) const; //设置表头数据
private:
//QVector向量容器 QVector是Qt对所有数组的封装
QVector<short> empindex; //短整型数组
QVector<short> empnameindex;
//Qmap是qt通用容器,存储(键,值),并提供与键相关联值的的快速查找 是按键的ASCII码排序存储的
QMap<short,QString> empno; //存放员工编号
QMap<short,QString> empname;//存放员工姓名
//Qstringlist提供一个字符串列表
//QStringlist 添加QString 字符串,直接用<<来添加字符串
QStringList viewlisttitle;//存放标题名称
QStringList department_list; //存放员工部门
void ModelFunc();
};
#endif // MODELEXTENDED_H
Modelextended.cpp
#include "Modelextended.h"
ModelExtended::ModelExtended(QObject *parent):QAbstractTableModel(parent)
{
//员工编号赋值
empno[1]="2022001";
empno[2]="2022002";
empno[3]="2022003";
empno[4]="2022004";
empno[5]="2022005";
//员工姓名赋值
empname[1]="李哥";
empname[2]="张哥";
empname[3]="王哥";
empname[4]="刘哥";
empname[5]="齐哥";
department_list<<"财务部"<<"研发部"<<"销售部"<<"后勤部"<<"董事会";
ModelFunc(); //模型设计
}
void ModelExtended::ModelFunc() //模型设置
{
//设置标题
viewlisttitle<<"员工编号"<<"员工姓名"<<"部门";
empindex<<1<<2<<3<<4<<5;
empnameindex<<1<<2<<3<<4<<5;
}
int ModelExtended::rowCount(const QModelIndex &parent)const //行
{
return empindex.size(); //表视图的行
}
int ModelExtended::columnCount(const QModelIndex &parent)const //列
{
return 3; //列数
}
QVariant ModelExtended::data(const QModelIndex &index,int role) const //显示数据
{
if(!index.isValid()){ //判断index是否有效合法
return QVariant();
}
if(role==Qt::DisplayRole){
switch (index.column()) { //获取列的值
case 0:
return empno[empindex[index.row()]];
break;
case 1:
return empname[empnameindex[index.row()]];
break;
case 2:
return department_list[index.row()];
break;
default:
return QVariant();
}
}
return QVariant();
}
QVariant ModelExtended::headerData(int section,Qt::Orientation orientateion,int role) const //设置表头数据
{
//首先判断角色(role)和方向(orientation)。如果角色是Qt::DisplayRole(用于显示数据),
//方向是水平方向(即列标题),那么就返回对应列的标题文本。
if(role==Qt::DisplayRole && orientateion== Qt::Horizontal){
return viewlisttitle[section];
}
return QAbstractTableModel::headerData(section,orientateion,role);
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <Modelextended.h> //自定义模型
#include <QTableView> //表视图
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//MainWindow w;
// w.show();
ModelExtended modeex;
QTableView view;
view.setModel(&modeex);
//view->setWindowTitle("表视图模型测试");
//view->resize(600,500);
view.show();
return a.exec();
}