Dynamically generate pygtk menu's based on dictionaries and lists
Question
I have a list of options that I read from an xml file. In the list there is information like codenames, item relations, child codenames ...
I use the following functions to generate pygtk boxes with the proper buttons in it. My problem is that I have to be able to hide/show those boxes at some points (one example would be self.btn_box_web.show()/hide().
How could I better generate my menu's or access them ?
I first generate a list of server install type and make a box with proper buttons in it
def build_custom_server(self, server_type_dict, component_dict):
self.custom_server_box = gtk.VBox(False, 0)
self.option_box.pack_start(self.custom_server_box, False)
self.custom_server_box.set_border_width(10)
self.custom_server_label = gtk.Label("Customize your server instalation:")
self.custom_server_box.pack_start(self.custom_server_label, True)
self.type_box = gtk.HBox(True, 0)
self.custom_server_box.pack_start(self.type_box, False)
self.type_label = gtk.Label("Server type:")
self.type_box.pack_start(self.type_label, True)
for stype in server_type_dict:
self.btn_name = "self.btn_" + stype
self.img_name = "self.img_" + stype
self.label_name = "self.label_" + stype
self.box_name = "self.btn_box_" + stype
vars()[self.btn_name] = gtk.ToggleButton()
vars()[self.box_name] = gtk.VBox(False, 0)
vars()[self.img_name] = gtk.Image()
vars()[self.img_name].set_from_file("art/" + stype + ".png")
vars()[self.label_name] = gtk.Label(server_type_dict[stype])
vars()[self.box_name].pack_start(vars()[self.img_name], False)
vars()[self.box_name].pack_end(vars()[self.label_name], False)
vars()[self.btn_name].add(vars()[self.box_name])
self.type_box.pack_start(vars()[self.btn_name], True)
self.load_type(server_type_dict, component_dict, stype)
Then for each type (type can be in 2 fields since we have main categories and secondaries) I generate a separate box with the components.
def load_type(self, server_type_dict, component_dict, stype):
self.up_label_name = "self.label_" + stype
self.up_box_name = "self.btn_box_" + stype
vars()[self.up_box_name] = gtk.HBox(False, 0)
vars()[self.up_label_name] = gtk.Label(server_type_dict[stype])
vars()[self.up_box_name].pack_start(vars()[self.up_label_name], False)
self.custom_server_box.pack_start(vars()[self.up_box_name], False)
for compo in component_dict:
if component_dict[compo][1] == stype:
self.btn_name = "self.btn_" + compo
self.img_name = "self.img_" + compo
self.label_name = "self.label_" + compo
self.box_name = "self.btn_box_" + compo
vars()[self.btn_name] = gtk.ToggleButton()
vars()[self.box_name] = gtk.VBox(False, 0)
vars()[self.img_name] = gtk.Image()
vars()[self.img_name].set_from_file("art/" + compo + ".png")
vars()[self.label_name] = gtk.Label(component_dict[compo][0])
vars()[self.box_name].pack_start(vars()[self.img_name], False)
vars()[self.box_name].pack_end(vars()[self.label_name], False)
vars()[self.btn_name].add(vars()[self.box_name])
vars()[self.up_box_name].pack_start(vars()[self.btn_name], True)
elif component_dict[compo][2] == stype:
self.btn_name = "self.btn_" + compo
self.img_name = "self.img_" + compo
self.label_name = "self.label_" + compo
self.box_name = "self.btn_box_" + compo
vars()[self.btn_name] = gtk.ToggleButton()
vars()[self.box_name] = gtk.VBox(False, 0)
vars()[self.img_name] = gtk.Image()
vars()[self.img_name].set_from_file("art/" + compo + ".png")
vars()[self.label_name] = gtk.Label(component_dict[compo][0])
vars()[self.box_name].pack_start(vars()[self.img_name], False)
vars()[self.box_name].pack_end(vars()[self.label_name], False)
vars()[self.btn_name].add(vars()[self.box_name])
vars()[self.up_box_name].pack_start(vars()[self.btn_name], True)
My full code can be found here
Solution
That's a lot of code to go through, so I'm not entirely sure that I know exactly what you want to do. I can think of a couple of ways that you can later access these dynamically created widgets, though.
One would be to use widget.set_name()
to give each widget a name. You could then later get all the child widgets and iterate over them looking for the one with that name. If you have a lot of widgets, this might be slow. It might be easier to just keep a dict()
object keyed with the names you get from the config file, which you could then dynamically access later. ie, something like:
widgets = {}
for stype in server_type_dict:
widgets[stype] = {}
widgets[stype]['btn'] = gtk.ToggleButton()
widgets[stype]['box'] = gtk.VBox(False, 0)
widgets[stype]['img'] = gtk.Image()
...
self.type_box.pack_start(widgets[stype]['btn'], True)
self.load_type(server_type_dict, component_dict, stype)
...and so on.
Later, if you need the "web" server-type button, you would just call widgets['web']['btn']