Qt 模型(model)/视图(view)详解

这篇具有很好参考价值的文章主要介绍了Qt 模型(model)/视图(view)详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

基于Qt6.2.0

  以下所有代码均可在Qt安装目录:Qt安装目录/examples中找到

一.模型/视图介绍

  在没有使用模型/视图的应用程序中,一个标准的表格组件是一个用户可以修改的数据元素的二维数组。表格组件能够通过读写表格组件提供的数据元素来集成到程序中。这种方法在大多数应用中都很直观而且很有用,但是当显示和编辑数据库的时候标准组件可能就有问题了。数据的两个副本必须协调:一个在组件外部,一个在组件内部。同步这两个副本的数据是开发者的职责。除了这个,显示和数据的紧密结合使得写单元测试变得更难。
而模型/视图是在处理数据集合的窗口组件中用来把数据从视图中分离出来的一种技术。MVC 把图形界面分为三个部分

  • 模型(Model):用于管理数据,注意,数据不一定需要位于模型之中。

  • 视图(View):就是呈现在用户面前的界面外观,视图负责把模型中的数据显示给用户

  • 控制器(Controller):处理用户在界面的交互数据操作

可以通过 view(可能有多个)来修改 data,当 data 改变了之后要通知所有的 view 修改自己的显示!

二.Qt中的模型/视图控件介绍

  表、列表和树控件是GUI中经常使用的组件。这些控件可以通过两种不同的方式访问其数据。传统的方式涉及用于存储数据的内部容器控件。这种方法非常直观,但在许多应用程序中,它会导致数据同步问题。第二种方法是模型/视图编程,其中控件不维护内部数据容器。他们通过标准化接口访问外部数据,因此避免了数据重复。

Widget Standard Widget
(an item based convenience class)
Model/View View Class
(for use with external data)
qtmodern,QT,qt,开发语言,ui QListWidget QListView
qtmodern,QT,qt,开发语言,ui QTableWidget QTableView
qtmodern,QT,qt,开发语言,ui QTreeWidget QTreeView
qtmodern,QT,qt,开发语言,ui QColumnView shows a tree as a hierarchy of lists
qtmodern,QT,qt,开发语言,ui QComboBox can work as both a view class and also as a traditional widget

Qt中模型类的继承关系:
qtmodern,QT,qt,开发语言,ui

不同模型(的结构):
qtmodern,QT,qt,开发语言,ui

Qt中预定义好的模型类:

Model类 说明
QStringListModel 存储字符串列表
QStandardItemModel 存储任意分层项目
QFileSystemModel 封装本地文件系统
QSqlQueryModel 封装SQL结果集
QSqlTableModel 封装SQL表
QSqlRelationalTableModel 用外键封装SQL表
QSortFilterProxyModel 排序和/或筛选其他模型

Qt中视图类的继承关系:
qtmodern,QT,qt,开发语言,ui

1. 在模型/视图控件中显示数据

视图(view)通过调用模型(model)的rowCount()calCount()函数获取显示的行数和列数,对于每个项中要显示什么,则是通过调用模型(model)的data()函数。data()函数的参数为项的索引以及项的角色(进行什么操作),通常,我们只需要根据项的索引编写相对应的逻辑,再判断需要对项进行什么操作即可。以下例程中,我们只需要显示数据即可,所以,每当data()函数被调用并且操作角色为Qt::DisplayRole显示数据时,我们就对显示的内容进行操作。

// main.cpp
#include <QApplication>
#include <QTableView>
#include "mymodel.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTableView tableView; //定义一个视图控件
    MyModel myModel; //定义一个模型
    tableView.setModel(&myModel); //将模型与视图进行绑定
    tableView.show(); //显示视图
    return a.exec();
}
// mymodel.h
#include <QAbstractTableModel>

class MyModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    MyModel(QObject *parent = nullptr); //模型的构造函数
    int rowCount(const QModelIndex &parent = QModelIndex()) const override; //返回模型中的行数
    int columnCount(const QModelIndex &parent = QModelIndex()) const override; //返回模型中的列数
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; //模型中数据的显示处理
};
// mymodel.cpp
#include "mymodel.h"

MyModel::MyModel(QObject *parent)
    : QAbstractTableModel(parent)
{
}

int MyModel::rowCount(const QModelIndex & /*parent*/) const
{
   return 2;
}

int MyModel::columnCount(const QModelIndex & /*parent*/) const
{
    return 3;
}

QVariant MyModel::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole)
       return QString("Row%1, Column%2")
                   .arg(index.row() + 1)
                   .arg(index.column() +1);

    return QVariant();
}

qtmodern,QT,qt,开发语言,ui

Qt中的Qt::ItemDataRole种类

Qt中模型/视图中的项的角色(enum Qt::ItemDataRole),有以下几种:

通用角色(以及相关类型)

Qt::ItemDataRole 描述
Qt::DisplayRole 0 以文本形式呈现的关键数据。(QString)
Qt::DecorationRole 1 以图标形式呈现为装饰的数据。(QColor, QIcon or QPixmap)
Qt::EditRole 2 适合在编辑器中编辑的格式中的数据。(QString)
Qt::ToolTipRole 项目工具提示中显示的数据。(QString)
Qt::StatusTipRole 4 状态栏中显示的数据。(QString)
Qt::WhatsThisRole 5 以“这是什么?”模式显示的项目数据。(QString)
Qt::SizeHintRole 13 将提供给视图的项的大小提示。(QSize)

描述外观和元数据的角色

Qt::ItemDataRole 描述
Qt::FontRole 6 使用默认委托呈现的项目所使用的字体。(QFont)
Qt::TextAlignmentRole 7 使用默认委托呈现的项的文本对齐方式。 (Qt::Alignment)
Qt::BackgroundRole 8 用于使用默认代理渲染的项目的背景画笔。(QBrush)
Qt::ForegroundRole 9 用于使用默认代理渲染的项目的前景画笔(通常为文本颜色)。(QBrush)
Qt::CheckStateRole 10 此角色用于获取项目的选中状态。(Qt::CheckState)
Qt::InitialSortOrderRole 14 此角色用于获取标题视图节的初始排序顺序。(Qt::SortOrder)。

辅助功能角色

Qt::ItemDataRole 描述
Qt::AccessibleTextRole 11 可访问性扩展和插件(如屏幕阅读器)使用的文本。(QString)
Qt::AccessibleDescriptionRole 12 出于可访问性目的对项目的描述。(QString)

用户角色

Qt::ItemDataRole 描述
Qt::UserRole 0x0100 可用于特定应用程序目的的第一个角色。

2. 更改模型/视图控件中显示数据的格式

想要更改视图中每个项的显示格式,只需要在data()中参数为对应的项以及操作角色时,返回对应的对象即可

// mymodel.cpp
QVariant MyModel::data(const QModelIndex &index, int role) const
{
    int row = index.row();
    int col = index.column();
    // generate a log message when this method gets called
    qDebug() << QString("row %1, col%2, role %3").arg(row).arg(col).arg(role);

    switch (role) {
    case Qt::DisplayRole:
        if (row == 0 && col == 1) return QString("<--left");
        if (row == 1 && col == 1) return QString("right-->");
        return QString("Row%1, Column%2").arg(row + 1).arg(col +1);
    case Qt::FontRole:
        if (row == 0 && col == 0) { //改变cell(0,0)的字体
            QFont boldFont;
            boldFont.setBold(true);
            return boldFont;
        }
        break;
    case Qt::BackgroundRole:
        if (row == 1 && col == 2)  //改变cell(1,2)的背景
            return QBrush(Qt::red);
        break;
    case Qt::TextAlignmentRole:
        if (row == 1 && col == 1) //改变cell(1,1)的对齐方式
            return int(Qt::AlignRight | Qt::AlignVCenter);
        break;
    case Qt::CheckStateRole:
        if (row == 1 && col == 0) //为cell(1,0)添加一个勾选框
            return Qt::Checked;
        break;
    }
    return QVariant();
}

qtmodern,QT,qt,开发语言,ui

3. 显示动态数据

为了进行动态的数据更新,我们需要先设定一个时间定时器:

MyModel::MyModel(QObject *parent)
    : QAbstractTableModel(parent)
    , timer(new QTimer(this))
{
    timer->setInterval(1000); //设置1000毫秒的定时器
    connect(timer, &QTimer::timeout , this, &MyModel::timerHit);  //绑定定时器的到点触发函数
    timer->start(); //开启定时器
}

定时器触发函数中进行数据的更新,数据更新后需要释放一个dataChanged()信号,信号的参数为要更新项的索引和所需操作

void MyModel::timerHit()
{
    QModelIndex topLeft = createIndex(0,0); //要更新的数据位置
    emit dataChanged(topLeft, topLeft, {Qt::DisplayRole}); //释放一个信号,让视图去更新数据
}

dataChanged()信号释放后,则会调用data()函数对数据进行更新

QVariant MyModel::data(const QModelIndex &index, int role) const
{
    int row = index.row();
    int col = index.column();

    if (role == Qt::DisplayRole && row == 0 && col == 0)
        return QTime::currentTime().toString();

    return QVariant();
}

qtmodern,QT,qt,开发语言,ui

4. 设置标题栏

要显示标题栏,只需要重新实现模型(model)的headerData()函数
视图中可以通过tableView->verticalHeader()->hide()函数进行标题栏的显示与设置

QVariant MyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
        switch (section) {
        case 0:
            return QString("first");
        case 1:
            return QString("second");
        case 2:
            return QString("third");
        }
    }
    return QVariant();
}

qtmodern,QT,qt,开发语言,ui

5. 添加可编辑的视图

/ mymodel.h
#include <QAbstractTableModel>
#include <QString>

const int COLS= 3;
const int ROWS= 2;

class MyModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    MyModel(QObject *parent = nullptr);
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; //重新实现此函数,以实现对被编辑的单元格的操作
    Qt::ItemFlags flags(const QModelIndex &index) const override;
private:
    QString m_gridData[ROWS][COLS];  //holds text entered into QTableView
signals:
    void editCompleted(const QString &);
};

模型(model)中的data()函数直接将m_gridData中的数据显示到视图中

QVariant MyModel::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole && checkIndex(index))
            return m_gridData[index.row()][index.column()];

    return QVariant();
}

要实现对于视图中项的的可编辑性,需要重新实现模型(model)中的setData()函数。每当视图中的某个项被编辑时,都会调用setData()函数,其中,参数index告诉函数那个项被编辑了,value代表被编辑的内容,role代表操作角色。如果要想设置勾选框,则操作角色就为Qt::CheckStateRole.

bool MyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (role == Qt::EditRole) {
        if (!checkIndex(index))
            return false;
            
        //将编辑的数据保存到m_gridData中
        m_gridData[index.row()][index.column()] = value.toString();
        
        //用于演示,将编辑的数据保存到一个字符串中
        QString result;
        for (int row = 0; row < ROWS; row++) {
            for (int col= 0; col < COLS; col++)
                result += m_gridData[row][col] + ' ';
        }
        
        //输出结果	
        std::cout << result std::endl;
        return true;
    }
    return false;
}
Qt::ItemFlags MyModel::flags(const QModelIndex &index) const
{
    return Qt::ItemIsEditable | QAbstractTableModel::flags(index);
}

6. 获取鼠标选中的项

利用QItemSelectionModel *selectionModel = tableView->selectionModel()可以获取到视图中选中的项,其中selectionModel 有一个信号&QItemSelectionModel::selectionChanged,即当被选中项发生改变时触发信号,利用该信号可以获取到所需要的选中项文章来源地址https://www.toymoban.com/news/detail-794051.html

//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <iostream>

QT_BEGIN_NAMESPACE
class QTableView; //forward declaration
class QItemSelection;
QT_END_NAMESPACE


class MainWindow : public QMainWindow
{
    Q_OBJECT
private:
    QTableView *tableView;
public:
    MainWindow(QWidget *parent = nullptr);
public slots:
    void showWindowTitle(const QString &title);

private slots:
    void selectionChangedSlot(const QItemSelection &newSelection, const QItemSelection &oldSelection);
};

#endif // MAINWINDOW_H
//mainwindow.cpp
#include "mainwindow.h"
#include "mymodel.h"

#include <QTableView>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , tableView(new QTableView(this))
{
    setCentralWidget(tableView);
    MyModel *myModel = new MyModel(this);
    tableView->setModel(myModel);

    //将项的编辑完成信号与处理函数进行绑定
    connect(myModel, &MyModel::editCompleted, this, &MainWindow::showWindowTitle);

    //将项的选中焦点变化与处理函数进行绑定
    QItemSelectionModel *selectionModel = tableView->selectionModel(); //选中对象
    connect(selectionModel, &QItemSelectionModel::selectionChanged, this, &MainWindow::selectionChangedSlot);
}

void MainWindow::showWindowTitle(const QString &title)
{
    setWindowTitle(title);
}

void MainWindow::selectionChangedSlot(const QItemSelection & /*newSelection*/, const QItemSelection & /*oldSelection*/)
{
    //获取选中项中的内容
    const QModelIndex index = tableView->selectionModel()->currentIndex();
    QString selectedText = index.data(Qt::DisplayRole).toString();
	
	//打印选中项的位置和内容
    QString showString = QString("%1, %2, %3").arg(index.row()).arg(index.column()).arg(selectedText);
    std::cout << showString.toStdString() << std::endl;
}

// mymodel.h
#include <QAbstractTableModel>
#include <QString>

const int COLS= 3;
const int ROWS= 2;

class MyModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    MyModel(QObject *parent = nullptr);
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; //重新实现此函数,以实现对被编辑的单元格的操作
    Qt::ItemFlags flags(const QModelIndex &index) const override;
private:
    QString m_gridData[ROWS][COLS];  //holds text entered into QTableView
signals:
    void editCompleted(const QString &);
};
//mymodel.cpp
#include "mymodel.h"

MyModel::MyModel(QObject *parent)
    : QAbstractTableModel(parent)
{
}

int MyModel::rowCount(const QModelIndex & /*parent*/) const
{
    return ROWS;
}

int MyModel::columnCount(const QModelIndex & /*parent*/) const
{
    return COLS;
}

QVariant MyModel::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole && checkIndex(index))
            return m_gridData[index.row()][index.column()];

    return QVariant();
}

bool MyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (role == Qt::EditRole) {
        if (!checkIndex(index))
            return false;
        //将数据保存到m_gridData
        m_gridData[index.row()][index.column()] = value.toString();
        //将所有项中的内容添加到result中
        QString result;
        for (int row = 0; row < ROWS; row++) {
            for (int col= 0; col < COLS; col++)
                result += m_gridData[row][col] + ' ';
        }
        emit editCompleted(result);
        return true;
    }
    return false;
}

Qt::ItemFlags MyModel::flags(const QModelIndex &index) const
{
    return Qt::ItemIsEditable | QAbstractTableModel::flags(index);
}

到了这里,关于Qt 模型(model)/视图(view)详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Qt扫盲-Model/View入门

    每个UI开发人员都应该了解ModelView编程, 表格格控件、列表格控件和树控件是gui中经常使用的组件。这些控件有两种不同的方式访问它们的数据。 1.传统方法 传统的方法就是让控件本身去储存数据,在控件内部有数据容器,这种方法非常直观,但是,在许多重要的应用程序中

    2024年02月13日
    浏览(40)
  • Qt Quick系列(7)—Model-View

    🚀作者:CAccept 🎂专栏:Qt Quick 在QML中,model和view由delegate连接,他们的关系如下👇 1、delegate 属性:delegate知道model的内容以及如何可视化它- 怎么显示 。 2、view知道delegate的概念以及如何布置它们- 怎么摆放 。 3、model属性:model只知道它所表示的数据- 要显示的内容集合 。

    2024年02月12日
    浏览(31)
  • Qt关于Model/View大数据量刷新的处理经验

    前段时间有同学咨询关于大数据量的Model刷新时卡顿的优化方案,通过评论留言的方式回答了一部分,但感觉不够全面。因为这个是之前项目重点解决的问题,处理的过程中收获颇多,这里就基于之前的项目经验进行完整的总结,希望对大家在处理类似问题的过程中能有所启

    2024年02月08日
    浏览(31)
  • 如何避免 QT 的 View/Model 模式产生消息激活的死循环?

    当收到QTableWidget的itemChanged信号时,关联的槽函数一般用于响应单元格数据的修改。它可以执行以下一些常见的工作: 更新数据:槽函数可以获取修改后的数据,并根据需要更新相关的数据结构或变量。 数据验证:槽函数可以对修改后的数据进行验证,检查其是否满足特定条

    2024年01月21日
    浏览(38)
  • 一文带你了解QT Model/View框架的设计思想和实现机制

    目录 1、QT Model/View框架简介 1.1、QT Model/View是什么? 1.2、QT Model/View框架核心思想 1.3、Model/View框架工作机制 1.4、Model/View框架的类 2、Model 2.1模型简介 2.2、模型索引 2.3、数据角色 2.4、QStringListModel 2.5、QFileSystemModel 2.6、QSortFilterProxyModel 3、View 4、Delegate 5、项选择模型 5.1、QIt

    2024年02月05日
    浏览(67)
  • 【Qt之模型视图】1. 模型和视图架构

    MVC(Model-View-Control)是一种源自 Smalltalk 的设计模式,通常用于构建用户界面。 MVC由三种类型的对象组成。模型是应用对象,用来表示数据;视图是模型的用户界面,用来显示数据;控制器定义了用户界面对用户输入的反应方式。在MVC之前,用户界面设计往往将这些对象混为

    2024年01月18日
    浏览(41)
  • Qt - 模型视图

    模型/视图结构将数据存储和界面展示分离,分别用不同的类实现 模型:存储数据 视图:界面上的视图组件显示模型中的数据;在视图组件里修改的数据会被自动保存在模型中 源数据 内存中的一个字符串列表 磁盘文件系统结构 数据库的一个数据表 sql查询结果 视图(视图组

    2024年02月12日
    浏览(26)
  • Qt6之模型和视图

    MVC是Model-View-Controller,即 模型 (Model)、 视图 (View)、 控制器 (Controller)。 模型 :用于管理数据; 视图 :就是呈现在用户面前的界面外观,视图负责把模型中的数据显示给用户; 控制器 :用于处理用户在用户界面的输入; MVC本质上目的是数据处理和显示分离,以提高灵活性

    2024年02月15日
    浏览(27)
  • Qt5开发及实例V2.0-第七章-Qt图形视图框架

    7.1.1 Graphics View的特点 Graphics View框架结构的主要特点如下。 (1)Graphics View框架结构中,系统可以利用Qt绘图系统的反锯齿、OpenGL工具来改善绘图性能。 (2)Graphics View支持事件传播体系结构,可以使图元在场景(scene)中的交互能力提高1倍,图元能够处理键盘事件和鼠标事

    2024年02月07日
    浏览(34)
  • 【Qt之模型视图】2. 模型类及QModelIndex模型索引、自定义模型

    在模型/视图体系结构中,模型提供了一个标准接口,视图和委托使用该接口访问数据。在Qt中,标准接口是由QAbstractItemModel类定义的。无论数据项如何存储在任何底层数据结构中,QAbstractItemModel的所有子类都会以层次结构来表示数据,这个结构包含了数据项表。视图使用约定

    2024年01月19日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包