Introduction
This topic explains how to use XML Resources (XRC) with wxPython.
Contents
Important Warning
The initial author of this page isn't a very experienced user of both XRC and wxPython (yet ;). It is possible that most statements made here are wrong - use them at your own risk (and feel free to correct them by editing this page if you find any errors).
Following my advice carelessly may damage your computer. You have been warned!
General concept
The idea behind the XRC resources is very simple: instead of writing code to create wxPython objects (frame, panel, menus), you can create a special resource file in XML format which describes the layout of your object, e.g. frame. You can later load your frame from the resource file and code the business logic of your application; you don't need to code interface itself.
Excerpt from wxWidgets documentation
The XML-based resource system, known as XRC, allows user interface elements such as dialogs, menu bars and toolbars, to be stored in text files and loaded into the application at run-time. XRC files can also be compiled into binary XRS files or C++ code (the former makes it possible to store all resources in a single file and the latter is useful when you want to embed the resources into the executable).
There are several advantages to using XRC resources.
- Recompiling and linking an application is not necessary if the resources change.
- If you use a dialog design tool that generates C++ code, it can be hard to reintegrate this into existing C++ code.
- Separation of resources and code is a more elegant solution.
- You can choose between different alternative resource files at run time, if necessary.
- The XRC format uses sizers for flexibility, allowing dialogs to be resizable and highly portable.
- The XRC format is a wxWidgets standard, and can be generated or postprocessed by any program that understands it. As it is based on the XML standard, existing XML editors can be used for simple editing purposes.
XRC was written by Vaclav Slavik.
First things first
First, create a .xrc file which will hold your design. There are two possible ways to do this:
Write XRC directly. There is a format description at http://docs.wxwidgets.org/trunk/overview_xrcformat.html.
- Use one of the many XRC editors:
XRCed ships with wxPython and can be found in the wxPython/tools/XRCed. More recent version is available at http://xrced.sourceforge.net/ My impression: Good simple editor, though it has some minor glitches. I've used it to create the following .xrc file.
wxGlade: available at the http://wxglade.sourceforge.net. Anthony Barker's impression: "my favorite - copying the best features of glade. Easy to use and extend. Actively developed. Not a full rad - more of a screen drawer. Outputs xml or code. Nice tutorial."
wxDesigner: a commercial GUI design tool which can generate xrc files as well as python, c++ and some other sources. Can be found at http://www.roebling.de/
dialogblocks: a commercial GUI design tool which can generate xrc as well as C++. Can be found at http://www.anthemion.co.uk/dialogblocks/
visualWx: a free GUI design & RAD Tool which can generate xrc as well as c++, python, perl, ruby and lua. Can be found at http://visualwx.altervista.org/index.php
wxSmith : wxSmith is a free Code::Blocks plugin for RAD editing of wxWidgets applications. It can generate xrc as well as c++. A nice comparison with other tools can be found at http://wiki.codeblocks.org/index.php?title=Comparison_of_wxSmith_features
wxFormBuilder: wxFormBuilder is a free GUI design tool that can generate xrc as well as C++. Can be found at http://wxformbuilder.org/
* Please add other options that you are know of here.
Full code: calc.pyw
1 """
2 Simple calculator that uses XRC.
3 """
4 import wx
5 from wx import xrc
6 class MyApp(wx.App):
7 def OnInit(self):
8 self.res = xrc.XmlResource("calc.xrc")
9 self.InitFrame()
10 self.InitMenu()
11 self.InitEverythingElse()
12 return True
13 def InitFrame(self):
14 self.frame = self.res.LoadFrame(None, "MainFrame")
15 self.panel = xrc.XRCCTRL(self.frame, "MainPanel")
16 self.first_arg = xrc.XRCCTRL(self.panel, "FirstArg")
17 self.second_arg = xrc.XRCCTRL(self.panel, "SecondArg")
18 self.result = xrc.XRCCTRL(self.panel, "Result")
19 self.first_arg.SetValue("Hi")
20 self.second_arg.SetValue("You")
21 self.result.SetValue("man")
22 def InitMenu(self):
23 self.menuBar = self.res.LoadMenuBar("MenuBar")
24 self.frame.Bind(wx.EVT_MENU, self.Add, id=xrc.XRCID("AddMenuItem"))
25 self.frame.Bind(wx.EVT_MENU, self.Subtract, id=xrc.XRCID("SubtractMenuItem"))
26 self.frame.Bind(wx.EVT_MENU, self.Multiply, id=xrc.XRCID("MultiplyMenuItem"))
27 self.frame.Bind(wx.EVT_MENU, self.Divide, id=xrc.XRCID("DivideMenuItem"))
28 self.frame.SetMenuBar(self.menuBar)
29 def InitEverythingElse(self):
30 sizer = self.panel.GetSizer()
31 sizer.Fit(self.frame)
32 sizer.SetSizeHints(self.frame)
33 self.frame.Show()
34 def InitArgs(self):
35 try:
36 self.first = float(self.first_arg.GetValue())
37 except ValueError:
38 return self.BadFloatValue(self.first_arg)
39 try:
40 self.second = float(self.second_arg.GetValue())
41 except ValueError:
42 return self.BadFloatValue(self.second_arg)
43 return True
44 def BadFloatValue(self, control):
45 dlg = wx.MessageDialog(self.frame, "I can't convert this to float.",
46 'Conversion error', wx.OK | wx.ICON_ERROR)
47 dlg.ShowModal()
48 dlg.Destroy()
49 control.SetFocus()
50 control.SetSelection(-1, -1)
51 return False
52 def Add(self, evt):
53 if self.InitArgs():
54 self.result.SetValue(str(self.first + self.second))
55 def Subtract(self, evt):
56 if self.InitArgs():
57 self.result.SetValue(str(self.first - self.second))
58 def Multiply(self, evt):
59 if self.InitArgs():
60 self.result.SetValue(str(self.first * self.second))
61 def Divide(self, evt):
62 if self.InitArgs():
63 if self.second != 0:
64 self.result.SetValue(str(self.first / self.second))
65 else:
66 self.result.SetValue("#ERROR")
67 def main():
68 app = MyApp(0)
69 app.MainLoop()
70 if __name__ == '__main__':
71 main()
Full code: calc.xrc
<?xml version="1.0" ?> <resource> <object class="wxFrame" name="MainFrame"> <title>Simple calculator</title> <centered>1</centered> <style></style> <object class="wxPanel" name="MainPanel"> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <object class="wxBoxSizer"> <orient>wxHORIZONTAL</orient> <object class="sizeritem"> <object class="wxStaticText"> <label>First arg:</label> </object> <option>1</option> <flag>wxALL|wxALIGN_CENTRE_VERTICAL</flag> <border>5</border> </object> <object class="spacer"> <size>10,10</size> <option>1</option> <flag>wxEXPAND</flag> </object> <object class="sizeritem"> <object class="wxTextCtrl" name="FirstArg"/> <flag>wxALL|wxALIGN_RIGHT</flag> <border>5</border> </object> </object> <option>1</option> <flag>wxEXPAND</flag> </object> <object class="sizeritem"> <object class="wxBoxSizer"> <orient>wxHORIZONTAL</orient> <object class="sizeritem"> <object class="wxStaticText"> <label>Second arg:</label> </object> <flag>wxALL|wxALIGN_CENTRE_VERTICAL</flag> <border>5</border> </object> <object class="spacer"> <size>10,10</size> <option>1</option> <flag>wxEXPAND</flag> </object> <object class="sizeritem"> <object class="wxTextCtrl" name="SecondArg"/> <flag>wxALL|wxALIGN_RIGHT</flag> <border>5</border> </object> </object> <option>1</option> <flag>wxEXPAND</flag> </object> <object class="sizeritem"> <object class="wxBoxSizer"> <orient>wxHORIZONTAL</orient> <object class="sizeritem"> <object class="wxStaticText"> <label>Result:</label> </object> <flag>wxALL|wxALIGN_CENTRE_VERTICAL</flag> <border>5</border> </object> <object class="spacer"> <size>10,10</size> <option>1</option> <flag>wxEXPAND</flag> </object> <object class="sizeritem"> <object class="wxTextCtrl" name="Result"/> <flag>wxALL|wxALIGN_RIGHT</flag> <border>5</border> </object> </object> <option>1</option> <flag>wxEXPAND</flag> </object> </object> </object> </object> <object class="wxMenuBar" name="MenuBar"> <object class="wxMenu" name="OperationMeu"> <label>Operations</label> <object class="wxMenuItem" name="AddMenuItem"> <label>&Add</label> <accel>Ctrl-A</accel> <help>Add second arg to the first arg.</help> </object> <object class="wxMenuItem" name="SubtractMenuItem"> <label>&Subtract</label> <accel>Ctrl-S</accel> <help>Subtract second arg from the first arg.</help> </object> <object class="separator"/> <object class="wxMenuItem" name="MultiplyMenuItem"> <label>&Multiply</label> <accel>Ctrl-M</accel> <help>Multiply first arg by second arg</help> </object> <object class="wxMenuItem" name="DivideMenuItem"> <label>&Divide</label> <accel>Ctrl-D</accel> <help>Divide first arg by second arg.</help> </object> </object> </object> </resource>
Comments
This initial version of this page was made by VictorKryukov. Please comment here any changes to this page.
Please also note that English is not my native language; incorrect word usage or grammar errors are possible - feel free to correct them.
Two small tricks
Just to make explicit two tricks that are in your code listing:
When you have made an XRC resource, you get the items within it for your program with two calls:
XRCID(XRC_name) gives you the ID of a button or menu item; and
XRCCTRL(XRC_name) lets you play with normal controls.
menubar bits in above code
Note that the above code won't work as-is in the most recent versions of wxPy/wxGlade. wxGlade 0.4.1 with wxPython 2.6.2.1 will create the menubar as a child element of the frame (this is assuming you check the "has menubar" button of the applicable frame).
Moreover, if you do add a child menubar element element to the frame, wxPython will (apparently) set it up for you automatically, so you all you need to do to get the menus to work is to bind their IDs to the appropriate functions. That is, if you change the files around like this:
<?xml version="1.0" ?> <resource> <object class="wxFrame" name="MainFrame"> <title>Simple calculator</title> <!-- Note that this is a child of the frame element, not the top-level resources element as above --> <object class="wxMenuBar" name="MenuBar"> <object class="wxMenu" name="OperationMenu"> ... </object> </object> </object> <!-- end of frame object --> </resource>
1 # ...
2 def InitMenu(self):
3 self.frame.Bind(wx.EVT_MENU, self.Add, id=xrc.XRCID("AddMenuItem"))
4 self.frame.Bind(wx.EVT_MENU, self.Subtract, id=xrc.XRCID("SubtractMenuItem"))
5 self.frame.Bind(wx.EVT_MENU, self.Multiply, id=xrc.XRCID("MultiplyMenuItem"))
6 self.frame.Bind(wx.EVT_MENU, self.Divide, id=xrc.XRCID("DivideMenuItem"))
7 # NB: previous references to self.menuBar and self.frame.setMenuBar()
8 # are no longer needed
...you can make some of the UI code implicit, which is a good thing. -- Tim Gilbert, 2007-02-28
AttachUnknownControl and Control Size
The wxXmlResource.AttachUnknownControl method is used to associate your own controls with a control in an XRC file. Unfortunately, it's a little tricky to get the size of the control correct. You can specify the size explicitly in the XRC file, but often you want the control itself to calculate the best size for itself. The example below shows how to get the controls and a Dialog to size themselves correctly when using wxXmlResource.AttachUnknownControl.
Note: If you set the sizer flag wxADJUST_MINSIZE on the unknown control and call wxSizer.Fit(), it will correctly resize the control and relayout everything to match. In my version of xrced, this sizer flag is not available in the menu, but you can type it in anyway. The manual method below is not needed. (I suggest the page owner remove it.) -- Reid Priedhorsky 2005-07-09
Full code: SizeXrc.py
1 """
2 Demonstrates how to get controls and a Dialog to size correctly when
3 attaching custom controls using AttachUnknownControl().
4 """
5 from wxPython.wx import *
6 from wxPython.xrc import *
7 import os
8 class Dialog(wxDialogPtr):
9 def __init__(self, parent, resource):
10 w = resource.LoadDialog(parent, 'Dialog')
11 wxDialogPtr.__init__(self, w.this)
12 self.thisown = 1
13 self.Center()
14 ctrlTable = [
15 ('ID_CUSTOM_CTRL', 'Ctrl 1'),
16 ('ID_CUSTOM_CTRL_WIDTH_SPECIFIED', 'Ctrl 2'),
17 ]
18 sizer = self.GetSizer()
19 sizer.SetVirtualSizeHints(self)
20 self.SetAutoLayout(True)
21 for idText, lable in ctrlTable:
22 id = XRCID(idText)
23 idCtrl = wxNewId()
24 ctrl = wxButton(self, idCtrl, lable)
25 if ctrl is not None:
26 resource.AttachUnknownControl(idText, ctrl, self)
27 EVT_BUTTON(self, id, self.OnButton)
28 size = ctrl.GetSize()
29 print `size`
30 sizeBest = ctrl.GetBestSize()
31 print `sizeBest`
32 sizeBest.width = size.width
33 container = ctrl.GetParent()
34 sizer.SetItemMinSize(container,
35 sizeBest.width, sizeBest.height)
36 sizeMin = sizer.CalcMin()
37 self.SetSizeHints(sizeMin.width, sizeMin.height)
38 sizer.Fit(self)
39 EVT_BUTTON(self, XRCID("ID_OK"), self.OnOk)
40 EVT_BUTTON(self, XRCID("ID_CANCEL"), self.OnCancel)
41 def OnButton(self, event):
42 print 'OnButton'
43 def OnCancel(self, event):
44 self.EndModal(wxID_CANCEL)
45 def OnOk(self, event):
46 self.EndModal(wxID_OK)
47 def testPreferencesDialog():
48 class MyApp(wxApp):
49 def __init__(self, num):
50 wxApp.__init__(self, num)
51 def OnInit(self):
52 RESFILE_DIALOGS = "SizeXrc.xrc"
53 import types
54 wxInitAllImageHandlers()
55 resourceText = open(RESFILE_DIALOGS).read()
56 resource = wxEmptyXmlResource()
57 resource.LoadFromString(resourceText)
58 dialog = Dialog(None, resource)
59 dialog.ShowModal()
60 dialog.Destroy()
61 return True
62 app = MyApp(0)
63 #----------------------------------------------------------------------------
64 if __name__ == '__main__':
65 testPreferencesDialog()
Full code: SizeXrc.xrc
<?xml version="1.0" encoding="ISO-8859-1"?> <resource> <object class="wxDialog" name="Dialog"> <title>Dialog</title> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <flag>wxGROW|wxALIGN_CENTER_VERTICAL|wxALL</flag> <border>5</border> <object class="wxFlexGridSizer"> <cols>2</cols> <rows>0</rows> <vgap>0</vgap> <hgap>0</hgap> <growablecols>1</growablecols> <object class="sizeritem"> <object class="wxStaticText" name=""> <label>Plain old button</label> </object> <border>0</border> </object> <object class="sizeritem"> <object class="wxButton" name="ID_BUTTON"> <label>Click Me</label> </object> <flag>wxGROW|wxALL|wxALIGN_CENTER_VERTICAL</flag> </object> <object class="sizeritem"> <flag>wxALIGN_CENTER_VERTICAL|wxALL</flag> <object class="wxStaticText" name=""> <label>Custom Control (size unspecified):</label> </object> <border>3</border> </object> <object class="sizeritem"> <object class="unknown" name="ID_CUSTOM_CTRL"> <size>-1, -1</size> </object> <flag>wxGROW|wxALL|wxALIGN_CENTER_VERTICAL</flag> </object> <object class="sizeritem"> <flag>wxALIGN_CENTER_VERTICAL|wxALL</flag> <object class="wxStaticText" name=""> <label>Custom Control (width specified):</label> </object> <border>3</border> </object> <object class="sizeritem"> <flag>wxGROW|wxALL|wxALIGN_CENTER_VERTICAL</flag> <object class="unknown" name="ID_CUSTOM_CTRL_WIDTH_SPECIFIED"> <size>100, -1</size> </object> </object> </object> </object> <object class="sizeritem"> <flag>wxALIGN_CENTRE|wxALL</flag> <border>5</border> <object class="wxBoxSizer"> <orient>wxHORIZONTAL</orient> <object class="sizeritem"> <flag>wxALIGN_CENTRE|wxALL</flag> <border>5</border> <object class="wxButton" name="ID_OK"> <label>OK</label> <default>1</default> </object> </object> <object class="sizeritem"> <flag>wxALIGN_CENTRE|wxALL</flag> <border>5</border> <object class="wxButton" name="ID_CANCEL"> <label>Cancel</label> </object> </object> </object> </object> </object> <centered>1</centered> <style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxTAB_TRAVERSAL</style> </object> </resource>
Comments
For all the caution you express in writing this- you should know that everything I know about XRC, I learned from this page..! -- LionKimbro 2003-09-17 22:11:27
I had the problem that the sizer I attached new panel to didn't respect the minimal size of the attached panel. Of course that was not good at all because most of the times I could see only a very small part of the panel. What finally helped was this trick: call panel_being_attached.GetParent().SetMinSize(panel_being_attached.GetMinSize()) after calling AttachUnknownWindow(). I didn't need to use any of the tricks described here, not even setting the wx.ADJUST_MINSIZE flags to the parent sizer, it just works. See http://article.gmane.org/gmane.comp.python.wxpython/34491 for more thorough description by mighty RobinDunn himself. TomasDvorak, regarding wxPython 2.7.2 on Win98.
Comments
SizeXRC.py above doesn't seem to work, at least not as of the latest release of Python/wxPython. The code fails saying that Dialog has no attribute OnButton. Anyone have any idea what gives? -- Brent W. York
I have figured out why:
in the example code, when wxDialogPtr.init(self, w.this) is called, the reference to self actually changes...invoking self.Hello before that line works, but not after that line...I suppose the wxDialogPtr.init(self, w.this) code is doing something weird...
The solution is actually to not use wxDialogPtr at all. As per a wxPython-users email:
The correct way to do the above in 2.5 is something like this:
class PrototypeFrame(wx.Frame): def __init__(self, parent, resource): w = resource.LoadFrame(parent, "Test") self.PostCreate(w)
The PostCreate method is new in 2.5, but if you need your code to still be compatible with 2.4 you can do the same things in your code and I think it will work correctly. It's implemented like this:
def PostCreate(self, pre): """ Phase 3 of the 2-phase create <wink!> Call this method after precreating the window with the 2-phase create method. """ self.this = pre.this self.thisown = pre.thisown pre.thisown = 0 if hasattr(self, '_setOORInfo'): self._setOORInfo(self) if hasattr(self, '_setCallbackInfo'): self._setCallbackInfo(self, self.__class__)
Sizeritem Proportion/Option/Ratio Tip
It took me a while to realise that the proportion of a sizeritem is set using the obscurely named <option> and not <ratio>. For example, if you have a horizontal wxBoxSizer containing a wxStaticText label, a wxTextCtrl and a wxButton, and you want the wxTextCtrl to expand to fill the available space, set <option>1</option> for the wxTextCtrl and omit <option> for the others (or set to zero).
Localisation
How would you localize an application that uses XML resources? If it doesn't use gettext then I suppose you must generate a different .XRC for each language. That sounds tedious. -- Nate Silva
The XmlResource class passes all labels, titles, values etc. through wx.GetTranslation by default, so if there are message catlogs loaded the localized versions of the strings will be put into the GUI. The wxrc (or pywxrc equivallent) utility can be used to extract all the label, title, value, etc. strings from an XRC file and write them to a file using _("label") syntax that can then be run through standard gettext tools. --RobinDunn
Example with derived classes in external modules
I have searched a long time for a complete real-world example with a derived class (like MyFrame) in a seperate module. A more real-world like, complete but also small example is given here.
This example contains three files. The main.py file, creating an app instance and loading the xml resources. A mainFrame.py with the code of the derived frame class and the gui.xrc file with the xml resources. --Ferry Dave
main.py
1 import wx
2 import wx.xrc as xrc
3 GUI_FILENAME = "gui.xrc"
4 GUI_MAINFRAME_NAME = "demoframe"
5 class MyApp(wx.App):
6 def OnInit(self):
7 # Load all controls:
8 self._do_layout()
9 return True
10 def _do_layout(self):
11 self.res = xrc.XmlResource( GUI_FILENAME )
12 self.frame = self.res.LoadFrame( None, GUI_MAINFRAME_NAME )
13 self.SetTopWindow(self.frame)
14 self.frame.Show(1)
15 if __name__ == '__main__':
16 app = MyApp()
17 app.MainLoop()
form.py
1 import wx
2 import wx.xrc as xrc
3 class MainFrame(wx.Frame):
4 def __init__(self):
5 pre = wx.PreFrame()
6 # the Create step is done by XRC.
7 self.PostCreate(pre)
8 self.Bind(wx.EVT_WINDOW_CREATE, self.OnCreate)
9 def OnCreate(self, event):
10 self.Unbind(wx.EVT_WINDOW_CREATE)
11 wx.CallAfter(self._PostInit)
12 event.Skip()
13 return True
14 def _PostInit(self):
15 # Do all init here
16 self.Fit()
17 self.SetAutoLayout(True)
18 self.btnExit = xrc.XRCCTRL(self, 'btnExit')
19 self.Bind(wx.EVT_BUTTON, self.OnBtnExit, self.btnExit)
20 # Set properties:
21 self.btnExit.SetLabel('Exit')
22 def OnBtnExit(self, evt=None):
23 self.Close()
gui.xrc
<?xml version="1.0" encoding="UTF-8"?> <resource version="2.3.0.1"> <object class="wxFrame" name="demoframe" subclass="form.MainFrame"> <centered>1</centered> <style>wxDEFAULT_FRAME_STYLE</style> <title>Testing wx XRC mechanism</title> <object class="wxBoxSizer"> <orient>wxHORIZONTAL</orient> <object class="sizeritem"> <object class="wxPanel"> <object class="wxBoxSizer"> <orient>wxHORIZONTAL</orient> <object class="sizeritem"> <object class="wxButton" name="btnExit"> <label></label> <default>1</default> </object> <flag>wxALL|wxALIGN_CENTRE_VERTICAL|wxALIGN_CENTRE_HORIZONTAL</flag> <border>20</border> </object> </object> </object> <flag>wxALL|wxEXPAND</flag> </object> </object> </object> </resource>
(edited : change some variable names to clarify the reading of the source)
Wrapper for wxPython objects loaded from an xml resource
I managed to write some relatively small wrapper classes by reverse engineering the wxPython code. One can derive from a wrapper class to extend its functionality.
The Frame wrapper class instantiates an object, in this case of wx.Frame, which takes over control of an already instantiated object (such as those created by wx.xrc.XmlResource(<filename>).LoadFrame(<framename>)).
For demonstration purposes I have taken the above gui.xrc from Ferry Dave, but without the frame's subclass attribute.
-- Alex Mekkering
wxWrapper.py
import wx class EvtHandler(wx.EvtHandler): def __init__(self, other): self.this = other.this self.thisown = 1 del other.this self._setOORInfo(self) class Frame(wx.Frame, EvtHandler): def __init__(self, other): EvtHandler.__init__(self, other)
usage.py
import wx import wx.xrc as xrc import wxWrapper class DemoFrame(wxWrapper.Frame): _xrcName = 'demoframe' def __init__(self, xmlResource, parent = None): wxWrapper.Frame.__init__(self, xmlResource.LoadFrame(parent, self._xrcName)) self.Fit() self.SetAutoLayout(True) self.btnExit = xrc.XRCCTRL(self, 'btnExit') self.Bind(wx.EVT_BUTTON, self.OnBtnExit, self.btnExit) # Set properties: self.btnExit.SetLabel('Exit') def OnBtnExit(self, evt=None): self.Close() class App(wx.App): def OnInit(self): xmlResource = xrc.XmlResource('gui.xrc') frame = DemoFrame(xmlResource) self.SetTopWindow(frame) frame.Show(True) return True def main(): app = App() app.MainLoop() if __name__ == '__main__': main()
gui.xrc
<?xml version="1.0" encoding="UTF-8"?> <resource version="2.3.0.1"> <object class="wxFrame" name="demoframe"> <centered>1</centered> <style>wxDEFAULT_FRAME_STYLE</style> <title>Testing wx XRC mechanism</title> <object class="wxBoxSizer"> <orient>wxHORIZONTAL</orient> <object class="sizeritem"> <object class="wxPanel"> <object class="wxBoxSizer"> <orient>wxHORIZONTAL</orient> <object class="sizeritem"> <object class="wxButton" name="btnExit"> <label></label> <default>1</default> </object> <flag>wxALL|wxALIGN_CENTRE_VERTICAL|wxALIGN_CENTRE_HORIZONTAL</flag> <border>20</border> </object> </object> </object> <flag>wxALL|wxEXPAND</flag> </object> </object> </object> </resource>
See Also
Menus from XML, XrcCheatSheet, XrcStartingPoints, TwoStageCreation, PyxBoil