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

>上篇介绍了如何自定义编辑项,这篇,我们将会使Model具备排序与筛选功能

排序

上篇的代码中的添加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   黑暗伯爵  阅读(3318)  评论(0编辑  收藏  举报

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述

导航

< 2012年4月 >
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 1 2 3 4 5
6 7 8 9 10 11 12

统计

点击右上角即可分享
微信分享提示