PyxBoil
The wxrc utility can create a C++ header with code that provides easy access to the controls defined in the XRC file.
There was no such utility for wxPython that I could find, so I wrote one myself. It is in a very preliminary state, so don't expect too much. It works though. I've even patched XRCed a bit to automatically generate the relevant Python code each time you save the XRC.
pyxboil.py
This is the source of the tool (which can also be used somewhere else as a module):
1 # pyxboil.py
2 #
3 # This script generates boilerplate classes out of an XRC resource file.
4 # For each top-level windows (Panel, Frame or Dialog) a class is generated
5 # and all the controls become attributes of the class.
6
7 import sys
8 import re
9 import os
10 from xml.dom import minidom
11
12 # --------------------------- Template definitions --------------------------
13 fileHeaderTemplate = """\
14 # This file has been automatically generated by PyXBoil.
15 # Please do not edit it manually.
16
17 import wx
18 from wx.xrc import *
19 """
20
21 classDeclarationTemplate = """\
22 class %(windowName)sBase(wx.%(windowClass)s):
23 def OnInit(self):
24 \"\"\" This function is called during the class's initialization.
25
26 Override it for custom setup (setting additional styles, etc.)\"\"\"
27 pass
28
29 def __init__(self, parent, res):
30 \"\"\" Pass an initialized wx.xrc.XmlResource into res \"\"\"
31
32 # Two stage creation (see http://wiki.wxpython.org/index.cgi/TwoStageCreation)
33 pre = wx.Pre%(windowClass)s()
34 res.LoadOnPanel(pre, parent, "%(windowName)s")
35 self.OnInit()
36 self.PostCreate(pre)
37
38 # Define variables for the controls"""
39
40 controlDeclationTemplate = """\
41 self.%(controlName)s = XRCCTRL(self, \"%(controlName)s\")"""
42
43 # ------------------------- GeneratePythonForXRC ----------------------------
44 def GeneratePython(xrcFile, outFile):
45 xmldoc = minidom.parse(xrcFile)
46 resource = xmldoc.childNodes[0]
47 topWindows = [e for e in resource.childNodes
48 if e.nodeType == e.ELEMENT_NODE and e.tagName == "object"]
49 print >> outFile, fileHeaderTemplate
50
51 # Generate a class for each top-window object (Frame, Panel, Dialog, etc.)
52 for topWindow in topWindows:
53 eventFunctions = [] # a list to store the code for the event functions
54 windowClass = topWindow.getAttribute("class")
55 windowClass = re.sub("^wx", "", windowClass)
56 windowName = topWindow.getAttribute("name")
57 print >> outFile, classDeclarationTemplate % locals()
58
59 # Generate a variable for each control, and standard event handlers
60 # for standard controls.
61 for control in topWindow.getElementsByTagName("object"):
62 controlClass = control.getAttribute("class")
63 controlClass = re.sub("^wx", "", controlClass)
64 controlName = control.getAttribute("name")
65 if controlName != "" and controlClass != "":
66 print >> outFile, controlDeclationTemplate% locals()
67
68 print >> outFile
69 print >> outFile, "\n".join(eventFunctions)
70
71 # --------------------- Main ----------------
72
73 def Usage():
74 print """
75 xrcpy -- Python boilerplate code generator for XRC resources.
76
77 Usage : python pyxrc.py <resource.xrc>
78
79 The Python code is printed to the standard output.
80 """
81
82 def main():
83 if len(sys.argv) != 2:
84 Usage()
85 else:
86 inFilename = sys.argv[1]
87 outFilename = os.path.splitext(inFilename)[0] + "_xrc.py"
88
89 try:
90 inStream = file(inFilename)
91 try:
92 outStream = file(outFilename, "w")
93 except IOError:
94 print >> sys.stderr, "Can't open '%s'!" % outFilename
95 else:
96 GeneratePython(inStream, outStream)
97 print "Result stored in %s." % outFilename
98 except IOError:
99 print >> sys.stderr, "Can't open '%s'!" % inFilename
100
101
102 if __name__ == "__main__":
103 main()
xrced_pyxboil.patch
This is a patch file for XRCed 0.1.7-1 so that when an resource.xrc is saved, a resource_xrc.py file is created.
383a384 > self.GeneratePython(path) 1155a1157,1170 > > def GeneratePython(self, xrcPath): > import pyxboil > import os.path > try: > pyPath = os.path.splitext(xrcPath)[0] + "_xrc.py" > infile = file(xrcPath) > outfile = file(pyPath, "w") > pyxboil.GeneratePython(infile, outfile) > except: > inf = sys.exc_info() > wxLogError(traceback.format_exception(inf[0], inf[1], None)[-1]) > wxLogError('Error writing file: %s' % pyPath) > raise
Demo
This is simple application that uses pyxboil. You'll need to run python pyxboil.py pyxboil_demo.xrc to generate the boilerplate code in pyxboil_demo_xrc.py before you run pyxboil_demo.py.
pyxboil_demo.py
1 import sys
2 import wx
3 from wx.xrc import *
4 from pyxboil_demo_xrc import *
5
6 XML_RESOURCE_FILE = "pyxboil_demo.xrc"
7
8 class MyFrame(wx.Frame):
9 def __init__(self, parent=None):
10 wx.Frame.__init__(self, parent)
11
12 class MyPanel(MyPanelBase):
13 def __init__(self, parent, res):
14 MyPanelBase.__init__(self, parent, res)
15 self.Bind(wx.EVT_BUTTON, self.OnOk, self.OkButton)
16
17 def OnOk(self, e):
18 message = "You are " + self.firstName.GetValue() + " " + self.lastName.GetValue() + "!"
19 dlg = wx.MessageDialog(self, message, "Hmm...", wx.OK | wx.ICON_INFORMATION)
20 dlg.ShowModal()
21 dlg.Destroy()
22
23 class MyApp(wx.App):
24 def OnInit(self):
25 self.res = XmlResource(XML_RESOURCE_FILE)
26 self.frame = MyFrame(None)
27 self.panel = MyPanel(self.frame, self.res)
28 self.frame.Center()
29 self.frame.Show(1)
30 return True
31
32 if __name__ == '__main__':
33 app = MyApp()
34 app.MainLoop()
pyxboil_demo.xrc
<?xml version="1.0" encoding="cp1255"?> <resource> <object class="wxPanel" name="MyPanel"> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <object class="wxStaticText"> <label>So, who are you?</label> <font> <size>12</size> <family>default</family> <style>normal</style> <weight>normal</weight> <underlined>0</underlined> </font> </object> <flag>wxALL</flag> <border>5</border> </object> <object class="spacer"> <size>0,15</size> </object> <object class="sizeritem"> <object class="wxBoxSizer"> <orient>wxHORIZONTAL</orient> <object class="sizeritem"> <object class="wxStaticText"> <label>First Name:</label> <size>80,20</size> </object> </object> <object class="spacer"> <size>5,0</size> </object> <object class="sizeritem"> <object class="wxTextCtrl" name="firstName"/> <option>1</option> <flag>wxEXPAND</flag> </object> </object> <flag>wxALL|wxEXPAND</flag> <border>5</border> </object> <object class="sizeritem"> <object class="wxBoxSizer"> <orient>wxHORIZONTAL</orient> <object class="sizeritem"> <object class="wxStaticText"> <label>Last Name:</label> <size>80,20</size> </object> </object> <object class="spacer"> <size>5,0</size> </object> <object class="sizeritem"> <object class="wxTextCtrl" name="lastName"/> <option>1</option> <flag>wxEXPAND</flag> </object> </object> <flag>wxALL|wxEXPAND</flag> <border>5</border> </object> <object class="spacer"> <option>1</option> </object> <object class="sizeritem"> <object class="wxBoxSizer"> <orient>wxHORIZONTAL</orient> <object class="spacer"> <size>0,0</size> <option>1</option> </object> <object class="sizeritem"> <object class="wxButton" name="OkButton"> <label>OK</label> <style>wxSUNKEN_BORDER</style> </object> </object> <object class="spacer"> <size>5,0</size> </object> </object> <flag>wxEXPAND</flag> </object> <object class="spacer"> <size>0,10</size> </object> </object> <size>350,100</size> </object> </resource>
pyxboil_demo_xrc.py
This is the file that is generated automatically by pyxboil for the pyxboil_demo.xrc XRC file.
1 # This file has been automatically generated by PyXBoil.
2 # Please do not edit it manually.
3
4 import wx
5 from wx.xrc import *
6
7 class MyPanelBase(wx.Panel):
8 def OnInit(self):
9 """ This function is called during the class's initialization.
10
11 Override it for custom setup (setting additional styles, etc.)"""
12 pass
13
14 def __init__(self, parent, res):
15 """ Pass an initialized wx.xrc.XmlResource into res """
16
17 # Two stage creation (see http://wiki.wxpython.org/index.cgi/TwoStageCreation)
18 pre = wx.PrePanel()
19 res.LoadOnPanel(pre, parent, "MyPanel")
20 self.OnInit()
21 self.PostCreate(pre)
22
23 # Define variables for the controls
24 self.firstName = XRCCTRL(self, "firstName")
25 self.lastName = XRCCTRL(self, "lastName")
26 self.OkButton = XRCCTRL(self, "OkButton")