What is the best way to use Tornado coroutines with a GUI such as PySide or PyQt? Because the GUI has its own event loop, it's not so easy to run the Tornado loop. It's also not as easy as just running Tornado in a background thread because all GUI code has to be run on the main thread. If not, it will glitch or crash.
I have gotten things working, but it's not completely ideal.
I basically subclassed SelectIOLoop so that I can split its start method into two methods - start and update:
class EventLoop(SelectIOLoop):
def start(self):
# The outside of the while loop in SelectIOLoop.start
try:
while True:
if self.update():
break
# The outside of the while loop in SelectIOLoop.start
def update(self):
# The inside of the while loop in SelectIOLoop.startclass
Then I run update at a frequent interval using a QTimer class:
class QtEventLoop(QObject):
_instance = None
@staticmethod
def instance():
if not QtEventLoop._instance:
QtEventLoop._instance = QtEventLoop()
return QtEventLoop._instance
def __init__(self):
super(QtEventLoop, self).__init__()
self._eventLoop = EventLoop()
self._eventLoop.install()
self._eventLoop._setup_logging()
self._updateTimer = QTimer()
# Default is 60 updates / second
defaultInterval = int((1.0 / 60.0) * 1000.0) + 1
self._updateTimer.setInterval(defaultInterval)
self._updateTimer.timeout.connect(self._onTimeout)
def start(self):
if not self._updateTimer.isActive():
self._updateTimer.start()
@Slot()
def _onTimeout(self):
self._eventLoop.update()
Then in my main window, I start the loop like this:
qtEventLoop = QtEventLoop.instance()
qtEventLoop.start()
The reason I say this is not ideal is because it doesn't work like a plugin. Instead, I have to copy the guts of the core Tornado source and copy them into my EventLoop class. So I'm hoping there is a better way.
Thanks.