我有三个模型: QAbstractItemModel "sourceModel“、QSortFilterProxyModel "proxyModel”用于过滤,以及QIdentityProxyModel "dataModel“用于修改列和显示的数据。
当我只使用layer QAbstractItemModel -> QIdentityProxyModel时,一切都很好。我的源模型只有一个默认列,我可以在我的QIdentifyProxyModel上添加多个新列,我的视图显示所有正确的数据。这允许我在多个不同数据的视图上重用相同的模型,非常好。
但是,如果I layer QAbstractItemModel -> QSortFilterProxyModel -> QIdentityProxyModel,那么我的视图只显示第一列中的数据,选择模型就会中断。如果我在源模型中定义了相等或更高数量的列,那么在我的视图中,所有QIdentityProxyModel列的行为都是正确的,并且显示了与我在源模型中定义的数据不同的数据。
当代理被嵌套时,QIdentityProxyModel类仍然可以使用数据访问源项,但是传递给QIdentityProxyModel的数据函数的索引只查询源模型中定义的数量列。
知道该怎么做吗?任何帮助都是非常感谢的!
from PySide2 import QtCore, QtWidgets, QtGui
class Item(dict):
def __init__(self, data=None):
super(Item, self).__init__()
self._children = list()
self._parent = None
if data:
self.update(data)
def childCount(self):
return len(self._children)
def child(self, row):
if row >= len(self._children):
return
return self._children[row]
def children(self):
return self._children
def parent(self):
return self._parent
def row(self):
if self._parent is not None:
siblings = self.parent().children()
return siblings.index(self)
def add_child(self, child):
child._parent = self
self._children.append(child)
class TreeModel(QtCore.QAbstractItemModel):
Columns = list()
ItemRole = QtCore.Qt.UserRole + 1
def __init__(self, parent=None):
super(TreeModel, self).__init__(parent)
self._root_item = Item()
def rowCount(self, parent):
if parent.isValid():
item = parent.internalPointer()
else:
item = self._root_item
return item.childCount()
def columnCount(self, parent):
return len(self.Columns)
def setColumns(self, keys):
assert isinstance(keys, (list, tuple))
self.Columns = keys
def data(self, index, role):
if not index.isValid():
return None
if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
item = index.internalPointer()
column = index.column()
key = self.Columns[column]
return item.get(key, None)
if role == self.ItemRole:
return index.internalPointer()
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if section < len(self.Columns):
return self.Columns[section]
super(TreeModel, self).headerData(section, orientation, role)
def parent(self, index):
item = index.internalPointer()
parent_item = item.parent()
if parent_item == self._root_item or not parent_item:
return QtCore.QModelIndex()
return self.createIndex(parent_item.row(), 0, parent_item)
def index(self, row, column, parent):
if not parent.isValid():
parent_item = self._root_item
else:
parent_item = parent.internalPointer()
child_item = parent_item.child(row)
if child_item:
return self.createIndex(row, column, child_item)
else:
return QtCore.QModelIndex()
def add_child(self, item, parent=None):
if parent is None:
parent = self._root_item
parent.add_child(item)
def column_name(self, column):
if column < len(self.Columns):
return self.Columns[column]
def clear(self):
self.beginResetModel()
self._root_item = Item()
self.endResetModel()
class CustomSortFilterProxyModel(QtCore.QSortFilterProxyModel):
def __init__(self, parent=None):
super(CustomSortFilterProxyModel, self).__init__(parent)
def filterAcceptsRow(self, row, parent):
model = self.sourceModel()
index = model.index(row, self.filterKeyColumn(), parent)
item = index.internalPointer()
if item.get('name'):
return True
else:
return False
class IdentityProxyModel(QtCore.QIdentityProxyModel):
def __init__(self, *args, **kwargs):
super(IdentityProxyModel, self).__init__(*args, **kwargs)
self.Columns = []
self._root_item = Item()
def setColumns(self, keys):
assert isinstance(keys, (list, tuple))
self.Columns = keys
#
def columnCount(self, parent):
# return 3
return len(self.Columns)
def column_name(self, column):
if column < len(self.Columns):
return self.Columns[column]
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.DisplayRole:
if section < len(self.Columns):
return self.Columns[section]
super(IdentityProxyModel, self).headerData(section, orientation, role)
def data(self, index, role):
if not index.isValid():
return
if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
item = self.mapToSource(index).data(TreeModel.ItemRole)
column = index.column()
key = self.Columns[column]
return item.get(key, None)
return super(IdentityProxyModel, self).data(index, role)
if __name__ == '__main__':
import sys
sourceModel = TreeModel()
sourceModel.setColumns(['name'])
sourceModel.add_child(Item({'name': 'itemA', 'number': '1', 'info': 'A'}))
sourceModel.add_child(Item({'name': 'itemB', 'number': '2', 'info': 'B'}))
proxyModel = CustomSortFilterProxyModel()
proxyModel.setSourceModel(sourceModel)
dataModel = IdentityProxyModel()
dataModel.setSourceModel(proxyModel)
dataModel.setColumns(['name', 'info'])
app = QtWidgets.QApplication(sys.argv)
view = QtWidgets.QTreeView()
view.setModel(dataModel)
view.show()
sys.exit(app.exec_())
发布于 2022-02-01 04:35:06
树模型是很棘手的。很多。
当你必须处理它们时,你必须真正理解递归。而Qt模型(在某种程度上是复杂的)变得更加困难,而且常常会导致严重的头痛和深夜。
下面的代码是基于previous answer of mine的,这是非常基本的,不考虑子列数量不一致的可能性。
其概念是,基于树结构的代理模型需要跟踪层次结构(通常基于父索引、内部指针或id),并且在创建“幽灵”列时必须考虑这一点。
所有这些都是非常重要的。Item视图需要所有的实现,以便正确更新其内容并允许有效的用户交互。
class IdentityProxyModel(QtCore.QIdentityProxyModel):
def __init__(self, *args, **kwargs):
super(IdentityProxyModel, self).__init__(*args, **kwargs)
self.Columns = []
self._parents = {}
self._root_item = Item()
# ...
def _isInvalid(self, column):
# we assume that the model always has the same column count
return column > self.sourceModel().columnCount() - 1
def mapToSource(self, index):
if self._isInvalid(index.column()):
index = index.sibling(index.row(), 0)
return super().mapToSource(index)
def index(self, row, column, parent=QtCore.QModelIndex()):
if self._isInvalid(column):
index = self.createIndex(row, column, parent.internalId())
self._parents[index] = parent
return index
return super().index(row, column, parent)
def parent(self, index):
if self._isInvalid(index.column()):
return self._parents[index]
return super().parent(index)
def flags(self, index):
if self._isInvalid(index.column()):
return self.flags(index.sibling(index.row(), 0))
return super().flags(index)
def sibling(self, row, column, idx):
if self._isInvalid(column):
return self.index(row, column, idx.parent())
elif self._isInvalid(idx.column()):
idx = self.index(idx.row(), 0, idx.parent())
return super().sibling(row, column, idx)
注意:重写应该始终使用它们的基本实现的签名。例如,rowCount()
和columnCount()
都必须接受无效的关键字父参数,该参数不用于模型顶层的“快速调用”。通常的做法是使用一个基本的QModelIndex实例,因为它基本上是一个不可变的对象(但None
也通常被接受):
def rowCount(self, parent=QtCore.QModelIndex()):
# ...
def columnCount(self, parent=QtCore.QModelIndex()):
# ...
https://stackoverflow.com/questions/70934947
复制相似问题