Pyqt Model/view框架 5.排序与过滤

>[上篇](http://www.cnblogs.com/hangxin1940/archive/2012/04/23/2806453.html)介绍了如何自定义编辑项,这篇,我们将会使Model具备排序与筛选功能 排序 --- 在[上篇](http://www.cnblogs.com/hangxin1940/archive/2012/04/23/2806453.html)的代码中的添加`SortProxyModel`类: class SortProxyModel(QSortFilterProxyModel): """ 排序代理 """ def lessThan(self,left_index,right_index): """ 比较方法 用于判断紧邻的两个数据的大小 """ #获取相邻的两个QVariant对象 left_var=left_index.data(Qt.DisplayRole) right_var=right_index.data(Qt.DisplayRole) #转化为Python对象 left_str=left_var.toPyObject() right_str=right_var.toPyObject() #转换为int left_int=int(left_str) right_int=int(right_str) #从方法名已经看出来,只要返回左是否比右小的bool值就行 return (left_int < right_int) 并更改`main`方法: def main(): app=QApplication(sys.argv) #新建一个自定义Model model=MyListModel() #新建一个委托(Delagate) delegate=MyDelegate() #新建一个排序代理 proxy=SortProxyModel() #设置代理的模型 proxy.setSourceModel(model) #从第0行开始排序 proxy.sort(0) #新建一个ListView view=QListView() #设置view的model,这里设置为代理 view.setModel(proxy) #设置view的delegate view.setItemDelegate(delegate) view.show() sys.exit(app.exec_()) 运行后,即会将数据排序显示,尝试一下,更改数据后没有自动排序,别急,后面会讲到 数据筛选 --- 添加下列方法至`SortProxyModel`类: def filterAcceptsRow(self,src_row,src_parent): """ 过滤接收的行 """ #获取数据Model src_model=self.sourceModel() #获得当前行的索引,0为列,我们目前只有一列,所以用第一列,也就是第0列 src_index=src_model.index(src_row,0) #获取当前索引的数据 item_var=src_index.data(Qt.DisplayRole) #转为int item_int=int(item_var.toPyObject()) #过滤大于等于60的数据 return (item_int >= 20) 并在`mian`方法中 新建`proxy`变量的下面加入下列语句: #开启动态排序与过滤 proxy.setDynamicSortFilter(True) 现在运行,并编辑,会发现排序与过滤的功能了 整个工程的完整代码 --- # -*- coding: utf-8 -*- import sys from PyQt4.QtCore import * from PyQt4.QtGui import * #################################################################### def main(): app=QApplication(sys.argv) #新建一个自定义Model model=MyListModel() #新建一个委托(Delagate) delegate=MyDelegate() #新建一个排序代理 proxy=SortProxyModel() #设置代理的模型 proxy.setSourceModel(model) #开启动态排序与过滤 proxy.setDynamicSortFilter(True) #从第0行开始排序 proxy.sort(0) #新建一个ListView view=QListView() #设置view的model,这里设置为代理 view.setModel(proxy) #设置view的delegate view.setItemDelegate(delegate) view.show() sys.exit(app.exec_()) #################################################################### class MyListModel(QAbstractListModel): """ 我的第一个模型 """ def __init__(self,parent=None): super(MyListModel,self).__init__(parent) #这是数据 self._data=[70,90,20,50] pass def rowCount(self, parent=QModelIndex()): """ 这个方法返回了数据的行数 也就是有多少个条目得数据 """ return len(self._data) def data(self,index,role=Qt.DisplayRole): """ 根据当前index索引,返回当前的数据 然后再由Qt进行渲染显示 """ #如果当前得索引是不活动得 if not index.isValid() or not 0 <= index.row() < self.rowCount(): #亦或者当前的索引值不在合理范围,即小于等于0,超出总行数 return QVariant() #返回一个QVariant,相当与空条目 #从索引取得当前的航号 row=index.row() #如果当前角色是DisplayRole if role==Qt.DisplayRole: #返回当前行的数据 return self._data[row] #当前角色为编辑模式,显示原本数据 #这样,当我们双击单元项时,不至于什么都不显示 if role==Qt.EditRole: return self._data[row] #如果角色不满足需求,则返回QVariant return QVariant() def flags(self, index): """ flag描述了view中数据项的状态信息 """ #首先获取超类的flags返回值 flag=super(MyListModel,self).flags(index) #或运算,将ItemIsEditable(可编辑)标志叠加上去 return flag | Qt.ItemIsEditable def setData(self,index,value,role=Qt.EditRole): """ 设置数据 """ #如果当前为编辑角色 if role==Qt.EditRole: #QVariant的这个方法,返回的bool类型表示这个值是否可以被转为int类型 value_int, ok=value.toInt() #如果可以转为int类型 if ok: #保存数据 self._data[index.row()]=value_int #发射数据更改信号,以便让view更新 self.dataChanged.emit(index,index) return True return False #################################################################### class SortProxyModel(QSortFilterProxyModel): """ 排序代理 """ def lessThan(self,left_index,right_index): """ 比较方法 用于判断紧邻的两个数据的大小 """ #获取相邻的两个QVariant对象 left_var=left_index.data(Qt.DisplayRole) right_var=right_index.data(Qt.DisplayRole) #转化为Python对象 left_str=left_var.toPyObject() right_str=right_var.toPyObject() #转换为int left_int=int(left_str) right_int=int(right_str) #从方法名已经看出来,只要返回左是否比右小的bool值就行 return (left_int < right_int) def filterAcceptsRow(self,src_row,src_parent): """ 过滤接收的行 """ #获取数据Model src_model=self.sourceModel() #获得当前行的索引,0为列,我们目前只有一列,所以用第一列,也就是第0列 src_index=src_model.index(src_row,0) #获取当前索引的数据 item_var=src_index.data(Qt.DisplayRole) #转为int item_int=int(item_var.toPyObject()) #过滤大于等于60的数据 return (item_int >= 20) #################################################################### class MyDelegate(QStyledItemDelegate): """ 自定义的委托 用来在Model获取后,view显示前,再将数据渲染一次 """ def paint(self,painter,option,index): """ paint,有了画布画笔,想怎么显示就怎么显示,画什么按自己的想法来 """ #首先,从索引获取数据,这里获取当前索引角色为DisplayQole的数据 item_var=index.data(Qt.DisplayRole) #[QVariant] #数据是C格式,我们再转为Python格式,记住这点 item_str=item_var.toPyObject() #[QVariant] -> str #我们将数据以进度条的方式显现 opts=QStyleOptionProgressBarV2() opts.rect=option.rect #进度条所占的矩形大小 opts.minimum=0 opts.maximum=100 opts.text=str(item_str) #显示的内容 opts.textAlignment=Qt.AlignCenter opts.textVisible=True opts.progress=int(item_str) #设置当前进度 #这是关键 #让QApplication根据当前的风格渲染控件并画出来 QApplication.style().drawControl(QStyle.CE_ProgressBar,opts,painter) def createEditor(self,parent,option,index): """ 创建编辑器 """ #创建一个QSPinBox sbox=QSpinBox(parent) sbox.setRange(0,100) #返回这个QSpinBox return sbox def setEditorData(self,editor,index): """ 设置编辑器数据 """ item_var=index.data(Qt.DisplayRole) item_str=item_var.toPyObject() item_int=int(item_str) #设置编辑器的数据为当前索引的值 editor.setValue(item_int) def setModelData(self,editor,model,index): """ 给model设置编辑后的数据 """ #获取编辑器的数据 data_int=editor.value() #把数据封装为Qt类型 data_var=QVariant(data_int) #设置Model的数据,当前索引与数据 model.setData(index,data_var) #################################################################### if __name__ == "__main__": main() >至此,所有 `Pyqt Model/view框架` 系列结束,不再赘述其他Python与Qt知识

posted on 2012-04-23 01:33  黑暗伯爵  阅读(3239)  评论(0编辑  收藏  举报

导航