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();

      int count = m_data.size();
      if(count > 0)
      {
         for(int i = 0; i < count; i++)
        {
            delete m_data.at(i);
        }
        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代理實現排序、過濾

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM