-
Notifications
You must be signed in to change notification settings - Fork 596
Description
Please Describe The Problem To Be Solved
When a control or the page needs to be updated, it must be done manually by calling the "update()" method, which could lead to calling the update method that does not correspond to the control that needs to be updated or skip calling this method after any data update.
import flet as ft
def main(page: ft.Page):
def add_clicked(e):
page.add(ft.Checkbox(label=new_task.value))
new_task.value = ""
page.update()
new_task = ft.TextField(hint_text="Whats needs to be done?")
page.add(new_task, ft.FloatingActionButton(icon=ft.icons.ADD, on_click=add_clicked))
ft.app(target=main)(Optional): Suggest A Solution
My suggestion is to replace the need of calling the "update" method and bring reactivity (for example, with reactive attributes), so the data updates automatically after any event. Which is where the trends of these UI libraries/frameworks tend to go. Other UI framework such as Flutter and Jetpack Compose already do, including a TUI library for Python named "Textual".
Python with Textual (Example and simple explanation of reactive attributes):
from time import monotonic
from textual.app import App, ComposeResult
from textual.containers import Container
from textual.reactive import reactive
from textual.widgets import Button, Header, Footer, Static
class TimeDisplay(Static):
"""A widget to display elapsed time."""
start_time = reactive(monotonic)
time = reactive(0.0)
def on_mount(self) -> None:
"""Event handler called when widget is added to the app."""
self.set_interval(1 / 60, self.update_time)
def update_time(self) -> None:
"""Method to update the time to the current time."""
self.time = monotonic() - self.start_time
def watch_time(self, time: float) -> None:
"""Called when the time attribute changes."""
minutes, seconds = divmod(time, 60)
hours, minutes = divmod(minutes, 60)
self.update(f"{hours:02,.0f}:{minutes:02.0f}:{seconds:05.2f}")
class Stopwatch(Static):
"""A stopwatch widget."""
def on_button_pressed(self, event: Button.Pressed) -> None:
"""Event handler called when a button is pressed."""
if event.button.id == "start":
self.add_class("started")
elif event.button.id == "stop":
self.remove_class("started")
def compose(self) -> ComposeResult:
"""Create child widgets of a stopwatch."""
yield Button("Start", id="start", variant="success")
yield Button("Stop", id="stop", variant="error")
yield Button("Reset", id="reset")
yield TimeDisplay()
class StopwatchApp(App):
"""A Textual app to manage stopwatches."""
CSS_PATH = "stopwatch04.css"
BINDINGS = [("d", "toggle_dark", "Toggle dark mode")]
def compose(self) -> ComposeResult:
"""Create child widgets for the app."""
yield Header()
yield Footer()
yield Container(Stopwatch(), Stopwatch(), Stopwatch())
def action_toggle_dark(self) -> None:
"""An action to toggle dark mode."""
self.dark = not self.dark
if __name__ == "__main__":
app = StopwatchApp()
app.run()Jetpack Compose:
@Composable
fun App() {
var text by remember { mutableStateOf("Hello, World!") }
MaterialTheme {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(onClick = {
text = "Hello, Desktop!"
}) {
Text(text)
}
}
}
}