WxWizard
From WxWiki
Contents |
[edit] Disabling the "Next" button
Quoth Vadim: "You can do it simply by using FindWindow(wxID_FORWARD)->Disable()."
In wxPython: wx.FindWindowById(wx.ID_FORWARD).Disable()
However, if the current focus is a single line textCtrl, I find that pressing Enter will still
advance to the next page even though the Next button is disabled! (using wxPython 2.6.3.2 on Linux. It works as it should under Windows.) Any workarounds?
- You might also want to catch wxEVT_WIZARD_PAGE_CHANGING events, and veto as necessary. --Tierra 16:09, 10 March 2007 (PST)
[edit] Using wx.wizard.Wizard as your only window (updated for wxPython 2.5.1.5)
The trick is to construct your wx.App, then construct your wizard and call RunWizard() on it, and only the (once RunWizard() has returned) call wx.App.MainLoop() to clean up. Here is an example:
import wx
import wx.wizard as wiz
def makePageTitle(wizPg, title):
sizer = wx.BoxSizer(wx.VERTICAL)
wizPg.SetSizer(sizer)
title = wx.StaticText(wizPg, -1, title)
title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
sizer.AddWindow(title, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
sizer.AddWindow(wx.StaticLine(wizPg, -1), 0, wx.EXPAND|wx.ALL, 5)
return sizer
class TitledPage(wiz.WizardPageSimple):
def __init__(self, parent, title):
wiz.WizardPageSimple.__init__(self, parent)
self.sizer = makePageTitle(self, title)
app = wx.PySimpleApp()
wizard = wiz.Wizard(None, -1, "Simple Wizard")
page1 = TitledPage(wizard, "Page 1")
page2 = TitledPage(wizard, "Page 2")
wiz.WizardPageSimple_Chain(page1, page2)
wizard.FitToPage(page1)
wizard.RunWizard(page1)
wizard.Destroy()
app.MainLoop()
[edit] Using WxWizard as your only window
The trick is to construct your wxApp, then construct your wizard and call RunWizard() on it, and only then (once RunWizard() has returned) call wxApp.MainLoop() to clean up. Here is an example (from Robin Dunn):
from wxPython.wx import *
from wxPython.wizard import *
def makePageTitle(wizPg, title):
sizer = wxBoxSizer(wxVERTICAL)
wizPg.SetSizer(sizer)
title = wxStaticText(wizPg, -1, title)
title.SetFont(wxFont(18, wxSWISS, wxNORMAL, wxBOLD))
sizer.AddWindow(title, 0, wxALIGN_CENTRE|wxALL, 5)
sizer.AddWindow(wxStaticLine(wizPg, -1), 0, wxEXPAND|wxALL, 5)
return sizer
class TitledPage(wxWizardPageSimple):
def __init__(self, parent, title):
wxWizardPageSimple.__init__(self, parent)
self.sizer = makePageTitle(self, title)
app = wxPySimpleApp()
wizard = wxWizard(None, -1, "Simple Wizard")
page1 = TitledPage(wizard, "Page 1")
page2 = TitledPage(wizard, "Page 2")
wxWizardPageSimple_Chain(page1, page2)
wizard.FitToPage(page1)
wizard.RunWizard(page1)
wizard.Destroy()
app.MainLoop()
[edit] Calculate the size
For the simple cases the following procedure will do:
void MyWizard::ComputeAndSetSize(wxWizardPage* startPagePtr)
{
wxSize size = startPagePtr->GetBestSize();
for(wxWizardPage* pPtr = startPagePtr->GetNext();
pPtr;
pPtr = pPtr->GetNext())
{
wxSize tmpSize = pPtr->GetBestSize();
if(tmpSize.GetHeight() > size.GetHeight())
size.SetHeight(tmpSize.GetHeight());
if(tmpSize.GetWidth() > size.GetWidth())
size.SetWidth(tmpSize.GetWidth());
}
SetPageSize(size);
}
[edit] Design tips
- Use wxWizardPageSimple if the sequence of pages is static.
- Use a subclass of either wxWizardPage or wxWizardPageSimple if you need anything more than just the basic logic.
- If possible, define a common superclass for all your wizard pages. Apply to it a member "state" which allows you to control further aspects of the whole process.
- Handle EVT_WIZARD_PAGE_CHANGING if your pages need information about the chosen direction. The event implements GetDirection(). You can transport this information by using the "state" member mentioned above.
- Overwrite the Transfer* and/or Validate* methods to be independend of the default behaviour. You could for example skip any transfer of data to the page if the last direction was backwards in the chain of pages.
- Use your own subclasses of wxPanel for each page content. It will be easy to re-use this panel in a dialog. Keep in mind that every single one of these panels should handle all events sent by itself and therefore might need an own event table. It's sometimes a good idea to provide actions (not handlers) for Ok/Cancel, too.
