微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

QListView 按数据属性过滤不是文本

如何解决QListView 按数据属性过滤不是文本

我希望视图能够根据数据的内部属性显示相同数据的不同子集,当然,这些视图共享相同的模型。

这是一个带有屏幕截图的示例:

1 - 显示带有“名称”和“状态”的项目列表的表格视图

2 - 显示按“状态”过滤的项目的列表视图,但不显示状态(理想情况下,我希望此列表视图在名称旁边显示状态颜色,但这可能是一个不同的问题)。

我的目标是创建 2 种查看数据的方式:作为全局(未过滤)表,以及作为一种带有每个“状态”(或任何其他属性)列表的看板。

表格视图显示所有

enter image description here

显示过滤数据的列表视图

enter image description here

这是我的模型的代码以及我如何构建数据。

我对 Qt 很满意,但我对它的 Model-View 类还不熟悉,所以如果有任何关于如何更好地做到这一点的建议,我们非常欢迎!


import sys
from pyside2.QtWidgets import *
from pyside2 import QtCore,QtGui
from pyside2.QtCore import Qt


class TestModel(QtCore.QAbstractTableModel):
    def __init__(self,items=None,parent=None):
        super(TestModel,self).__init__(parent)
        self.__items = items or []

    def headerData(self,section,orientation,role):
        headers = ('Name','Status')
        if role == Qt.displayRole and orientation == Qt.Horizontal:
                return headers[section]

    def columnCount(self,parent):
        return 2

    def rowCount(self,parent):
        return len(self.__items)

    def data(self,index,role):
        column = index.column()
        item = self.__items[index.row()]
        # Name
        if column == 0:
            if role == Qt.displayRole:
                return item.name
            if role == Qt.EditRole:
                return item.name
        # Status
        elif column == 1:
            if role == Qt.displayRole:
                return item.status
            if role == Qt.EditRole:
                return item.status
            if role == Qt.decorationRole:
                pixmap = QtGui.Qpixmap(26,26)
                pixmap.fill(item.status_color)
                icon = QtGui.QIcon(pixmap)
                return icon

        if role == Qt.ToolTipRole:
            return item.__repr__()


class Item(object):
    def __init__(self,name='',status=None):
        self._valid_statuses = ('active','hold','closed','done')
        self._color_map = {self._valid_statuses[0]: '#56FF51',# valid
                           self._valid_statuses[1]: '#B8E5EC',# hold
                           self._valid_statuses[2]: '#F42525',self._valid_statuses[3]: '#E7F64D'
                           } # closed
        self.name = name
        self._status = status or self._valid_statuses[0]

    @property
    def status(self):
        return self._status

    @status.setter
    def status(self,status):
        if status not in self._valid_statuses:
            status = self._valid_statuses[0]
        self._status = status

    @property
    def status_color(self):
        # return black if invalid
        return self._color_map.get(self._status,'#000000')


app = QApplication([])

data = [
    Item(name='one',status='active'),Item(name='two',Item(name='three',status='hold'),Item(name='four',status='closed'),Item(name='five',status='done'),]

model = TestModel(data)

# Table
table_view = QTableView()
table_view.show()
table_view.setModel(model)

# List with the wanted filters i.e.: by 'approved' status
list_view = QListView()
list_view.show()
list_view.setModel(model)

sys.exit(app.exec_())

解决方法

在这种情况下,解决方案是使用 QSortFilterProxyModel 并制作自定义过滤器:

class StatusFilterModel(QtCore.QSortFilterProxyModel):
    def __init__(self,parent=None):
        super(StatusFilterModel,self).__init__(parent)
        self._status = None

    @property
    def status(self):
        return self._status

    @status.setter
    def status(self,status):
        self._status = status
        self.invalidateFilter()

    def filterAcceptsRow(self,source_row,source_parent):
        if self.status is None:
            return True
        source_index = self.sourceModel().index(source_row,1,source_parent)
        status = source_index.data()
        return self.status == status
list_view = QListView()
list_view.show()
proxy_model = StatusFilterModel()
proxy_model.setSourceModel(model)
proxy_model.status = "active"
list_view.setModel(proxy_model)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。