The interact loop

Thanks much to everyone for all the helpful suggestions. I was particularly interested in the comment below. If it’s not too much to ask, could you sketch very briefly the wxPython statements that would be required to set this up? Thanks.

Instead of the “rate” function posting a render request, the secondary thread could have the renderer running off a timer, no? The renderer would simply use the current state of the graphic object attributes (position, orientation, etc.) and the camera position. This is how VPython works.

···

Another thought – strictly speaking, wxPython does not need to be in
the main thread, it just needs to all be in same thread, so your
initialization code can sart up wxPython in a secondary thread, then
your “rate(100)” or whatever function can post an event to wxPython to
refresh the screen. I’m pretty sure iPython used to do a trick like
this to keep a command line open with GUI code.

Bruce Sherwood wrote:

Thanks much to everyone for all the helpful suggestions. I was
particularly interested in the comment below. If it's not too much to
ask, could you sketch very briefly the wxPython statements that would
be required to set this up? Thanks.

There's no difference in the Python code.

Here's the restriction. Many people think that the window message queue
is global, so there is one per application, but that's not actually
true. A message queue is associated with a thread. Each thread has
one. The messages for a given window are always sent to the thread that
created that window, and graphics processing is synchronized by sending
stuff through the message queue.

In the usual case, you just create a bunch of windows and call MainLoop
in your main thread, but if your rmain thread is busy doing something
else, it's quite possible to spin off another thread, create some
windows, and then call MainLoop from that thread.

Instead of the "rate" function posting a render request, the secondary
thread could have the renderer running off a timer, no? The renderer
would simply use the current state of the graphic object attributes
(position, orientation, etc.) and the camera position. This is how
VPython works.

That's the OpenGL way of thinking. The efficiency of that approach
depends on how often your render requests will arrive. If render
requests only come through less than a few times per second then the
posting of a message is smarter. This is the normal GUI method -- you
use Update or Refresh when an update is necessary. But if render
requests and come through faster than your refresh rate, then the timer
approach is better.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Thanks much to everyone for all the helpful suggestions. I was particularly
interested in the comment below. If it's not too much to ask, could you
sketch very briefly the wxPython statements that would be required to set
this up? Thanks.

not much to it -- you could start with a regular wxPthon app, then
just start the whole thing from a separate thread -- but no time to
demo that right now -- maybe there is an example somewhere? anyone?

I'll bet if you red up a touch in threading in Python, it won't take
much to get a prototype together -- if it doesn't work as you expect,
post it here, and I'm sure someone will step in to help.

Instead of the "rate" function posting a render request, the secondary
thread could have the renderer running off a timer, no? The renderer would
simply use the current state of the graphic object attributes (position,
orientation, etc.) and the camera position. This is how VPython works.

sure -- I just saw the rate() call inside the while loop...if it's not
doing anything else, why not a call to time.sleep() or something to
cause a dealy between changes in the object?

and as Tim points out, there is something to be said for only
re-drawing when somethign actualy changes

-Chris

···

On Fri, Jun 22, 2012 at 9:05 AM, Bruce Sherwood <bruce.sherwood@gmail.com> wrote:

--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Thanks much to everyone for all the helpful suggestions. I was particularly
interested in the comment below. If it's not too much to ask, could you
sketch very briefly the wxPython statements that would be required to set
this up? Thanks.

not much to it -- you could start with a regular wxPthon app, then
just start the whole thing from a separate thread -- but no time to
demo that right now -- maybe there is an example somewhere? anyone?

OK -- I whipped on up. Interestingly, this crashes on OS-X with the
almost-latest wxCocoa2.9 build -- but works on 2.8 on Windows.

SeparateThread.py is pretty simple -- it creates a thread that starts
up the wx app and main loop.

Then it starts that thread, then runs through an infinite while loop
that updates a drawing in the wx thread by calling a method of the
Frame object.

You could just as easily have the Frame re-drawing with a timer, as
you suggested -- I just did it this way, as I could easily re-use the
DoubleBufferDemo that I wrote for a wiki page (also enclosed).

HTH,

-Chris

SeparateThread.py (1.18 KB)

DoubleBufferDemo.py (7.45 KB)

···

On Fri, Jun 22, 2012 at 12:54 PM, Chris Barker <chris.barker@noaa.gov> wrote:

I'll bet if you red up a touch in threading in Python, it won't take
much to get a prototype together -- if it doesn't work as you expect,
post it here, and I'm sure someone will step in to help.

Instead of the "rate" function posting a render request, the secondary
thread could have the renderer running off a timer, no? The renderer would
simply use the current state of the graphic object attributes (position,
orientation, etc.) and the camera position. This is how VPython works.

sure -- I just saw the rate() call inside the while loop...if it's not
doing anything else, why not a call to time.sleep() or something to
cause a dealy between changes in the object?

and as Tim points out, there is something to be said for only
re-drawing when somethign actualy changes

-Chris

--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Many thanks!

This is very good news (that you’ve given me a concrete example to work with) and very bad news (that it doesn’t work with Cocoa). One of the main reasons for my getting interested in wxPython is that VPython on the Mac uses Carbon, which is untenable due to the fact that it means that VPython can’t work with 64-bit Python. Four years ago David Scherer and I tried unsucessfully to base the Mac version of VPython on Cocoa. Our attempt foundered on the requirement that it seemed that Cocoa had to be the primary thread, whereas we need it to be a secondary thread. The failure of your example to run on Cocoa sounds ominously familiar.

···

On Tuesday, June 26, 2012 10:21:06 AM UTC-6, Chris Barker wrote:

OK – I whipped on up. Interestingly, this crashes on OS-X with the

almost-latest wxCocoa2.9 build – but works on 2.8 on Windows.

SeparateThread.py is pretty simple – it creates a thread that starts

up the wx app and main loop.

Then it starts that thread, then runs through an infinite while loop

that updates a drawing in the wx thread by calling a method of the

Frame object.

You could just as easily have the Frame re-drawing with a timer, as

you suggested – I just did it this way, as I could easily re-use the

DoubleBufferDemo that I wrote for a wiki page (also enclosed).

HTH,

-Chris

Hey Chris,

Thanks much to everyone for all the helpful suggestions. I was particularly
interested in the comment below. If it's not too much to ask, could you
sketch very briefly the wxPython statements that would be required to set
this up? Thanks.

not much to it -- you could start with a regular wxPthon app, then
just start the whole thing from a separate thread -- but no time to
demo that right now -- maybe there is an example somewhere? anyone?

OK -- I whipped on up. Interestingly, this crashes on OS-X with the
almost-latest wxCocoa2.9 build -- but works on 2.8 on Windows.

This approach is a non-starter on Mac, since the GUI stuff has to be run on the main thread on Mac. This is documented in the OS X documentation. (Though I can't remember where I read it off-hand, as it was years ago.) Not sure if it's OS X in general, or Cocoa in particular, though, but that's sort of moot as Carbon will be gone at some point and is already in fairly bad shape.

So if you want to use threads cross-platform, you need to run the other code in a separate thread, or I think it's possible to craft your own main loop that juggles the GUI events and other things concurrently.

SeparateThread.py is pretty simple -- it creates a thread that starts
up the wx app and main loop.

Then it starts that thread, then runs through an infinite while loop
that updates a drawing in the wx thread by calling a method of the
Frame object.

You could just as easily have the Frame re-drawing with a timer, as
you suggested -- I just did it this way, as I could easily re-use the
DoubleBufferDemo that I wrote for a wiki page (also enclosed).

BTW, some updates you could make to that code:

- use wx.AutoBufferedPaintDC (as you only need to do the buffering yourself on Windows, and it causes a performance hit on other platforms)

- avoid the use of self.Update on Mac. There's talk of having the Mac implementation just call Refresh() because Update typically just hurts performance there, but until then, I'd restrict it to non-Mac platforms. (Depending on the window manager, GTK may not want Update either, but I haven't done much testing there.)

Regards,

Kevin

···

On Jun 26, 2012, at 9:21 AM, Chris Barker wrote:

On Fri, Jun 22, 2012 at 12:54 PM, Chris Barker <chris.barker@noaa.gov> wrote:

HTH,

-Chris

I'll bet if you red up a touch in threading in Python, it won't take
much to get a prototype together -- if it doesn't work as you expect,
post it here, and I'm sure someone will step in to help.

Instead of the "rate" function posting a render request, the secondary
thread could have the renderer running off a timer, no? The renderer would
simply use the current state of the graphic object attributes (position,
orientation, etc.) and the camera position. This is how VPython works.

sure -- I just saw the rate() call inside the while loop...if it's not
doing anything else, why not a call to time.sleep() or something to
cause a dealy between changes in the object?

and as Tim points out, there is something to be said for only
re-drawing when somethign actualy changes

-Chris

--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en&lt;SeparateThread\.py&gt;&lt;DoubleBufferDemo\.py&gt;

This approach is a non-starter on Mac, since the GUI stuff has to be run on the main thread on Mac. This is documented in the OS X documentation.

THanks Kevin, I had forgotten about that.

But I don't suppose it would be too hard to re-arrange so that the
users code was running in the secondary thread.

BTW, some updates you could make to that code:

well, it's been a while since I wrote that! I guess I should update it
-- particularly for the Wiki -- note, if anone else wants to, feel
free!

- use wx.AutoBufferedPaintDC (as you only need to do the buffering yourself on Windows, and it causes a performance hit on other platforms)

yup -- I have been triple buffering on teh Mac for years, I guess!

- avoid the use of self.Update on Mac. There's talk of having the Mac implementation just call Refresh() because Update typically just hurts performance there,

I have found there are times when you really need the Update (though I
haven't tested with Cocoa) there can be a significant time delay
between the call to Refresh() and when the screen actually re-draws.

-Chris

···

On Tue, Jun 26, 2012 at 11:05 AM, Kevin Ollivier <kevin-lists@theolliviers.com> wrote:

--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

But I don’t suppose it would be too hard to re-arrange so that the users code was running in the secondary thread.

Alas, no, it’s (nearly) impossible. Remember that the VPython API requires that it be possible for a user to write a program of the following simple kind:

from visual import *

b = box()

while True:

b.pos.x += .001

I don’t see any way for the module import to throw the user’s 3-line program into a secondary thread, unless I create a special program text editor (based on IDLE, presumably) that rearranges the program appropriately. However, if someone sees a way to achieve the effect without a preprocessor, I’m all ears.

Nor can I imagine somehow writing my own interact loop that is somehow Cocoa but somehow not Cocoa, somehow getting around the requirement that the Cocoa interact loop be in the primary thread.

A different approach, should it prove literally impossible to achieve the necessary result on a Mac: Is there a way to tell wxPython (or wxWidgets) to use the Unix/X11 framework instead of Cocoa? In other words, to do something similar to what is done on Linux? That would of course have the disadvantage of not looking completely native, but it would make possible running on 64-bit Python, which is impossible with the current Carbon implementation of VPython.

I misspoke. A minimal VPython program would look like this:

from visual import *

b = box()

while True:

rate(100)

b.pos.x += .001

The rate(100) statement clamps the animation by limiting the calculation to no more than 100 iterations per second.

If it turns out to be necessary to build a Unix/X11 framework on the Mac instead of using Cocoa, presumably I would need to build wxPython/wxWidgets from source. However, in the build instructions I don’t see an option for choosing X11.

···

A different approach, should it prove literally impossible to achieve the necessary result on a Mac: Is there a way to tell wxPython (or wxWidgets) to use the Unix/X11 framework instead of Cocoa? In other words, to do something similar to what is done on Linux? That would of course have the disadvantage of not looking completely native, but it would make possible running on 64-bit Python, which is impossible with the current Carbon implementation of VPython.

    But I don't suppose it would be too hard to re-arrange so that
    the users code was running in the secondary thread.

Alas, no, it's (nearly) impossible. Remember that the VPython API
requires that it be possible for a user to write a program of the
following simple kind:

from visual import *
b = box()
while True:
     rate(100)
     b.pos.x += .001

I don't see any way for the module import to throw the user's 3-line
program into a secondary thread, unless I create a special program text
editor (based on IDLE, presumably) that rearranges the program
appropriately. However, if someone sees a way to achieve the effect
without a preprocessor, I'm all ears.

Is the above something that the user would expect to be able to run in the plain interactive interpreter? Or is it something that they will save to a file and then run?

If the latter then it would not be difficult to write a loader script which starts the wx application in the main thread and starts the worker thread which then loads the source file and executes it within the thread's context.

If it's supposed to work in an interactive interpreter environment then creating a GUI shell like PyCrust (or using it as a starting point) would allow you to essentially share the MainLoop with the interactive interpreter and the VPython code. As long as there is nothing that totally blocks without yielding then it would probably work ok.

Nor can I imagine somehow writing my own interact loop that is somehow
Cocoa but somehow not Cocoa, somehow getting around the requirement that
the Cocoa interact loop be in the primary thread.

You could call try calling wx.GetApp().Yield() from within whatever is your inner loop. Inside the rate() function I guess. If that doesn't fully work because the real MainLoop hasn't been called yet, then you can probably do the same thing it would do by creating your own instance of an wx.GUIEventLoop, activating it, and calling its Yield or YieldFor methods. I think that will effectively be the same as performing one iteration of the MainLoop.

A different approach, should it prove literally impossible to achieve
the necessary result on a Mac: Is there a way to tell wxPython (or
wxWidgets) to use the Unix/X11 framework instead of Cocoa? In other
words, to do something similar to what is done on Linux? That would of
course have the disadvantage of not looking completely native, but it
would make possible running on 64-bit Python, which is impossible with
the current Carbon implementation of VPython.

It should be possible to use the wxGTK port, but some work would need to be done to accomplish it as the build-wxpython and build-wxwidgets scripts assume that if you are running them on a Mac then you are wanting to build one of the Mac ports. So you would need to do what they are doing (run wx's configure and make, run wxPython's setup.py, etc.) by hand so you can use different options. I expect that wxWidgets will build okay using the --with-gtk configure option, although it may need some tweaks here and there. wxPython's setup.py and config.py will likely need some hacking to make it work. Look for anything inside conditionals based on sys.platform == 'darwin'

···

On 6/26/12 10:24 PM, Bruce Sherwood wrote:

--
Robin Dunn
Software Craftsman

Thanks much for the useful advice.

The normal context for using VPython is to create or open a file in IDLE and press F5 to run, which does an auto-save. So yes, it would be possible as I hinted earlier to make an altered version of IDLE which would set things up appropriately. However, that has the down side that the user file couldn’t be executed with “python user.py”.

But it could be done with something like "python -m visualRunner user.py" or "visualRunner user.py" which is almost as good.

It might take a little back magic but another idea I just had is that when your visual module is imported it could do something like check if it is running in the main thread and if so then it could respawn Python using the visualRunner (or whatever you want to call it) module so it will load the original script in the proper environment. It may not even need to respawn Python if you do a sys.exit(0) after the wx.App's MainLoop returns, so it won't actually return to the original main script. It sounds ugly describing it here, but it would probably work fine and would likely be transparent to the user as long as they don't have code before the "from visual import *" that would cause problems if it is executed twice.

···

On 6/27/12 11:54 AM, Bruce Sherwood wrote:

Thanks much for the useful advice.

The normal context for using VPython is to create or open a file in IDLE
and press F5 to run, which does an auto-save. So yes, it would be
possible as I hinted earlier to make an altered version of IDLE which
would set things up appropriately. However, that has the down side that
the user file couldn't be executed with "python user.py".

--
Robin Dunn
Software Craftsman

Robin, many thanks for your interesting ideas, which I’ll try out. I’ve been traveling for a week, with a Windows laptop, and no opportunity to try something on a Mac. I’m grateful for the possible solution you’ve proposed.

I’ll mention that four years ago when I asked similar questions in the cocoa-dev group I got in quick succession 1) an abusive response asking why I would ask such a really stupid question followed by 2) a knowledgeable guy saying no, Sherwood has a real problem, that it had been similarly extremely difficult to get Java to work with Cocoa, for similar reasons.

···

On Wednesday, June 27, 2012 1:14:40 PM UTC-6, Robin Dunn wrote:

On 6/27/12 11:54 AM, Bruce Sherwood wrote:

Thanks much for the useful advice.

The normal context for using VPython is to create or open a file in IDLE

and press F5 to run, which does an auto-save. So yes, it would be

possible as I hinted earlier to make an altered version of IDLE which

would set things up appropriately. However, that has the down side that

the user file couldn’t be executed with “python user.py”.

But it could be done with something like “python -m visualRunner
user.py” or “visualRunner user.py” which is almost as good.

It might take a little back magic but another idea I just had is that
when your visual module is imported it could do something like check if
it is running in the main thread and if so then it could respawn Python
using the visualRunner (or whatever you want to call it) module so it
will load the original script in the proper environment. It may not
even need to respawn Python if you do a sys.exit(0) after the wx.App’s
MainLoop returns, so it won’t actually return to the original main
script. It sounds ugly describing it here, but it would probably work
fine and would likely be transparent to the user as long as they don’t
have code before the “from visual import *” that would cause problems if
it is executed twice.


Robin Dunn

Software Craftsman

http://wxPython.org

Following up on your suggestion, I’ve kludged up the following structure, which works on both Windows and Mac Cocoa (hurray!):

A file visual.py sets up the wx machinery (and a “line” class), but before starting MainLoop it creates a thread whose run method performs execfile(‘user.py’, globals()), where user.py contains the following code (which for the moment doesn’t contain a statement to import visual):

rod = line()

while True:

rate(100)

rod.angle += .01

So there’s a proof of concept, but I don’t see how to do it really right. I would want the user, editing in IDLE, to create the file user.py (with an import of visual) and press F5 to run. I sort of see how the visual module could do what I’ve kludged up (based on your suggestion), but how would it know the name and location of the file “user.py”? I suppose I could modify IDLE to pass this file name somehow, but perhaps you have some specific scheme in mind that I haven’t grasped?

I’ll mention that simple demo programs running on wxPython Mac Cocoa (which I gather is somewhat experimental), do not quit properly when run from IDLE. They do quit properly when run from a terminal.

This includes the “Putting it all together” demo at

http://wiki.wxpython.org/Optimizing%20for%20Mac%20OS%20X

Is this a known problem?

···

On Wednesday, June 27, 2012 1:14:40 PM UTC-6, Robin Dunn wrote:

On 6/27/12 11:54 AM, Bruce Sherwood wrote:

Thanks much for the useful advice.

The normal context for using VPython is to create or open a file in IDLE

and press F5 to run, which does an auto-save. So yes, it would be

possible as I hinted earlier to make an altered version of IDLE which

would set things up appropriately. However, that has the down side that

the user file couldn’t be executed with “python user.py”.

But it could be done with something like “python -m visualRunner
user.py” or “visualRunner user.py” which is almost as good.

It might take a little back magic but another idea I just had is that
when your visual module is imported it could do something like check if
it is running in the main thread and if so then it could respawn Python
using the visualRunner (or whatever you want to call it) module so it
will load the original script in the proper environment. It may not
even need to respawn Python if you do a sys.exit(0) after the wx.App’s
MainLoop returns, so it won’t actually return to the original main
script. It sounds ugly describing it here, but it would probably work
fine and would likely be transparent to the user as long as they don’t
have code before the “from visual import *” that would cause problems if
it is executed twice.


Robin Dunn

Software Craftsman

http://wxPython.org

I can be more specific about quit problems with Mac Cocoa http://wiki.wxpython.org/Optimizing%20for%20Mac%20OS%20X

When I run from IDLE, I can quit okay using the Quit option on the Python menu, but things lock up if I click the Quit button or the red close box. Also, the File menu has only Open, not Exit nor Preferences.

This is because IDLE does not terminate the process when the program it executes is finished. It keeps it alive so you can interact with it in the Shell window. If you use the Restart Shell menu item then it will exit that process and the application will finish its termination.

···

On 6/30/12 10:56 PM, Bruce Sherwood wrote:

I'll mention that simple demo programs running on wxPython Mac Cocoa
(which I gather is somewhat experimental), do not quit properly when run
from IDLE. They do quit properly when run from a terminal.

--
Robin Dunn
Software Craftsman

I can be more specific about quit problems with Mac Cocoa
Optimizing for Mac OS X - wxPyWiki
<http://wiki.wxpython.org/Optimizing%20for%20Mac%20OS%20X&gt;

When I run from IDLE, I can quit okay using the Quit option on the
Python menu, but things lock up if I click the Quit button or the red
close box.

If you don't restart the shell before running again then I think IDLE will reuse the same process and you'll have problems with wx since it is still loaded and initialized.

Also, the File menu has only Open, not Exit nor Preferences.

If they use the stock IDs then those menu items are moved to the application menu as per the Apple HIG standards.

···

On 7/1/12 8:01 PM, Bruce Sherwood wrote:

--
Robin Dunn
Software Craftsman