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, Footer, Header, StaticA widget to display elapsed time.
class TimeDisplay(Static): start_time = reactive(monotonic)
time = reactive(0.0)
total = reactive(0.0)Event handler called when widget is added to the app.
def on_mount(self) -> None: self.update_timer = self.set_interval(1 / 60, self.update_time, pause=True)Method to update time to current.
def update_time(self) -> None: self.time = self.total + (monotonic() - self.start_time)Called when the time attribute changes.
def watch_time(self, time: float) -> None: minutes, seconds = divmod(time, 60)
hours, minutes = divmod(minutes, 60)
self.update(f"{hours:02,.0f}:{minutes:02.0f}:{seconds:05.2f}")Method to start (or resume) time updating.
def start(self) -> None: self.start_time = monotonic()
self.update_timer.resume()Method to stop the time display updating.
def stop(self): self.update_timer.pause()
self.total += monotonic() - self.start_time
self.time = self.totalMethod to reset the time display to zero.
def reset(self): self.total = 0
self.time = 0class StopWatch(Static): def on_button_pressed(self, event: Button.Pressed) -> None:
button_id = event.button.id
time_display = self.query_one(TimeDisplay)
if button_id == "start":
time_display.start()
self.add_class("started")
elif button_id == "stop":
time_display.stop()
self.remove_class("started")
elif button_id == "reset":
time_display.reset() def compose(self) -> ComposeResult:
yield Button("Start", id="start", variant="success")
yield Button("Stop", id="stop", variant="error")
yield Button("Reset", id="reset")
yield TimeDisplay("00:00:00.00")class StopWatchApp(App):
CSS_PATH = "textual-stopwatch.css"
BINDINGS = [("d", "toggle_dark", "Toggle Dark Mode")] def compose(self) -> ComposeResult:
yield Header()
yield Footer()
yield Container(StopWatch(), StopWatch(), StopWatch()) def action_toggle_dark(self) -> None:
self.dark = not self.dark
if __name__ == "__main__":
app = StopWatchApp()
app.run()