I’ve been experimenting with a conventional structure in which MainLoop is started in the primary thread and a calculational loop is run in a secondary thread.
Is it possible instead to not initiate MainLoop but instead call the underlying event handler periodically (polling)? Something like the following user program, where this program is in the primary loop, and the rate statement (do no more than 100 iterations per second) calls the event-handling machinery periodically:
from wxvisual import *
rod = line()
while True:
rate(100)
rod.angle += .01
What I’m trying to do would be a lot simpler if this is possible, by eliminating the threading (and simplifying some import issues in the user program). This would have to work on all platforms to be useful, including Cocoa on the Mac.
Yes, I think I mentioned in the prior discussion that it should be possible to do one iteration at a time of the equivalent of MainLoop(). Something like this would probably do it:
def oneMainLoopIteration():
evtloop = wx.GUIEventLoop()
old = wx.EventLoop.GetActive()
wx.EventLoop.SetActive(evtloop)
while evtloop.Pending():
evtloop.Dispatch()
evtloop.ProcessIdle()
wx.EventLoop.SetActive(old)
You may want to refactor it so the creation and activation of the new eventloop, as well as resetting it to the old one is done just once outside of this function.
···
On 7/21/12 8:18 AM, Bruce Sherwood wrote:
I've been experimenting with a conventional structure in which MainLoop
is started in the primary thread and a calculational loop is run in a
secondary thread.
Is it possible instead to not initiate MainLoop but instead call the
underlying event handler periodically (polling)? Something like the
following user program, where this program is in the primary loop, and
the rate statement (do no more than 100 iterations per second) calls the
event-handling machinery periodically:
from wxvisual import *
rod = line()
while True:
rate(100)
rod.angle += .01
What I'm trying to do would be a lot simpler if this is possible, by
eliminating the threading (and simplifying some import issues in the
user program). This would have to work on all platforms to be useful,
including Cocoa on the Mac.
On Sat, Jul 21, 2012 at 1:24 PM, Robin Dunn <robin@alldunn.com> wrote:
On 7/21/12 8:18 AM, Bruce Sherwood wrote:
I've been experimenting with a conventional structure in which MainLoop
is started in the primary thread and a calculational loop is run in a
secondary thread.
Is it possible instead to not initiate MainLoop but instead call the
underlying event handler periodically (polling)? Something like the
following user program, where this program is in the primary loop, and
the rate statement (do no more than 100 iterations per second) calls the
event-handling machinery periodically:
from wxvisual import *
rod = line()
while True:
rate(100)
rod.angle += .01
What I'm trying to do would be a lot simpler if this is possible, by
eliminating the threading (and simplifying some import issues in the
user program). This would have to work on all platforms to be useful,
including Cocoa on the Mac.
Yes, I think I mentioned in the prior discussion that it should be possible
to do one iteration at a time of the equivalent of MainLoop(). Something
like this would probably do it:
def oneMainLoopIteration():
evtloop = wx.GUIEventLoop()
old = wx.EventLoop.GetActive()
wx.EventLoop.SetActive(evtloop)
while evtloop.Pending():
evtloop.Dispatch()
evtloop.ProcessIdle()
wx.EventLoop.SetActive(old)
You may want to refactor it so the creation and activation of the new
eventloop, as well as resetting it to the old one is done just once outside
of this function.
Alas, this works fine on Windows but not on the Mac (Cocoa). I call your function oneMainLoopIteration():from the rate function called in the following program’s while loop, which works fine on Windows but on the Mac it fires only once, and the rod gets displayed but doesn’t rotate.
from wxpoll import *
from math import cos
print(‘after getting math’)
print(cos(3.14159/4))
rod = line()
while True:
rate(100)
rod.angle += .01
I tried to attach the files (userpoll.py and wxpoll.py) but I don’t see evidence that they are in fact attached. I’d be happy to send them to you if you’d like to try this yourself. My email is bruce.sherwood@gmail.com.
Bruce
···
On Saturday, July 21, 2012 1:24:48 PM UTC-6, Robin Dunn wrote:
On 7/21/12 8:18 AM, Bruce Sherwood wrote:
I’ve been experimenting with a conventional structure in which MainLoop
is started in the primary thread and a calculational loop is run in a
secondary thread.
Is it possible instead to not initiate MainLoop but instead call the
underlying event handler periodically (polling)? Something like the
following user program, where this program is in the primary loop, and
the rate statement (do no more than 100 iterations per second) calls the
event-handling machinery periodically:
from wxvisual import *
rod = line()
while True:
rate(100)
rod.angle += .01
What I’m trying to do would be a lot simpler if this is possible, by
eliminating the threading (and simplifying some import issues in the
user program). This would have to work on all platforms to be useful,
including Cocoa on the Mac.
Yes, I think I mentioned in the prior discussion that it should be
possible to do one iteration at a time of the equivalent of MainLoop().
Something like this would probably do it:
def oneMainLoopIteration():
evtloop = wx.GUIEventLoop()
old = wx.EventLoop.GetActive()
wx.EventLoop.SetActive(evtloop)
while evtloop.Pending():
evtloop.Dispatch()
evtloop.ProcessIdle()
wx.EventLoop.SetActive(old)
You may want to refactor it so the creation and activation of the new
eventloop, as well as resetting it to the old one is done just once
outside of this function.
Robin, I should add that it would be wonderful for your polling scheme to work with Cocoa, because it would greatly simplify my code. In the wxpoll import file I simply set up wxPython and exec the importing program (with the wxpoll import commented out but the imported items provided in the globals dictionary given to exec). There are no threads, so there are no problems with other imports in the importing program, whereas a thread started from an import file cannot execute import statements, which is an obscure Python restriction.
Alas, this works fine on Windows but not on the Mac (Cocoa). I call your function oneMainLoopIteration():from the rate function called in the following program's while loop, which works fine on Windows but on the Mac it fires only once, and the rod gets displayed but doesn't rotate.
from wxpoll import *
from math import cos
print('after getting math')
print(cos(3.14159/4))
rod = line()
while True:
rate(100)
rod.angle += .01
I tried to attach the files (userpoll.py and wxpoll.py) but I don't see evidence that they are in fact attached. I'd be happy to send them to you if you'd like to try this yourself. My email is bruce.sherwood@gmail.com.
I don't see them attached. In any case, try Robin's suggestion of creating and destroying the new event loop outside of that function. So something like this:
newloop = None
oldloop = None
def myEvtLoop():
global newloop
global oldloop
if newloop is None:
newloop = wx.GUIEventLoop()
oldloop = wx.EventLoop.GetActive()
wx.EventLoop.SetActive(newloop)
return newloop
def oneMainLoopIteration():
evtloop = myEvtLoop()
while evtloop.Pending():
evtloop.Dispatch()
evtloop.ProcessIdle()
I'm not sure if you need to restore the old event loop for your use case, but you can have a function that calls wx.EventLoop.SetActive(oldloop) when you want to restore the old one.
···
On Jul 23, 2012, at 12:01 PM, Bruce Sherwood wrote:
Bruce
On Saturday, July 21, 2012 1:24:48 PM UTC-6, Robin Dunn wrote:
On 7/21/12 8:18 AM, Bruce Sherwood wrote:
> I've been experimenting with a conventional structure in which MainLoop
> is started in the primary thread and a calculational loop is run in a
> secondary thread.
>
> Is it possible instead to not initiate MainLoop but instead call the
> underlying event handler periodically (polling)? Something like the
> following user program, where this program is in the primary loop, and
> the rate statement (do no more than 100 iterations per second) calls the
> event-handling machinery periodically:
>
> from wxvisual import *
> rod = line()
> while True:
> rate(100)
> rod.angle += .01
>
> What I'm trying to do would be a lot simpler if this is possible, by
> eliminating the threading (and simplifying some import issues in the
> user program). This would have to work on all platforms to be useful,
> including Cocoa on the Mac.
Yes, I think I mentioned in the prior discussion that it should be
possible to do one iteration at a time of the equivalent of MainLoop().
Something like this would probably do it:
def oneMainLoopIteration():
evtloop = wx.GUIEventLoop()
old = wx.EventLoop.GetActive()
wx.EventLoop.SetActive(evtloop)
while evtloop.Pending():
evtloop.Dispatch()
evtloop.ProcessIdle()
wx.EventLoop.SetActive(old)
You may want to refactor it so the creation and activation of the new
eventloop, as well as resetting it to the old one is done just once
outside of this function.
Thanks for the suggestion, but it doesn't change anything. Works fine
on Windows, but on Mac Cocoa a print statement in the loop "while
evtloop.Pending():" runs forever; the loop never ends. I've made
another effort to attach the files.
I'm glad that you and Robin believe this should work (which could mean
I just have a minor error due to my shaky understanding of the
interact loop issues). It sure would make my code simple and
straightforward.
Incidentally, on Windows the following code is sufficient:
On Mon, Jul 23, 2012 at 3:37 PM, Kevin Ollivier <kevin-lists@theolliviers.com> wrote:
Hi Bruce,
On Jul 23, 2012, at 12:01 PM, Bruce Sherwood wrote:
Alas, this works fine on Windows but not on the Mac (Cocoa). I call your function oneMainLoopIteration():from the rate function called in the following program's while loop, which works fine on Windows but on the Mac it fires only once, and the rod gets displayed but doesn't rotate.
from wxpoll import *
from math import cos
print('after getting math')
print(cos(3.14159/4))
rod = line()
while True:
rate(100)
rod.angle += .01
I tried to attach the files (userpoll.py and wxpoll.py) but I don't see evidence that they are in fact attached. I'd be happy to send them to you if you'd like to try this yourself. My email is bruce.sherwood@gmail.com.
I don't see them attached. In any case, try Robin's suggestion of creating and destroying the new event loop outside of that function. So something like this:
newloop = None
oldloop = None
def myEvtLoop():
global newloop
global oldloop
if newloop is None:
newloop = wx.GUIEventLoop()
oldloop = wx.EventLoop.GetActive()
wx.EventLoop.SetActive(newloop)
return newloop
def oneMainLoopIteration():
evtloop = myEvtLoop()
while evtloop.Pending():
evtloop.Dispatch()
evtloop.ProcessIdle()
I'm not sure if you need to restore the old event loop for your use case, but you can have a function that calls wx.EventLoop.SetActive(oldloop) when you want to restore the old one.
That reminds me that I also ran in to this problem when I was rewriting the mainloop sample for Phoenix. You can see it here: wxTrac has been migrated to GitHub Issues - wxWidgets, look in the MyEventLoop.Run method.
You won't be able to use that directly because the wxEventLoop methods are not overridable in Classic, but it should help you see how to tweak your algorithm a little so it will work.
···
On 7/23/12 3:01 PM, Bruce Sherwood wrote:
Thanks for the suggestion, but it doesn't change anything. Works fine
on Windows, but on Mac Cocoa a print statement in the loop "while
evtloop.Pending():" runs forever; the loop never ends. I've made
another effort to attach the files.
Hurray! That did it! With the following version of
oneMainLoopIteration, called from rate statements in loops in the user
program, I can now run an animation on Windows and on Mac Cocoa, using
the same code:
def oneMainLoopIteration():
while not evtloop.Pending() and evtloop.ProcessIdle(): pass
if wx.GetApp(): wx.GetApp().ProcessPendingEvents()
if not evtloop.Dispatch(): return
# Currently on wxOSX Pending always returns true, so the
# ProcessIdle above is not ever called. Call it here instead.
if 'wxOSX' in wx.PlatformInfo: evtloop.ProcessIdle()
while True:
checkAgain = False
if wx.GetApp() and wx.GetApp().HasPendingEvents():
wx.GetApp().ProcessPendingEvents()
checkAgain = True
if 'wxOSX' not in wx.PlatformInfo and evtloop.Pending():
evtloop.Dispatch()
checkAgain = True
if not checkAgain:
break
There's some cleanup to do, such as quitting more gracefully. But for
the first time I've seen an architecture that (1) runs on Cocoa, (2)
permits using the standard VPython API, (3) makes minimal change to
the user code (effectively comments out the main import statement),
(4) eliminates the need for threading, with all of its attendant
complexities, and (5) permits normal import operations from the user
program. Having seen a test program work, I can now proceed to trying
to use this architecture in VPython.
I'm very grateful for all the help, especially from Robin. Thanks!
Bruce
···
On Mon, Jul 23, 2012 at 4:52 PM, Robin Dunn <robin@alldunn.com> wrote:
On 7/23/12 3:01 PM, Bruce Sherwood wrote:
Thanks for the suggestion, but it doesn't change anything. Works fine
on Windows, but on Mac Cocoa a print statement in the loop "while
evtloop.Pending():" runs forever; the loop never ends. I've made
another effort to attach the files.
That reminds me that I also ran in to this problem when I was rewriting the
mainloop sample for Phoenix. You can see it here: wxTrac has been migrated to GitHub Issues - wxWidgets,
look in the MyEventLoop.Run method.
You won't be able to use that directly because the wxEventLoop methods are
not overridable in Classic, but it should help you see how to tweak your
algorithm a little so it will work.
As explained earlier, thanks to Robin’s gift of oneMainLoopIteration(), I’m able to run both the user’s program and the GUI machinery in the same primary thread, and it works on Windows and Mac (but not Ubuntu, because wxPython 2.9 is required to get wx.GUIEventLoop).
The module imported by the user has this structure:
set up GUI machinery
exec modified user program source
infinite loop, calling oneMainLoopIteration()
The user program in its animation loop calls rate function, which calls oneMainLoopIteration(). The modification to the user program source is to comment out the import statement that invoked this module.
When or if the user program exits its animation loop, the infinite loop in the imported module keeps the window active for quitting, zooming a camera position, etc.
It would be cleaner not to do the exec but just let the user program run normally following the import. However, if the user program exits its animation loop, there will be nothing to handle events (quit, zoom camera position, etc.). It occurred to me to have the import module start a simple secondary thread to do something to keep event handling alive, but I don’t quite see how to do this. Or maybe a wx timer in the frame setup could do this somehow. Does anyone have a good idea? Thanks!
Hmm. Maybe I should try using CallAfter in some way? Can a secondary thread post a CallAfter that will be run in the primary thread?
···
On Saturday, July 21, 2012 9:18:40 AM UTC-6, Bruce Sherwood wrote:
I’ve been experimenting with a conventional structure in which MainLoop is started in the primary thread and a calculational loop is run in a secondary thread.
Is it possible instead to not initiate MainLoop but instead call the underlying event handler periodically (polling)? Something like the following user program, where this program is in the primary loop, and the rate statement (do no more than 100 iterations per second) calls the event-handling machinery periodically:
from wxvisual import *
rod = line()
while True:
rate(100)
rod.angle += .01
What I’m trying to do would be a lot simpler if this is possible, by eliminating the threading (and simplifying some import issues in the user program). This would have to work on all platforms to be useful, including Cocoa on the Mac.
As far as I understand it, any secondary thread can use wx.CallAfter to post information to the main GUI thread. The GUI thread will act on the information as soon as it can.
Mike
···
On Wednesday, July 25, 2012 12:54:49 PM UTC-5, Bruce Sherwood wrote:
Hmm. Maybe I should try using CallAfter in some way? Can a secondary thread post a CallAfter that will be run in the primary thread?
Yes, but is uses events and so if you're wanting to do this in order to keep the event processing happening then you'll have a problem. (Can't send an event if events are not being processed, can't process events until you get the event to process events...) In other words, you have to have an event loop to be able to use CallAfter, so you can't use CallAfter to call code that would run an iteration of the event loop. Timers would have the same problem.
···
On 7/25/12 10:54 AM, Bruce Sherwood wrote:
Hmm. Maybe I should try using CallAfter in some way? Can a secondary
thread post a CallAfter that will be run in the primary thread?
Hmm. Maybe I should try using CallAfter in some way? Can a secondary thread post a CallAfter that will be run in the primary thread?
Are you trying to keep an event loop running after your custom animation loop finishes? In that case, would restoring the original event loop (which you can save by doing oldloop = wx.EventLoop.GetActive())? i.e.
get the stock wx event loop and save it for later
oldloop = wx.EventLoop.GetActive()
… do your custom animation loop stuff
restore the stock wx event loop to keep UI events flowing
wx.EventLoop.SetActive(oldloop)
Regards,
Kevin
···
On Jul 25, 2012, at 10:54 AM, Bruce Sherwood wrote:
On Saturday, July 21, 2012 9:18:40 AM UTC-6, Bruce Sherwood wrote:
I’ve been experimenting with a conventional structure in which MainLoop is started in the primary thread and a calculational loop is run in a secondary thread.
Is it possible instead to not initiate MainLoop but instead call the underlying event handler periodically (polling)? Something like the following user program, where this program is in the primary loop, and the rate statement (do no more than 100 iterations per second) calls the event-handling machinery periodically:
from wxvisual import *
rod = line()
while True:
rate(100)
rod.angle += .01
What I’m trying to do would be a lot simpler if this is possible, by eliminating the threading (and simplifying some import issues in the user program). This would have to work on all platforms to be useful, including Cocoa on the Mac.
Thanks. I was afraid of that. I guess I have to retain the current
structure (an infinite loop in the import file, following the exec
statement). And to Kevin, the user's program doesn't contain any
statement after the animation loop that could restore the GUI loop,
nor can I ask users to put such a statement in their programs because
I have to maintain the current API.
The current structure isn't totally disgusting, since only the import
of my module is affected (processed in the import module itself, then
commented out in the source text before the exec). Other imports in
the user program (math, etc.) are unaffected because the user program
now runs in the primary thread, avoiding the problem I had before,
that executing the user program in a secondary thread meant that
imports could not be done there.
Bruce
···
On Wed, Jul 25, 2012 at 12:47 PM, Robin Dunn <robin@alldunn.com> wrote:
On 7/25/12 10:54 AM, Bruce Sherwood wrote:
Hmm. Maybe I should try using CallAfter in some way? Can a secondary
thread post a CallAfter that will be run in the primary thread?
Yes, but is uses events and so if you're wanting to do this in order to keep
the event processing happening then you'll have a problem. (Can't send an
event if events are not being processed, can't process events until you get
the event to process events...) In other words, you have to have an event
loop to be able to use CallAfter, so you can't use CallAfter to call code
that would run an iteration of the event loop. Timers would have the same
problem.
I'm a bit confused now -- why can't you __import__ the user's code?
Or for that matter, just run it -- when the wxVisual (or whatever)
module is run, it can set a flag, so that it knows that it's the first
import or not, and do something there only once.
There are probably good reasons why not -- but I've lost track
-Chris
···
On Wed, Jul 25, 2012 at 1:38 PM, Bruce Sherwood <bruce.sherwood@gmail.com> wrote:
Thanks. I was afraid of that. I guess I have to retain the current
structure (an infinite loop in the import file, following the exec
statement). And to Kevin, the user's program doesn't contain any
statement after the animation loop that could restore the GUI loop,
nor can I ask users to put such a statement in their programs because
I have to maintain the current API.
The current structure isn't totally disgusting, since only the import
of my module is affected (processed in the import module itself, then
commented out in the source text before the exec). Other imports in
the user program (math, etc.) are unaffected because the user program
now runs in the primary thread, avoiding the problem I had before,
that executing the user program in a secondary thread meant that
imports could not be done there.
Bruce
On Wed, Jul 25, 2012 at 12:47 PM, Robin Dunn <robin@alldunn.com> wrote:
On 7/25/12 10:54 AM, Bruce Sherwood wrote:
Hmm. Maybe I should try using CallAfter in some way? Can a secondary
thread post a CallAfter that will be run in the primary thread?
Yes, but is uses events and so if you're wanting to do this in order to keep
the event processing happening then you'll have a problem. (Can't send an
event if events are not being processed, can't process events until you get
the event to process events...) In other words, you have to have an event
loop to be able to use CallAfter, so you can't use CallAfter to call code
that would run an iteration of the event loop. Timers would have the same
problem.
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
Yeah, I'm losing track, too -- too many options (but few of them work).
Interestingly, if I put mmm = __import__('math') in the import module,
I can access mmm.cos() in the user program. But if I try
__import__(sys.argv(0)) to import the user program, I get
ImportError: Import by filename is not supported.
Though the error message doesn't say, I'm guessing that it's
complaining about a circular import cycle.
As for simply running the user program, the problem is that when the
user's program finishes an animation loop, it is essential that the
window still be active, which it won't be with the no-thread
architecture.
Bruce
···
On Wed, Jul 25, 2012 at 3:45 PM, Chris Barker <chris.barker@noaa.gov> wrote:
Bruce,
I'm a bit confused now -- why can't you __import__ the user's code?
Or for that matter, just run it -- when the wxVisual (or whatever)
module is run, it can set a flag, so that it knows that it's the first
import or not, and do something there only once.
There are probably good reasons why not -- but I've lost track
-Chris
On Wed, Jul 25, 2012 at 1:38 PM, Bruce Sherwood > <bruce.sherwood@gmail.com> wrote:
Thanks. I was afraid of that. I guess I have to retain the current
structure (an infinite loop in the import file, following the exec
statement). And to Kevin, the user's program doesn't contain any
statement after the animation loop that could restore the GUI loop,
nor can I ask users to put such a statement in their programs because
I have to maintain the current API.
The current structure isn't totally disgusting, since only the import
of my module is affected (processed in the import module itself, then
commented out in the source text before the exec). Other imports in
the user program (math, etc.) are unaffected because the user program
now runs in the primary thread, avoiding the problem I had before,
that executing the user program in a secondary thread meant that
imports could not be done there.
Bruce
On Wed, Jul 25, 2012 at 12:47 PM, Robin Dunn <robin@alldunn.com> wrote:
On 7/25/12 10:54 AM, Bruce Sherwood wrote:
Hmm. Maybe I should try using CallAfter in some way? Can a secondary
thread post a CallAfter that will be run in the primary thread?
Yes, but is uses events and so if you're wanting to do this in order to keep
the event processing happening then you'll have a problem. (Can't send an
event if events are not being processed, can't process events until you get
the event to process events...) In other words, you have to have an event
loop to be able to use CallAfter, so you can't use CallAfter to call code
that would run an iteration of the event loop. Timers would have the same
problem.
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
I was wrong. The __import__ does work, if you manipulate the full path
name given by sys.argv[0] to extract just the file name, without the
.py extension. What gave the error message was giving the full path
name. So the circular import cycle doesn't cause a problem in this
case.
However, I don't see how to make this work in general, because my
import module will be in (say) site-packages, whereas the user program
will be in some place that is very unlikely to be on the Python module
search path. For that reason I think the exec is essential.
Bruce
···
On Wed, Jul 25, 2012 at 5:31 PM, Bruce Sherwood <bruce.sherwood@gmail.com> wrote:
Yeah, I'm losing track, too -- too many options (but few of them work).
Interestingly, if I put mmm = __import__('math') in the import module,
I can access mmm.cos() in the user program. But if I try
__import__(sys.argv[0]) to import the user program, I get
ImportError: Import by filename is not supported.
Though the error message doesn't say, I'm guessing that it's
complaining about a circular import cycle.
As for simply running the user program, the problem is that when the
user's program finishes an animation loop, it is essential that the
window still be active, which it won't be with the no-thread
architecture.
Bruce
On Wed, Jul 25, 2012 at 3:45 PM, Chris Barker <chris.barker@noaa.gov> wrote:
Bruce,
I'm a bit confused now -- why can't you __import__ the user's code?
Or for that matter, just run it -- when the wxVisual (or whatever)
module is run, it can set a flag, so that it knows that it's the first
import or not, and do something there only once.
There are probably good reasons why not -- but I've lost track
-Chris
On Wed, Jul 25, 2012 at 1:38 PM, Bruce Sherwood >> <bruce.sherwood@gmail.com> wrote:
Thanks. I was afraid of that. I guess I have to retain the current
structure (an infinite loop in the import file, following the exec
statement). And to Kevin, the user's program doesn't contain any
statement after the animation loop that could restore the GUI loop,
nor can I ask users to put such a statement in their programs because
I have to maintain the current API.
The current structure isn't totally disgusting, since only the import
of my module is affected (processed in the import module itself, then
commented out in the source text before the exec). Other imports in
the user program (math, etc.) are unaffected because the user program
now runs in the primary thread, avoiding the problem I had before,
that executing the user program in a secondary thread meant that
imports could not be done there.
Bruce
On Wed, Jul 25, 2012 at 12:47 PM, Robin Dunn <robin@alldunn.com> wrote:
On 7/25/12 10:54 AM, Bruce Sherwood wrote:
Hmm. Maybe I should try using CallAfter in some way? Can a secondary
thread post a CallAfter that will be run in the primary thread?
Yes, but is uses events and so if you're wanting to do this in order to keep
the event processing happening then you'll have a problem. (Can't send an
event if events are not being processed, can't process events until you get
the event to process events...) In other words, you have to have an event
loop to be able to use CallAfter, so you can't use CallAfter to call code
that would run an iteration of the event loop. Timers would have the same
problem.
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
As I've explained earlier, I process the source of the user program to
give the user program just those symbols that are relevant, not all of
wx etc. Then I comment out the import statement in the source and exec
this modified source.
The program does actually run okay if I simply exec the full
unmodified user source, because the second time an import is
performed, no statements in the module are executed. However, "from
wxvisual import *" would pick up wx etc., which isn't good.
Because I've done various cleanups, I've attached the latest files,
which include quite a bit of documentation. This includes some minor
adjustments to Robin's one-shot interact function to work on both
Windows and Mac Cocoa.
This has been very educational for me, and I hope not entirely
uninteresting for those reading this saga.