Add initial Qt-trio integration
Use the new "guest mode" available on trio master branch. Add entrypoint for `pyqtgraph` based charting based on the `Quantdom` project.its_happening
parent
0fa515d0e3
commit
b7f306b715
|
@ -0,0 +1,117 @@
|
|||
"""
|
||||
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 datetime import datetime
|
||||
|
||||
import PyQt5 # noqa
|
||||
from pyqtgraph import QtGui
|
||||
from PyQt5 import QtCore
|
||||
from PyQt5.QtCore import pyqtRemoveInputHook
|
||||
import qdarkstyle
|
||||
import trio
|
||||
from outcome import Error
|
||||
|
||||
from _chart import QuotesTabWidget
|
||||
from quantdom.base import Symbol
|
||||
from quantdom.loaders import get_quotes
|
||||
|
||||
|
||||
# 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,
|
||||
) -> 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:
|
||||
|
||||
# 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,
|
||||
}
|
||||
|
||||
# guest mode
|
||||
trio.lowlevel.start_guest_run(
|
||||
func,
|
||||
widgets,
|
||||
run_sync_soon_threadsafe=run_sync_soon_threadsafe,
|
||||
done_callback=done_callback,
|
||||
)
|
||||
|
||||
window.main_widget = main_widget
|
||||
window.setCentralWidget(instance)
|
||||
window.show()
|
||||
app.exec_()
|
||||
|
||||
|
||||
async def plot_aapl(widgets):
|
||||
qtw = widgets['main']
|
||||
s = Symbol(ticker='AAPL', mode=Symbol.SHARES)
|
||||
get_quotes(
|
||||
symbol=s.ticker,
|
||||
date_from=datetime(1900, 1, 1),
|
||||
date_to=datetime(2030, 12, 31),
|
||||
)
|
||||
# spawn chart
|
||||
qtw.update_chart(s)
|
||||
await trio.sleep_forever()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_qtrio(plot_aapl, (), QuotesTabWidget)
|
Loading…
Reference in New Issue