QSortFilterProxyModel的使用

来源:互联网 发布:js sort 排序 编辑:程序博客网 时间:2024/04/28 03:45

QSortFilterProxyModel类提供在其他的model和view之间排序和过滤数据的支持

QSortFilterProxyModel可以用来对item进行排序,筛选,它把一个model的source结构通过model的index结构map到他新提供的index里面,这种方法允许一个model重新组织,当和他相关联的view,不需要在数据上请求任何转换,也不需要复制内存中的数据

代码如下
QTreeView *treeView = new QTreeView;
MyItemModel *sourceModel = new MyItemModel(this);
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(sourceModel);
treeView->setModel(proxyModel);
此时,排序和过滤都不可用,原始的数据在view中显示,通过QSortFilterProxyModel做的任何改动都会被作用在原始的model中

QSortFilterProxyModel对于原始的model来讲就相当于一个包装工具,如果想把原始的QModelIndex转换成可排序/过滤的model,或者反之亦然,使用 mapToSource(), mapFromSource(), mapSelectionToSource(), and mapSelectionFromSource()这些方法

默认的,当原始的model改变时候,它不会动态自动重新排序和重新过滤数据,但可以通过设置dynamicSortFilter性质来改变,方法:void setDynamicSortFilter (bool enable)

具体看例子 Basic Sort/Filter Model 和 Custom Sort/Filter Model


QTableView和QTreeView有一个sortingEnabled性质,控制着view是否可以通过点击表头来排序,例如treeView->setSortingEnabled(true);  默认是不可排序的
当这个性质打开时候,点击header就会对本列的item排序,通过重复点击header,用户可以交替的看到升序和排序的排序


MVC中,在场景scene后,view可以调用model的虚函数sort()来记录model的数据,为了可以使自己的数据可以排序,我们可以使用sort()方法,或者使用QSortFilterProxyModel来做这个model的外包装,QSortFilterProxyModel提供了共有的sort()方法来操作items的sortRole(默认是Qt::DisplayRole),包括int,QString,QDateTime

传统的排序行为可以通过子类化QSortFilterProxyModel和使用lessThan()方法,lessThan()方法用来对比items,例如:

 

 bool MySortFilterProxyModel::lessThan(const QModelIndex &left,
                                       const QModelIndex &right) const
 {
     QVariant leftData = sourceModel()->data(left);
     QVariant rightData = sourceModel()->data(right);

     if (leftData.type() == QVariant::DateTime) {
         return leftData.toDateTime() < rightData.toDateTime();
     } else {
         QRegExp *emailPattern = new QRegExp("([//w//.]*@[//w//.]*)");

         QString leftString = leftData.toString();
         if(left.column() == 1 && emailPattern->indexIn(leftString) != -1)
             leftString = emailPattern->cap(1);

         QString rightString = rightData.toString();
         if(right.column() == 1 && emailPattern->indexIn(rightString) != -1)
             rightString = emailPattern->cap(1);

         return QString::localeAwareCompare(leftString, rightString) < 0;
     }
 }

 

 


Filetering
除了排序外,QSortFilterProxyModel可以用来隐藏那些和过滤器不匹配的items,过滤器使用 QRegExp类对象,对一个给定的列, QRegExp对象可以用来匹配一个正则表达式,一个通配符,一个字符串,例如
proxyModel->setFilterRegExp(QRegExp(".png", Qt::CaseInsensitive,QRegExp::FixedString));
proxyModel->setFilterKeyColumn(1);
对于分层的models,过滤器对他所有的孩子都有用,如果父item不匹配过滤器,孩子item也不会显示,

通常的一个用法是让用户通过QLineEdit指定过滤器正则表达式,通配符,然后通过发送信号textChanged()信号,使用 setFilterRegExp(), setFilterWildcard(), or setFilterFixedString()来响应过滤器
一般的过滤行为可以在实现filterAcceptsRow() and filterAcceptsColumn()函数,下面的例子中,函数实现中忽略了 filterKeyColumn性质,只在第一和第二三列实现过滤
 bool MySortFilterProxyModel::filterAcceptsRow(int sourceRow,const QModelIndex &sourceParent) const
 {
     QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent);
     QModelIndex index1 = sourceModel()->index(sourceRow, 1, sourceParent);
     QModelIndex index2 = sourceModel()->index(sourceRow, 2, sourceParent);

     return (sourceModel()->data(index0).toString().contains(filterRegExp())
             || sourceModel()->data(index1).toString().contains(filterRegExp()))
            && dateInRange(sourceModel()->data(index2).toDate());
 }
如果工作中有大量的过滤器要使用,频繁的调用invalidateFilter(),使用reset()可能更有效,具体视你的model的实现,然而,reset()返回代理model给他原始的model,丢失选择信息,将会引起代理model重新注入


原创粉丝点击