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之前了,所以我们应该避免这种问题。

上面所述的简单排序谁都会,如何把前面的数据按照字符串比较,而后面的数据按照整形比较呢?如何将整形显示为字符串,而排序依然正常呢?这都是我们下节要分享的精彩内容,请持续关注!

相关文章
|
6月前
|
Ubuntu iOS开发 MacOS
Qt5标题栏自定义QHeaderView自定义
Qt5标题栏自定义QHeaderView自定义
160 0
Qt实现单击或双击QTableWidge/View表头进行排序
Qt实现单击或双击QTableWidge/View表头进行排序
895 0
|
JavaScript 大数据
Qt+ECharts开发笔记(五):ECharts的动态排序柱状图介绍、基础使用和Qt封装Demo
上一篇的demo使用隐藏js代码的方式,实现了一个饼图的基本交互方式,并预留了Qt模块对外的基础接口。   本篇的demo实现了自动排序的柱状图,实现了一个自动排序柱状图的基本交互方式,即Qt调用js脚本操作html。   本篇demo使用Qt定时器方式,实现数据定时刷新自增,并预留出了定时器间隔参数。   像大数据网页常看的人口增长时间图,收入年度增长时间图等都是这一类。
Qt+ECharts开发笔记(五):ECharts的动态排序柱状图介绍、基础使用和Qt封装Demo
|
索引
Qt之QHeaderView自定义排序(获取正确的QModelIndex)
简述 前几节中分享过关于自定义排序的功能,貌似我们之前的内容已经可以很好地解决排序问题了,但是,会由此引发一些很难发现的问题。。。比如:获取QModelIndex索引错误。 下面,我们先来实现一个整行选中的效果。 简述 错误处理 效果 源码 分析 正常处理 效果 源码 错误处理 效果 下面是一个非正常的的效果,选中当前行会造成更新错误,
1040 0
|
C++ 搜索推荐
Qt之QHeaderView自定义排序(QSortFilterProxyModel)
简述 对以上节的排序,我们衍伸了两点: 把一个字符串前面的数据按照字符串比较,而后面的数据按照整形比较。 将整形显示为字符串,而排序依然正常呢。 为了分别描述,这里我们先解决问题1。 简述 效果 处理大小显示 QAbstractTableModel QSortFilterProxyModel 提示 效果 处理大小显示 // 定义GB
1248 0
|
索引
Qt之QHeaderView添加复选框
简述 前面分享了QTableView中如何添加复选框。本节主要介绍QTableView中的表头-QHeaderView添加复选框的功能,下面以水平表头为例,垂直表头类似! 简述 效果 QHeaderView 源码 接口说明 QAbstractTableModel 源码 接口说明 使用 效果 QHeaderView 源码
1927 0