Qt-模型和视图的学习

模型关系

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

模型

由上面的关系图可以看出,模型并不存储数据,有一个数据体来存储,可能是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;
}

猜你喜欢

转载自blog.csdn.net/wayrboy/article/details/79245968