Qt 实战(10)模型视图 | 10.2、自定义模型


前言:

Qt的模型/视图(Model/View)架构是Qt中一个强大的特性,它允许数据的表示(Model)与数据的展示(View)分离,极大地提高了程序的灵活性和可重用性。自定义模型是Qt开发中的一项重要技能,特别是在处理复杂数据结构或需要特殊数据交互方式时。

一、自定义模型

1、模型相关的类

在Qt中,自定义模型通常意味着你需要从QAbstractItemModel或其子类(如QAbstractListModelQAbstractTableModel)派生你的类。这些基类提供了管理数据的基本接口,包括数据的插入、删除、修改以及查询等。

  • QAbstractItemModel:这是最通用的模型基类,适用于树形结构的数据。
  • QAbstractListModel:适用于列表或一维数组类型的数据。
  • QAbstractTableModel:适用于表格或二维数组类型的数据。

下面是模型类的继承图,如下:

在这里插入图片描述

2、自定义模型

2.1、继承QAbstractTableModel

要自定义一个QAbstractTableModel,需要从该类派生一个新的类,并在其中实现一些关键的方法。这些方法定义了模型如何与表格视图交互,包括数据的获取、行列的数量、数据项的修改等。如下:

#include <QAbstractTableModel>  
  
class MyModel : public QAbstractTableModel {  
    Q_OBJECT  
  
public:  
    // 构造函数、析构函数等  
    MyModel (QObject *parent = nullptr);  
    ~MyModel ();  
  
    // 必须重写的方法  
    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;  
  
    // 可选重写的方法,用于编辑等  
    Qt::ItemFlags flags(const QModelIndex &index) const override;  
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;  
    
    // 可选重写的方法,用于设置表头显示的信息
    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
  
    // 自定义方法
    void InitData();
  
private:  
    // 数据存储,这里以QStringList的QList为例  
    QVector<QString> m_headers;
    QVector<QVector<QString>> m_data;
};

2.2、实现关键方法

需要实现在类中声明的所有方法,下面是关键方法的实现

  • rowCountcolumnCount 方法应该返回表格的行数和列数。
  • data 方法用于根据索引和角色返回数据。在表格视图中,这通常用于显示数据。
  • flags 方法定义了表格项的属性,如是否可编辑、可选择等。
  • setData 方法用于更新模型中的数据。如果模型是可编辑的,那么这个方法非常重要。
  • headerData 方法设置表头显示的信息。
#include "MyModel.h"

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

MyModel::~MyModel()
{

}

void MyModel::InitData()
{
    // 初始化数据  
    m_headers << "Name" << "Age" << "Sex";

    QVector<QString> data1 = { "Alice", "30", "女" };
    QVector<QString> data2 = { "Bob", "25", "男" };
    QVector<QString> data3 = { "Charlie", "35", "女" };
    m_data << data1 << data2 << data3;
}

int MyModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_data.size();
}

int MyModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_headers.size();
}

QVariant MyModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || index.row() >= m_data.size() || index.column() >= m_headers.size())
        return QVariant();

    if (role == Qt::DisplayRole) {
        const QVector<QString> &row = m_data[index.row()];
        return row[index.column()];
    }

    return QVariant();
}

bool MyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (index.isValid() && index.row() < m_data.size() && index.column() < m_headers.size() && role == Qt::EditRole) {
        QVector<QString> &row = m_data[index.row()];
        row[index.column()] = value.toString();
        emit dataChanged(index, index);
        return true;
    }
    return false;
}

QVariant MyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
        return m_headers[section];
    }

    // 可以默认去除每行的编号
    return QVariant();
}


Qt::ItemFlags MyModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return Qt::NoItemFlags;

    return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
}

2.3、使用自定义模型

自定义模型创建完,可以将这个模型设置为某个表格视图(如QTableView)的模型,如下:

// 假设你已经创建了一个MyTableModel的实例叫做model  
QTableView *tableView = new QTableView(this);  
tableView->setModel(model);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值