Sample code
In the introduction we just imported an existing example application, but let's look at its internal and explain it.
from trame.app import get_server
from trame.ui.vuetify3 import SinglePageLayout
from trame.widgets import vuetify3 as v3, vtk as vtk_widgets
class Cone:
def __init__(self, server_or_name=None):
self.server = get_server(server_or_name)
self.ui = self._generate_ui()
@property
def ctrl(self):
return self.server.controller
@property
def state(self):
return self.server.state
@property
def resolution(self):
return self.state.resolution
@resolution.setter
def resolution(self, v):
with self.state:
self.state.resolution = v
def reset_resolution(self):
self.resolution = 6
def _generate_ui(self):
with SinglePageLayout(self.server) as layout:
layout.title.set_text("Trame demo")
with layout.toolbar as toolbar:
toolbar.dense = True
v3.VSpacer()
v3.VSlider(
v_model=("resolution", 6),
min=3,
max=60,
step=1,
hide_details=True,
style="max-width: 300px;",
)
with v3.VBtn(icon=True, click=self.reset_resolution):
v3.VIcon("mdi-lock-reset")
with v3.VBtn(icon=True, click=self.ctrl.view_reset_camera):
v3.VIcon("mdi-crop-free")
with layout.content:
with v3.VContainer(fluid=True, classes="pa-0 fill-height"):
with vtk_widgets.VtkView() as view:
self.ctrl.view_reset_camera = view.reset_camera
with vtk_widgets.VtkGeometryRepresentation():
vtk_widgets.VtkAlgorithm(
vtk_class="vtkConeSource", state=("{ resolution }",)
)
return layout
def main(**kwargs):
cone = Cone()
cone.server.start(**kwargs)
if __name__ == "__main__":
main()
from trame.app import get_server
from trame.ui.vuetify3 import SinglePageLayout
from trame.widgets import vuetify3 as v3, vtk as vtk_widgets
class Cone:
def __init__(self, server_or_name=None):
self.server = get_server(server_or_name)
self.ui = self._generate_ui()
@property
def ctrl(self):
return self.server.controller
@property
def state(self):
return self.server.state
@property
def resolution(self):
return self.state.resolution
@resolution.setter
def resolution(self, v):
with self.state:
self.state.resolution = v
def reset_resolution(self):
self.resolution = 6
def _generate_ui(self):
with SinglePageLayout(self.server) as layout:
layout.title.set_text("Trame demo")
with layout.toolbar as toolbar:
toolbar.dense = True
v3.VSpacer()
v3.VSlider(
v_model=("resolution", 6),
min=3,
max=60,
step=1,
hide_details=True,
style="max-width: 300px;",
)
with v3.VBtn(icon=True, click=self.reset_resolution):
v3.VIcon("mdi-lock-reset")
with v3.VBtn(icon=True, click=self.ctrl.view_reset_camera):
v3.VIcon("mdi-crop-free")
with layout.content:
with v3.VContainer(fluid=True, classes="pa-0 fill-height"):
with vtk_widgets.VtkView() as view:
self.ctrl.view_reset_camera = view.reset_camera
with vtk_widgets.VtkGeometryRepresentation():
vtk_widgets.VtkAlgorithm(
vtk_class="vtkConeSource", state=("{ resolution }",)
)
return layout
def main(**kwargs):
cone = Cone()
cone.server.start(**kwargs)
if __name__ == "__main__":
main()
Key take away
When a trame application is laid out like above, you can just run the following inside a cell to access it.
from module import App
app = App()
await app.ui.ready
app.ui
from module import App
app = App()
await app.ui.ready
app.ui
And in case you want to have a second instance independent of the first one, you can do
app2 = App('v2')
await app2.ui.ready
app2.ui
app2 = App('v2')
await app2.ui.ready
app2.ui
Changing application state
In trame you simply can change a state variable to see the change reflected in the UI. But when doing that in another cell, it does not seems to work. The reason is the same as when you update a state variable from an asynchronous task, you need to be explicit when the state synchronization needs to happen. A simpler way to do that is to use the state as context manager like below.
with app.state:
app.state.resolution = 24
with app.state:
app.state.resolution = 24
That is why in our setter we added such logic which allow us to simply call from anywhere
app.resolution = 32
app.resolution = 32
Create several small UI
from trame.app import get_server
from trame.widgets import html
from trame.ui.html import DivLayout
server = get_server()
state = server.state
def reset_slider():
state.slider_a = 2
@state.change("slider_a")
def udpate_result(slider_a, **_):
state.result = slider_a / 2
with DivLayout(server, 'a', height=30) as ui_a:
html.Input(
type="range",
min=-1,
max=50,
step=0.1,
v_model_number=("slider_a", 2),
style="width: 100%;",
)
await ui_a.ready
ui_a
from trame.app import get_server
from trame.widgets import html
from trame.ui.html import DivLayout
server = get_server()
state = server.state
def reset_slider():
state.slider_a = 2
@state.change("slider_a")
def udpate_result(slider_a, **_):
state.result = slider_a / 2
with DivLayout(server, 'a', height=30) as ui_a:
html.Input(
type="range",
min=-1,
max=50,
step=0.1,
v_model_number=("slider_a", 2),
style="width: 100%;",
)
await ui_a.ready
ui_a
Then you can create more ui on the same server
with DivLayout(server, 'b', height=30) as ui_b:
html.Button(
"Reset Value",
click=reset_slider,
)
html.Span("{{ slider_a }} / 2 = {{ result }}", style="margin-left: 2rem")
ui_b
with DivLayout(server, 'b', height=30) as ui_b:
html.Button(
"Reset Value",
click=reset_slider,
)
html.Span("{{ slider_a }} / 2 = {{ result }}", style="margin-left: 2rem")
ui_b