您当前的位置: 首页 >  qt

龚建波

暂无认证

  • 4浏览

    0关注

    312博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

QTableView自定义Model实现排序 

龚建波 发布时间:2020-05-31 10:26:57 ,浏览量:4

(2020-8-26 更新)

排序是一个常用的功能,QTableView 也可以点击表头进行排序,相关接口:

//允许点击排序
ui->tableView->setSortingEnabled(true);

//按第0列升序
ui->tableView->sortByColumn(0,Qt::AscendingOrder);  

但只对 QTableView 进行设置还不能生效,需要借助 QAbstractItemModel 类的 sort 接口(需要重写 sort 接口进行排序),或者借助  QSortFilterProxyModel 类(可以重写 lessThan 接口自定义排序规则)。

Qt 提供的 QAbstractItemModel 及其派生类是有 sort 接口的,但是没有实现,对于一些简单的排序,可以继承并重写这个虚函数:

#include 
//自定义Model
class MyTableModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    //... ...
    void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override
    {
        if(modelData.isEmpty()||modelData.first().count()tableView);
    QSortFilterProxyModel *proxy_model = new QSortFilterProxyModel(this);
    //默认排序role应该是dispalyRole,我们可以修改
    proxy_model->setSortRole(Qt::InitialSortOrderRole);
    proxy_model->setSourceModel(table_model);
    ui->tableView->setModel(proxy_model);

也可以重写 QSortFilterProxyModel 类的 lessThan 接口来实现自己的排序:

#include 
//自定义SortProxy
class MySortProxy: public QSortFilterProxyModel
{
    Q_OBJECT
public:
    BaseTableProxy(QObject *parent = nullptr)
        : QSortFilterProxyModel(parent)
    {
        //排序role,也就是获取model-data时用的role
        setSortRole(Qt::InitialSortOrderRole);
        //本地化,对中文排序有影响
        //在对字符串排序时,是否考虑本地因素,默认false
        setSortLocaleAware(true);
    }
    //... ...
    //重写虚函数接口
    bool lessThan(const QModelIndex &source_left,
                  const QModelIndex &source_right) const override
    {
        //参照源码
        QVariant l = (source_left.model() ? source_left.model()->data(source_left, sortRole()) : QVariant());
        QVariant r = (source_right.model() ? source_right.model()->data(source_right, sortRole()) : QVariant());
        return isVariantLessThan(l, r, sortCaseSensitivity(), isSortLocaleAware());
    }

    //修改自源码QAbstractItemModelPrivate
    bool isVariantLessThan(const QVariant &left,
                           const QVariant &right,
                           Qt::CaseSensitivity cs = Qt::CaseSensitive,
                           bool isLocaleAware = false) const
    {
        //修改源码对无效值得判断
        //if (left.userType() == QVariant::Invalid)
        //    left = false;
        //if (right.userType() == QVariant::Invalid)
        //    right = true;
        //无效值作为0来判断,这样就在正负数之间展示
        if((left.userType() == QVariant::Invalid)||
                (right.userType() == QVariant::Invalid))
            return left.toDouble() < right.toDouble();
        //下面未改动
        switch (left.userType()) {
        case QVariant::Int:
            return left.toInt() < right.toInt();
        case QVariant::UInt:
            return left.toUInt() < right.toUInt();
        case QVariant::LongLong:
            return left.toLongLong() < right.toLongLong();
        case QVariant::ULongLong:
            return left.toULongLong() < right.toULongLong();
        case QMetaType::Float:
            return left.toFloat() < right.toFloat();
        case QVariant::Double:
            return left.toDouble() < right.toDouble();
        case QVariant::Char:
            return left.toChar() < right.toChar();
        case QVariant::Date:
            return left.toDate() < right.toDate();
        case QVariant::Time:
            return left.toTime() < right.toTime();
        case QVariant::DateTime:
            return left.toDateTime() < right.toDateTime();
        case QVariant::String:
        default:
            if (isLocaleAware)
                return left.toString().localeAwareCompare(right.toString()) < 0;
            else
                return left.toString().compare(right.toString(), cs) < 0;
        }
    }
    //... ...
};

QSortFilterProxyModel 还有个问题是:排序之后,表头也会跟着排序,如果表头本身想展示固定行列号就尴尬了。一个临时的解决方法是在 model 的 data 接口返回 visualIndex 的 row(即直接返回当前显示的行数)。

QVariant MySortProxy::data(const QModelIndex & index, int role) const
{
    //index有效值判断可以自己修改
	QModelIndex source_index = mapToSource(index);
	if (index.isValid() && !source_index.isValid())
		return QVariant();
	//orderColumn 就是我们指定的要显示行数的列
	if (source_index.column() == orderColumn && role == Qt::DisplayRole) {
		return QString::number(index.row() + 1);
	}
	return sourceModel()->data(source_index, role);
}

 

关注
打赏
1655829268
查看更多评论
立即登录/注册

微信扫码登录

0.0495s