Following on from an earlier question I can now create a Pyqt QTreeWidget from a dictionary, edit the tree and save it to and edited dictionary. However when I comes to dictionary values which contain a list of dictionaries, it compiles the values under the same parent (see dictionary where the 'Property' key contains a list of dictionaries, and output to QTreeWidget below)
self.d = {'TestName': {'Ref': 'ABC/DEF', 'Property': [{'Number': '2', 'Zipcode': '0002234',
'KeyAvailable': 'Yes'}, {'Number': '3',
'Zipcode': '2342444'}]}}
For neatness it would probably be nicer to have another parent of 'Property' for the second list item (dictionary). The main problem I have is converting back into a dictionary, as at the moment the last entry overwrites the previous, with the additional problem if there's an extra key in one of the dictionaries (in this case 'KeyAvailable').
Here's the output converting back to a dictionary:
{'TestName': {'Ref': 'ABC/DEF', 'Property': {'Number': '3', 'Zipcode': '2342444', 'KeyAvailable': 'Yes'}}}
Is there a simple solution for handling these list instances in my 'tree_from_dict' and 'tree_2_dict' functions below?
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_())