• QT MV\MVC结构


    简介、作用

    • Model/View 结构将数据模型和用户界面分离开来,分别用不同的实现,是一种显示和编辑数据的有效结构,在处理大型数据时尤其明显。

    • 可以将一个数据模型在不同的视图中显示,也可以在不修改数据模型的情况下,设计特殊的视图组件

    MVC

    MVC由三种对象组成:

    • 模型负责获取需要显示的数据,并且能够存储这些数据的修改。每种数据类型都有它自己对应的模型,但是这些模型提供一个相同的 API,用于隐藏内部实现。
    • 视图用于将模型数据显示给用户。对于很大的数据,或许只显示一小部分,这样就能很好的提高性能。
    • 控制器(QT中使用delegate代理)是模型和视图之间的媒介,将用户的动作解析成对数据的操作,比如查找数据或者修改数据,然后转发给模型执行,最后再将模型中需要被显示的数据直接转发给视图进行显示。

    一个 model 注册给多个 view,为同一个数据提供不同的显示方式。Qt 会自动地对这些 view 保持同步,自动刷新所有的 view 以显示最新的数据。这样,我们就可以只对 model 进行修改,view 会自动更新

    但是对于很大的数据,我们则需要使用 Qt 的 view 类,比如 QListView,QTabelView 和 QTreeView,同时需要提供一个 model,可以是自定义 model,也可以是 Qt 预置的model。例如,如果数据来自数据库,那么你可以使用 QTabelView 和 QSqlTableModel 这两个类。(在少量数据的情形下,我们不需要动用 model 这样重量级的组件。Qt 为了方便起见也提供了 item view 类,分别是 QListWidget,QTableWidget 和 QTreeWidget,使用这些类可以直接对 item 进行操作。这种实现很像 Qt 早期版本,组件中包含了相应的 item,例如 QTableWidget 中包含有QTableWidgetItem 等。)

    流程

    源数据模型 (Model) 读取,然后在视图 (View) 组件上显示和编辑在界面上编辑修改的数据又通过模型保存到源数据
    在这里插入图片描述

    • Data(源数据)是原始数据,如数据库的一个数据表或SQL查询结果、内存中的一个字符串列表或磁盘文件结构等。
    • Model(模型/数据模型)与源数据通信,并为视图组件提供数据接口。它从源数据提取需要的数据,用于视图组件进行显示和编辑。
    • View(视图/视图组件)是界面控件,视图从数据模型中根据一定条件(如行号、列号等)获得模型索引(一个指向数据项的引用),然后显示在界面上。
    • Delegate(代理)在视图与模型之间交互操作时提供临时编辑组件的功能。

    通信机制

    • 当源数据发生变化时,数据模型发射信号通知视图组件。
    • 当用户在界面上操作数据时,视图组件发射信号表示这些操作信息。
    • 在编辑数据时,代理会发射信号告知数据模型视图组件编辑器的状态。

    实现

    • 实现自定义模型可以通过**QAbstractItemModel(复杂数据)类继承,也可以通过QAbstractListModel(一维)QAbstractTableModel(二维)**类继承实现列表模型或者表格模型。

    QModelIndex 模型索引

    通过数据模型存取的每个数据都有一个模型索引,视图组件和代理都通过索引来获取数据。

    模型内部组织数据的结构可能随时改变,所以模型索引是临时的。例如,对于一个QTreeView组件,如果获取一个节点的模型索引后又修改了模型数据,则先前获得的模型索引或不再指向原节点

    通过行号、列号、父项的模型索引三个参数来获得需要的模型索引。

    数据模型的基本形式是用行和列定义的表格数据,但这并不意味着底层的数据是用二维数组存储的。

    item role 角色

    为数据模型的一个项设置数据时,可以为项设置不同角色的数据。
    一个项可以有不同角色的数据,对应不同的用途。

    实际上是Qt的一个enum定义的,比较常见的有Qt::DisplayRole和Qt::EditRole,另外还有Qt::ToolTipRole, Qt::StatusTipRole, 和Qt::WhatsThisRole等。并且,还有一些属性是用来描述基本的展现属性的,比如Qt::FontRole, Qt::TextAlignmentRole, Qt::TextColorRole, Qt::BackgroundColorRole等。

    Model

    在这里插入图片描述

    View

    在这里插入图片描述

    QStringListModel + QListView

    // 创建一个QStringListModel的对象。然后创建一个QStringList对象,并且把这个对象设置为model的数据
    QStringListModel *model = new QStringListModel(this);
    QStringList data;
    data << "a" << "b" << "c";
    
    // QListView数据展示:创建一个QListView的对象,并把model设置为它的model
    QListView *view = new QListView(this);
    view->setModel(model);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    数据插入:

    int irow = view->currentIndex().row();  // 获取QListView当前行
    model->insertRows(row, 1);
    
    QModelIndex index = model->index(row);
    model->setData(index, text);
    view->setCurrentIndex(index);
    view->edit(index);  // 这一行可以被编辑
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    几乎所有操作都是针对model的,model侦测到数据发生了变化,会立刻通知view刷新。这样,我们就可以把精力集中到对数据的操作上,而不用担心view的同步等操作。

    代理

    QStringListModel *model = new QStringListModel(QColor::colorNames(), this);
    
    QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this);  // 代理(QListView必须用QSortFilterProxyModel代理,否则不生效)
    proxy->setSourceModel(model);  // 对model代理
    proxy->setFilterKeyColumn(0);  // 过滤第0列
    
    QListView *view = new QListView(this);
    view->setModel(proxy);
    
    QRegExp::PatternSyntax syntax = QRegExp::PatternSyntax(....);
    modelProxy->setFilterRegExp(regExp);  // 设置proxy过滤器的表达式
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    自定义model

    1. 继承QAbstractTableModel(parent)
    2. 重写model中rowCount() \ columnCount() \ data() 方法。
    CurrencyModel::CurrencyModel(QObject *parent)
    : QAbstractTableModel(parent)
    {
    }
    
    QMap<QString, double> map;
    int CurrencyModel::rowCount(const QModelIndex & parent) const
    {
    	return map.count();
    }
    int CurrencyModel::columnCount(const QModelIndex & parent) const
    {
    	return map.count();
    }
    
    // 虚函数 在用户编辑数据时会自动调用: 用户新修改的数据被作为参数value传入
    QVariant CurrencyModel::data(const QModelIndex &index, const QVariant &value, int role) const
    {
    	...
    }
    
    QVariant CurrencyModel::headerData(int section, Qt::Orientation orientation, int role) const
    {
    	...
    }
    
    void CurrencyModel::setCurrencyMap(const QMap<QString, double> &map)
    {
    	...
    }
    
    // 调用
    CurrencyModel *model = new CurrencyModel();
    model->setCurrencyMap(data);
    QTableView *view = new QTableView(this);
    view->setModel(model);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    Delegate 代理

    代理在视图与模型之间交互操作时提供临时编辑组件的功能。(模型向视图提供数据是单向的,一般仅用于显示。当需要在视图上编辑数据时,代理功能会为编辑数据提供一个编辑器,这个编辑器获取模型的数据、接受用户编辑的数据后又提交给模型:在QTableView组件上双击一个单元格编辑数据时,在单元格里就会出现一个QLineEdit组件,这个编辑框就是代理提供的临时编辑器。)

    对于一些特殊的数据编辑需求,例如只允许输入整型数,使用一个QSpinBox作为代理组件更合适;从列表中选择一个数据,使用一个QComboBox作为代理组件更好。这时就需要从QStyledItemDelegate、QItemDelegate继承创建自定义代理类

    自定义代理:QStyledItemDelegate、QItemDelegate

    如果delegate没有支持为你的数据类型进行绘制,或者你希望自己绘制item,那么就可以继承 QStyledItemDelegate 类,并且重写 paint()sizeHint() 函数。paint() 函数会被每一个item独立调用,而sizeHint()函数则可以定义每一个item 的大小

    方法

    1. QStyledItemDelegate继承
    2. QItemDelegate继承
      默认的delegate是 QStyledItemDelegate。QStyledItemDelegate 使用当前的风格(style)去绘制组件
    • createEditor() 创建用于编辑模型数据的widget组件,如一个QSpinBox或一个QComboBox组件。
    • setEditorData() 从模型获得数据,供widget组件进行编辑。
    • setModelData() 将widget上的数据更新到数据模型
    • updateEditorGeometry() 用于给widget组件设置合适的大小。

    使用:

    tableWidget->setItemDelegate(new TrackDelegate());
    
    • 1

    https://zhuanlan.zhihu.com/p/378805209

    https://blog.51cto.com/devbean/268468

  • 相关阅读:
    java数组转List的几种方式
    第十一章 配置数据库(三)
    Docker 完整版教程
    Pyecharts绘制动态地图
    nginx--install
    深度学习在自然语言处理中的应用
    前端工程化之:webpack4-1(babel的安装和使用)
    uafxcw.lib(afxmem.obj) : error LNK2005
    散列表:Word文档中的单词拼写检查功能是如何实现的?
    代码随想录算法训练营 动态规划part13
  • 原文地址:https://blog.csdn.net/qq_21980099/article/details/126052436