Model-View是一项通用的技术框架,不是Qt独有的,很多的编程语言均有model-view的实现。
model-view是模型-视图的含义,其中模型属于业务逻辑层,同时模型与数据源实时绑定。视图用于显示数据,同时负责与用户的交互。当用户在视图层操作时,模型层实现各种响应逻辑,并及时把数据源更新。
在Qt中,实际上还有一个代理(delegate)角色,代理功能可以让用户定制数据的界面显示和编辑方式。所以完整的架构简称MVD (Model-View-Delegate)。
模型、视图和代理之间使用信号和槽通信。当源数据发生变化时,数据模型发射信号通知视图组件;当用户在界面上操作数据时,视图组件发射信号表示这些操作信息;当编辑数据时,代理发射信号告知数据模型和视图组件编辑器的状态。
所有的基于项数据的数据模型(Model) 都是基于QAbstractItemModel 类的,这个类定义了视图组件和代理存取数据的接口。数据无需存储再数据模型里,数据可以是其他类、文件、数据库或任何数据源。
Qt 中与数据模型相关的几个主要的类的层次结构如图 2 所示:
视图组件(View)是显示数据模型的数据的界面组件,Qt 提供的视图组件有:
QListView:用于显示单列的列表数据,适用于一维数据的操作。
QTreeView:用于显示树状结构数据,适用于树状结构数据的操作。
QTableView:用于显示表格状数据,适用于二维表格型数据的操作。
QColumnView:用多个QListView显示树状层次结构,树状结构的一层用一个QListView显示。
QHeaderView:提供行表头或列表头的视图组件,如QTableView的行表头和列表头。
关于以上几个视图组件的使用在前面的博客中有介绍,需要了解的朋友请转至:Qt6教程之二(4) item views_爱折腾的业余程序员的博客-CSDN博客本节主要讲解Qt的项目视图!https://blog.csdn.net/XiaoWang_csdn/article/details/129070847
模型索引(model index)
为了保证数据的表示与数据存取方式隔离,数据模型中引入了模型索引的概念。通过数据模型存取的每个数据都有一个模型索引,视图组件和代理都通过模型索引来获取数据。
QModelIndex 表示模型索引的类。模型索引提供数据存取的一个临时指针,用于通过数据模型提取或修改数据。因为模型内部组织数据的结构随时可能改变,所以模型索引是临时的。如果需要使用持久性的模型索引,则要使用 QPersistentModelIndex 类。
上面是对Qt的MVD架构的简单介绍,下面我们来做一个使用默认代理和使用自定义代理的示例,视图使用QListView,模型使用QStringListModel ,。
话不多说,开始敲代码:
新建一个新的工程叫test_QListViewDemo,不需要ui文件,
使用默认代理,就在mainwindow.cpp中写几行代码,其他保持不变,代码非常简单,如下:
mainwindow.cpp
#include "mainwindow.h"
#include<QVBoxLayout>
#include<QListView>
#include<QStringListModel>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
resize(900,900);
setWindowTitle("listView");
QVBoxLayout *vl=new QVBoxLayout(this);
QStringList list;
list<<"hello world" <<"hello listView"<<"hello listModel";
QStringListModel *listModel=new QStringListModel;
listModel->setStringList(list);
QListView *view=new QListView(this);
view->setModel(listModel);
view->resize(800,800);
vl->addWidget(view);
setLayout(vl);
//view->show();
}
MainWindow::~MainWindow()
{
}
运行效果:
使用自定义代理实现:
新建一个代理类,叫MyDelegate ,头文件代码:
MyDelegate.h
#ifndef MYDELEGATE_H
#define MYDELEGATE_H
#include <QItemDelegate>
class MyDelegate : public QItemDelegate
{
Q_OBJECT
public:
MyDelegate(QWidget *parent = nullptr);
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void setEditorData(QWidget *editor, const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
#endif // MYDELEGATE_H
MyDelegate.cpp
#include "mydelegate.h"
#include <QPainter>
#include <QPainterPath>
#include<QLineEdit>
MyDelegate::MyDelegate(QWidget *parent) : QItemDelegate(parent)
{
}
//提供编辑器
QWidget *MyDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QLineEdit *lineEdit=new QLineEdit(parent);
lineEdit->setText("please inpit text");
return lineEdit;
}
//将Model数据复制到编辑器里
void MyDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QString text = index.model()->data(index, Qt::EditRole).toString();
QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
lineEdit->setText(text);
}
//提交数据给模型
void MyDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
QString text = lineEdit->text();
model->setData(index, text, Qt::EditRole);
}
//更新编辑器几何外形
void MyDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}
最后,把我们自定义的委托安装到当前视图中,只需要在mainwindow.cpp中加一行代码:
view->setItemDelegate(new MyDelegate());
mainwindow.cpp完整代码:
#include "mainwindow.h"
#include<QVBoxLayout>
#include<QListView>
#include<QStringListModel>
#include <mydelegate.h>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
resize(900,900);
setWindowTitle("listView");
QVBoxLayout *vl=new QVBoxLayout(this);
QStringList list;
list<<"hello world" <<"hello listView"<<"hello listModel";
QStringListModel *listModel=new QStringListModel;
listModel->setStringList(list);
QListView *view=new QListView(this);
view->setModel(listModel);
view->setItemDelegate(new MyDelegate());
view->resize(800,800);
vl->addWidget(view);
setLayout(vl);
//view->show();
}
MainWindow::~MainWindow()
{
}
此时,当双击编辑单行文本时,会自动提供一个单行文本编辑框,效果如下:
上一篇文章:
下一篇文章: