wxPython before MainLoop

Chris Mellon arkanes at gmail.com
Fri Aug 10 15:46:26 EDT 2007


On 8/9/07, Heikki Toivonen <heikki at osafoundation.org> wrote:
> [david] wrote:
> > I'd like to refresh the display before I start the main loop.
>
> We have this kind of situation in Chandler, where we display and update
> the splash screen before we enter MainLoop.
>
> 1. Create app object
>    http://lxr.osafoundation.org/source/chandler/Chandler.py#080
>
> 2. During app object creation, in OnInit, put up splash screen and update it
>
> http://lxr.osafoundation.org/source/chandler/application/Application.py#433
>
> 3. The splash screen refresh is basically: draw new stuff,
> self.Layout(), self.Update(), wx.Yield()
> http://lxr.osafoundation.org/source/chandler/application/Application.py#1421
>
> 3. Start MainLoop
>    http://lxr.osafoundation.org/source/chandler/Chandler.py#086
>

wxYield spins the event loop in place. This can have some serious
consequences if you aren't very careful with your usage, like
recursively entering event handlers. I generally consider it an
experts only interface, and avoid it.

Thankfully, in Python 2.5 you can do some very nice things with
Pythons generators. Basically, replace your wxYielding code with a
python generator that just yields where you used to wxYield, and then
call your generator repeatedly with wx.CallAfter.

Here's an (unpolished) example of a progress dialog that is updated
via generator:

import wx


def startupTask():
    for ii in xrange(1001):
        cont, skip = yield ii, "step %s"%str(ii)
        if not cont:
            raise StopIteration



class GeneratorProgress(wx.ProgressDialog):
    """ Progress dialog fed via generator.
    Task let should be a python generator that yields (value, message) tuples
    and is sent (continue, skip) tuples, as per the arguments to and return
    values from the wx.ProgressDialog.Update method.
    """
    def __init__(self, title, message, tasklet, *args, **kwargs):
        super(GeneratorProgress, self).__init__(title, message, *args, **kwargs)
        self.tasklet = tasklet
        wx.CallAfter(self.iterate)

    def iterate(self, cont=None, skip=None):
        try:
            if cont is None and skip is None:
                value, msg = self.tasklet.next()
            else:
                value, msg = self.tasklet.send((cont, skip))
            cont, skip = self.Update(value, msg)
            wx.CallAfter(self.iterate, cont, skip)
        except StopIteration:
            self.Destroy()

def main():
    app = wx.App(False)
    f = wx.Frame(None)
    pg = GeneratorProgress("Startup", "running task...",
startupTask(), parent=f, maximum=1000)
    pg.Show()
    f.Show()
    app.MainLoop()

if __name__ == '__main__':
    main()



More information about the Python-list mailing list