您当前的位置: 首页 > 

龚建波

暂无认证

  • 3浏览

    0关注

    313博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

QAbstractTableModel基本使用:数据加载以及增删行列

龚建波 发布时间:2020-09-17 01:25:01 ,浏览量:3

前言

QAbstractTableModel 继承自 QAbstractItemModel,主要用于为 QTableView 提供相关接口,我们可以子类化该抽象类并实现相关接口。本文主要讲 QAbstractTableModel 数据的加载与更新,以及行列的增删。

(请确保自己已经熟悉了 rowCount、columnCount、data 等基础的接口)

加载数据并刷新

当我们想重置 model 的数据时,可以定义一个成员函数,然后将重置的逻辑放在 beginResetModel 和 endResetModel 两个函数调用之间,这样 model 就能正常的刷新数据。调用 beginResetModel 之后,将触发modelAboutToBeReset信号,而 endResetModel 会触发 modelReset 信号。

void MyTableModel::setModelData(const QList &datas)
{
    //重置model数据之前调用beginResetModel,此时会触发modelAboutToBeReset信号
    beginResetModel();
    //重置model中的数据
    modelData=datas;
    //数据设置结束后调用endResetModel,此时会触发modelReset信号
    endResetModel();  
    //注意:reset model后,选中的item会失效,我们可以自己写保存和恢复选中项的逻辑
}

要注意的是,model 重置后选中项也失效了,我们可以自己写保存和恢复选中项的逻辑,比如在 view 中关联这两个 reset 信号。

    QTableView *table=ui->tableView;
    model=new MyTableModel(ui->tableView);
    table->setModel(model);

    //保存和恢复model选中项,因为在resetModel后会失效
    connect(model,&MyTableModel::modelAboutToBeReset,this,[=]{
        selectedIndex=table->currentIndex();
    },Qt::DirectConnection);
    connect(model,&MyTableModel::modelReset,this,[=]{
        //不用担心无效的index,接口内部会处理
        table->setCurrentIndex(selectedIndex);
    },Qt::DirectConnection);

如果表的行列数是固定的,只是数据变更了,我们可以用 dataChanged 信号来请求刷新。

    //重置model中的数据,此时行列数一致
    modelData=datas;
    //如果表的行列数是固定的,只是数据变更了,我们可以用 dataChanged 信号来请求刷新。
    emit dataChanged(index(0,0),index(RowMax-1,ColMax-1),QVector());
行列动态增删

因为我做这个表格列是固定的,所以就只用增删行来讲解,操作都是类似的。

增删行相关接口(虚函数是我们需要实现的,增删单行的其实也是回调增删多行的接口):

//插入相关接口
bool insertColumn(int column, const QModelIndex &parent = QModelIndex())
virtual bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex())
bool insertRow(int row, const QModelIndex &parent = QModelIndex())
virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex())
//删除相关接口
bool removeColumn(int column, const QModelIndex &parent = QModelIndex())
virtual bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex())
bool removeRow(int row, const QModelIndex &parent = QModelIndex())
virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex())

类似 resetModel ,增删行的逻辑也要放在 beginXX 和 endXXX 的调用之间:

bool MyTableModel::insertRows(int row, int count, const QModelIndex &parent)
{
    //row为0就是开始,为rowcount就在尾巴
    if(rowtableView->currentIndex().row()+1,1);
    model->insertRow(ui->tableView->currentIndex().row()+1);
}

void DemoTableModel::delRow()
{
    //删除选中行
    //model->removeRows(ui->tableView->currentIndex().row(),1);
    model->removeRow(ui->tableView->currentIndex().row());
}

如果我们想将有效的数据插入,可以自定义一个接口,比如:

bool MyTableModel::insertModelData(int row, const MyModelItem &datas)
{
    //row为0就是开始,为rowcount就在尾巴
    if(rowrowCount())
        return false;
    //需要将操作放到beginInsertRows和endInsertRows两个函数调用之间
    beginInsertRows(QModelIndex(), row, row);
    //在接口对应行插入空数据
    modelData.insert(row,datas);
    endInsertRows();
    return true;
}
结束语

数据展示和修改接口加上增删行已经能满足基本的需求了。下一篇我准备写 model 中表头相关接口的使用。

参考

官方文档:https://doc.qt.io/qt-5/qabstracttablemodel.html

官方文档:https://doc.qt.io/qt-5/model-view-programming.html

主要代码

(因为有点多,所以放最后)

#ifndef MYTABLEMODEL_H
#define MYTABLEMODEL_H

#include 

/**
 * @brief 表格展示的一行的数据结构,随便写的
 */
struct MyModelItem
{
    QString name; //姓名
    int age; //年龄
    QString info; //相关信息
};

/**
 * @brief 自定义TableModel,用于展示接口的使用
 * @details
 * 继承QAbstractTableModel需要实现至少三个接口:
 * rowCount、columnCount、data
 */
class MyTableModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    explicit MyTableModel(QObject *parent = nullptr);

    //自定义导入导出数据的接口
    void setModelData(const QList &datas);
    QList getModelData() const;
    //自定义插入行数据
    bool insertModelData(int row,const MyModelItem &datas);

    //获取表头数据
    //QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
    //设置表头数据
    //bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override;

    //获取行数
    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;

    //添加行列
    bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
    //bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override;

    //移除行列
    bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
    //bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override;

private:
    //数据
    QList modelData;
};


#endif // MYTABLEMODEL_H
#include "MyTableModel.h"

MyTableModel::MyTableModel(QObject *parent)
    : QAbstractTableModel(parent)
{

}

void MyTableModel::setModelData(const QList &datas)
{
    //重置model数据之前调用beginResetModel,此时会触发modelAboutToBeReset信号
    beginResetModel();
    //重置model中的数据
    modelData=datas;
    //数据设置结束后调用endResetModel,此时会触发modelReset信号
    endResetModel();
    //注意:reset model后,选中的item会失效,我们可以自己写保存和恢复选中项的逻辑
    //如果表的行列数是固定的,只是数据变更了,我们可以用 dataChanged 信号来请求刷新。
    //emit dataChanged(index(0,0),index(RowMax-1,ColMax-1),QVector());
}

QList MyTableModel::getModelData() const
{
    //将内存数据返回
    return modelData;
}

bool MyTableModel::insertModelData(int row, const MyModelItem &datas)
{
    //row为0就是开始,为rowcount就在尾巴
    if(rowrowCount())
        return false;
    //需要将操作放到beginInsertRows和endInsertRows两个函数调用之间
    beginInsertRows(QModelIndex(), row, row);
    //在接口对应行插入空数据
    modelData.insert(row,datas);
    endInsertRows();
    return true;
}

/*QVariant MyTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    // FIXME: Implement me!
}

bool MyTableModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
{
    if (value != headerData(section, orientation, role)) {
        // FIXME: Implement me!
        emit headerDataChanged(orientation, section, section);
        return true;
    }
    return false;
}*/


int MyTableModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;
    //返回表格行数
    return modelData.count();
}

int MyTableModel::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;
    //返回表格列数
    return 3;
}

QVariant MyTableModel::data(const QModelIndex &index, int role) const
{
    if(!index.isValid())
        return QVariant();
    if(role == Qt::DisplayRole || role == Qt::EditRole)
    {
        //DisplayRole返回显示的文本值
        const int row = index.row();
        switch(index.column())
        {
        case 0: return modelData.at(row).name;
        case 1: return modelData.at(row).age;
        case 2: return modelData.at(row).info;
        }
    }
    return QVariant();
}

bool MyTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    //将界面修改的值进行保存
    if (index.isValid() && role == Qt::EditRole) {
        const int row = index.row();
        switch(index.column())
        {
        case 0: modelData[row].name = value.toString(); break;
        case 1: modelData[row].age = value.toInt(); break;
        case 2: modelData[row].info = value.toString(); break;
        }
        //发送信号触发刷新
        emit dataChanged(index, index, QVector() setModelData(new_data);
}

void DemoTableModel::getData()
{
    //调用自定义接口获取model数据
    //QList old_data=model->getModelData();
}

void DemoTableModel::addRow()
{
    //在选中行和下一行之间插入
    //model->insertRows(ui->tableView->currentIndex().row()+1,1);
    //model->insertRow(ui->tableView->currentIndex().row()+1);
    QRandomGenerator *random=QRandomGenerator::global();
    model->insertModelData(ui->tableView->currentIndex().row()+1,{
                               QString("name new"),
                               random->bounded(20,40),
                               QString("info new %1").arg(random->bounded(0,100))
                           });
}

void DemoTableModel::delRow()
{
    //删除选中行
    //model->removeRows(ui->tableView->currentIndex().row(),1);
    model->removeRow(ui->tableView->currentIndex().row());
}

 

关注
打赏
1655829268
查看更多评论
立即登录/注册

微信扫码登录

0.0367s