I’ve been experimenting with both wxPython and Twisted. wxPython is a GUI toolkit and Twisted is a network programming framework. They’re both event driven and I wanted to use Twisted for the I/O and wxPython for the GUI. Twisted ships with a mechanism for doing this, but at least on Windows it results in polling — which means the CPU spikes. On my desktop machine, I didn’t even notice this happening. On the laptop, though, the fan spun up to jet turbine mode. I dug into the implementation a bit and saw how the wxreactor that came with Twisted was essentially setting things up so the wxPython main loop functionality code was called every millisecond and left the Twisted event loop in control. class WxReactor(default.SelectReactor): “”“wxPython reactor. wx drives the event loop, and calls Twisted every millisecond, and Twisted then iterates until a ms has passed. “”” […]
While poking around the examples previously, I noticed mainloop.py was an example of overriding the C main loop with one written in python, expressly for the purpose for including some user code in the main event loop.
So I combined the two to create an overriden MainLoop that did not poll but did call the Twisted methods in an appropriate way (or at least in a way matching my understanding and that appears to work on Windows)..
class MyApp(wx.App): def __init__(self, reactor): self.reactor = reactor wx.App.__init__(self, 0) def MainLoop(self): reactor = self.reactor self.keepGoing = True if "wxMac" in wx.PlatformInfo: # TODO: Does wxMac implement wxEventLoop yet??? wx.App.MainLoop() else: reactor.startRunning(1) # Create an event loop and make it active. If you are # only going to temporarily have a nested event loop then # you should get a reference to the old one and set it as # the active event loop when you are done with this one... evtloop = wx.EventLoop() old = wx.EventLoop.GetActive() wx.EventLoop.SetActive(evtloop) # This outer loop determines when to exit the application, # for this example we let the main frame reset this flag # when it closes. while self.keepGoing: # At this point in the outer loop you could do # whatever you implemented your own MainLoop for. It # should be quick and non-blocking, otherwise your GUI # will freeze. reactor.iterate(0.10) # This inner loop will process any GUI events # until there are no more waiting. while evtloop.Pending(): evtloop.Dispatch() # Send idle events to idle handlers. You may want to # throttle this back a bit somehow so there is not too # much CPU time spent in the idle handlers. For this # example, I'll just snooze a little... # krf: this snoozing is now being handled as the timeout of the # twisted .iterate() call self.ProcessIdle() wx.EventLoop.SetActive(old) [...] app = MyApp(reactor) app.MainLoop()
Note that the reactor here is the standard Twisted SelectReactor (the default).
This code is pretty freshly apparently-working, but it’s a starting point for being able to use both Twisted and wxPython in a way that isn’t so loud.