MVC全称是 Model View Controller,是一种非常非常流行的架构模式。
有时,我们的系统需要显示大量数据,比如从数据库中读取数据,以自己的方式显示在自己的应用程序的界面中。早期的 Qt 要实现这个功能,需要定义一个组件,在这个组件中保存一个数据对象,比如一个列表。我们对这个列表进行查找、插入等的操作,或者把修改的地方写回,然后刷新组件进行显示。这个思路很简单,也很清晰,但是对于大型程序,这种设计就显得苍白无力。比如,在一个大型系统中,你的数据可能很大,全部存入一个组件的数据对象中,效率会很低,并且这样的设计也很难在不同组件之间共享数据。如果你要几个组件共享一个数据对象,要么你就要用存取函数公开这个数据对象,要么你就必须把这个数据对象放进不同的组件分别进行维护。
Smalltalk 语言发明了一种崭新的实现,用来解决这个问题,这就是著名的 MVC 模型。对这个模型无需多言。MVC 是 Model-View-Controller 的简写,即模型-视图-控制器。在 MVC 中,模型负责获取需要显示的数据,并且存储这些数据的修改。每种数据类型都有它自己对应的模型,但是这些模型提供一个相同的 API,用于隐藏内部实现。视图用于将模型数据显示给用户。对于数量很大的数据,或许只显示一小部分,这样就能很好的提高性能。控制器是模型和视图之间的媒介,将用户的动作解析成对数据的操作,比如查找数据或者修改数据,然后转发给模型执行,最后再将模型中需要被显示的数据直接转发给视图进行显示。MVC 的核心思想是分层,不同的层应用不同的功能。
Qt 4 开始,引入了类似的 model/view 架构来处理数据和面向最终用户的显示之间的关系。当 MVC 的 V 和 C 结合在一起,我们就得到了 model/view 架构。这种架构依然将数据和界面分离,但是框架更为简单。同样,这种架构也允许使用不同界面显示同一数据,也能够在不改变数据的情况下添加新的显示界面。为了处理用户输入,我们还引入了委托(delegate)。引入委托的好处是,我们能够自定义数据项的渲染和编辑。
关于Qt中的MVC
其实Qt中的MVC并不叫MVC,而是叫“MVD”,Qt中没有Controller的说法,而是使用了另外一种抽象: Delegate (委托) ,其行为和传统的MVC是相同的。 这里delegate 类似 Control 负责协调Model和View之间的数据。
模型与数据源进行交互,为框架中其它组件提供接口。这种交互的本质在于数据源的类型以及模型的实现方式。视图从模型获取模型索引,这种索引就是数据项的引用。通过将这个模型索引反向传给模型,视图又可以从数据源获取数据。在标准视图中,委托渲染数据项;在需要编辑数据时,委托使用直接模型索引直接与模型进行交互。
总的来说,model/view 架构将传统的 MV 模型分为三部分:模型、视图和委托。每一个组件都由一个抽象类定义,这个抽象类提供了基本的公共接口以及一些默认实现。模型、视图和委托则使用信号槽进行交互:
所有的模型都是QAbstractItemModel
的子类。这个类定义了供视图和委托访问数据的接口。模型并不存储数据本身。这意味着,你可以将数据存储在一个数据结构中、另外的类中、文件中、数据库中,或者其他你所能想到的东西中。我们将在后面再详细讨论这些内容。
QAbstractItemModel
提供的接口足够灵活,足以应付以表格、列表和树的形式显示的数据。但是,如果你需要为列表或者表格设计另外的模型,直接继承QAbstractListModel
和QAbstractTableModel
类可能更好一些,因为这两个类已经实现了很多通用函数。关于这部分内容,我们也会在后文中详述。
Qt 内置了许多标准模型:
QStringListModel
:存储简单的字符串列表。QStandardItemModel
:可以用于树结构的存储,提供了层次数据。QFileSystemModel
:本地系统的文件和目录信息。QSqlQueryModel
、QSqlTableModel
和QSqlRelationalTableModel
:存取数据库数据。正如上面所说,如果这些标准模型不能满足你的需要,就必须继承QAbstractItemModel
、QAbstractListModel
或者QAbstractTableModel
,创建自己的模型类。
Qt 还提供了一系列预定义好的视图:QListView
用于显示列表,QTableView
用于显示表格,QTreeView
用于显示层次数据。这些类都是QAbstractItemView
的子类。这意味着,如果你要创建新的视图类,则可以继承QAbstractItemView
。QAbstractItemDelegate
则是所有委托的抽象基类。自 Qt 4.4 依赖,默认的委托实现是QStyledItemDelegate
。但是,QStyledItemDelegate
和QItemDelegate
都可以作为视图的编辑器,二者的区别在于,QStyledItemDelegate
使用当前样式进行绘制。在实现自定义委托时,推荐使用QStyledItemDelegate
作为基类,或者结合 Qt style sheets。
如果你觉得 model/view 模型过于复杂,或者有很多功能是用不到的,Qt 还有一系列方便使用的类。这些类都是继承自标准的视图类,并且继承了标准模型。这些类并不是为其他类继承而准备的,只是为了使用方便。它们包括QListWidget
、QTreeWidget
和QTableWidget
。这些类远不如视图类灵活,不能使用另外的模型,因此只适用于简单的情形。
这个例子使用QTableView和QStandardItemModel,Delegate在这里不需要关注,默认的Delegate就可以很好的协调Model和View了。 在一个Widget类中我们分别定义一个QTableView和一个QStandardItemModel;
ui 使用 Qt Designer生成的类,使用 QTableView显示数据,构造函数中我们使用setModel函数就可以把Model和view进行绑定:
showtableform.h
#ifndef SHOWTABLEFORM_H
#define SHOWTABLEFORM_H
#include
#include
namespace Ui {
class ShowTableForm;
}
class ShowTableForm : public QWidget
{
Q_OBJECT
public:
explicit ShowTableForm(QWidget *parent = 0);
~ShowTableForm();
private:
Ui::ShowTableForm *ui;
QStandardItemModel* mModel;
};
#endif // SHOWTABLEFORM_H
showtableform.cpp
#include "showtableform.h"
#include "ui_showtableform.h"
ShowTableForm::ShowTableForm(QWidget *parent) :
QWidget(parent),
ui(new Ui::ShowTableForm), mModel(new QStandardItemModel())
{
ui->setupUi(this);
mModel->setHorizontalHeaderItem(0, new QStandardItem(QObject::tr("Name")));
mModel->setHorizontalHeaderItem(1, new QStandardItem(QObject::tr("Type")));
mModel->setHorizontalHeaderItem(2, new QStandardItem(QObject::tr("Size")));
mModel->setHorizontalHeaderItem(3, new QStandardItem(QObject::tr("Time")));
for(int i =0;i<5;i++)
{
QList item;
item.append(new QStandardItem(QObject::tr("Qt.css")));
item.append(new QStandardItem(QObject::tr("css")));
item.append(new QStandardItem(QObject::tr("100KB")));
item.append(new QStandardItem(QObject::tr("2016-1-10")));
mModel->appendRow(item);
}
ui->mtableView->setModel(mModel);
}
ShowTableForm::~ShowTableForm()
{
delete ui;
}
简单的几步就可以出结果,足见qt强大,效果图:
Demo
参考:
https://blog.csdn.net/rl529014/article/details/52072380