'creating a QTreeWidget from a parent-child table in python
I need to display the relations of parts to subassemblies or higher level assemblies. For that reasons I have a SQL table with relation pairs of parts represented by their ID (ID is from a different table where further details are stored):
| parent_ID | child_ID |
|---|---|
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 5 | 4 |
| 5 | 6 |
| 4 | 7 |
| 7 | 8 |
| 4 | 8 |
A child can have multiple parents (a part can be used in multiple products) as well as a parent have multiple childs (a product is assembled from multiple parts).
By selecting a part from a list, I want to have one QTreeWidget to show all higher assemblies and another QTreeWidget to show all subcomponents. Based on the table above the results should be: Higher Assembly
- 4
- 1
- 5
Subassemblies
- 4
- 7
- 8
- 8
- 7
The table read via pandas and stored during runtime as a dataframe.
I did not manage to create the trees by an iterative or recursive loop and store it in a way which allows an easy transfer into the QTree Widget.
Solution 1:[1]
Anytime I've had to deal with complex key/id data from a database I like to convert or pre-process it to an organized dict (nested if needed, which mimics a tree) before adding it to a widget.
It makes it easier to debug while fine tuning your conversion code and then creating the widgets is usually a pretty simple loop. It simplifies your code quite a bit rather than creating a custom class with custom methods/attributes for trying to find already created parent items to add children to further down the loop. You can also use this new dict as a sort of "mapping" for later processing if needed (like creating folders based on these relationships). If nothing else it's just a lot easier to understand what's happening if you have to come back and edit the code later.
win = QtWidgets.QWidget()
main_layout = QtWidgets.QVBoxLayout(win)
win.setLayout(main_layout)
tree_widget = QtWidgets.QTreeWidget(win)
tree_widget.setHeaderLabels(["parents/children",])
main_layout.addWidget(tree_widget)
# replace with fuction for getting data directly from database
db_data = [{"parent_ID": 1, "child_ID": 2},
{"parent_ID": 1, "child_ID": 3},
{"parent_ID": 1, "child_ID": 4},
{"parent_ID": 5, "child_ID": 4},
{"parent_ID": 5, "child_ID": 6},
{"parent_ID": 4, "child_ID": 7},
{"parent_ID": 7, "child_ID": 8},
{"parent_ID": 4, "child_ID": 8}
]
organized_dict = dict()
for entry in db_data:
parent_list = organized_dict.setdefault(entry["parent_ID"], [])
parent_list.append(entry["child_ID"])
for parent in organized_dict:
# print(f"{parent}") # debugging
parent_item = QtWidgets.QTreeWidgetItem([f"parent: {parent}",])
tree_widget.addTopLevelItem(parent_item)
for child in organized_dict[parent]:
# print(f"\t{child}") # debugging
child_item = QtWidgets.QTreeWidgetItem([f"child: {child}",])
parent_item.addChild(child_item)
win.show()
This is a simple example based just on a flat parent/child relationship. I'll leave it to you to adapt it to fit your needs. If you plan on having an undefined depth to your relationships, you will have to use recursion to create a nested organized dict and then again to create the widgets.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | PyHP3D |
