Qt-模型和视图的学习

本文介绍了Qt中的模型/视图体系结构,模型作为数据源的接口,视图通过模型索引获取数据。模型中每个数据项由唯一索引标识,角色定义数据类型。模型的维度可通过rowCount和columnCount获取。data()函数返回指定位置的数据,headerData()返回行列信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

模型关系

模型关系
模型/视图体系结构
该模型与数据源进行通信,为架构中的其他组件提供接口。沟通的性质取决于数据源的类型以及模型的实施方式。
该视图从模型中获得模型索引 ; 这些是对数据项的引用。通过向模型提供模型索引,视图可以从数据源中检索数据项。
在标准视图中,委托呈现数据项。编辑项目时,委托使用模型索引直接与模型进行通信。

模型

由上面的关系图可以看出,模型并不存储数据,有一个数据体来存储,可能是stringlist或者是别的数据体来负责具体的存储数据,用命令返回模型的数据其实就是返回数据体的数据,内部已经封装了。
模型中,每个数据都有一个唯一的索引指定(QModelIndex)。用索引可以表示数据的位置
索引示例
该图显示了一个基本模型的表示形式,每一个项目由一个行号和列号进行定位

//通过指定QMOdelIndex()为父项来表示模型中的顶级项目
QModelIndex A = model->index(0, 0, QModelIndex());//A数据的位置
QModelIndex B = model->index(1, 1, QModelIndex());//b数据的位置
QModelIndex C = model->index(2, 1, QModelIndex());//C数据的位置

树状结构
这种树状结构的模型,必须要指定父项目,不然数据就会出错

QModelIndex indexA = model->index(0, 0, QModelIndex());
QModelIndex indexB = model->index(1, 0, indexA);//指定父项为A。从A下的索引开始查找
QModelIndex indexC = model->index(2, 1, QModelIndex());

项目角色

项目角色
角色指出了从模型中引用的是哪一种类型的数据
一般会使用DisplayRole角色,因为这个是返回的文本类型。
角色类型可以自行查看QT文档

概要

  • 模型索引以独立于任何基础数据结构的方式给出视图并委托有关模型提供的项目位置的信息。
  • 项目由其行号和列号引用,并由父项的模型索引引用。QModelIndex(row, column, parent)
  • 模型索引由模型根据其他组件的请求构建,如视图和委托。
  • 如果在使用index()请求索引时为父项目指定了有效的模型索引,则返回的索引引用模型中该父项目下的项目。获得的索引是指该项目的一个子项。
  • 如果在使用index()请求索引时为父项指定了无效的模型索引,则返回的索引将引用模型中的顶级项目。
  • 该角色的不同种类与项目相关的数据进行了区分。
  • 可以使用rowCount()和columnCount()来找到模型的维度。这些函数通常需要指定父模型索引。
  • 模型索引用于访问模型中的项目。需要行,列和父模型索引来指定项目。
  • 要访问模型中的顶级项目,请使用空模型索引作为父级索引QModelIndex()。
  • 项目包含不同角色的数据。要获取特定角色的数据,模型索引和角色都必须提供给模型。

行和列

可以把一个模型看成一个表格进行访问,在这个表格中,可以用行号和列号来指定某一个数据的位置。但是这并不意味着底层的数据纯在一个数组结构中;行号和列号的使用知识一个允许组件相互通信的约定。

data()

此函数用于返回模型中的数据
根据QModelIndex中的行列号指定

QVariant StringListModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())//先判断是否有效
        return QVariant();//无效则返回无效的变体型

    if (index.row() >= stringList.size())//如果行号超过数据存储的大小
        return QVariant();//返回无效的变体型

    if (role == Qt::DisplayRole || role == Qt::EditRole)//如果角色等于可以用文本呈现的方式,意思就是数据可以用QString来显示,或者数据的角色是可以编辑的。
        return stringList.at(index.row);//先找到这个模型的行号,然后在存储数据的stringList里面找到相对应的数据,这个内部的数据体是stringlist,stringlist负责具体的存储数据。所以想要获得某项模型的数据,其实就是找到他的行列号之后获得对应数据体的数据。
    else
        return QVariant();//返回无效变体型
}

headerData()

返回行列号。

函数原型
QVariant QAbstractItemModel::headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const
// section 返回的序号
// orientation 返回的方向,有Qt::Horizontal 和 Qt::vertical.分别对应列和行。
// role 角色,分为好多种,自行查文档
QVariant AbstractItemModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if(role == Qt::DisplayRole)//如果数据的角色可以用QString来代表
    {
        if(orientation == Qt::Horizontal)//如果方向是水平的
            return section + 1;
        else if(orientation == Qt::Vertical)//如果方向是垂直的
            return section + 1;
    }
    return QVariant();//返回无效变体型。
}

rowCount 和 columnCount

由于一般都有一个数据载体来承载数据。例如list等等
把输入写入完成的时候获得list的size即可。这个就是行数,如果获得列数,就得二维数组了,再判断每个数组的长度即可。

完整代码

头文件

#ifndef ABSTRACTITEMMODEL_H
#define ABSTRACTITEMMODEL_H

#include <QAbstractTableModel>

class AbstractItemModel : public QAbstractTableModel ///继承tablemodel类
{
    Q_OBJECT
public:
    explicit AbstractItemModel(QObject *parent = 0);

    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
    int rowCount(const QModelIndex &parent) const override;///< override关键字防止函数覆盖
    int columnCount(const QModelIndex &parent) const override;
    QVariant data(const QModelIndex &index, int role) const override;

    /// @brief 获取数据到本类
    bool getData(QVariant &data);
    QList<QList<QVariant>> saveData;
    int m_rowCount;///< 行数
    int m_columnCount;///< 列数
signals:

public slots:

private:
    QStringList m_headerData;///< 
};

#endif // ABSTRACTITEMMODEL_H

源代码

#include "abstractitemmodel.h"

AbstractItemModel::AbstractItemModel(QObject *parent) : QAbstractTableModel(parent)
{
    m_headerData << "姓名" << "性别" << "身份证号" << "专业" << "层次" << "学校" << "学号" << "考生号" << "录入人" << "联系方式";
}

QVariant AbstractItemModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    //section可以开看做是一个数字或者是一个索引,只是指向的是列号或者行号。从0开始计算
    if(role == Qt::DisplayRole)
    {
        if(orientation == Qt::Horizontal)//如果是水平的即为列的时候时候
            return m_headerData[section];//返回某个数据
        else if(orientation == Qt::Vertical)//如果为垂直就是行
            return section + 1;
    }
    return QVariant();
}

int AbstractItemModel::rowCount(const QModelIndex &/*parent*/) const
{
    return m_rowCount;
}

int AbstractItemModel::columnCount(const QModelIndex &/*parent*/) const
{
    return 10;
}

QVariant AbstractItemModel::data(const QModelIndex &index, int role) const
{
    //判断是否有效
    if(! index.isValid())
        return QVariant();
    if(role == Qt::DisplayRole)//判断角色是否正确
    {
        const int row = index.row();
        const int column = index.column();
        if(row >= saveData.size())// 如果索引大于数据载体的大小肯定会出错的,是一个无效的数据
            return QVariant();
        if(column >= saveData.at(row).size())// 某行的大小
            return QVariant();
        return saveData.at(row).at(column);//返回某行某列
    }
    return QVariant();

}

bool AbstractItemModel::getData(QVariant &data)//这个函数我自己写的,用于获得外部的一个数据。可以自己写自己的
{
    /*!
     * \brief 获得数据进行分解处理成一个QList<QList<QVariant>>数据类型。
     * 因为获取的数据是一个QVariant类型的,所以先
     */
    QVariantList varRows = data.toList();
    if(varRows.isEmpty())
        return false;
    m_rowCount = varRows.size();
    m_columnCount = 0;
    QVariantList rowData;
    for(int i=0; i<m_rowCount; i++)
    {
        rowData = varRows[i].toList();//每行都再次分解成list
        saveData.push_back(rowData);//压入数据
    }
    return true;
}
本课程详细、全面地介绍了 Qt 开发中的各个技术细节,并且额外赠送在嵌入式端编写Qt程序的技巧。整个课程涵盖知识点非常多,知识模块囊括 Qt-Core 组件、QWidgets、多媒体、网络、绘图、数据库,超过200个 C++ 类的分析使用,学完之后将拥有 Qt 图形界面开发的非常坚实的功底。 每个知识点不仅仅会通过视频讲解清楚,并且会配以精心安排的实验作业,用来保证学习过程中切实掌握核心技术概念,通过实验来巩固,通过实验来检验,实验与作业的目的是发现问题,发现技术盲点,通过答疑沟通夯实技术技能。注意:本套视频教程来源于线下的实体班级,因此视频中有少量场景对话学生问答,对此比较介意的亲们谨慎购买。注意:本套视频教程包含大量课堂源码,包含对应每个知识点的精心编排的作业。由于优快云官方规定在课程介绍中不能出现作者的联系方式,因此在这里无法直接给出QQ答疑号,视频中的源码、资料作业文档链接统一在购买后从优快云平台跟我沟通,我会及时回复跟进。注意:本套视频教程包含全套10套作业题,覆盖所有视频知识点,循序渐进,各个击破,作业总纲如下:下面是部分作业题目展示,每道题都有知识点说明,是检验学习效果的一大利器:(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)…… ……
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值