[SciPy-user] pyqwt or matplotlib
Zachary Pincus
zachary.pincus at yale.edu
Wed Aug 27 12:00:01 EDT 2008
Hi Fernando,
>> It's quite hackable, too -- I rigged up a very simple system to run
>> pyglet windows in a background thread, so I could control the
>> microscope from an interactive python interpreter, while still being
>> able to programmatically interact with pyglet window objects. (Happy
>> to share this code with anyone who desires. It's much cleaner, IMO,
>> than the gyrations that ipython has to go through to support
>> nonblocking QT, Tk, etc. windows. This is becase the pyglet mainloop
>> is in python, and is easy to subclass and otherwise mess with.)
>
> Does your code work as-is inside ipython? Would you want to
> contribute it to ipython? We'd love to ship an
> out-of-the-box-pyglet-shell, just let us know.
I'd be happy to provide this code. There are a few caveats to its use,
though -- perhaps you could help me come up with an easier interface.
Out of the box, pyglet ships with a main-loop that uses platform-
specific code to sleep until a GUI event happens, or after a certain
time elapses (to enforce a user-specified minimum framerate). Every
time the loop wakes up, it sends repaint (in pyglet: on_draw) events
to all of the windows.
Now, Pyglet works fine if all the calls to it are made from one thread
only. So what I do is run a subclass of the default event loop in a
background thread. This subclassed event loop checks a "message
queue" (basically, a list of callback functions) every time it wakes
up, and if the queue is non-empty, calls a few of the callbacks. This
way, code that calls pyglet functions can be added to the message
queue so that it will be called in the context of the pyglet thread.
(I've added a few bells and whistles, like proxy objects that "look"
like pyglet windows, but route method calls and getattr/setattr
through the event loop, so that interaction is seamless.)
Here comes the caveat, though: to keep latency down for tending the
message queue, the main loop needs to wake up frequently (at least 20
Hz). However, sending repaint events to every window that often is
pretty inefficient in most cases. So I elected to not send the repaint
events by default. Instead, a pyglet window needs to call it's on_draw
method after every event that requires a redraw (e.g. a clock tick, a
GUI interaction).
This sort of event loop is a more efficient than the default pyglet
loop in general, but unfortunately, the coding style is a bit
different. As such, my code doesn't work with any old pyglet window
class out of the box -- some very minor changes need to be made. I
could perhaps fix things so this isn't necessary -- figure out a way
for the main-loop to distinguish between being awoken to tend the
message queue, and being awoken on GUI events or for "minimum
framerate" reasons. But perhaps the issue is un-fixable...
Another caveat is that this approach is almost completely backwards to
that taken by the rest of the interactive windowing code in ipython.
(That code essentially feeds an embedded python interpreter, which
runs as a callback from the GIU mainloop, line-by-line input from
stdin.) As such, my code might be a bit out-of-place and harder to
maintain. I suspect that the original ipython approach will work fine
for pyglet too, and perhaps without the above caveat; however it might
be a bit more processor-intensive.
Zach
More information about the SciPy-User
mailing list