117 lines
2.8 KiB
Python
117 lines
2.8 KiB
Python
"""
|
|
Trio - Qt integration
|
|
|
|
Run ``trio`` in guest mode on top of the Qt event loop.
|
|
All global Qt runtime settings are mostly defined here.
|
|
"""
|
|
import traceback
|
|
from functools import partial
|
|
|
|
import PyQt5 # noqa
|
|
from pyqtgraph import QtGui
|
|
from PyQt5 import QtCore
|
|
from PyQt5.QtCore import pyqtRemoveInputHook
|
|
import qdarkstyle
|
|
import trio
|
|
import tractor
|
|
from outcome import Error
|
|
|
|
|
|
# Taken from Quantdom
|
|
class MainWindow(QtGui.QMainWindow):
|
|
|
|
size = (800, 500)
|
|
title = 'piker: chart'
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
# self.setMinimumSize(*self.size)
|
|
self.setWindowTitle(self.title)
|
|
|
|
|
|
def run_qtrio(
|
|
func,
|
|
args,
|
|
main_widget,
|
|
loglevel = None,
|
|
) -> None:
|
|
# avoids annoying message when entering debugger from qt loop
|
|
pyqtRemoveInputHook()
|
|
|
|
app = QtGui.QApplication.instance()
|
|
if app is None:
|
|
app = PyQt5.QtWidgets.QApplication([])
|
|
|
|
# This code is from Nathaniel, and I quote:
|
|
# "This is substantially faster than using a signal... for some
|
|
# reason Qt signal dispatch is really slow (and relies on events
|
|
# underneath anyway, so this is strictly less work)."
|
|
REENTER_EVENT = QtCore.QEvent.Type(QtCore.QEvent.registerEventType())
|
|
|
|
class ReenterEvent(QtCore.QEvent):
|
|
pass
|
|
|
|
class Reenter(QtCore.QObject):
|
|
def event(self, event):
|
|
event.fn()
|
|
return False
|
|
|
|
reenter = Reenter()
|
|
|
|
def run_sync_soon_threadsafe(fn):
|
|
event = ReenterEvent(REENTER_EVENT)
|
|
event.fn = fn
|
|
app.postEvent(reenter, event)
|
|
|
|
def done_callback(outcome):
|
|
print(f"Outcome: {outcome}")
|
|
if isinstance(outcome, Error):
|
|
exc = outcome.error
|
|
traceback.print_exception(type(exc), exc, exc.__traceback__)
|
|
app.quit()
|
|
|
|
# load dark theme
|
|
app.setStyleSheet(qdarkstyle.load_stylesheet(qt_api='pyqt5'))
|
|
|
|
# make window and exec
|
|
window = MainWindow()
|
|
instance = main_widget()
|
|
|
|
widgets = {
|
|
'window': window,
|
|
'main': instance,
|
|
}
|
|
|
|
# force mp since we may spawn an ib asyncio based backend
|
|
tractor._spawn.try_set_start_method('forkserver')
|
|
# setup tractor entry point args
|
|
args = (
|
|
# async_fn
|
|
func,
|
|
# args
|
|
(widgets,),
|
|
# kwargs
|
|
{'loglevel': 'info'},
|
|
# arbiter_addr
|
|
(
|
|
tractor._default_arbiter_host,
|
|
tractor._default_arbiter_port,
|
|
),
|
|
# name
|
|
'qtrio',
|
|
)
|
|
|
|
# guest mode
|
|
trio.lowlevel.start_guest_run(
|
|
tractor._main,
|
|
*args,
|
|
run_sync_soon_threadsafe=run_sync_soon_threadsafe,
|
|
done_callback=done_callback,
|
|
)
|
|
|
|
window.main_widget = main_widget
|
|
window.setCentralWidget(instance)
|
|
# actually render to screen
|
|
window.show()
|
|
app.exec_()
|