Better than editing the XML #268
|
I have a grid layout and I want to repeat the final row many times Currently I am editing the .ui XML before I use builder and it works The .ui XML is then subject to change by the designer saving over any edits but also potentially invalidating my logic for find the portion of the XML I want to edit/replace If there was a way for builder.get_object to use a multi line string for just the nodes I'm manipulating, but I can't put all columns in one widget/frame and I need to update their values I think duplication of XML nodes after its loaded by the builder might be the right point to do the changes, is there a callback or access to the tree? This is possibly a really bad question, I'm not really sure I'm taking the right approach, apologies if this was hard to read. Kind Regards |
Replies: 1 comment 1 reply
|
Hello @coffeelover1010, thanks for trying pygubu.
The dirty way, manipulate the UI before window creation using methods from UIDefinition class. Example: It will depend on how you designed the ui. In this example, you have a "container" frame, and some other "row" frame that you will duplicate. def manipulate_ui(self, builder:Builder):
# Get the UIDefinition
ui: UIDefinition = builder.uidefinition
# Get the container frame
container = ui.get_xmlnode("fcontainer")
# Get the "template" row frame
row_tpl = ui.get_xmlnode("row_template")
# template = ET.tostring(row_tpl)
# Duplicate the template x times
for index in range(0, 10):
# Copy template node
row_node = copy.deepcopy(row_tpl)
# Rename node. Nodes with same id are no created again by builder.
node_id = row_node.get("id")
new_id = f"{node_id}_{index}"
row_node.set("id", new_id)
# Rename all children nodes
xpath = f".//object"
sub_objects = row_node.findall(xpath)
for node in sub_objects:
node_id = node.get("id")
new_id = f"{node_id}_{index}"
node.set("id", new_id)
print(f"New node: {new_id}")
# Add new node to the container frame
ui.add_xmlchild(container, row_node)See the full example attached. Another approach. More cleaner (I think), you can create a custom widget.
This approach will depend on whether it is possible to define your "final row" as a widget (or frame). Example. Your "final row" is a frame with "first name" and "last name" inputs. You want to duplicate this widget 10 times. Some advantages over the first approach:
#!/usr/bin/python3
import pathlib
import tkinter as tk
import pygubu
import mainappui as baseui
from widgets.person_frame import PersonFrame
baseui.PROJECT_UI = baseui.PROJECT_PATH / "ui/mainapp.ui"
class Issue268App(baseui.Issue268AppUI):
def __init__(self, master=None):
super().__init__(master)
self.persons = []
self.populate_ui()
def populate_ui(self):
container = self.builder.get_object("fcontainer")
for i in range(0, 10):
new = PersonFrame(container)
new.pack(fill="x")
self.persons.append(new)
if __name__ == "__main__":
app = Issue268App()
app.run()Full examples: Hope this helps. Let me know. Regards! |




Hello @coffeelover1010, thanks for trying pygubu.
The dirty way, manipulate the UI before window creation using methods from UIDefinition class.
Example: It will depend on how you designed the ui. In this example, you have a "container" frame, and some other "row" frame that you will duplicate.