子类化QAbstractTableModel,实现table列排序和整列拖动功能

子类化QAbstractTableModel,实现table列排序和整列拖动功能

本程序基于Qt5.9.9,Qt creator 4.11.0实现。
效果图

在这里插入图片描述

1、子类化QAbstractTableModel

主要是实现QAbstractTableModel中的rowCount、columnCount、data这三个纯虚函数;

headerData是用来实现上方和左侧的头显示的接口,这里我也重新override了。

下面看主要代码:

头文件MyTableModel.h

#ifndef MYTABLEMODEL_H
#define MYTABLEMODEL_H
#include <QAbstractTableModel>
#include <vector>
#include <QDateTime>

typedef struct StuInfo
{
    QString id_;
    QString name_;
    int age_;
    float score_;
    QDateTime time_;
}STUINFO;

class MyTableModel : public QAbstractTableModel
{
public:
    MyTableModel(QObject *parent = 0);
    // 设置数据源
    void setStudents(const std::vector<STUINFO> &students);
    // 主要override的函数
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    QVariant data(const QModelIndex &index, int role) const override;
    QVariant headerData(int section, Qt::Orientation orientation,
                        int role = Qt::DisplayRole) const override;
    // 排序用到的函数
    void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
    bool lessThan(const QVariant &left,const QVariant &right);

private:
    // 数据源
    std::vector<STUINFO> m_students;
    // 上方表格显示的头名称
    QStringList headers;
};

#endif // MYTABLEMODEL_H

rowCount、columnCount、data、headerData接口的具体实现

int MyTableModel::rowCount(const QModelIndex &parent) const
{
    // 源数据数量
    return m_students.size();
}

int MyTableModel::columnCount(const QModelIndex &parent) const
{
    // 头数量
    return headers.size();
}

QVariant MyTableModel::data(const QModelIndex &index, int role) const
{
    if(!index.isValid())
        return QVariant();
    switch(role){
            // 对齐模式
    case Qt::TextAlignmentRole:
        return int(Qt::AlignHCenter | Qt::AlignVCenter);
    case Qt::DisplayRole:
        int row = index.row();
        int column = index.column();
        switch(column){
        case 0:
            return m_students[row].id_;
        case 1:
            return m_students[row].name_;
        case 2:
            return m_students[row].age_;
        case 3:
            return m_students[row].score_;
        case 4:
            return m_students[row].time_;
        default:
            return QVariant();
        }
    }
    return QVariant();
}

QVariant MyTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if(role != Qt::DisplayRole)
        return QVariant();
    if(orientation == Qt::Horizontal){
        // 水平方向的就是上方显示的header
        return headers[section];
    }else{
        // 垂直方向就是左侧显示的header,这里用section+1的方式返回,效果就是1,2....
        return section + 1;
    }
    return QVariant();
}

2、实现案列排序功能

首先需要在QTableView上设置可以排序,使用setSortingEnabled(true)这个接口进行设置

然后override QAbstractTableModel接口中的sort接口实现自己的排序方式,代码如下:

void MyTableModel::sort(int column, Qt::SortOrder order)
{
    if(m_students.empty() || column < 0 || column >= headers.size())
        return;

    const bool is_asc = (order == Qt::AscendingOrder);

    std::sort(m_students.begin(),m_students.end(),
              [column,is_asc,this](const STUINFO &left, const STUINFO &right){
       QVariant left_val, right_val;
       switch(column){
       case 0:
           left_val = left.id_;
           right_val = right.id_;
           break;
       case 1:
           left_val = left.name_;
           right_val = right.name_;
           break;
       case 2:
           left_val = left.age_;
           right_val = right.age_;
           break;
       case 3:
           left_val = left.score_;
           right_val = right.score_;
           break;
       case 4:
           left_val = left.time_;
           right_val = right.time_;
           break;
       }
       return is_asc ?
                   lessThan(left_val, right_val):
                   lessThan(right_val,left_val);
    });
    dataChanged(index(0,0),index(m_students.size()-1,headers.size()-1));
}

bool MyTableModel::lessThan(const QVariant &left, const QVariant &right)
{
    qDebug() << "^^^^^^" << left.userType() << "******" << right.userType() << "&&&&" << QMetaType::UnknownType;
    if(left.userType() == QMetaType::UnknownType)
        return false;
    if(right.userType() == QMetaType::UnknownType)
        return true;
    switch (left.userType()) {
    case QMetaType::Int:
        return left.toInt() < right.toInt();
    case QMetaType::Float:
        return left.toFloat() < right.toFloat();
    case QMetaType::Double:
        return left.toDouble() < right.toDouble();
    case QMetaType::QDateTime:
        return left.toDateTime() < right.toDateTime();
    case QMetaType::QString:
        break;
    default:
        break;
    }
    return left.toString().localeAwareCompare(right.toString()) < 0;
}

详情可参考:https://blog.csdn.net/gongjianbo1992/article/details/108674875

3、实现整列拖拽功能

只需要在QTableView设置horizontalHeader的setSectionMovable为true便可。

代码如下:main.cpp

#include <QApplication>
#include "mytablemodel.h"
#include <QTableView>
#include <QHeaderView>
#include <vector>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    std::vector<STUINFO> stus;
    stus.push_back({"1","wangqiang",23,120, QDateTime::fromString("20170112 12:13:14","yyyyMMdd HH:mm:ss")});
    stus.push_back({"2","liuwei",21,110.2, QDateTime::fromString("20170113 12:13:14","yyyyMMdd HH:mm:ss")});
    stus.push_back({"3","zhaoqian",22,150.2, QDateTime::fromString("20170112 15:13:14","yyyyMMdd HH:mm:ss")});
    stus.push_back({"4","wuxue",25,112.3, QDateTime::fromString("20170114 12:21:14","yyyyMMdd HH:mm:ss")});
    stus.push_back({"5","lifei",24,134.2, QDateTime::fromString("20170122 12:22:14","yyyyMMdd HH:mm:ss")});
    stus.push_back({"6","qianjiang",22,120.1, QDateTime::fromString("20170212 13:13:14","yyyyMMdd HH:mm:ss")});
    MyTableModel model;
    model.setStudents(stus);

    QTableView view;
    view.setModel(&model);
    view.setAlternatingRowColors(true);
    // 设置排序功能
    view.setSortingEnabled(true);
    // 设置水平头可拖动功能
    view.horizontalHeader()->setSectionsMovable(true);
    view.show();
    return a.exec();
}

完整代码可私信发送,谢谢!

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
`QStandardItemModel` 是 `Qt` 提供的一个很方便的模型类,它可以用来存储和管理 `QStandardItem` 的表。但是,如果你需要更精细的控制和自定义功能,你可能需要使用 `QAbstractTableModel` 来实现自己的模型类。 以下是一个简单的例,演示如何用 `QAbstractTableModel` 实现 `QStandardItemModel` 的基本功能: ```cpp class MyTableModel : public QAbstractTableModel { public: MyTableModel(QObject* parent = nullptr) : QAbstractTableModel(parent) {} int rowCount(const QModelIndex& parent = QModelIndex()) const override { if (parent.isValid()) { return 0; } return m_items.count(); } int columnCount(const QModelIndex& parent = QModelIndex()) const override { if (parent.isValid()) { return 0; } return m_headers.count(); } QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override { if (!index.isValid()) { return QVariant(); } if (role == Qt::DisplayRole || role == Qt::EditRole) { return m_items[index.row()][index.column()].text(); } return QVariant(); } bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override { if (!index.isValid()) { return false; } if (role == Qt::EditRole) { m_items[index.row()][index.column()].setText(value.toString()); emit dataChanged(index, index); return true; } return false; } QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { return m_headers[section]; } return QVariant(); } Qt::ItemFlags flags(const QModelIndex& index) const override { if (!index.isValid()) { return Qt::NoItemFlags; } return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; } void setRowCount(int count) { if (count == rowCount()) { return; } if (count < rowCount()) { beginRemoveRows(QModelIndex(), count, rowCount() - 1); m_items.resize(count); endRemoveRows(); } else { beginInsertRows(QModelIndex(), rowCount(), count - 1); m_items.resize(count); endInsertRows(); } } void setColumnCount(int count) { if (count == columnCount()) { return; } if (count < columnCount()) { beginRemoveColumns(QModelIndex(), count, columnCount() - 1); m_headers.resize(count); for (auto& row : m_items) { row.resize(count); } endRemoveColumns(); } else { beginInsertColumns(QModelIndex(), columnCount(), count - 1); m_headers.resize(count); for (auto& row : m_items) { row.resize(count); } endInsertColumns(); } } void setHeaderData(int section, Qt::Orientation orientation, const QVariant& value, int role = Qt::EditRole) override { if (role != Qt::EditRole || orientation != Qt::Horizontal || section < 0 || section >= columnCount()) { return; } m_headers[section] = value.toString(); emit headerDataChanged(orientation, section, section); } private: QList<QList<QStandardItem>> m_items; QStringList m_headers; }; ``` 在这个例中,我们定义了一个叫做 `MyTableModel` 的类,它继承自 `QAbstractTableModel`。它包含一个 `QList<QList<QStandardItem>>` 类型的成员变量 `m_items`,用于存储所有的数据项,以及一个 `QStringList` 类型的成员变量 `m_headers`,用于存储所有的标题。 我们重写了 `rowCount()` 和 `columnCount()` 函数来返回行数和数。在 `data()` 函数中,我们返回指定单元格的数据,同时处理了 `Qt::DisplayRole` 和 `Qt::EditRole` 两种角色。在 `setData()` 函数中,我们设置指定单元格的数据,并发出 `dataChanged()` 信号来通知视图更新界面。在 `headerData()` 函数中,我们返回指定的标题。在 `flags()` 函数中,我们指定单元格的属性,使其可编辑。 最后,我们还实现了 `setRowCount()`、`setColumnCount()` 和 `setHeaderData()` 函数,用于动态改变行数、数和标题。 希望这个例能帮到你!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值