Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

wxPython before MainLoop

1 view
Skip to first unread message

[david]

unread,
Aug 9, 2007, 1:25:27 AM8/9/07
to
I'd like to refresh the display before I start the main loop.

I have code like this:

app = App()
app.Show()
app.long_slow_init()
app.MainLoop()


The main frame partly loads at Show, but because the mainloop has not
started yet, the display does not update until long_slow_init() finishes.

Alternatively, I could code

app = App()
app.long_slow_init()
app.Show()
app.MainLoop()

Which would give me a crisp Show, but there would be a long slow wait
before the app showed any activity at all. I would need a splash screen.

I'd rather not have a splash screen (and I don't know how anyway). I'd
like to just make app.Show() finish correctly before running
long_slow_init.

Is there a wx internal method that I can use to give Windows the
opportunity to finish painting the frame before I run long_slow_init()?

Or is there a better idea?

(david)

Message has been deleted

7stud

unread,
Aug 9, 2007, 5:16:52 AM8/9/07
to
I reorganized my Thread class a little bit:

------------
class MyThread(threading.Thread):
def __init__(self, a_frame):
threading.Thread.__init__(self)
self.frame_obj = a_frame

def run(self):
result = self.long_slow_init()

wx.CallAfter(self.frame_obj.receive_result, result)
#CallAfter() calls the specified function with the specified
argument
#when the next pause in execution occurs in this thread.

def long_slow_init(self):
print "starting long_slow_init()..."
time.sleep(6)
result = 20.5
return result
--------------

Bjoern Schliessmann

unread,
Aug 9, 2007, 6:16:56 AM8/9/07
to
[david] wrote:

> I'd like to refresh the display before I start the main loop.

> [...]


> I'd like to just make app.Show() finish correctly before running
> long_slow_init.

IMHO, this will bring no gain. If you see an inresponsive user
interface or not is quite meaningless.

> Or is there a better idea?

As suggested, a solution using threads is feasible.

Regards,


Björn

--
BOFH excuse #422:

Someone else stole your IP address, call the Internet detectives!

kyos...@gmail.com

unread,
Aug 9, 2007, 9:03:34 AM8/9/07
to

Yeah, I think 7stud's thread is the way to go. It's what I do with
long running tasks, see also:
http://wiki.wxpython.org/LongRunningTasks

If your screen doesn't load correctly, be sure to call the Layout()
method.

Mike

7stud

unread,
Aug 9, 2007, 12:03:58 PM8/9/07
to

I don't see my original post, so here it is again....


You can use another thread to execute long_slow_init():

--------------
import wx
import threading
import time

class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "My Window")

panel = wx.Panel(self, -1)
button = wx.Button(panel, -1, "click me, quick!", pos=(40,
40))
self.Bind(wx.EVT_BUTTON, self.onclick)

def onclick(self, event):
print "button clicked"

def receive_result(self, result):
print "Hey, I'm done with that long, slow initialization."
print "The result was:", result


class MyApp(wx.App):
def __init__(self):
wx.App.__init__(self, redirect=False)


def OnInit(self): #called by wx.Python
the_frame = MyFrame()
the_frame.Show()

t = MyThread(the_frame)
t.start() #calls t.run()

return True

class MyThread(threading.Thread):
def __init__(self, a_frame):
threading.Thread.__init__(self)
self.frame_obj = a_frame

def run(self):
result = self.long_slow_init()

wx.CallAfter(self.frame_obj.receive_result, result)
#CallAfter() calls the specified function with the

#specified argument when the next pause in execution
#occurs in this thread:

def long_slow_init(self):
print "starting long_slow_init()..."
time.sleep(6)
result = 20.5
return result


app = MyApp()
app.MainLoop()

[david]

unread,
Aug 9, 2007, 9:51:39 PM8/9/07
to
I'm disappointed that I didn't get a wxPython solution.

If the only way to get wxPython to correctly handle
this simple task is to code around it, I don't think
wxPython is really ready for Windows.

Is there a better place to ask?

Regarding the suggestions:

Bjoern, you're wrong. The GUI needs to be displayed
for the user to analyse. A delay between display and
readiness is much better than a delay before display
or a delay with the GUI half-drawn.

Mike, the screen does display correctly, it's just
that in Windows, screen updates are not processed
while the application is busy.

7Stud, that's a solution. Unless anyone comes up
with a direct solution, I guess I'll have to do that.

[david]

Heikki Toivonen

unread,
Aug 10, 2007, 12:47:40 AM8/10/07
to
[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

--
Heikki Toivonen

Chris Mellon

unread,
Aug 10, 2007, 8:43:10 AM8/10/07
to pytho...@python.org
On 8/9/07, [david] <da...@nospam.spam> wrote:
> I'm disappointed that I didn't get a wxPython solution.
>
> If the only way to get wxPython to correctly handle
> this simple task is to code around it, I don't think
> wxPython is really ready for Windows.
>

This sort of blathering is really just insulting. You don't know what
you're doing, but that doesn't mean that "wxPython isn't really ready
for Windows".

You can't interact with a window without an event loop running. This
is not (just) a wxPython limitation, it's intrinsic in guis in general
and in the windows platform in particular.

You need to do 2-step initialization, and you need to break it into
bits (or threads) that can operate independently of the event loop. If
you would like some suggestions as to how to do that in your
particular case, please feel free to post details on the wx-python
list, but leave your attitude at the door.

kyos...@gmail.com

unread,
Aug 10, 2007, 9:10:39 AM8/10/07
to

Chris is right. The only way to interact with a gui is with a separate
thread, otherwise you're blocking the gui's mainloop thread. That's
why I gave that link. That's how to do it in every GUI I'm aware of.

Mike

Bjoern Schliessmann

unread,
Aug 10, 2007, 10:29:07 AM8/10/07
to
[david] wrote:

> I'm disappointed that I didn't get a wxPython solution.
>
> If the only way to get wxPython to correctly handle
> this simple task is to code around it,

LOL -- did you try coding this app with native windows means, like
MFC? You will have *exactly* the same problem, and *exactly* for
the same reason. The organisation of wxWidgets (and thus, wxPython)
is very near to Windows GUI coding philosophy.

> I don't think wxPython is really ready for Windows.

I suggest you first went getting experience with other GUI libraries
before you make such statements.

Also, wxPython is a thin wrapper around wxWidgets C++ library which
is widely used for Windows apps. And with wxWidgets, you'd *also*
have the same problem.

> Bjoern, you're wrong. The GUI needs to be displayed
> for the user to analyse. A delay between display and
> readiness is much better than a delay before display
> or a delay with the GUI half-drawn.

This may be, but it strongly depends on the application itself.



> Mike, the screen does display correctly, it's just
> that in Windows, screen updates are not processed
> while the application is busy.

That's the matter in just about *every* GUI framework using an event
loop. And I don't know any that doesn't. Thus, there are two widely
used standard solutions:

* use a worker thread, or

* call a "process all pending events now" function repeatedly during
the work (here: wx.Yield, wx.SafeYield, wx.YieldIfNeeded).

Regards,


Björn

--
BOFH excuse #92:

Stale file handle (next time use Tupperware(tm)!)

Steve Holden

unread,
Aug 10, 2007, 10:48:30 AM8/10/07
to pytho...@python.org
[david] wrote:
> [...] I don't think wxPython is really ready for Windows.
>
I don't think you are really ready to for GUIs ;-)

Fortunately, it doesn't matter what *I* think.

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://del.icio.us/steve.holden
--------------- Asciimercial ------------------
Get on the web: Blog, lens and tag the Internet
Many services currently offer free registration
----------- Thank You for Reading -------------

Chris Mellon

unread,
Aug 10, 2007, 3:46:26 PM8/10/07
to pytho...@python.org

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()

[david]

unread,
Aug 13, 2007, 8:52:59 PM8/13/07
to
Well yes, I have tried this app with native windows,
and I know how to do it.

But if all wxPython can offer is a poor imitation
of MFC, I'm better off using MFC aren't I?

And too all those people who wrote back to insist
that users MUST explicitly build a multi-threaded
framework for wxPython:

It's supposed to already be a framework :~)

(david)

Steve Holden

unread,
Aug 13, 2007, 9:43:27 PM8/13/07
to pytho...@python.org
[david] wrote:
> Well yes, I have tried this app with native windows,
> and I know how to do it.
>
> But if all wxPython can offer is a poor imitation
> of MFC, I'm better off using MFC aren't I?
>
> And too all those people who wrote back to insist
> that users MUST explicitly build a multi-threaded
> framework for wxPython:
>
> It's supposed to already be a framework :~)
>
The answer is simple. If you don't see any advantage to using wxPython
then don't use it. Personally I believe wxPython is far from a poor
imitation of MFC, but if you are already familiar with MFC then go ahead
and use it.

[david]

unread,
Aug 13, 2007, 11:19:35 PM8/13/07
to
Steve, it wasn't me that raised the comparison
with MFC. If you don't think that's a helpful
comparison, why not reply to that post instead?

I don't mind Björn's suggestion that I don't
know what I'm talking about, because I started
it by telling him he was wrong.

But you don't have that excuse.

(david)

Chris Mellon

unread,
Aug 14, 2007, 8:57:55 AM8/14/07
to pytho...@python.org
On 8/13/07, [david] <da...@nospam.spam> wrote:
> Well yes, I have tried this app with native windows,
> and I know how to do it.
>

I don't believe you. If you meant "I copied something that does this
off of code project", that I'll believe.

> But if all wxPython can offer is a poor imitation
> of MFC, I'm better off using MFC aren't I?
>

MFC offers no special support at all for anything you're doing.
wxPython actually does have some, but that may or may not be helpful
since you haven't been exactly clear as to what your needs are (Show()
should never be slow, and if it is you're doing something wrong) and
you've got an egregiously bad attitude that cuts my interest in
helping you down rather a lot.

> And too all those people who wrote back to insist
> that users MUST explicitly build a multi-threaded
> framework for wxPython:
>
> It's supposed to already be a framework :~)
>

wxPython doesn't *need* a multi-threading framework. It's got a
threadsafe way to schedule events, and the Python standard library has
all the other synchronization primitives you need, including a queue.
There's nothing special that needs to be done to it. Nobody told you
to "build a multi-threaded framework", they told you to use the
threading framework which already exists.

Bjoern Schliessmann

unread,
Aug 14, 2007, 4:21:49 PM8/14/07
to
[david] wrote:

> Well yes, I have tried this app with native windows,
> and I know how to do it.

Then I wonder why you complained about concurrency problems (solved
by using a worker thread, or using wx.Yield) in the first place.
Windows has the same solutions, just as about every GUI framework.

http://msdn2.microsoft.com/en-us/library/69644x60(VS.80).aspx



> But if all wxPython can offer is a poor imitation of MFC,

From what did you conclude this? As already stated, almost ALL GUI
toolkits available function in a similar way (using an event loop).
To say that every such toolkit was just an imitation of MFC is
quite childish, IMHO.

Same niveau would be to say that all other cars are poor imitations
of Ford cars because they all have four wheels.

> I'm better off using MFC aren't I?

That depends on your demands. If you don't want it cross platform
you may be right, especially if you require very special Windows
features.

> And too all those people who wrote back to insist
> that users MUST explicitly build a multi-threaded
> framework for wxPython:

Could you please cite one posting where this is claimed? I can't
find this claim.

> It's supposed to already be a framework :~)

wxWidgets _has_ cross-platform threads implemented on its own:

http://www.wxwidgets.org/manuals/stable/wx_wxthread.html#wxthread

It has just been dropped from wxPython because cross-platform
threads are already part of the Python library. C++, the basis for
wxWidgets, has no multithreading support in STL.

Regards,


Björn

--
BOFH excuse #61:

not approved by the FCC

Bjoern Schliessmann

unread,
Aug 14, 2007, 4:27:25 PM8/14/07
to
[david] wrote:
> Steve, it wasn't me that raised the comparison
> with MFC. If you don't think that's a helpful
> comparison, why not reply to that post instead?

It _was_ a comparison, saying that they follow similar principles.
You twisted this comparison by saying wxPython was an imitation of
MFC. You ignored the fact that your problem is solved by MFC in a
similar way, just as in every other GUI toolkit other posters here
and me know of.

> I don't mind Björn's suggestion that I don't
> know what I'm talking about,

Where did I write this?

> because I started it by telling him he was wrong.

Excuse me, where am I wrong?


Björn

--
BOFH excuse #163:

no "any" key on keyboard

samwyse

unread,
Aug 15, 2007, 7:40:24 AM8/15/07
to
Chris Mellon wrote:
> On 8/9/07, Heikki Toivonen <hei...@osafoundation.org> wrote:
>
>>[david] wrote:
>>
>>>I'd like to refresh the display before I start the main loop.

If your window isn't able to interact with the user, then I'd consider
it a splash screen, no matter if it does look exactly like your main
application interface.

>>We have this kind of situation in Chandler, where we display and update
>>the splash screen before we enter MainLoop.
>>

[...]


>>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

Looking at the Chandler code suggests a solution to [david]'s original
problem. It is possible that, on Windows only, he may need to call
Update to finish painting the display.

1432 self.Layout()
1433 if wx.Platform == '__WXMSW__':
1434 self.Update()
1435 wx.GetApp().Yield(True)

> 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.

I'll confess to being one of those old-school programmers who, back in
the day, wrote his code around big select loops instead of using
threads, but I'm intriged by the "experts only" designation. Can
someone explain further? Thanks!

Chris Mellon

unread,
Aug 15, 2007, 9:31:54 AM8/15/07
to pytho...@python.org

The biggest problem is recursive events. You can end up entering an
event handler downstack from itself. There's other common problems -
event handlers are generally written to be short and sweet and not to
expect recursion and to complete without interruption. wxYield can
easily end up breaking that. Components that call wxYield are
especially dangerous. For example, some parts of wxWidgets call
wxYield internally. An event handler that aquired a lock was changed
to use one of those components and ended up deadlocking when it was
re-entered by the yield. I've also seen crashes when wxYield processed
a destroy event for a window in the middle of it's own event handler.

Because analyzing your event code to make sure it's reentrant is hard,
and is complicated even more by the fact that wxYield in a component
can cause problems far upstack in a caller, and because there is an
excellent alternative in the form of python generators, I avoid it's
usage from wxPython entirely.

Grant Edwards

unread,
Aug 15, 2007, 6:13:52 PM8/15/07
to
On 2007-08-14, [david] <da...@nospam.spam> wrote:

> Steve, it wasn't me that raised the comparison
> with MFC. If you don't think that's a helpful
> comparison, why not reply to that post instead?
>
> I don't mind Björn's suggestion that I don't
> know what I'm talking about, because I started
> it by telling him he was wrong.
>
> But you don't have that excuse.
>
> (david)

Oh dear, arguing with Steve Holden is a rather inauspicious way
to start out in c.l.p.

--
Grant Edwards grante Yow! CHUBBY CHECKER just
at had a CHICKEN SANDWICH in
visi.com downtown DULUTH!

[david]

unread,
Aug 21, 2007, 3:58:40 AM8/21/07
to
> Looking at the Chandler code suggests a solution
> ... he may need to call Update to finish painting
> the display.


Yes, and thank you to Chandler for pointing that out.

Without the splash screen there was no need to call
Yield or use a generator.

(david)

[david]

unread,
Aug 21, 2007, 4:10:37 AM8/21/07
to
Thanks for that suggestion, and sorry I took so
long to get back to you. That worked.

Because I don't want the splash screen, just
self.Update

regards,

[david]

0 new messages