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

Posted

技术标签:

【中文标题】从具有值列表的字典创建 Pyqt QtableWidget,然后返回字典【英文标题】:Creating a Pyqt QtableWidget from a dictionary with list of values, and back to a dictionary 【发布时间】:2021-11-21 07:20:18 【问题描述】:

继之前的问题之后,我现在可以从字典创建 Pyqt QTreeWidget,编辑树并将其保存到并编辑字典。但是,当我谈到包含字典列表的字典值时,它会编译同一父级下的值(请参阅字典,其中“属性”键包含字典列表,并输出到下面的 QTreeWidget)

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

为了简洁起见,为第二个列表项(字典)设置另一个“属性”父级可能会更好。我遇到的主要问题是转换回字典,因为此时最后一个条目会覆盖前一个条目,如果其中一个字典中有一个额外的键(在本例中为“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_())
    

【问题讨论】:

您对结构有控制权,还是来自第三方?您是否需要在应用程序中保留该特定数据结构?您需要首先决定如何呈现信息,然后设计一个合适的数据结构来适应它。 嗨@ekhumoro,我正在使用xmltodict,但只是在我的XML 的“正文”部分。然后,我希望通过以 QTreeWidget 的形式呈现 dict 来向用户呈现主体标签和值,允许他们进行任何编辑。然后,我希望将这些编辑转换回字典,以便稍后在创建 XML 时使用。 XML 中的重复标记名称通过 xmltodict 转换为带有 dicts 列表的单个键,因此我希望使用该格式,以便更轻松地通过 xmltodict.unparse 函数创建 XML。 我应该添加,理想情况下,我想在 QTreeview 中为每个列表项(dict)显示重复的父级,但我更关心在将 Qtreewidget 转换回来时使用 xmltodict 格式到一个字典 您的解决方案是包含多个 Property 字段还是您更愿意只包含一个(如您的示例所示)?调用tree_2_dict函数时是否要获取原始的XML结构? 嗨@angelogro,理想情况下,我希望QTreeWidget中有多个“属性”字段,以提供更清晰的外观,或者是否有更清晰的方法将两个dict内容分开在同一个'财产的父母?但如果这很难做到,我主要关心的是在 QTreeWidget 中进行任何编辑后运行 tree_2_dict 函数时再次恢复原始字典结构,这最终将使我能够运行 xmltodict.unparse 来构建 XML又回来了。 【参考方案1】:

我很确定这不是最优雅的解决方案。该函数现在检查 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

【讨论】:

感谢@angelogro,这正是我希望实现的。 QTreeWidget 在树中具有重复的父名称而不是将所有子绑定在单个父级下看起来要好得多。我会花点时间来回顾一下你做了什么。再次感谢!

以上是关于从具有值列表的字典创建 Pyqt QtableWidget,然后返回字典的主要内容,如果未能解决你的问题,请参考以下文章

从字典列表创建 Pandas MultiIndex 的最佳方法是啥?

使用 PyQt5“更新”从具有多个参数的函数中销毁返回值 [关闭]

Python - 从包含值列表的字典中添加具有映射值的新列

将列表字典传递给 Qtablewidget - PyQT5

从具有可变长度的列表字典创建数据框

从字典列表中查找值,其中dicts具有不同数量的键