前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >60.QT-QabstractTableModel模型、重写sort方法排序

60.QT-QabstractTableModel模型、重写sort方法排序

作者头像
诺谦
发布2020-12-18 10:53:54
2.8K0
发布2020-12-18 10:53:54
举报
文章被收录于专栏:Linux驱动Linux驱动

在之前25.QT-模型视图章节中,没有具体描述如何重写model模型,所以本章以QabstractTableModel为例,来谈谈model如何实现.

1.QabstractTableModel常用功能

QAbstractTableModel子类化时,必须覆写:

代码语言:javascript
复制
Int rowCount();
//返回显示的行数

int columnCount();
//返回显示的列数

Qvariant headerData(int section, Qt::Orientation orientation, int role);
//返回标题role角色对应的值
// section:段号,从0开始,对于Qt::Horizontal水平标题,则是每列的标题名,对于Qt::Vertical垂直标题,则是每行的左侧标题名
//orientation:标题类型
//role:对应值是Qt:: ItemDataRole枚举, 对于role角色,常用的有:
//Qt::DisplayRole  :以文本方式显示数据(QString)
//Qt::DecorationRole :将数据作为图标来装饰(QIcon,QPixmap)
//Qt::EditRole  :可编辑的数据信息显示(QString)
//Qt::ToolTipRole :作为工具提示显示(QString)
//Qt::StatusTipRole :作为状态栏中显示的数据(QString)
//Qt::WhatsThisRole :作为帮助信息栏中显示的数据(QString)
//Qt::FontRole   :设置字体(QFont)
//Qt::TextAlignmentRole :设置模型数据的文本对齐(Qt::AlignmentFlag)
//Qt::BackgroundRole :设置模型数据的背景色(QBrush)
//Qt::ForegroundRole : 设置模型数据的前景色,比如字体(QBrush)
//Qt::SizeHintRole  : 设置模型数据的大小
代码语言:javascript
复制
QVariant data(const QModelIndex &index, int role);
//返回index单元格下的role角色数据。通过index可以获取行号和列号

bool setData(const QModelIndex &index, const QVariant &value, int role);
//将index单元格下的role角色设置为value
//对于可编辑模型,必须重写该函数,然后还需要重写flags()
//返回值为true:表示设置成功,然后还需要显式发射dataChanged信号

2.QabstractTableModel可编辑功能

如果不想实现QabstractTableModel可编辑功能, 则调用QTableView ->setEditTriggers(QAbstractItemView::NoEditTriggers)即可.

如果要实现的话,则需要覆写下面函数:

代码语言:javascript
复制
Qt::ItemFlags  flags(const QModelIndex &index);
//设置每个单元格的flag,对于可编辑模型,必须重写它,添加Qt::ItemIsEditable(可编辑属性)
//然后当我们双击时,会默认创建一个编辑组件(这是由 delegate 完成的)然后delegate会调用QAbstractTableModel ::data(index, Qt::EditRole)读取默认编辑值
//当我们编辑完成后, delegate会调用QAbstractTableModel :: setData (index, value, Qt::EditRole)告诉我们是否保存数据.

如果对于可调整行列的模型,可以重写insertRows()、removeRows()、insertColumns()、removeColumns().在实现这些函数时,还需要调用合适的父类函数,用来通知model调整了哪些内容:

代码语言:javascript
复制
insertRows():
//在向数据结构插入新行之前需要调用父类的beginInsertRows(),并且必须在之后立即调用endInsertRows()。

insertColumns():
//在向数据结构插入新列之前需要调用父类的beginInsertColumns(),并且必须在之后立即调用endInsertColumns()。

RemoveRows():
//在删除行之前需要调用父类的beginRemoveRows(),并且必须在之后立即调用endRemoveRows()。

RemoveColumns():
//在删除列之前需要调用父类的beginRemoveColumns(),并且必须在之后立即调用endRemoveColumns()。

注意:如果要重新刷新model数据,则必须在刷新model之前调用beginResetModel(),然后刷新之后调用endResetModel。

或者在刷新之后,emit dataChanged(index(0,0),index(rowCount,columnCount))来进行刷新视图

3.model排序之重写sort方法

首先需要调用QtableView->setSortingEnabled(true)使能排序,sort函数声明如下所示:

代码语言:javascript
复制
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
//当用户点击标题进行降序/升序排序时,会调用该方法
//或者调用QtableView->sortByColumn()时,也会调用该方法
// column:第几列进行排序
// order:升序(AscendingOrder)、降序(DescendingOrder) 

排序方法则使用std::sort()来实现.然后写个sort类来配合column和order实现排序.

进行排序的时候,必须得调用beginResetModel(),endResetModel()进行界面刷新.

4.代码实现

界面如下所示:

custommodel.h如下所示:

代码语言:javascript
复制
#ifndef CUSTOMMODEL_H
#define CUSTOMMODEL_H

#include <QObject>
#include <QAbstractTableModel>
#include <QModelIndex>
#include <QFont>
#include <QPixmap>

//排序类
class DataSort
{
public:

    int  mColumn;
    Qt::SortOrder   mSortOrder;
    DataSort(int column, Qt::SortOrder order)
        : mColumn(column)
        , mSortOrder(order)
    {}
    bool operator()(const QVector<QString>* v1, const QVector<QString>*  v2)
    {
        int compare = 0;        //>0:大于 <0:小于
        bool ret=false;
        switch ( mColumn )
        {
            case 0 :     //序号,需要判断数字
            case 3 :     //信号ID,需要判断数字
                compare = v1->at(mColumn).toInt() -  v2->at(mColumn).toInt();
                break;
            default :    //其它,只判断字符串
                compare = v1->at(mColumn).compare(v2->at(mColumn));
                break;
        }

        if(compare==0)      //相等必须返回flase,否则的话,对于一列相同的值进行降序,那么会一直返回true,从而死循环
        {
            return false;
        }
        else
            ret = compare>0?false:true;

        if ( mSortOrder == Qt::DescendingOrder )    //降序
        {
            ret =  !ret;
        }
        return ret;
    }
};

class CustomModel : public QAbstractTableModel
{
    Q_OBJECT


public:
    explicit CustomModel(QAbstractTableModel *parent = nullptr);

    int rowCount(const QModelIndex &parent = QModelIndex()) const;
    int columnCount(const QModelIndex &parent = QModelIndex()) const;
    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
    Qt::ItemFlags flags(const QModelIndex &index) const;

    void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);

public slots:
    void UpdateData(void);

private:
    QList<QVector<QString> * > m_data;
    int m_columnCount;
    int m_rowCount;
    QFont m_Font;
    QPixmap m_icon;

signals:

};

#endif // CUSTOMMODEL_H

custommodel.cpp如下所示:

代码语言:javascript
复制
#include "custommodel.h"
#include <QDateTime>
#include <QDebug>
CustomModel::CustomModel(QAbstractTableModel *parent) : QAbstractTableModel(parent)
{
    m_columnCount = 5;     //5行
    m_rowCount = 60;

    m_Font.setFamily("Microsoft Yahei");
    m_Font.setPixelSize(17);

    m_icon.load(":alarm");
    m_icon = m_icon.scaled(20,22,Qt::KeepAspectRatio,Qt::SmoothTransformation);

    UpdateData();
}


void CustomModel::UpdateData(void)
{
    beginResetModel();
    m_data.clear();

    for (int i = 0; i < m_rowCount; i++) {

        QVector<QString>* line = new QVector<QString>(m_columnCount);
        line->replace(0,QString("%1").arg(i+1));   
        line->replace(1,"显示器");                   
        line->replace(2,"未显示");                   
        line->replace(3,QString("%1").arg(qrand()%100));
        line->replace(4,QDateTime::currentDateTime().addDays(-10).toString("hh:mm:ss"));
        m_data.append(line);
    }
    endResetModel();
   //emit dataChanged(index(0,0),index(m_data.count()-1,columnCount()-1));   //和beginResetModel()、endResetModel() 本质一样
}


int CustomModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)        //由于parent未使用,所以通过Q_UNUSED去掉编译警告
    return m_data.count();
}

int CustomModel::columnCount(const QModelIndex &parent) const      //列
{
    Q_UNUSED(parent)
    return m_columnCount;
}

QVariant CustomModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role != Qt::DisplayRole)
        return QVariant();

    if (orientation == Qt::Horizontal) {
        switch (section) {
            case 0 :
                return "序号";
            case 1 :
                return "设备";
            case 2 :
                return "状态";
            case 3 :
                return "信号ID";
            case 4 :
                return "上报时间";
            default :
                return "";
        }
    } else {
        return QString("%1").arg(section + 1);
    }
}

QVariant CustomModel::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole) {              //显示内容
        return m_data[index.row()]->at(index.column());
    } else if (role == Qt::EditRole) {          //正在启动编辑,返回当前默认编辑值
        return m_data[index.row()]->at(index.column());
    } else if (role == Qt::TextAlignmentRole) {   //内容排版
        return Qt::AlignCenter;
    } else if (role == Qt::FontRole) {           //字体
        return m_Font;
    } else if (role == Qt::DecorationRole) {       //图标
        if (index.column() == 2)
            return m_icon;
    }

    return QVariant();
}

bool CustomModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (index.isValid() && role == Qt::EditRole) {   //编辑完成,保存数据到model,并返回true
        m_data[index.row()]->replace(index.column(), value.toString());
        emit dataChanged(index, index);             //重新实现setData()函数时,必须显式发出该信号。
        return true;
    }
    return false;
}

Qt::ItemFlags CustomModel::flags(const QModelIndex &index) const
{
    return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;       //设置item可编辑
}


void CustomModel::sort(int column, Qt::SortOrder order)
{
    beginResetModel();
    DataSort comp(column,order);
    std::sort(m_data.begin(), m_data.end(),comp);
    endResetModel();
}

第二种排序方法则是通过使用QsortFilterProxyModel代理类实现排序,QsortFilterProxyModel类用来为model和view之间提供强大的排序和过滤支持,并且无需对模型中的数据进行任何转换,也无需对模型在中数据进行修改。

未完待续.下章学习:61.QT-QSortFilterProxyModel代理实现排序、过滤

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-12-16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 2.QabstractTableModel可编辑功能
  • 3.model排序之重写sort方法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档