zoukankan      html  css  js  c++  java
  • 60.QT-QabstractTableModel模型、重写sort方法排序

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

    1.QabstractTableModel常用功能

    QAbstractTableModel子类化时,必须覆写:

    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 : 设置模型数据的大小
    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)即可.

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

    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调整了哪些内容:

    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函数声明如下所示:

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

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

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

    4.代码实现

    界面如下所示,支持自定义排序:

    下载链接:https://download.csdn.net/download/qq_37997682/13709956

     custommodel.h如下所示:

    #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如下所示:

    #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代理实现排序、过滤

  • 相关阅读:
    外部程序启动App
    简单修改文件名python脚本
    监听软键盘的显示
    ActionBar 笔记
    ActionBar 笔记
    Android Lock Pattern 图案解锁
    通过反射实现圆角ImageView
    android 通过命令行启动Apk
    ubuntu svn rabbitvcs 安装
    Android 两个界面间快速切换时,会发现有短暂黑屏
  • 原文地址:https://www.cnblogs.com/lifexy/p/14144776.html
Copyright © 2011-2022 走看看