Core concepts¶
A ComposeUI app is made of views, signals, an optional model, and studies, which a backend shows:
Concept |
Role |
|---|---|
View ( |
A typed |
Main view |
The root view, a subclass of |
Signal ( |
An event of a view or a model, such as |
Model ( |
The app’s data beside the views. It is optional. |
Study |
The file that the File menu saves and opens: the state of the views, and the data of the model. The |
Backend |
The toolkit that shows the views: Qt, Textual, or the web. |
Jobs ( |
|
Task |
|
A backend binds each view to a widget with a renderer. The renderer keeps the two in sync in both directions, so the app’s code never calls it. The technical guide explains renderers.
How ComposeUI maps to MVVM¶
ComposeUI follows the Model-View-ViewModel pattern, but its names are not the usual ones:
MVVM |
ComposeUI |
|---|---|
Model |
The model, a |
ViewModel |
The views of |
View |
The widget of the backend: a Qt widget, a Textual widget, or an HTML element. Your code does not touch it. |
Binding |
The renderer. It pushes each change of a view to its widget, and copies the widget’s state back. |
Each view has one widget, and views nest as their widgets do. So the views are the widget tree of the UI, without the toolkit. One app runs on each backend without a change.
Views are reactive¶
When code sets an attribute of a view (view.text = "..."), the view pushes the change to
its renderer. You do not call update() or refresh() for normal state changes.
Signals inject arguments¶
Signal.connect and Application.connect read the callback’s parameter names. When a
callback asks for view, main_view, or model, it gets them:
# `main_view` is injected automatically because it's a requested parameter.
def _on_name_changed(self, text: str, *, main_view: MainView) -> None:
main_view.status_bar.show_message(f"Hello, {text}!" if text else "")
A callback can take fewer of the signal’s arguments than the signal emits. It then gets the
first ones, or none. connect(callback, now=True) also calls the callback once, right away.