I've been trying to run the wxWindows event loop in a separate thread. What I want to be able to do is start an interactive python session, open up a window from it without loosing the prompt and be able to send drawing commands to the window. The following will allow me to open a window using a new thread so I don't lose my prompt:
from threading import *
class MyThread(Thread):
def __init__(self):
Thread.__init__(self)
def run(self):
app = MyApp(0)
app.cube_canvas.newCube()
app.MainLoop()
t = MyThread()
t.start()
That's great, but I don't have any way to call methods on my app so I can ask it to do things. MyApp actually has a wxGLcanvas in it (called cube_canvas) and I want to be able to give it methods so I can add 3D objects to the canvas (see the newCube() method call above). I can't do that because I have to reference to the app. (not to mention thread synchronization issues). So the obvious thing to do was this (see code below): make the app global and just call its MainLoop() method in the thread. This causes a segmentation fault on my Linux system.
···
#-----------------------------------------------------------
app = MyApp(0)
from threading import *
class MyThread(Thread):
def __init__(self):
Thread.__init__(self)
self.app = 0
def run(self):
global app
app.cube_canvas.newCube()
app.MainLoop()
t = MyThread()
t.start()
Then I moved the line contructing a MyApp back into the thread's run method and tried running it interactively. To my surprise, the 'app' variable is accessible from the prompt, however, if I try to do the same thing in a script, it tells me 'app' is not
def run(self):
global app
app = MyApp(0)
app.cube_canvas.newCube()
app.MainLoop()
At a shell prompt:
$ python -i cube3.py
>>> app
<__main__.MyApp instance; proxy of C++ wxPyApp instance at _82fa058_wxPyApp_p>
>>> app.cube_canvas.rotx = 0
>>> app.cube_canvas.AddPendingEvent(wxPaintEvent())
>>>
Sure enough this works. rotx is the rotation of a cube around the X axis. It rotates and repaints as expected. Cool!
However, trying to put the same code in a script fails:
#!/usr/bin/python
from threading import *
.
. (definition of MyApp deleted)
.
class MyThread(Thread):
def __init__(self):
Thread.__init__(self)
def run(self):
global app
app = MyApp(0)
app.cube_canvas.newCube()
app.MainLoop()
t = MyThread()
t.start()
cube = app.cube_canvas
cube.rotx = 10
cube.AddPendingEvent(wxPaintEvent())
$ cube3.py
Traceback (most recent call last):
File "<stdin>", line 177, in ?
NameError: global name 'app' is not defined
I tried various other things like giving the Thread a method that returns a reference to MyApp, but it doesn't work except in an interactive session. It seems like it shouldn't work at all to me, but that the first code example I gave above should work. Doesn't anybody understand the thread model better and can explain the behavior documented above?
Thanks, oh wise ones,
Barry Tolnas
tolnasb@evergreen.edu