什么是MVC架构:
MVC模式(Model–view–controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。
MVC模式最早由Trygve Reenskaug在1978年提出[1],是施乐帕罗奥多研究中心(Xerox PARC)在20世纪80年代为程序语言Smalltalk发明的一种软件架构。MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。除此之外,此模式透过对复杂度的简化,使程序结构更加直观。软件系统透过对自身基本部分分离的同时也赋予了各个基本部分应有的功能。专业人员可以依据自身的专长分组:
模型(Model) - 程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能)。
视图(View) - 界面设计人员进行图形界面设计。
控制器(Controller)- 负责转发请求,对请求进行处理。
Qt的MVD架构又是什么?
模型(Model) - 程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能)。
视图(View) - 界面设计人员进行图形界面设计。
代理(Delegate)- 负责转发请求,对请求进行处理
UI样式实现:
其实你就只要去实现下面的代码,你就能完全使用MVD架构,随心所欲
class TableModel : public QAbstractTableModel
{
Q_OBJECT
public:
enum Columns { Element = 0, Value, Count = Value + 1 };
explicit TableModel(QObject *parent = nullptr);
Qt::ItemFlags flags(const QModelIndex &index) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole);
void addElement(const QString &element, int value);
private:
};
class TableDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit TableDelegate(QObject *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 paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
//--------------------cpp---------------------
#include "tablemodel.h"
TableModel::TableModel(QObject *parent) : QAbstractTableModel(parent)
{
}
Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
{
return QAbstractTableModel::flags(index);
}
int TableModel::rowCount(const QModelIndex &parent) const
{
return 2;
}
int TableModel::columnCount(const QModelIndex &parent) const
{
return Count;
}
QVariant TableModel::data(const QModelIndex &index, int role) const
{
return QVariant();
}
QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
return QAbstractTableModel::headerData(section, orientation, role);
}
bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() || index.row() < 0 || index.row() >= mElements.count())
{
return false;
}
return false;
}
void TableModel::addElement(const QString &element, int value)
{
}
TableDelegate::TableDelegate(QObject *parent) : QStyledItemDelegate(parent)
{
}
QWidget *TableDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
return QStyledItemDelegate::createEditor(parent, option, index);
}
void TableDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QStyledItemDelegate::setEditorData(editor, index);
}
void TableDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QStyledItemDelegate::setModelData(editor, model, index);
}
void TableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyledItemDelegate::paint(painter, option, index);
}
void TableDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
Q_UNUSED(index)
editor->setGeometry(option.rect);
}
Model
class QAbstractItemModel {
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const = 0;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const = 0;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) = 0;
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const = 0;
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const = 0;
virtual Qt::ItemFlags flags(const QModelIndex &index) const = 0;
};
实现上面的代码,你就能使用MVD架构,理解Qt的框架,
View 与 Model 的绑定流程
- 存储指针:View 内部保存QAbstractItemModel*类型的指针指向用户的 Model 对象
- 信号连接:View 自动连接 Model 的信号(如 dataChanged())到自身的槽(如 update()),实现数据变化时的视图更新
- 数据请求:当视图需要渲染时,会通过 Model 指针调用虚函数(如data(), rowCount()))
// 伪代码:QAbstractItemView 的渲染流程
void QAbstractItemView::paintEvent() {
for (int row = 0; row < model->rowCount(); ++row) { // 多态调用 model->rowCount()
QVariant data = model->data(index(row)); // 多态调用 model->data()
delegate->paint(painter, data); // 多态调用 delegate->paint()
}
}
Delegate 的动态调用机制
- 渲染阶段:View 在绘制每个数据项时,调用delegate->paint(painter, option, index)
- 编辑阶段:当用户双击单元格时,调用delegate->createEditor()创建编辑器
- 数据回写:编辑器关闭时,调用delegate->setModelData()将数据写回 Model
// 伪代码:委托的编辑器创建过程
void QAbstractItemView::edit(const QModelIndex &index) {
QWidget* editor = delegate->createEditor(parent, option, index); // 多态调用
connect(editor, &QWidget::destroyed, [this, index]() {
delegate->setModelData(editor, model, index); // 多态调用
});
}