首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Qt和Python在嵌套在QSortFilterProxyModel上时没有得到正确的列计数。

Qt和Python在嵌套在QSortFilterProxyModel上时没有得到正确的列计数。
EN

Stack Overflow用户
提问于 2022-02-01 02:17:30
回答 1查看 148关注 0票数 0

我有三个模型: QAbstractItemModel "sourceModel“、QSortFilterProxyModel "proxyModel”用于过滤,以及QIdentityProxyModel "dataModel“用于修改列和显示的数据。

当我只使用layer QAbstractItemModel -> QIdentityProxyModel时,一切都很好。我的源模型只有一个默认列,我可以在我的QIdentifyProxyModel上添加多个新列,我的视图显示所有正确的数据。这允许我在多个不同数据的视图上重用相同的模型,非常好。

但是,如果I layer QAbstractItemModel -> QSortFilterProxyModel -> QIdentityProxyModel,那么我的视图只显示第一列中的数据,选择模型就会中断。如果我在源模型中定义了相等或更高数量的列,那么在我的视图中,所有QIdentityProxyModel列的行为都是正确的,并且显示了与我在源模型中定义的数据不同的数据。

当代理被嵌套时,QIdentityProxyModel类仍然可以使用数据访问源项,但是传递给QIdentityProxyModel的数据函数的索引只查询源模型中定义的数量列。

知道该怎么做吗?任何帮助都是非常感谢的!

代码语言:javascript
运行
复制
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_())
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-02-01 04:35:06

树模型是很棘手的。很多

当你必须处理它们时,你必须真正理解递归。而Qt模型(在某种程度上是复杂的)变得更加困难,而且常常会导致严重的头痛和深夜。

下面的代码是基于previous answer of mine的,这是非常基本的,不考虑子列数量不一致的可能性。

其概念是,基于树结构的代理模型需要跟踪层次结构(通常基于父索引、内部指针或id),并且在创建“幽灵”列时必须考虑这一点。

所有这些都是非常重要的。Item视图需要所有的实现,以便正确更新其内容并允许有效的用户交互。

代码语言:javascript
运行
复制
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也通常被接受):

代码语言:javascript
运行
复制
    def rowCount(self, parent=QtCore.QModelIndex()):
        # ...

    def columnCount(self, parent=QtCore.QModelIndex()):
        # ...
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70934947

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档