Pyqt Model/view框架 5.排序與過濾
>[上篇](http://www.rzrgm.cn/hangxin1940/archive/2012/04/23/2806453.html)介紹了如何自定義編輯項,這篇,我們將會使Model具備排序與篩選功能
排序
---
在[上篇](http://www.rzrgm.cn/hangxin1940/archive/2012/04/23/2806453.html)的代碼中的添加`SortProxyModel`類:
class SortProxyModel(QSortFilterProxyModel):
"""
排序代理
"""
def lessThan(self,left_index,right_index):
"""
比較方法
用于判斷緊鄰的兩個數(shù)據(jù)的大小
"""
#獲取相鄰的兩個QVariant對象
left_var=left_index.data(Qt.DisplayRole)
right_var=right_index.data(Qt.DisplayRole)
#轉(zhuǎn)化為Python對象
left_str=left_var.toPyObject()
right_str=right_var.toPyObject()
#轉(zhuǎn)換為int
left_int=int(left_str)
right_int=int(right_str)
#從方法名已經(jīng)看出來,只要返回左是否比右小的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_())
運行后,即會將數(shù)據(jù)排序顯示,嘗試一下,更改數(shù)據(jù)后沒有自動排序,別急,后面會講到
數(shù)據(jù)篩選
---
添加下列方法至`SortProxyModel`類:
def filterAcceptsRow(self,src_row,src_parent):
"""
過濾接收的行
"""
#獲取數(shù)據(jù)Model
src_model=self.sourceModel()
#獲得當前行的索引,0為列,我們目前只有一列,所以用第一列,也就是第0列
src_index=src_model.index(src_row,0)
#獲取當前索引的數(shù)據(jù)
item_var=src_index.data(Qt.DisplayRole)
#轉(zhuǎn)為int
item_int=int(item_var.toPyObject())
#過濾大于等于60的數(shù)據(jù)
return (item_int >= 20)
并在`mian`方法中 新建`proxy`變量的下面加入下列語句:
#開啟動態(tài)排序與過濾
proxy.setDynamicSortFilter(True)
現(xiàn)在運行,并編輯,會發(fā)現(xiàn)排序與過濾的功能了
整個工程的完整代碼
---
# -*- 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)
#開啟動態(tài)排序與過濾
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)
#這是數(shù)據(jù)
self._data=[70,90,20,50]
pass
def rowCount(self, parent=QModelIndex()):
"""
這個方法返回了數(shù)據(jù)的行數(shù)
也就是有多少個條目得數(shù)據(jù)
"""
return len(self._data)
def data(self,index,role=Qt.DisplayRole):
"""
根據(jù)當前index索引,返回當前的數(shù)據(jù)
然后再由Qt進行渲染顯示
"""
#如果當前得索引是不活動得
if not index.isValid() or not 0 <= index.row() < self.rowCount():
#亦或者當前的索引值不在合理范圍,即小于等于0,超出總行數(shù)
return QVariant() #返回一個QVariant,相當與空條目
#從索引取得當前的航號
row=index.row()
#如果當前角色是DisplayRole
if role==Qt.DisplayRole:
#返回當前行的數(shù)據(jù)
return self._data[row]
#當前角色為編輯模式,顯示原本數(shù)據(jù)
#這樣,當我們雙擊單元項時,不至于什么都不顯示
if role==Qt.EditRole:
return self._data[row]
#如果角色不滿足需求,則返回QVariant
return QVariant()
def flags(self, index):
"""
flag描述了view中數(shù)據(jù)項的狀態(tài)信息
"""
#首先獲取超類的flags返回值
flag=super(MyListModel,self).flags(index)
#或運算,將ItemIsEditable(可編輯)標志疊加上去
return flag | Qt.ItemIsEditable
def setData(self,index,value,role=Qt.EditRole):
"""
設置數(shù)據(jù)
"""
#如果當前為編輯角色
if role==Qt.EditRole:
#QVariant的這個方法,返回的bool類型表示這個值是否可以被轉(zhuǎn)為int類型
value_int, ok=value.toInt()
#如果可以轉(zhuǎn)為int類型
if ok:
#保存數(shù)據(jù)
self._data[index.row()]=value_int
#發(fā)射數(shù)據(jù)更改信號,以便讓view更新
self.dataChanged.emit(index,index)
return True
return False
####################################################################
class SortProxyModel(QSortFilterProxyModel):
"""
排序代理
"""
def lessThan(self,left_index,right_index):
"""
比較方法
用于判斷緊鄰的兩個數(shù)據(jù)的大小
"""
#獲取相鄰的兩個QVariant對象
left_var=left_index.data(Qt.DisplayRole)
right_var=right_index.data(Qt.DisplayRole)
#轉(zhuǎn)化為Python對象
left_str=left_var.toPyObject()
right_str=right_var.toPyObject()
#轉(zhuǎn)換為int
left_int=int(left_str)
right_int=int(right_str)
#從方法名已經(jīng)看出來,只要返回左是否比右小的bool值就行
return (left_int < right_int)
def filterAcceptsRow(self,src_row,src_parent):
"""
過濾接收的行
"""
#獲取數(shù)據(jù)Model
src_model=self.sourceModel()
#獲得當前行的索引,0為列,我們目前只有一列,所以用第一列,也就是第0列
src_index=src_model.index(src_row,0)
#獲取當前索引的數(shù)據(jù)
item_var=src_index.data(Qt.DisplayRole)
#轉(zhuǎn)為int
item_int=int(item_var.toPyObject())
#過濾大于等于60的數(shù)據(jù)
return (item_int >= 20)
####################################################################
class MyDelegate(QStyledItemDelegate):
"""
自定義的委托
用來在Model獲取后,view顯示前,再將數(shù)據(jù)渲染一次
"""
def paint(self,painter,option,index):
"""
paint,有了畫布畫筆,想怎么顯示就怎么顯示,畫什么按自己的想法來
"""
#首先,從索引獲取數(shù)據(jù),這里獲取當前索引角色為DisplayQole的數(shù)據(jù)
item_var=index.data(Qt.DisplayRole) #[QVariant]
#數(shù)據(jù)是C格式,我們再轉(zhuǎn)為Python格式,記住這點
item_str=item_var.toPyObject() #[QVariant] -> str
#我們將數(shù)據(jù)以進度條的方式顯現(xiàn)
opts=QStyleOptionProgressBarV2()
opts.rect=option.rect #進度條所占的矩形大小
opts.minimum=0
opts.maximum=100
opts.text=str(item_str) #顯示的內(nèi)容
opts.textAlignment=Qt.AlignCenter
opts.textVisible=True
opts.progress=int(item_str) #設置當前進度
#這是關(guān)鍵
#讓QApplication根據(jù)當前的風格渲染控件并畫出來
QApplication.style().drawControl(QStyle.CE_ProgressBar,opts,painter)
def createEditor(self,parent,option,index):
"""
創(chuàng)建編輯器
"""
#創(chuàng)建一個QSPinBox
sbox=QSpinBox(parent)
sbox.setRange(0,100)
#返回這個QSpinBox
return sbox
def setEditorData(self,editor,index):
"""
設置編輯器數(shù)據(jù)
"""
item_var=index.data(Qt.DisplayRole)
item_str=item_var.toPyObject()
item_int=int(item_str)
#設置編輯器的數(shù)據(jù)為當前索引的值
editor.setValue(item_int)
def setModelData(self,editor,model,index):
"""
給model設置編輯后的數(shù)據(jù)
"""
#獲取編輯器的數(shù)據(jù)
data_int=editor.value()
#把數(shù)據(jù)封裝為Qt類型
data_var=QVariant(data_int)
#設置Model的數(shù)據(jù),當前索引與數(shù)據(jù)
model.setData(index,data_var)
####################################################################
if __name__ == "__main__":
main()
>至此,所有 `Pyqt Model/view框架` 系列結(jié)束,不再贅述其他Python與Qt知識
浙公網(wǎng)安備 33010602011771號