== Creating Wizards for wmPython using wxGlade == wxGlade is a great tool for visual development of wxPython GUIs, but (at time of writing this page), is missing some vital features, such as support for wizards. This page provides an easy recipe for using wxGlade to build the required panels of a wizard, then using a simple wizard subclass to build these panels into the wizard. == Process Overview == The basic steps in this recipe are: 1. Create a dummy frame in wxGlade, consisting of a notebook which is populated with panels (each panel being a page to be added to our final wizard) 2. Instantiate a wx.Wizard subclass (code provided below) to create a wizard 3. Populate this wizard with the pages from the notebook we created in wxGlade == Creating Wizard Pages in wxGlade == Presently, wxGlade has no support for wizards, but it does support notebooks. We will create a notebook within a dummy frame, and populate it with two or more pages, where each page will ultimately end up in our wizard. Start up wxGlade, and follow these steps: 1. Starting out 1.1. Create a new frame 1.2. Within the sizer that wxGlade automatically adds, insert a Notebook 1.3. Within the design window, you should see a single notebook tab 2. Adding pages 2.1. Click on the notebook within the wxglade 'tree' window 2.2. Click on the 'widget' tab in the wxglade 'properties' window 2.3. Using the 'add' button, create as many tabs as you need, one for each page you want in your wizard 2.4. For each tab you create, choose a name which is a legal python identifier, and is meaningful for the page 2.5. Populate the body of each notebook pane with the widgets you need. 2.6. Click on the 'apply' button when done 3. Creating panel classes 3.1. For each tab you have just created: 3.1.1. Click on that tab in the design window 3.1.2. Click on the body of the pane 3.1.3. Within the 'properties' window: 3.1.3.1. Click on the 'common' tab 3.1.3.2. Change the 'name' to the python identifier you chose 3.1.3.3. Change the 'class' from 'wxPanel' to a legal and meaningful python class identifier such as '!MyWizard_page1' 4. Generate the code 4.1. Save the wxglade file 4.2. Generate python code (ctrl-g) 5. Add the wizard subclass to your code: {{{ #!python class GladeWizard(wx.wizard.Wizard): """ Wizard that can be built up from panel classes generated by wxGlade """ def __init__(self, parent, id=-1, title=wx.EmptyString, bitmap=wx.NullBitmap, *args, **kw): wx.wizard.Wizard.__init__(self, parent, id, title, bitmap, *args, **kw) self.prevPanel = None def addPages(self, pages): """ Builds this wizard up from a set of panel classes generated by wxGlade Args: - pages - a sequence of (name, cls) tuples, specifying each page of the wizard. Each 'name' in the tuple is the attribute under which the corresponding page of the wizard will be stored in this wizard object as an attribute. Each 'cls' in the tuple is a Panel subclass, as generated by wxGlade Wizard creation recipe: 1. create a dummy frame in wxglade 2. insert a notebook into that frame's sizer 3. for each desired page of the wizard, insert a pane into the notebook, and give it a unique class name 4. instantiate this wizard class, then call this method with a list of (name, panelClass) tuples """ for name, pageClass in pageClasses: self.addPage(name, pageClass) return def addPage(self, attrname, panelClass): """ Adds a panel to this wizard Arguments: - attrname - attribute under which to save a ref to the instantiated panel within the wizard abject - panelClass - a subclass of wx.Panel, to add to the new page of the wizard """ # create wizard page object, and add on # instance of our panel class to it page = wx.wizard.WizardPageSimple(self) page.sizer = wx.BoxSizer(wx.VERTICAL) page.SetSizer(page.sizer) pageInst = panelClass(page) page.sizer.Add(pageInst, 0, wx.ALIGN_CENTRE|wx.ALL, 5) # save the panel instance as named attribute setattr(self, attrname, pageInst) # chain to previous, if this is not the first page if self.prevPanel: wx.wizard.WizardPageSimple_Chain(self.prevPanel, page) else: self.firstPanel = page # remember this as 'previous' page, for adding/chaining the next self.prevPanel = page def run(self): return self.RunWizard(self.firstPanel) }}} == Creating and using the wizard in your program == Assuming you have set wxglade to generate its python code in 'mygui.py', add to your python program the line: {{{ #!python import mygui as gui }}} Within your wxApp code, possibly within your .!OnInit() method, use code such as: {{{ #!python wizard = self.wizard = GladeWizard( parent=self.frame, title="my wizard", ) wizard.buildFromPanels( [("pane1", gui.WizardPane_1), ("pane2", gui.WizardPane_2), ], ) }}} If you have a bitmap, you could add it via a 'bitmap=' keyword to the !GladeWizard constructor. With the example above: * Our wizard has two pages, present in the wxGlade generated file as !WizardPane_1 and !WizardPane_2 * Instances of these pane classes will be stored in the wizard object as attributes 'pane1' and 'pane2' respectively * We can easily address each of the widgets on each page of the wizard. For example: {{{ #!python self.maxRetries = int(self.wizard.pane1.fld_maxRetries.GetValue()) }}} == Conclusion == This is a hack, and will hopefully be obsolete soon (when the wxGlade developers add wizard support). While it might seem cumbersome, it's probably not much more complicated than it will be when full wizard support is finally added.