从具有值列表的字典创建 Pyqt QtableWidget,然后返回到字典

Creating a Pyqt QtableWidget from a dictionary with list of values, and back to a dictionary

根据之前的问题,我现在可以从字典创建 Pyqt QTreeWidget,编辑树并将其保存到编辑字典。但是,当我涉及到包含字典列表的字典值时,它会编译同一父项下的值(请参阅字典,其中 'Property' 键包含字典列表,并输出到下面的 QTreeWidget)

self.d = {'TestName': {'Ref': 'ABC/DEF', 'Property': [{'Number': '2', 'Zipcode': '0002234',
                                                           'KeyAvailable': 'Yes'}, {'Number': '3',
                                                                                    'Zipcode': '2342444'}]}}

为了整洁起见,为第二个列表项(字典)设置 'Property' 的另一个父项可能会更好。我遇到的主要问题是转换回字典,因为在最后一个条目覆盖前一个条目的那一刻,如果其中一个字典中有一个额外的键(在本例中为 'KeyAvailable'),则会出现额外的问题。

这是转换回字典的输出:

{'TestName': {'Ref': 'ABC/DEF', 'Property': {'Number': '3', 'Zipcode': '2342444', 'KeyAvailable': 'Yes'}}}

在下面的 'tree_from_dict' 和 'tree_2_dict' 函数中是否有处理这些列表实例的简单解决方案?

import sys
from PyQt5.QtWidgets import QWidget, QApplication, QTreeWidget, QTreeWidgetItem, QPushButton, QMainWindow
from PyQt5.QtCore import *


class MyMainWindow(QMainWindow):

    def __init__(self, dialog):
        QMainWindow.__init__(self)

        self.d = {'TestName': {'Ref': 'ABC/DEF', 'Property': [{'Number': '2', 'Zipcode': '0002234',
                                                               'KeyAvailable': 'Yes'}, {'Number': '3',
                                                                                        'Zipcode': '2342444'}]}}

        self.setWindowTitle('Example')
        self.setGeometry(20, 20, 400, 400)

        central = QWidget(self)
        self.setCentralWidget(central)

        self.button = QPushButton('Save button', central)
        self.button.move(100, 350)

        self.tree = QTreeWidget(self.centralWidget())
        self.tree.setGeometry(QRect(30, 30, 300, 300))

        self.tree.setColumnCount(2)
        self.tree.setHeaderLabels(["XML Property", "Value"])

        self.tree.itemDoubleClicked.connect(self.editItem)
        self.button.clicked.connect(self.save_changes)

        self.tree_from_dict(data=self.d, parent=self.tree)

    def editItem(self, item, column):

        try:
            if column == 1:
              item.setFlags(item.flags() | Qt.ItemIsEditable)
            else:
                pass
        except Exception as e:
            print(e)

    def tree_from_dict(self, data=None, parent=None):
        for key, value in data.items():
            item = QTreeWidgetItem(parent)

            item.setText(0, key)

            if isinstance(value, dict):
                self.tree_from_dict(data=value, parent=item)
            elif isinstance(value, list):
                [self.tree_from_dict(i, parent=item) for idx, i in enumerate(value)]

            else:
                item.setText(1, value)

    def save_changes(self):
        d = self.tree_2_dict(self.tree.invisibleRootItem())
        print(d)

    def tree_2_dict(self, parent, d=None):
        if d is None:
            d = {}
        for index in range(parent.childCount()):
            child = parent.child(index)
            if child.childCount():
                self.tree_2_dict(child, d.setdefault(child.text(0), {}))
            else:
                d[child.text(0)] = child.text(1)
        return d


if __name__ == '__main__':
    app = QApplication(sys.argv)
    dialog = QMainWindow()
    foo = MyMainWindow(dialog)
    foo.show()
    sys.exit(app.exec_())
    

我很确定这不是最优雅的解决方案。该函数现在检查 list 是否作为数据传递并添加 属性 与该列表中的元素一样多。

def tree_from_dict(self, data=None, parent=None):
    for key, value in data.items():
        item = QTreeWidgetItem(parent)
        item.setText(0, key)

        if isinstance(value, dict):               
            self.tree_from_dict(data=value, parent=item)
        elif isinstance(value, list):               
            for idx, i in enumerate(value):
                if idx!=0:
                    item = QTreeWidgetItem(parent)
                    item.setText(0, key)
                self.tree_from_dict(i, parent=item)
        else:
            item.setText(1, value)

另一个函数现在额外检查 属性 是否已经是 dict 的键。如果是这样,它将相应的值转换为 list 并附加新值。

 def tree_2_dict(self, item, dic):
    # Variable for saving all occuring property names in that scope
    childrenNames=[]
    for index in range(item.childCount()):
        child = item.child(index)
        if child.text(0) not in childrenNames:
            childrenNames.append(child.text(0))
            if child.childCount():
                dic[child.text(0)]=self.tree_2_dict(child, {})
            else:
                dic[child.text(0)] = child.text(1)
        else:
            ele = dic[child.text(0)]
            
            if child.childCount():
                child_dic =self.tree_2_dict(child,  {})
                if isinstance(ele,list):
                    ele.append(child_dic)
                else:
                    ele=[ele,child_dic]
            else:
                if isinstance(ele,list):
                    ele.append(child.text(1))
                else:
                    ele=[ele,child.text(1)]
            dic[child.text(0)] = ele
    return dic