This commit is contained in:
Will McGugan
2022-09-17 10:31:21 +01:00
parent 76404b70f5
commit 1013f84ffc
7 changed files with 122 additions and 30 deletions

View File

@@ -51,14 +51,40 @@ Let's explore how Textual decides what method to call for a given event.
### Default behaviors
You may be familiar with using Python's [super](https://docs.python.org/3/library/functions.html#super) function to call a function defined in a base class. You will not have to do this for Textual event handlers as Textual will automatically call any handler methods defined in the base class *after* the current handler has run. This allows textual to run any default behavior for the given event.
You may be familiar with Python's [super](https://docs.python.org/3/library/functions.html#super) function to call a function defined in a base class. You will not have to do this for Textual event handlers as Textual will automatically call any handler methods defined in the base class.
For instance if a widget defines an `on_key` handler it will run when the user hits a key. Textual will also run `Widget.on_key`, which allows Textual to respond to any key bindings. This is generally desirable, but you can prevent Textual from running the base class handler by calling [prevent_default()][textual.message.Message.prevent_default] on the event object.
For instance if you define a custom widget, Textual will call its `on_key` handler when you hit a key. Textual will also run any `on_key` methods found in the widget's base classes, including `Widget.on_key` where key bindings are processed. Without this behavior, you would have to remember to call `super().on_key(event)` or key bindings would break.
If you don't want this behavior you can call [prevent_default()][textual.message.Message.prevent_default] on the event object. This tells Textual not to call any handlers on base classes.
For the case of key events, you may want to prevent the default behavior for keys that you handle by calling `event.prevent_default()`, but allow the base class to handle all other keys.
### Bubbling
Messages have a `bubble` attribute. If this is set to `True` then events will be sent to their parent widget. Input events typically bubble so that a widget will have the opportunity to process events after its children.
The following diagram shows an (abbreviated) DOM for a UI with a container and two buttons. With the "No" button [focused](#) it will receive the key event first.
<div class="excalidraw">
--8<-- "docs/images/events/bubble1.excalidraw.svg"
</div>
After Textual calls `Button.on_key` it _bubbles_ the event to its parent and call `Container.on_key` (if it exists).
<div class="excalidraw">
--8<-- "docs/images/events/bubble2.excalidraw.svg"
</div>
Then it will bubble to the container's parent (the App class).
<div class="excalidraw">
--8<-- "docs/images/events/bubble3.excalidraw.svg"
</div>
The App class is always the root of the DOM, so there is no where for the event to bubble to.
#### Stopping bubbling
Event handlers may stop this bubble behavior by calling the [stop()][textual.message.Message.stop] method on the event or message. You might want to do this if a widget has responded to the event in an authoritative way. For instance if a text input widget as responded to a key event you probably do not want it to also invoke a key binding.