QSortFilterProxyModel实现QTreeView的过滤的缺点和改进

   一般如果需要对一个视图进行关键字过滤,我们会使用QT的类QSortFilterProxyModel,将视图(view)的模型设置为这个代理类,将代理类的源模型定义为原始模型,然后定义代理模型的filterKeyColumn, filterRole, filterFixString或filterRegExp等属性后就可以实现过滤功能。如:

 

  1. MyTreeModel model;  
  2. QSortFilterProxyModel sfmodel;  
  3. MyView view;  
  4.   
  5. view.setModel(&sfmodel);  
  6. sfmodel.setSourceModel(&model);  
  7. sfmodel.setFilterKeyColumn(0);  // optional  
  8. sfmodel.setFilterRole(Qt::DisplayRole); // default, optional  
  9. sfmodel.setFilterFixedString("keyword");  
  10. sfmodel.setFilterRegExp("[hH]ello");  


    但是对于TreeView和TreeModel,这样的做法有些缺陷,如果在子节点上的数据根据过滤规则可以显示,但它的parent节点根据过滤规则是不显示的。这样以来会因为父节点被过滤掉,而导致符合条件的子节点也一起被过滤掉了。如果需要对这个缺陷进行改进,可以这样来做:从QSortFilterProxyModel继承一个自己的代理类,重新实现它的filterAcceptsRow函数,当节点不是一个叶子节点(在末端,没有子节点)时不应用过滤规则,只对叶子节点应用过滤规则,这样就可以达到上述要求。代码如下:

 

 

  1. // \reimp  
  2. bool MyFilterProxyModel::filterAcceptsRow ( int source_row,  
  3.                             const QModelIndex & source_parent ) const  
  4. {  
  5.     QModelIndex source_index = sourceModel()->index(source_row, 0, source_parent);  
  6.     if (sourceModel()->rowCount(source_index)>0)  
  7.         return true;  
  8.     else  
  9.         return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);  
  10. }      


    上面的代码会带来一个新的缺陷,就是对于非叶子节点不应用过滤规则,对于那些没有子节点符合过滤规则,且自身节点也不符合过滤规则的节点,也会一直在视图中显示。如果需要弥补这个问题,可以继续做以下的改进:在应用过滤规则时,如果自身不符合过滤规则,再去检查所有的子节点(递归调用至所有的后代节点),若所有的子节点都不符合过滤规则,那么这个子节点就不显示,只要有一个后代节点符合规则,就需要显示这个节点。代码如下:

 

 

  1. // \reimp  
  2. bool MyFilterProxyModel::filterAcceptsRow ( int source_row,  
  3.                             const QModelIndex & source_parent ) const  
  4. {  
  5.     bool filter = QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);  
  6.   
  7.     if (filter)  
  8.     {  
  9.         return true;  
  10.     }  
  11.     else  
  12.     {  
  13.         // check all decendant's  
  14.         QModelIndex source_index = sourceModel()->index(source_row, 0, source_parent);  
  15.         for (int k=0; k<sourceModel()->rowCount(source_index); k++)  
  16.         {  
  17.             if (filterAcceptsRow(k, source_index))  
  18.             {  
  19.                 return true;  
  20.             }  
  21.         }  
  22.     }  
  23.   
  24.     return false;  
  25. }  

    按照这样的做法,就可以达到一个比较理想的过滤效果。

原文转自:http://blog.csdn.net/lutx/article/details/7161467

posted @ 2013-05-28 19:21  云端的思念  阅读(3129)  评论(0)    收藏  举报