mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
blog post (#2465)
* blog posts * fix typo * word * version bump * changelog * update words
This commit is contained in:
268
docs/blog/images/frogmouth.svg
Normal file
268
docs/blog/images/frogmouth.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 128 KiB |
88
docs/blog/posts/release0-23-0.md
Normal file
88
docs/blog/posts/release0-23-0.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
draft: false
|
||||
date: 2023-05-03
|
||||
categories:
|
||||
- Release
|
||||
title: "Textual 0.23.0 improves message handling"
|
||||
authors:
|
||||
- willmcgugan
|
||||
---
|
||||
|
||||
# Textual 0.23.0 improves message handling
|
||||
|
||||
It's been a busy couple of weeks at Textualize.
|
||||
We've been building apps with [Textual](https://github.com/Textualize/textual), as part of our *dog-fooding* week.
|
||||
The first app, [Frogmouth](https://github.com/Textualize/frogmouth), was released at the weekend and already has 1K GitHub stars!
|
||||
Expect two more such apps this month.
|
||||
|
||||
<!-- more -->
|
||||
|
||||
<div>
|
||||
--8<-- "docs/blog/images/frogmouth.svg"
|
||||
</div>
|
||||
|
||||
!!! tip
|
||||
|
||||
Join our [mailing list](http://eepurl.com/hL0BF1) if you would like to be the first to hear about our apps.
|
||||
|
||||
We haven't stopped developing Textual in that time.
|
||||
Today we released version 0.23.0 which has a really interesting API update I'd like to introduce.
|
||||
|
||||
Textual *widgets* can send messages to each other.
|
||||
To respond to those messages, you implement a message handler with a naming convention.
|
||||
For instance, the [Button](/widget_gallery/#button) widget sends a `Pressed` event.
|
||||
To handle that event, you implement a method called `on_button_pressed`.
|
||||
|
||||
Simple enough, but handler methods are called to handle pressed events from *all* Buttons.
|
||||
To manage multiple buttons you typically had to write a large `if` statement to wire up each button to the code it should run.
|
||||
It didn't take many Buttons before the handler became hard to follow.
|
||||
|
||||
## On decorator
|
||||
|
||||
Version 0.23.0 introduces the [`@on`](/guide/events/#on-decorator) decorator which allows you to dispatch events based on the widget that initiated them.
|
||||
|
||||
This is probably best explained in code.
|
||||
The following two listings respond to buttons being pressed.
|
||||
The first uses a single message handler, the second uses the decorator approach:
|
||||
|
||||
=== "on_decorator01.py"
|
||||
|
||||
```python title="on_decorator01.py"
|
||||
--8<-- "docs/examples/events/on_decorator01.py"
|
||||
```
|
||||
|
||||
1. The message handler is called when any button is pressed
|
||||
|
||||
=== "on_decorator02.py"
|
||||
|
||||
```python title="on_decorator02.py"
|
||||
--8<-- "docs/examples/events/on_decorator02.py"
|
||||
```
|
||||
|
||||
1. Matches the button with an id of "bell" (note the `#` to match the id)
|
||||
2. Matches the button with class names "toggle" *and* "dark"
|
||||
3. Matches the button with an id of "quit"
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="docs/examples/events/on_decorator01.py"}
|
||||
```
|
||||
|
||||
The decorator dispatches events based on a CSS selector.
|
||||
This means that you could have a handler per button, or a handler for buttons with a shared class, or parent.
|
||||
|
||||
We think this is a very flexible mechanism that will help keep code readable and maintainable.
|
||||
|
||||
## Why didn't we do this earlier?
|
||||
|
||||
It's a reasonable question to ask: why didn't we implement this in an earlier version?
|
||||
We were certainly aware there was a deficiency in the API.
|
||||
|
||||
The truth is simply that we didn't have an elegant solution in mind until recently.
|
||||
The `@on` decorator is, I believe, an elegant and powerful mechanism for dispatching handlers.
|
||||
It might seem obvious in hindsight, but it took many iterations and brainstorming in the office to come up with it!
|
||||
|
||||
|
||||
## Join us
|
||||
|
||||
If you want to talk about this update or anything else Textual related, join us on our [Discord server](https://discord.gg/Enf6Z3qhVr).
|
||||
@@ -12,7 +12,7 @@ class OnDecoratorApp(App):
|
||||
yield Button("Toggle dark", classes="toggle dark")
|
||||
yield Button("Quit", id="quit")
|
||||
|
||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||
def on_button_pressed(self, event: Button.Pressed) -> None: # (1)!
|
||||
"""Handle all button pressed events."""
|
||||
if event.button.id == "bell":
|
||||
self.bell()
|
||||
|
||||
@@ -181,6 +181,8 @@ In the following example we have three buttons, each of which does something dif
|
||||
--8<-- "docs/examples/events/on_decorator01.py"
|
||||
```
|
||||
|
||||
1. The message handler is called when any button is pressed
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="docs/examples/events/on_decorator01.py"}
|
||||
|
||||
Reference in New Issue
Block a user