diff --git a/docs/imgs/qt_app_embed.gif b/docs/imgs/qt_app_embed.gif new file mode 100644 index 0000000..012d9ec Binary files /dev/null and b/docs/imgs/qt_app_embed.gif differ diff --git a/docs/qt_embed.md b/docs/qt_embed.md new file mode 100644 index 0000000..e78a8fe --- /dev/null +++ b/docs/qt_embed.md @@ -0,0 +1,46 @@ +# Embeding generated window to a PyQt app + +You can integrate oneFace generated Qt windows by embedding them in a Qt application: + +```Python +# demo_qt_embed.py +import sys +from oneface.qt import gui +from oneface import one +from qtpy import QtWidgets + +app = QtWidgets.QApplication([]) + + +@gui +@one +def add(a: int, b: int): + res = a + b + print(res) + +@gui +@one +def mul(a: int, b: int): + res = a * b + print(res) + + +main_window = QtWidgets.QWidget() +main_window.setWindowTitle("MyApp") +main_window.setFixedSize(200, 100) +layout = QtWidgets.QVBoxLayout(main_window) +layout.addWidget(QtWidgets.QLabel("Apps:")) +btn_open_add = QtWidgets.QPushButton("add") +btn_open_mul = QtWidgets.QPushButton("mul") +btn_open_add.clicked.connect(add.window.show) +btn_open_mul.clicked.connect(mul.window.show) +layout.addWidget(btn_open_add) +layout.addWidget(btn_open_mul) +main_window.show() + +sys.exit(app.exec()) +``` + +Run it: + +![qt_embed](imgs/qt_app_embed.gif) diff --git a/mkdocs.yml b/mkdocs.yml index 75f1d6d..f699e06 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -14,6 +14,7 @@ nav: - Dash configs: dash_confs.md - Wrap command line: wrap_cli.md - Embedding: + - qt_embed.md - dash_embed.md markdown_extensions: diff --git a/oneface/__init__.py b/oneface/__init__.py index 8e07126..83b05c0 100644 --- a/oneface/__init__.py +++ b/oneface/__init__.py @@ -1,5 +1,5 @@ from .core import one, Arg -__version__ = '0.1.7' +__version__ = '0.1.8' __all__ = [one, Arg] diff --git a/oneface/qt.py b/oneface/qt.py index a99746a..3ba0c3e 100644 --- a/oneface/qt.py +++ b/oneface/qt.py @@ -1,3 +1,4 @@ +import typing as T import functools from qtpy import QtWidgets from qtpy import QtCore @@ -26,28 +27,38 @@ def gui(func=None, **kwargs): return GUI(func, **kwargs) +def get_app(): + app = QtWidgets.QApplication.instance() + if app is None: + app = QtWidgets.QApplication([]) + return app + + class GUI(): type_to_widget_constructor = {} - def __init__(self, func, name=None, size=None, - run_once=True): + def __init__( + self, + func: T.Callable, name: T.Optional[str] = None, + size: T.Optional[T.List] = None, + run_once=True): self.func = func self.run_once = run_once self.result = None - self.app = QtWidgets.QApplication([]) - self.main_window = QtWidgets.QMainWindow() + self.app = get_app() if name is not None: - name = name + self.name = name elif hasattr(func, "name"): - name = func.name + self.name = func.name else: - name = func.__name__ - self.main_window.setWindowTitle(name) + self.name = func.__name__ + self.window = QtWidgets.QWidget() + self.window._oneface_wrap = self + self.window.setWindowTitle(self.name) if size: - self.main_window.setFixedSize(*size) + self.window.setFixedSize(*size) self.arg_widgets = {} - self.window = QtWidgets.QWidget() self.layout = QtWidgets.QVBoxLayout() self.compose_ui() self.connect_events() @@ -58,7 +69,6 @@ def compose_ui(self): self.layout.addWidget(self.run_btn) self.terminal = QtWidgets.QTextEdit() self.window.setLayout(self.layout) - self.main_window.setCentralWidget(self.window) def compose_arg_widgets(self, layout: QtWidgets.QVBoxLayout): arg_objs = get_func_argobjs(self.func) @@ -86,9 +96,9 @@ def get_args(self): def run_func(self): kwargs = self.get_args() if self.run_once: - self.main_window.hide() + self.window.hide() self.result = self.func(**kwargs) - self.main_window.close() + self.window.close() else: thread = self.thread = QtCore.QThread() worker = self.worker = Worker(self.func, kwargs) @@ -106,7 +116,7 @@ def finish(): thread.finished.connect(finish) def __call__(self): - self.main_window.show() + self.window.show() self.app.exec() return self.result