子类化 QAbstractItemModel 以将嵌套的 dict 数据显示为树

如何解决子类化 QAbstractItemModel 以将嵌套的 dict 数据显示为树

我正在尝试使用嵌套字典来实现树状结构来存储我的数据并使用 QTreeView 显示它。 对我来说,关键部分是跟踪对嵌套 dict 结构或 QTreeView 中的数据所做的更改。我尝试对 qabstractitemmodel 进行子类化,但无法弄清楚如何将 QTreeView 中所做的更改与我的嵌套 dict 结构同步,唯一有效的是在每次更改时重新填充整个树......是否可以在不重建的情况下实现这样的事情每次进行更改时都会生成一棵树?

所需的行为是这样的: 嵌套dict中的更改数据->更改会自动显示在QTreeView中。

我发现了类似的问题,但用 QTreeWidget 代替:QTreeWidget to Mirror python Dictionary

但是,这种方法也需要在每次更改时重新填充树...

嵌套字典(树数据)看起来像这样:

root_node = {
            node1: { leaf1: data,leaf2: data}
            node2: { node3: { leaf3: data,leaf4: data }}
       }

UPD:添加了我目前得到的代码

from PyQt5.QtCore import QModelIndex,Qt,qabstractitemmodel


class TreeNode(object):
    def __init__(self,data,parent=None):
        self.parent_node = parent
        self.node_data = data  # it's also []
        self.child_nodes = []

    def child(self,row):
        return self.child_nodes[row]

    def child_count(self):
        return len(self.child_nodes)

    def child_number(self):
        if self.parent_node is not None:
            return self.parent_node.child_nodes.index(self)
        return 0

    def column_count(self):
        return len(self.node_data)

    def data(self,column):
        return self.node_data[column]

    def insert_children(self,position,count,columns):
        if position < 0 or position > len(self.child_nodes):
            return False

        for row in range(count):
            data = [None for v in range(columns)]
            node = TreeNode(data,self)
            self.child_nodes.insert(position,node)

        return True

    def append_child_by_node(self,node):
        node.parent_node = self
        self.child_nodes.append(node)

    def append_child_by_data(self,data):
        self.child_nodes.append(TreeNode(data,self))

    def insert_columns(self,columns):
        if position < 0 or position > len(self.node_data):
            return False

        for column in range(columns):
            self.node_data.insert(position,None)

        for child in self.child_nodes:
            child.insert_columns(position,columns)

        return True

    def parent(self):
        return self.parent_node

    def remove_children(self,count):
        if position < 0 or position + count > len(self.child_nodes):
            return False

        for row in range(count):
            self.child_nodes.pop(position)

        return True

    def remove_columns(self,columns):
        if position < 0 or position + columns > len(self.node_data):
            return False

        for column in range(columns):
            self.node_data.pop(position)

        for child in self.child_nodes:
            child.remove_columns(position,columns)

        return True

    def set_data(self,column,value):
        if column < 0 or column >= len(self.node_data):
            return False

        self.node_data[column] = value

        return True


class TreeModel(qabstractitemmodel):
    def __init__(self,parent=None,nested_dict=dict):
        super(TreeModel,self).__init__(parent)
        self.root_node = TreeNode(["Name","Type"])
        self.update_tree(self.root_node,nested_dict)

        print(self.root_node.child_count())

    def columnCount(self,parent=QModelIndex()):
        return self.root_node.column_count()

    def data(self,index,role):
        if not index.isValid():
            return None

        if role != Qt.displayRole and role != Qt.EditRole:
            return None

        node = self.get_node(index)
        return node.data(index.column())

def flags(self,index):
    if not index.isValid():
        return 0

    return Qt.ItemIsEnabled | Qt.ItemIsSelectable

def get_node(self,index):
    if index.isValid():
        node = index.internalPointer()
        if node:
            return node

    return self.root_node

def headerData(self,section,orientation,role=Qt.displayRole):
    if orientation == Qt.Horizontal and role == Qt.displayRole:
        return self.root_node.data(section)

    return None

def index(self,row,parent=QModelIndex()):
    if parent.isValid() and parent.column() != 0:
        return QModelIndex()

    parent_node = self.get_node(parent)
    child_node = parent_node.child(row)
    if child_node:
        return self.createIndex(row,child_node)
    else:
        return QModelIndex()

def insertColumns(self,columns,parent=QModelIndex()):
    self.beginInsertColumns(parent,position + columns - 1)
    success = self.root_node.insert_columns(position,columns)
    self.endInsertColumns()

    return success

def insertRows(self,rows,parent=QModelIndex()):
    parent_node = self.get_node(parent)
    self.beginInsertRows(parent,position + rows - 1)
    success = parent_node.insert_children(position,self.root_node.column_count())
    self.endInsertRows()

    return success

def parent(self,index):
    if not index.isValid():
        return QModelIndex()

    child_node = self.get_node(index)
    parent_node = child_node.parent()

    if parent_node == self.root_node:
        return QModelIndex()

    return self.createIndex(parent_node.child_number(),parent_node)

def removeColumns(self,parent=QModelIndex()):
    self.beginRemoveColumns(parent,position + columns - 1)
    success = self.root_node.remove_columns(position,columns)
    self.endRemoveColumns()

    if self.root_node.column_count() == 0:
        self.removeRows(0,self.rowCount())

    return success

def removeRows(self,parent=QModelIndex()):
    parent_node = self.get_node(parent)

    self.beginRemoveRows(parent,position + rows - 1)
    success = parent_node.remove_children(position,rows)
    self.endRemoveRows()

    return success

def rowCount(self,parent=QModelIndex()):
    parent_node = self.get_node(parent)

    return parent_node.child_count()

def setData(self,value,role=Qt.EditRole):
    if role != Qt.EditRole:
        return False

    node = self.get_node(index)
    result = node.set_data(index.column(),value)

    if result:
        self.dataChanged.emit(index,index)

    return result

def setHeaderData(self,role=Qt.EditRole):
    if role != Qt.EditRole or orientation != Qt.Horizontal:
        return False

    result = self.root_node.set_data(section,value)
    if result:
        self.headerDataChanged.emit(orientation,section)

    return result

def update_tree(self,parent,nested_dict):
    self.layoutChanged.emit()
    parent.child_nodes.clear()
    for k,v in nested_dict.items():
        if isinstance(v,dict):
            parent.append_child_by_data([k[0] if isinstance(k,tuple) else k,None])
            self.update_tree(parent.child(parent.child_count() - 1),v)
        else:
            parent.append_child_by_data([k,None])

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

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?