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

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

  • 相关阅读:
    思念
    空白
    curl json string with variable All In One
    virtual scroll list All In One
    corejs & RegExp error All In One
    socket.io All In One
    vue camelCase vs PascalCase vs kebabcase All In One
    element ui 表单校验,非必填字段校验 All In One
    github 定时任务 UTC 时间不准确 bug All In One
    input range & color picker All In One
  • 原文地址:https://www.cnblogs.com/itrena/p/5938375.html
Copyright © 2020-2023  润新知