wxPython before MainLoop

D

[david]

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

7stud

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)

You can use a separate 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):
the_frame = MyFrame()
the_frame.Show()

t = MyThread(the_frame)
t.start() #calls run() in t's class

return True


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

self.frame_obj = a_frame

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

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

#Send result to frame:
wx.CallAfter(self.frame_obj.receive_result, result)

app = MyApp()
app.MainLoop()
----------------------------
 
7

7stud

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

Bjoern Schliessmann

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
 
K

kyosohma

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)

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
 
7

7stud

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)

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

[david]

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

Heikki Toivonen

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
 
C

Chris Mellon

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

kyosohma

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]

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?

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
 
B

Bjoern Schliessmann

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
 
S

Steve Holden

[...] 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 -------------
 
C

Chris Mellon

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

[david]

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

Steve Holden

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.

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

[david]

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

Chris Mellon

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

Bjoern Schliessmann

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
 
B

Bjoern Schliessmann

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
 
S

samwyse


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!
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top