您当前的位置: 首页 > 

龚建波

暂无认证

  • 3浏览

    0关注

    313博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

QAbstractTableModel基本使用:数据展示与编辑

龚建波 发布时间:2020-09-16 00:56:46 ,浏览量:3

前言

QAbstractTableModel 继承自 QAbstractItemModel,主要用于为 QTableView 提供相关接口,我们可以子类化该抽象类并实现相关接口。本文主要讲 QAbstractTableModel 数据展示和编辑相关的接口如何使用。

表格数据的展示

继承 QAbstractTableModel 后,至少要实现三个纯虚函数接口才能进行实例化:

virtual int rowCount(const QModelIndex &parent = QModelIndex()) const = 0;
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const = 0;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const = 0;

前两个接口比较简单,直接返回展示表格的行列,参数忽略(这个 parent 参数主要是给树形列表用的)。我们主要关注 data 这个接口,当 view 或者 delegate 需要从 model 获取单元格相关数据(如显示内容、颜色等)时会调用该接口,只有两个参数,模型索引和 role ,数据通过返回值传出来。

QModelIndex 模型索引,提供了对信息的临时引用,可用于通过模型检索或修改数据,一般情况下我们只需要取他附带的行列值即可。

获取数据的类型是通过 role 角色参数来区分的,这是一个 Qt::ItemDataRole 枚举,一般用已有的 role 枚举就足够了。 

    enum ItemDataRole {
        DisplayRole = 0,
        DecorationRole = 1,
        EditRole = 2,
        ToolTipRole = 3,
        StatusTipRole = 4,
        WhatsThisRole = 5,
        // Metadata
        FontRole = 6,
        TextAlignmentRole = 7,
        BackgroundRole = 8,
        ForegroundRole = 9,
#if QT_DEPRECATED_SINCE(5, 13) // ### Qt 6: remove me
        BackgroundColorRole Q_DECL_ENUMERATOR_DEPRECATED = BackgroundRole,
        TextColorRole Q_DECL_ENUMERATOR_DEPRECATED = ForegroundRole,
#endif
        CheckStateRole = 10,
        // Accessibility
        AccessibleTextRole = 11,
        AccessibleDescriptionRole = 12,
        // More general purpose
        SizeHintRole = 13,
        InitialSortOrderRole = 14,
        // Internal UiLib roles. Start worrying when public roles go that high.
        DisplayPropertyRole = 27,
        DecorationPropertyRole = 28,
        ToolTipPropertyRole = 29,
        StatusTipPropertyRole = 30,
        WhatsThisPropertyRole = 31,
        // Reserved
        UserRole = 0x0100
    };

最后是返回数据,这是一个 QVariant 类型的值,可以理解为任意类型。对于 Qt 常用的数据类型可以直接用 toXXX 接口转换,自定义类型可以用 convert 和 value 接口装箱拆箱。

了解了接口之后来一个简单的例子,看看具体是怎么用的:

#include 

class MyTableModel : public QAbstractTableModel
{
    Q_OBJECT
    struct ModelItem
    {
        QString name;
        int sex;
        int age;
        int score;
    };

public:
    explicit MyTableModel(QObject *parent = nullptr)
        : QAbstractTableModel(parent)
    {
        modelData=QList{
        {"aa",1,20,90},
        {"bb",1,23,91},
        {"cc",0,21,95},
    };
    }

    //获取行数
    int rowCount(const QModelIndex &parent = QModelIndex()) const override
    {
        return modelData.count();
    }
    //获取列数
    int columnCount(const QModelIndex &parent = QModelIndex()) const override
    {
        return 4;
    }
    //获取单元格数据
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
    {
        if(!index.isValid())
            return QVariant();
        if(role == Qt::DisplayRole || role == Qt::EditRole)
        {
            const int row=index.row();
            switch(index.column())
            {
            case 0: return modelData.at(row).name;
            case 1: return (modelData.at(row).sex==0)?"woman":"man";
            case 2:return modelData.at(row).age;
            case 3:return modelData.at(row).score;
            }
        }
        return QVariant();
    }

private:
    //数据
    QList modelData;
};

然后使用 view 的 setModel 接口将 new 出来的 model 实例设置给 view:

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

显示如下:

单元格启用编辑

如果使用通用的编辑功能(通过 view 的 editTriggers 设置触发编辑状态的方式,一般为双击),model 需要实现两个接口:

//设置单元格数据
bool setData(const QModelIndex &index, const QVariant &value,int role = Qt::EditRole) override;
//单元格的可操作性标志位,如可编辑,可选中等
Qt::ItemFlags flags(const QModelIndex& index) const override;

flags 接口告诉我们某个单元格支持哪些操作,返回一个 Qt::ItemFlags 枚举值:

    enum ItemFlag {
        NoItemFlags = 0,
        ItemIsSelectable = 1,
        ItemIsEditable = 2,
        ItemIsDragEnabled = 4,
        ItemIsDropEnabled = 8,
        ItemIsUserCheckable = 16,
        ItemIsEnabled = 32,
        ItemIsAutoTristate = 64,
#if QT_DEPRECATED_SINCE(5, 6)
        ItemIsTristate = ItemIsAutoTristate,
#endif
        ItemNeverHasChildren = 128,
        ItemIsUserTristate = 256
    };

如果仅仅是需要编辑,只需要返回 :

    return Qt::ItemIsEnabled|Qt::ItemIsEditable;

当我们双击单元格,允许编辑的单元格会创建一个编辑组件(这是由 delegate 完成的),我们修改数据后回车或切换焦点完成编辑,编辑好的数据会通过 setData 接口设置给 model。

setData 接口参数含义和 data 差不多,只是有一个设置成功或失败的返回值,接下来看下基本的写法:

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].sex = (value.toString() == "man")?1:0; break;
        case 2: modelData[row].age = value.toInt(); break;
        case 3: modelData[row].score = value.toInt(); break;
        }
        //发送信号触发刷新
        emit dataChanged(index, index, QVector()             
关注
打赏
1655829268
查看更多评论
0.2567s