Generating Tkinter User Interfaces from XML
Fredrik Lundh | August 2003 | Originally posted to online.effbot.org
Note: Simon Forman has combined a small custom language with ideas from this article into a tool for generating Tkinter user interfaces from short textual descriptions, called Pygoo.
The following snippet takes an element tree, and uses it to populate a Tkinter Frame widget.
import Tkinter def realize(master, element): if element.tag == "form": frame = Tkinter.Frame(master, **element.attrib) for subelement in element: widget = realize(frame, subelement) widget.pack() return frame else: options = element.attrib if element: options = options.copy() for subelement in element: options[subelement.tag] = subelement.text widget_factory = getattr(Tkinter, element.tag.capitalize()) return widget_factory(master, **options)
The function supports two kinds of elements; form elements and widget elements such as entry, label, text, etc.
Form elements are used to create and populate Tkinter frame widgets. Each form element can contain one or more widget elements, and can also contain other forms. Attributes on a form element as passed as options to the underlying frame widget.
Widget elements map directly to the corresponding Tkinter widget, with options taken from the element attributes. For widget elements, subelements are also mapped to Tkinter options. For example, you can specify label text using either a text attribute or a text subelement.
Let’s try it out:
from elementtree.ElementTree import XML from Tkinter import Tk form = XML("""\ <form> <label><text>entry:</text></label> <entry width='30' bg='gold' /> <checkbutton><text>checkbutton</text></checkbutton> <button text='OK' /> <button text='Cancel' /> </form> """) root = Tk() root.title("ElementTk") frame = realize(root, form) frame.pack() root.mainloop()
Here’s the resulting window:
To add some behaviour to this example, you need a way to get your hands on the actual widget instances. Tkinter’s name option comes in handy; by naming the widgets, you can access them via the frame’s children attribute:
from elementtree.ElementTree import XML from Tkinter import Tk form = XML("""\ <form> <label><text>entry:</text></label> <entry name='entry' width='30' bg='gold' /> <checkbutton><text>checkbutton</text></checkbutton> <button name='ok' text='OK' /> <button name='cancel' text='Cancel' /> </form> """) root = Tk() frame = realize(root, form) frame.pack() def ok(): print frame.children["entry"].get() root.quit() # add button behaviour frame.children["ok"].config(command=ok) frame.children["cancel"].config(command=root.quit) root.mainloop()
Not perfect, but it’s good enough to play with. (If you have any good ideas on how to make it better, feel free to leave a comment).