mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
diagrams
This commit is contained in:
@@ -51,14 +51,40 @@ Let's explore how Textual decides what method to call for a given event.
|
|||||||
|
|
||||||
### Default behaviors
|
### 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
|
### 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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
16
docs/images/events/bubble1.excalidraw.svg
Normal file
16
docs/images/events/bubble1.excalidraw.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 24 KiB |
16
docs/images/events/bubble2.excalidraw.svg
Normal file
16
docs/images/events/bubble2.excalidraw.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 34 KiB |
16
docs/images/events/bubble3.excalidraw.svg
Normal file
16
docs/images/events/bubble3.excalidraw.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 42 KiB |
@@ -71,10 +71,11 @@ class Message:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def handler_name(self) -> str:
|
def handler_name(self) -> str:
|
||||||
|
"""The name of the handler associated with this message."""
|
||||||
# Property to make it read only
|
# Property to make it read only
|
||||||
return self._handler_name
|
return self._handler_name
|
||||||
|
|
||||||
def set_forwarded(self) -> None:
|
def _set_forwarded(self) -> None:
|
||||||
"""Mark this event as being forwarded."""
|
"""Mark this event as being forwarded."""
|
||||||
self._forwarded = True
|
self._forwarded = True
|
||||||
|
|
||||||
@@ -90,7 +91,8 @@ class Message:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def prevent_default(self, prevent: bool = True) -> Message:
|
def prevent_default(self, prevent: bool = True) -> Message:
|
||||||
"""Suppress the default action.
|
"""Suppress the default action(s). This will prevent handlers in any base classes
|
||||||
|
from being called.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
prevent (bool, optional): True if the default action should be suppressed,
|
prevent (bool, optional): True if the default action should be suppressed,
|
||||||
|
|||||||
@@ -71,6 +71,22 @@ class ScrollView(Widget):
|
|||||||
def watch_virtual_size(self, virtual_size: Size) -> None:
|
def watch_virtual_size(self, virtual_size: Size) -> None:
|
||||||
self._scroll_update(virtual_size)
|
self._scroll_update(virtual_size)
|
||||||
|
|
||||||
|
def watch_show_horizontal_scrollbar(self, value: bool) -> None:
|
||||||
|
"""Watch function for show_horizontal_scrollbar attribute.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value (bool): Show horizontal scrollbar flag.
|
||||||
|
"""
|
||||||
|
self.refresh(layout=True)
|
||||||
|
|
||||||
|
def watch_show_vertical_scrollbar(self, value: bool) -> None:
|
||||||
|
"""Watch function for show_vertical_scrollbar attribute.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value (bool): Show vertical scrollbar flag.
|
||||||
|
"""
|
||||||
|
self.refresh(layout=True)
|
||||||
|
|
||||||
def _size_updated(
|
def _size_updated(
|
||||||
self, size: Size, virtual_size: Size, container_size: Size
|
self, size: Size, virtual_size: Size, container_size: Size
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|||||||
@@ -234,10 +234,10 @@ class Widget(DOMNode):
|
|||||||
Args:
|
Args:
|
||||||
value (bool): Show horizontal scrollbar flag.
|
value (bool): Show horizontal scrollbar flag.
|
||||||
"""
|
"""
|
||||||
self.refresh(layout=True)
|
# self.refresh(layout=True)
|
||||||
# if not value:
|
if not value:
|
||||||
# # reset the scroll position if the scrollbar is hidden.
|
# reset the scroll position if the scrollbar is hidden.
|
||||||
# self.scroll_to(0, 0, animate=False)
|
self.scroll_to(0, 0, animate=False)
|
||||||
|
|
||||||
def watch_show_vertical_scrollbar(self, value: bool) -> None:
|
def watch_show_vertical_scrollbar(self, value: bool) -> None:
|
||||||
"""Watch function for show_vertical_scrollbar attribute.
|
"""Watch function for show_vertical_scrollbar attribute.
|
||||||
@@ -245,10 +245,10 @@ class Widget(DOMNode):
|
|||||||
Args:
|
Args:
|
||||||
value (bool): Show vertical scrollbar flag.
|
value (bool): Show vertical scrollbar flag.
|
||||||
"""
|
"""
|
||||||
self.refresh(layout=True)
|
# self.refresh(layout=True)
|
||||||
# if not value:
|
if not value:
|
||||||
# # reset the scroll position if the scrollbar is hidden.
|
# reset the scroll position if the scrollbar is hidden.
|
||||||
# self.scroll_to(0, 0, animate=False)
|
self.scroll_to(0, 0, animate=False)
|
||||||
|
|
||||||
def mount(self, *anon_widgets: Widget, **widgets: Widget) -> None:
|
def mount(self, *anon_widgets: Widget, **widgets: Widget) -> None:
|
||||||
"""Mount child widgets (making this widget a container).
|
"""Mount child widgets (making this widget a container).
|
||||||
@@ -507,7 +507,7 @@ class Widget(DOMNode):
|
|||||||
elif overflow_y == "auto":
|
elif overflow_y == "auto":
|
||||||
show_vertical = self.virtual_size.height > height
|
show_vertical = self.virtual_size.height > height
|
||||||
|
|
||||||
if show_vertical and not show_horizontal:
|
if show_vertical and not show_horizontal and overflow_x == "auto":
|
||||||
show_horizontal = (
|
show_horizontal = (
|
||||||
self.virtual_size.width + styles.scrollbar_size_vertical > width
|
self.virtual_size.width + styles.scrollbar_size_vertical > width
|
||||||
)
|
)
|
||||||
@@ -853,7 +853,7 @@ class Widget(DOMNode):
|
|||||||
y (int | None, optional): Y coordinate (row) to scroll to, or None for no change. Defaults to None.
|
y (int | None, optional): Y coordinate (row) to scroll to, or None for no change. Defaults to None.
|
||||||
animate (bool, optional): Animate to new scroll position. Defaults to True.
|
animate (bool, optional): Animate to new scroll position. Defaults to True.
|
||||||
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
||||||
duration (float | None, optional): Duration of animation, if animate is True and speed is False.
|
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if the scroll position changed, otherwise False.
|
bool: True if the scroll position changed, otherwise False.
|
||||||
@@ -895,8 +895,8 @@ class Widget(DOMNode):
|
|||||||
scroll_y = self.scroll_y
|
scroll_y = self.scroll_y
|
||||||
self.scroll_target_y = self.scroll_y = y
|
self.scroll_target_y = self.scroll_y = y
|
||||||
scrolled_y = scroll_y != self.scroll_y
|
scrolled_y = scroll_y != self.scroll_y
|
||||||
if scrolled_x or scrolled_y:
|
# if scrolled_x or scrolled_y:
|
||||||
self.refresh(repaint=False, layout=True)
|
# self.refresh(repaint=False, layout=False)
|
||||||
|
|
||||||
return scrolled_x or scrolled_y
|
return scrolled_x or scrolled_y
|
||||||
|
|
||||||
@@ -916,7 +916,7 @@ class Widget(DOMNode):
|
|||||||
y (int | None, optional): Y distance (rows) to scroll, or ``None`` for no change. Defaults to None.
|
y (int | None, optional): Y distance (rows) to scroll, or ``None`` for no change. Defaults to None.
|
||||||
animate (bool, optional): Animate to new scroll position. Defaults to False.
|
animate (bool, optional): Animate to new scroll position. Defaults to False.
|
||||||
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
||||||
duration (float | None, optional): Duration of animation, if animate is True and speed is False.
|
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if the scroll position changed, otherwise False.
|
bool: True if the scroll position changed, otherwise False.
|
||||||
@@ -941,7 +941,7 @@ class Widget(DOMNode):
|
|||||||
Args:
|
Args:
|
||||||
animate (bool, optional): Animate scroll. Defaults to True.
|
animate (bool, optional): Animate scroll. Defaults to True.
|
||||||
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
||||||
duration (float | None, optional): Duration of animation, if animate is True and speed is False.
|
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if any scrolling was done.
|
bool: True if any scrolling was done.
|
||||||
@@ -962,7 +962,7 @@ class Widget(DOMNode):
|
|||||||
Args:
|
Args:
|
||||||
animate (bool, optional): Animate scroll. Defaults to True.
|
animate (bool, optional): Animate scroll. Defaults to True.
|
||||||
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
||||||
duration (float | None, optional): Duration of animation, if animate is True and speed is False.
|
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if any scrolling was done.
|
bool: True if any scrolling was done.
|
||||||
@@ -986,7 +986,7 @@ class Widget(DOMNode):
|
|||||||
Args:
|
Args:
|
||||||
animate (bool, optional): Animate scroll. Defaults to True.
|
animate (bool, optional): Animate scroll. Defaults to True.
|
||||||
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
||||||
duration (float | None, optional): Duration of animation, if animate is True and speed is False.
|
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if any scrolling was done.
|
bool: True if any scrolling was done.
|
||||||
@@ -1008,7 +1008,7 @@ class Widget(DOMNode):
|
|||||||
Args:
|
Args:
|
||||||
animate (bool, optional): Animate scroll. Defaults to True.
|
animate (bool, optional): Animate scroll. Defaults to True.
|
||||||
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
||||||
duration (float | None, optional): Duration of animation, if animate is True and speed is False.
|
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if any scrolling was done.
|
bool: True if any scrolling was done.
|
||||||
@@ -1030,7 +1030,7 @@ class Widget(DOMNode):
|
|||||||
Args:
|
Args:
|
||||||
animate (bool, optional): Animate scroll. Defaults to True.
|
animate (bool, optional): Animate scroll. Defaults to True.
|
||||||
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
||||||
duration (float | None, optional): Duration of animation, if animate is True and speed is False.
|
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if any scrolling was done.
|
bool: True if any scrolling was done.
|
||||||
@@ -1052,7 +1052,7 @@ class Widget(DOMNode):
|
|||||||
Args:
|
Args:
|
||||||
animate (bool, optional): Animate scroll. Defaults to True.
|
animate (bool, optional): Animate scroll. Defaults to True.
|
||||||
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
||||||
duration (float | None, optional): Duration of animation, if animate is True and speed is False.
|
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if any scrolling was done.
|
bool: True if any scrolling was done.
|
||||||
@@ -1074,7 +1074,7 @@ class Widget(DOMNode):
|
|||||||
Args:
|
Args:
|
||||||
animate (bool, optional): Animate scroll. Defaults to True.
|
animate (bool, optional): Animate scroll. Defaults to True.
|
||||||
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
||||||
duration (float | None, optional): Duration of animation, if animate is True and speed is False.
|
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if any scrolling was done.
|
bool: True if any scrolling was done.
|
||||||
@@ -1099,7 +1099,7 @@ class Widget(DOMNode):
|
|||||||
Args:
|
Args:
|
||||||
animate (bool, optional): Animate scroll. Defaults to True.
|
animate (bool, optional): Animate scroll. Defaults to True.
|
||||||
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
||||||
duration (float | None, optional): Duration of animation, if animate is True and speed is False.
|
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if any scrolling was done.
|
bool: True if any scrolling was done.
|
||||||
@@ -1124,7 +1124,7 @@ class Widget(DOMNode):
|
|||||||
Args:
|
Args:
|
||||||
animate (bool, optional): Animate scroll. Defaults to True.
|
animate (bool, optional): Animate scroll. Defaults to True.
|
||||||
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
||||||
duration (float | None, optional): Duration of animation, if animate is True and speed is False.
|
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if any scrolling was done.
|
bool: True if any scrolling was done.
|
||||||
@@ -1151,7 +1151,7 @@ class Widget(DOMNode):
|
|||||||
Args:
|
Args:
|
||||||
animate (bool, optional): Animate scroll. Defaults to True.
|
animate (bool, optional): Animate scroll. Defaults to True.
|
||||||
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration.
|
||||||
duration (float | None, optional): Duration of animation, if animate is True and speed is False.
|
duration (float | None, optional): Duration of animation, if animate is True and speed is None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if any scrolling was done.
|
bool: True if any scrolling was done.
|
||||||
@@ -1408,8 +1408,8 @@ class Widget(DOMNode):
|
|||||||
self._container_size = container_size
|
self._container_size = container_size
|
||||||
if self.is_scrollable:
|
if self.is_scrollable:
|
||||||
self._scroll_update(virtual_size)
|
self._scroll_update(virtual_size)
|
||||||
self.refresh(layout=True)
|
# self.refresh(layout=True)
|
||||||
self.scroll_to(self.scroll_x, self.scroll_y)
|
# self.scroll_to(self.scroll_x, self.scroll_y)
|
||||||
else:
|
else:
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user