1. 程式人生 > >Qt 之 QHeaderView 排序

Qt 之 QHeaderView 排序

簡述

在Windows中我們經常會遇到表頭排序,比如可以對檔案按照名稱、修改日期、型別、大小進行排序,方便我們統一的歸類查詢。

Qt中,我們可以通過點選表頭來對QTableView或QTreeView等一系列高階檢視進行排序,對於一般的資料來說-比如:int、QString等,簡單的幾句程式碼就可以搞定,因為Qt內部做了很好的排序處理,但是一般情況下,我們需要處理一些特殊格式的資料,這時,我們就不得不自己處理,以達到理想的效果。

|

效果

這裡寫圖片描述

自定義資料

定義各列資料及結構體

#define FILE_NAME_COLUMN 0   // 檔名
#define DATE_TIME_COLUMN 1   // 修改日期
#define FILE_SIZE_COLUMN 2 // 檔案大小 typedef struct FileRecord { QString strFileName; // 檔名 QDateTime dateTime; // 修改日期 qint64 nSize; // 檔案大小 } fileRecord;

QAbstractTableModel

原始碼

自定義模型

TableModel::TableModel(QObject *parent)
    : QAbstractTableModel(parent)
{

}

TableModel::~TableModel()
{

}

// 更新表格資料
void TableModel::updateData(QList<FileRecord> recordList) { m_recordList = recordList; beginResetModel(); endResetModel(); } // 行數 int TableModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return m_recordList.count(); } // 列數 int TableModel::columnCount(const
QModelIndex &parent) const { Q_UNUSED(parent); return 3; } // 設定表格項資料 bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid()) return false; int nColumn = index.column(); FileRecord record = m_recordList.at(index.row()); switch (role) { case Qt::DisplayRole: { if (nColumn == FILE_NAME_COLUMN) { record.strFileName = value.toString(); } else if (nColumn == DATE_TIME_COLUMN) { record.dateTime = value.toDateTime(); } else if (nColumn == FILE_SIZE_COLUMN) { record.nSize = value.toLongLong(); } m_recordList.replace(index.row(), record); emit dataChanged(index, index); return true; } default: return false; } return false; } // 表格項資料 QVariant TableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); int nRow = index.row(); int nColumn = index.column(); FileRecord record = m_recordList.at(nRow); switch (role) { case Qt::TextColorRole: return QColor(Qt::white); case Qt::TextAlignmentRole: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); case Qt::DisplayRole: { if (nColumn == FILE_NAME_COLUMN) { return record.strFileName; } else if (nColumn == DATE_TIME_COLUMN) { return record.dateTime; } else if (nColumn == FILE_SIZE_COLUMN) { return record.nSize; } return ""; } default: return QVariant(); } return QVariant(); } // 表頭資料 QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const { switch (role) { case Qt::TextAlignmentRole: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); case Qt::DisplayRole: { if (orientation == Qt::Horizontal) { if (section == FILE_NAME_COLUMN) return QStringLiteral("名稱"); if (section == DATE_TIME_COLUMN) return QStringLiteral("修改日期"); if (section == FILE_SIZE_COLUMN) return QStringLiteral("大小"); } } default: return QVariant(); } return QVariant(); } // 表格可選中 Qt::ItemFlags TableModel::flags(const QModelIndex &index) const { if (!index.isValid()) return QAbstractItemModel::flags(index); Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; return flags; }

介面說明

  • updateData
    主要用於更新資料,重新整理介面。

  • data
    用來顯示資料,根據角色(顏色、文字、對齊方式、選中狀態等)判斷需要顯示的內容。

  • setData
    用來設定資料,根據角色(顏色、文字、對齊方式、選中狀態等)判斷需要設定的內容。

  • headerData
    用來顯示水平/垂直表頭的資料。

  • flags
    用來設定單元格的標誌(可用、可選中、可複選等)。

使用

QTableView *pTableView = new QTableView(this);
TableModel *pModel = new TableModel(this);
QSortFilterProxyModel *pProxyModel = new QSortFilterProxyModel(this);
// 設定資料來源模型
pProxyModel->setSourceModel(pModel);
pTableView->setModel(pProxyModel);
// 設定可排序
pTableView->setSortingEnabled(true);
// 設定按照檔名升序排列
pTableView->sortByColumn(FILE_NAME_COLUMN, Qt::AscendingOrder);

// 構造資料,更新介面
QList<FileRecord> recordList;

// 獲取隨機值
QTime time = QTime::currentTime();
qsrand(time.msec() + time.second()*1000);

for (int i = 0; i < 5; ++i)
{
    int nIndex = qrand()%20 + 1;
    int nHour = qrand()%24;
    int nMinute = qrand()%60;
    int nSecond = qrand()%60;
    int nBytes = qrand()%100000;

    QDateTime dateTime(QDate(2016, 5, 1), QTime(nHour, nMinute, nSecond));

    FileRecord record;
    record.strFileName = QString("Name %1.cpp").arg(nIndex);
    record.dateTime = dateTime;
    record.nSize = nBytes;

    recordList.append(record);
}
pModel->updateData(recordList);

思考

  1. 細心地童鞋可能會發現,當點選表頭(檔名)的時候,如果按照升序排列時,順序依次是:Name 14、Name 19、Name 4、Name 8、Name 9,降序則相反。為什麼呢?

    其實這個很好理解,因為檔名所在的列顯示的資料型別為QString,而QString排序是按照第一個字母開始比較,直至最後一個字母,例如:Name 19和Name 4,首先比較Name是相同的,當比較1和4(注意這裡不是按照整形比較19和4)的時候,發現1比4小,所以Name 19排在Name 4之前。

  2. 對於檔案大小的顯示,一般情況下,我們顯示的是KB、MB、GB等單位,而不會顯示位元組,那麼按照1的說法,在這種情況下,升序排列時,10 K 就會排在8 K之前了,所以我們應該避免這種問題。

上面所述的簡單排序誰都會,如何把前面的資料按照字串比較,而後面的資料按照整形比較呢?如何將整形顯示為字串,而排序依然正常呢?這都是我們下節要分享的精彩內容,請持續關注!