views:

723

answers:

6

I'm making a program that fits the wizard concept ideally; the user is walked through the steps to create a character for a game.

However, I'm realizing that the limitations of the wizard are making it difficult to design "elegant" logic flow. For example, because all pages of the wizard are initalized at the same time, I can't have the values entered in one page available to the next one. I have to put a button on each page to get the values from a previous page rather than simply having fields auto-populated.

I've thought about alternatives to using the wizard. I think the best idea is to have some buttons on one panel that change the information on another panel, e.g. a splitter window.

However, I can't find any documentation in wxPython on how to dynamically change the panel. Everything I've found so far is really pretty static, hence the use of the wizard. Even the "wxPython in Action" book doesn't mention it.

Are there any tutorials for making "dynamic panels" or better management of a wizard?

A: 

How do you switch from page to page? Can that mechanism be extended to update the information on the new page?

Sorry, that this is not really an answer, but just the things that strike me as obvious when looking at your description.

HS
The wizard class automatically handles the "back" and "next" buttons. I would have to look at the source code to see how it actually works because there is no API given for the wizard in that aspect, AFAIK.
crystalattice
+3  A: 

Here is a simple example. This way you can make your "wizard" work like a finite state machine where states are different pages that are initialized on demand. Also, the data is shared between pages.

import wx
import wx.lib.newevent


(PageChangeEvent, EVT_PAGE_CHANGE) = wx.lib.newevent.NewEvent()


class Data:
    foo = None
    bar = None


class Page1(wx.Panel):
    def __init__(self, parent, data):
        wx.Panel.__init__(self, parent)
        self.parent = parent
        self.data = data

        sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(sizer)
        label = wx.StaticText(self, label="Page 1 - foo")
        self.foo = wx.TextCtrl(self)
        goto_page2 = wx.Button(self, label="Go to page 2")

        for c in (label, self.foo, goto_page2):
            sizer.Add(c, 0, wx.TOP, 5)

        goto_page2.Bind(wx.EVT_BUTTON, self.OnPage2)

    def OnPage2(self, event):
        self.data.foo = self.foo.Value
        wx.PostEvent(self.parent, PageChangeEvent(page=Page2))


class Page2(wx.Panel):
    def __init__(self, parent, data):
        wx.Panel.__init__(self, parent)
        self.parent = parent
        self.data = data

        sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(sizer)
        label = wx.StaticText(self, label="Page 2 - bar")
        self.bar = wx.TextCtrl(self)
        goto_finish = wx.Button(self, label="Finish")

        for c in (label, self.bar, goto_finish):
            sizer.Add(c, 0, wx.TOP, 5)

        goto_finish.Bind(wx.EVT_BUTTON, self.OnFinish)

    def OnFinish(self, event):
        self.data.bar = self.bar.Value
        wx.PostEvent(self.parent, PageChangeEvent(page=finish))


def finish(parent, data):
    wx.MessageBox("foo = %s\nbar = %s" % (data.foo, data.bar))
    wx.GetApp().ExitMainLoop()


class Test(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None)
        self.data = Data()
        self.current_page = None

        self.Bind(EVT_PAGE_CHANGE, self.OnPageChange)
        wx.PostEvent(self, PageChangeEvent(page=Page1))

    def OnPageChange(self, event):
        page = event.page(self, self.data)
        if page == None:
            return
        if self.current_page:
            self.current_page.Destroy()
        self.current_page = page
        page.Layout()
        page.Fit()
        page.Refresh()


app = wx.PySimpleApp()
app.TopWindow = Test()
app.TopWindow.Show()
app.MainLoop()
Toni Ruža
A: 

You could try using a workflow engine like WFTK. In this particular case author has done some work on wx-based apps using WFTK and can probably direct you to examples.

ConcernedOfTunbridgeWells
+1  A: 

The wxPython demo has an example of a "dynamic" wizard. Pages override GetNext() and GetPrev() to show pages dynamically. This shows the basic technique; you can extend it to add and remove pages, change pages on the fly, and rearrange pages dynamically.

The wizard class is just a convenience, though. You can modify it, or create your own implementation. A style that seems popular nowadays is to use an HTML-based presentation; you can emulate this with the wxHtml control, or the IEHtmlWindow control if your app is Windows only.

Ryan Ginstrom
A: 

I'd get rid of wizard in whole. They are the most unpleasant things I've ever used.

The problem that requires a wizard-application where you click 'next' is perhaps a problem where you could apply a better user interface in a bit different manner. Instead of bringing up a dialog with annoying 'next' -button. Do this:

Bring up a page. When the user inserts the information to the page, extend or shorten it according to the input. If your application needs to do some processing to continue, and it's impossible to revert after that, write a new page or disable the earlier section of the current page. When you don't need any input from the user anymore or the app is finished, you can show a button or enable an existing such.

I don't mean you should implement it all in browser. Make simply a scrolling container that can contain buttons and labels in a flat list.

Benefit: The user can just click a tab, and you are encouraged to put all the processing into the end of filling the page.

Cheery
A: 

It should be noted that a Wizard should be the interface for mutli-step, infrequently-performed tasks. The wizard is used to guide the user through something they don't really understand, because they almost never do it.

And if some users might do the task frequently, you want to give those power users a lightweight interface to do the same thing - even if it less self explanatory.

See: Windows Vista User Experience Guidelines - Top Violations

Wizards

Consider lightweight alternatives first, such as dialog boxes, task panes, or single pages. Wizards are a heavy UI, best used for multi-step, infrequently performed task. You don't have to use wizards—you can provide helpful information and assistance in any UI.

Ian Boyd