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")

PyxBoil (last edited 2008-03-11 10:50:20 by localhost)

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.