GUI Wizard: flow control?

Discussion in 'Python' started by Steve Holden, Aug 31, 2004.

  1. Steve Holden

    Steve Holden Guest

    David Chan wrote:

    > Hi,
    >
    > I'm trying to use python to create GUI wizards, i.e. sequences of dialog
    > boxes with <BACK and NEXT> buttons. Since I want to re-use some of the
    > dialog boxes in different wizards, I want to have a main function which
    > calls each dialog box, much like this:
    >
    > def select_item():
    > """runs GUI wizard to select item"""
    >
    > client = show_client_dialog()
    > job = show_job_dialog(client)
    > invoice, rate = show_invoice_dialog(job)
    > item = choose_item_dialog(invoice, rate)
    > return item
    >
    > This works fine until you want to implement the <BACK button, which should
    > return to the previous dialog. Theoretically, what I'd really like is to be
    > able to jump backwards through the control flow, like this:
    >
    > class GoBack(Exception): pass
    > def select_item():
    > """runs GUI wizard to select item - can go <BACK"""
    > back = HERE
    > client = show_client_dialog()
    >
    > try: job = show_job_dialog(client)
    > except GoBack: back.goto()
    > back = HERE
    >
    > try: invoice, rate = show_invoice_dialog(job)
    > except GoBack: back.goto()
    > back = HERE
    >
    > try: item = show_item_dialog(invoice, rate)
    > except GoBack: back.goto()
    >
    > return item
    >
    > But I couldn't find a way of doing anything like that. You could do
    > something almost as unhorrible with nested breaks:'
    >
    > class GoBack(Exception): pass
    > def select_item():
    > """runs GUI wizard to select item - can go <BACK"""
    > CLIENT: while 1:
    > client = show_client_dialog()
    >
    > JOB: while 1:
    > try: job = show_job_dialog(client)
    > except GoBack: continue CLIENT
    >
    > INVOICE: while 1:
    > try: invoice, rate = show_invoice_dialog(job)
    > except GoBack: continue JOB
    >
    > try: item = show_item_dialog(invoice, rate)
    > except GoBack: continue INVOICE
    > break CLIENT
    >
    > Or you could do all the flow control manually in a "do_wizard" function and
    > make the caller create a horrible data structure instead of writing readable
    > code:
    >
    > calls = [
    > {'meth': show_client_dialog, 'args': [], 'ret': ['client']},
    > {'meth': show_job_dialog, 'args': ['client'], 'ret': ['job']},
    > {'meth': show_invoice_dialog, 'args': ['job'], 'ret': ['invoice', 'rate']},
    > {'meth': show_item_dialog, 'args': ['invoice', 'rate'], 'ret': ['item']},
    > ] # this just says: "client = show_client_dialog()", etc.
    > do_wizard(calls, locals())
    >
    >
    > But this is too hideous to deploy, because I might have to remember what it
    > does in six months :)
    >
    > Can anyone suggest something better, or should I abandon my goal of having a
    > main function which calls each dialog box?
    >
    > Many thanks,


    Caveat: I am assuming that your chosen GUI allows you to easily choose
    which of a number of panels is displayed inside a dialog. This is
    typically most easily done with the component usually known as a notebook.

    You create a list a panels, each of which you have constructed using
    your chosen GUI. You then associate the "Next" button with a function
    that displays the next panel in the sequence, and the "Back" button with
    a function that displays the preceding panel in the sequence.

    The dialog then becomes just a list of the panels, plus a counter to
    tell you which in the sequence is currently being displayed.

    You *don't* want to try and control flow through the sequence in the way
    you have attempted. Typically windows are actually just data structures,
    and so data-driven methods will work best.

    Naturally, each of the panels in the notebook will have callbacks
    associated with the various widgets, and interaction with those widgets
    will change the data that your program eventually sees when the user
    clicks the "Finish" button.

    If you want to reuse the panels then make sure they are properly
    modularized so their creators can be called used in different programs.

    regards
    Steve
    Steve Holden, Aug 31, 2004
    #1
    1. Advertising

  2. Steve Holden

    David Chan Guest

    Hi,

    I'm trying to use python to create GUI wizards, i.e. sequences of dialog
    boxes with <BACK and NEXT> buttons. Since I want to re-use some of the
    dialog boxes in different wizards, I want to have a main function which
    calls each dialog box, much like this:

    def select_item():
    """runs GUI wizard to select item"""

    client = show_client_dialog()
    job = show_job_dialog(client)
    invoice, rate = show_invoice_dialog(job)
    item = choose_item_dialog(invoice, rate)
    return item

    This works fine until you want to implement the <BACK button, which should
    return to the previous dialog. Theoretically, what I'd really like is to be
    able to jump backwards through the control flow, like this:

    class GoBack(Exception): pass
    def select_item():
    """runs GUI wizard to select item - can go <BACK"""
    back = HERE
    client = show_client_dialog()

    try: job = show_job_dialog(client)
    except GoBack: back.goto()
    back = HERE

    try: invoice, rate = show_invoice_dialog(job)
    except GoBack: back.goto()
    back = HERE

    try: item = show_item_dialog(invoice, rate)
    except GoBack: back.goto()

    return item

    But I couldn't find a way of doing anything like that. You could do
    something almost as unhorrible with nested breaks:'

    class GoBack(Exception): pass
    def select_item():
    """runs GUI wizard to select item - can go <BACK"""
    CLIENT: while 1:
    client = show_client_dialog()

    JOB: while 1:
    try: job = show_job_dialog(client)
    except GoBack: continue CLIENT

    INVOICE: while 1:
    try: invoice, rate = show_invoice_dialog(job)
    except GoBack: continue JOB

    try: item = show_item_dialog(invoice, rate)
    except GoBack: continue INVOICE
    break CLIENT

    Or you could do all the flow control manually in a "do_wizard" function and
    make the caller create a horrible data structure instead of writing readable
    code:

    calls = [
    {'meth': show_client_dialog, 'args': [], 'ret': ['client']},
    {'meth': show_job_dialog, 'args': ['client'], 'ret': ['job']},
    {'meth': show_invoice_dialog, 'args': ['job'], 'ret': ['invoice', 'rate']},
    {'meth': show_item_dialog, 'args': ['invoice', 'rate'], 'ret': ['item']},
    ] # this just says: "client = show_client_dialog()", etc.
    do_wizard(calls, locals())


    But this is too hideous to deploy, because I might have to remember what it
    does in six months :)

    Can anyone suggest something better, or should I abandon my goal of having a
    main function which calls each dialog box?

    Many thanks,
    --
    David Chan
    Clockwork Software Systems

    intY has scanned this email for all known viruses (www.inty.com)
    David Chan, Aug 31, 2004
    #2
    1. Advertising

  3. Steve Holden

    djw Guest

    David Chan wrote:

    > Hi,
    >
    > I'm trying to use python to create GUI wizards, i.e. sequences of dialog
    > boxes with <BACK and NEXT> buttons. Since I want to re-use some of the
    > dialog boxes in different wizards, I want to have a main function which
    > calls each dialog box, much like this:
    >
    > def select_item():
    > """runs GUI wizard to select item"""
    >
    > client = show_client_dialog()
    > job = show_job_dialog(client)
    > invoice, rate = show_invoice_dialog(job)
    > item = choose_item_dialog(invoice, rate)
    > return item
    >
    > This works fine until you want to implement the <BACK button, which should
    > return to the previous dialog. Theoretically, what I'd really like is to
    > be able to jump backwards through the control flow, like this:
    >
    > class GoBack(Exception): pass
    > def select_item():
    > """runs GUI wizard to select item - can go <BACK"""
    > back = HERE
    > client = show_client_dialog()
    >
    > try: job = show_job_dialog(client)
    > except GoBack: back.goto()
    > back = HERE
    >
    > try: invoice, rate = show_invoice_dialog(job)
    > except GoBack: back.goto()
    > back = HERE
    >
    > try: item = show_item_dialog(invoice, rate)
    > except GoBack: back.goto()
    >
    > return item
    >
    > But I couldn't find a way of doing anything like that. You could do
    > something almost as unhorrible with nested breaks:'
    >
    > class GoBack(Exception): pass
    > def select_item():
    > """runs GUI wizard to select item - can go <BACK"""
    > CLIENT: while 1:
    > client = show_client_dialog()
    >
    > JOB: while 1:
    > try: job = show_job_dialog(client)
    > except GoBack: continue CLIENT
    >
    > INVOICE: while 1:
    > try: invoice, rate = show_invoice_dialog(job)
    > except GoBack: continue JOB
    >
    > try: item = show_item_dialog(invoice, rate)
    > except GoBack: continue INVOICE
    > break CLIENT
    >
    > Or you could do all the flow control manually in a "do_wizard" function
    > and make the caller create a horrible data structure instead of writing
    > readable code:
    >
    > calls = [
    > {'meth': show_client_dialog, 'args': [], 'ret': ['client']},
    > {'meth': show_job_dialog, 'args': ['client'], 'ret': ['job']},
    > {'meth': show_invoice_dialog, 'args': ['job'], 'ret': ['invoice',
    > {'rate']}, 'meth': show_item_dialog, 'args': ['invoice', 'rate'],
    > {'ret': ['item']},
    > ] # this just says: "client = show_client_dialog()", etc.
    > do_wizard(calls, locals())
    >
    >
    > But this is too hideous to deploy, because I might have to remember what
    > it does in six months :)
    >
    > Can anyone suggest something better, or should I abandon my goal of having
    > a main function which calls each dialog box?
    >
    > Many thanks,


    I always code this sort of situation up as a simple state machine. Each
    NEXT/BACK button controls the next state, each state being the display of a
    particular dialog. A state machine can be a good candidate for flow control
    that has to go "forwards" and "backwards".

    -Don
    djw, Aug 31, 2004
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John R. Lewis
    Replies:
    0
    Views:
    659
    John R. Lewis
    Jan 4, 2006
  2. =?Utf-8?B?VGVycnk=?=

    Gridview Control in a Wizard Control issue

    =?Utf-8?B?VGVycnk=?=, Aug 24, 2006, in forum: ASP .Net
    Replies:
    0
    Views:
    642
    =?Utf-8?B?VGVycnk=?=
    Aug 24, 2006
  3. Replies:
    0
    Views:
    596
  4. Jack Dowson
    Replies:
    0
    Views:
    453
    Jack Dowson
    May 7, 2007
  5. Andy B
    Replies:
    0
    Views:
    432
    Andy B
    Apr 19, 2008
Loading...

Share This Page