QListView 按数据属性(不是文本)过滤
QListView filter by data attribute (not text)
我希望视图基于数据的内部属性显示相同数据的不同子集,当然,视图共享相同的模型。
这是一个带有屏幕截图的示例:
1 - 显示具有“名称”和“状态”的项目列表的 table 视图
2 - 显示按“状态”过滤的项目的列表视图,但不显示状态(理想情况下,我希望此列表视图在名称旁边显示状态颜色,但这可能是一个不同的问题).
我的目标是创建两种查看数据的方式:作为全局(未过滤)table,以及作为一种看板,其中包含每个“状态”(或任何其他属性)的列表).
Table 视图显示全部
显示筛选数据的列表视图
这是我的模型代码以及我构建数据的方式。
我对 Qt 很满意table,但我是它的模型视图 类 的新手,所以如果有任何关于如何更好地做到这一点的建议,我们非常欢迎!
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', status='active'),
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)
我希望视图基于数据的内部属性显示相同数据的不同子集,当然,视图共享相同的模型。
这是一个带有屏幕截图的示例:
1 - 显示具有“名称”和“状态”的项目列表的 table 视图
2 - 显示按“状态”过滤的项目的列表视图,但不显示状态(理想情况下,我希望此列表视图在名称旁边显示状态颜色,但这可能是一个不同的问题).
我的目标是创建两种查看数据的方式:作为全局(未过滤)table,以及作为一种看板,其中包含每个“状态”(或任何其他属性)的列表).
Table 视图显示全部
显示筛选数据的列表视图
这是我的模型代码以及我构建数据的方式。
我对 Qt 很满意table,但我是它的模型视图 类 的新手,所以如果有任何关于如何更好地做到这一点的建议,我们非常欢迎!
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', status='active'),
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)