mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
more words
This commit is contained in:
@@ -5,12 +5,6 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
### Unreleased
|
||||
|
||||
## Added
|
||||
|
||||
- Added `CenterMiddle` container
|
||||
|
||||
## [3.5.0] - 2025-06-20
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -24,10 +24,10 @@ class ContainerApp(App):
|
||||
"""
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Box("Box 1")
|
||||
with Center(classes="with-border"):
|
||||
yield Box("Box 1") # (1)!
|
||||
with Center(classes="with-border"): # (2)!
|
||||
yield Box("Box 2")
|
||||
with Right(classes="with-border"):
|
||||
with Right(classes="with-border"): # (3)!
|
||||
yield Box("Box 3")
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.containers import HorizontalGroup, Middle
|
||||
from textual.containers import Middle
|
||||
from textual.widgets import Placeholder
|
||||
|
||||
|
||||
@@ -24,11 +24,10 @@ class ContainerApp(App):
|
||||
"""
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
with HorizontalGroup():
|
||||
yield Box("Box 1")
|
||||
with Middle(classes="with-border"):
|
||||
yield Box("Box 2")
|
||||
yield Box("Box 3")
|
||||
with Middle(classes="with-border"): # (1)!
|
||||
yield Box("Box 1.")
|
||||
yield Box("Box 2.")
|
||||
yield Box("Box 3.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
# Work with containers
|
||||
# Save time with Textual containers
|
||||
|
||||
Textual's [containers][textual.containers] provide a convenient way of arranging your widgets. Let's look at them in a little detail.
|
||||
|
||||
!!! info "Are you in the right place?"
|
||||
|
||||
We are talking about Textual container widgets here. Not to be confused with [containerization](https://en.wikipedia.org/wiki/Containerization_(computing))—which is something else entirely!
|
||||
|
||||
Textual's [containers][textual.containers] provide a convenient way of arranging your widgets. Let's look at them in a little detail!
|
||||
|
||||
## What are containers?
|
||||
|
||||
@@ -30,7 +35,7 @@ Before I describe some of the other containers, I would like to show how contain
|
||||
The following is the actual source of the `Horizontal` widget:
|
||||
|
||||
```python
|
||||
class Horizontal(Widget, inherit_bindings=False):
|
||||
class Horizontal(Widget):
|
||||
"""An expanding container with horizontal layout and no scrollbars."""
|
||||
|
||||
DEFAULT_CSS = """
|
||||
@@ -47,8 +52,6 @@ That's it!
|
||||
A simple widget with a few preset styles.
|
||||
The other containers are just as simple.
|
||||
|
||||
You can customize the container with TCSS in the same way as other widgets.
|
||||
|
||||
## Horizontal and Vertical
|
||||
|
||||
We've seen the `Horizontal` container in action.
|
||||
@@ -69,6 +72,10 @@ And here's the output:
|
||||
|
||||
Three boxes, vertically stacked.
|
||||
|
||||
!!! tip "Styling layout"
|
||||
|
||||
You can set the layout of a compound widget with the [layout](../styles/layout.md) rule.
|
||||
|
||||
### Size behavior
|
||||
|
||||
Something to keep in mind when using `Horizontal` or `Vertical` is that they will consume the remaining space in the screen. Let's look at an example to illustrate that.
|
||||
@@ -100,7 +107,7 @@ And here's the result:
|
||||
```
|
||||
|
||||
Two horizontal containers divide the remaining screen space in two.
|
||||
If you were to add another horizontal it would divide the screen space in to thirds--and so on.
|
||||
If you were to add another horizontal it would divide the screen space in to thirds—and so on.
|
||||
|
||||
This makes `Horizontal` and `Vertical` excellent for designing the macro layout of your app's interface, but not for making tightly packed rows or columns. For that you need the *group* containers which I'll cover next.
|
||||
|
||||
@@ -132,7 +139,7 @@ We can see that the widgets are arranged horizontally as before, but they only u
|
||||
Something to watch out for regarding the previous containers we have discussed, is that they don't scroll by default.
|
||||
Let's see what happens if we add more boxes than could fit on the screen.
|
||||
|
||||
In the following example, we will add boxes:
|
||||
In the following example, we will add 10 boxes:
|
||||
|
||||
```python hl_lines="28 29"
|
||||
--8<-- "docs/examples/how-to/containers06.py"
|
||||
@@ -161,7 +168,84 @@ Here's the output:
|
||||
|
||||
We now have a scrollbar we can click and drag to see all the boxes.
|
||||
|
||||
!!! tip "Automatic scrollbars"
|
||||
!!! tip "Automatic scrollbars"
|
||||
|
||||
You can implement automatic scrollbars with the [overflow](../styles/overflow.md) style.
|
||||
|
||||
You can also implement automatic scrollbars with the [overflow](../styles/overflow.md) style.
|
||||
|
||||
|
||||
## Center, Right, and Middle
|
||||
|
||||
The [Center][textual.containers.Center], [Right][textual.containers.Right], and [Middle][textual.containers.Middle] containers are handy for setting the alignment of select widgets.
|
||||
|
||||
First lets look at `Center` and `Right` which align their children on the horizontal axis (there is no `Left` container, as this is the default).
|
||||
|
||||
Here's an example:
|
||||
|
||||
```python hl_lines="2 28 30"
|
||||
--8<-- "docs/examples/how-to/containers08.py"
|
||||
```
|
||||
|
||||
1. The default is to align widgets to the left.
|
||||
2. Align the child to the center.
|
||||
3. Align the child to the right edge.
|
||||
|
||||
Here's the output:
|
||||
|
||||
```{.textual path="docs/examples/how-to/containers08.py"}
|
||||
```
|
||||
|
||||
Note how `Center` and `Right` expand to fill the horizontal dimension, but are only as tall as they need to be.
|
||||
|
||||
!!! tip "Alignment in TCSS"
|
||||
|
||||
You can set alignment in TCSS with the [align](../styles/align.md) rule.
|
||||
|
||||
The [Middle][textual.containers.Middle] container aligns its children to the center of the *vertical* axis.
|
||||
Let's look at an example.
|
||||
The following code aligns three boxes on the vertical axis:
|
||||
|
||||
```python hl_lines="2 27"
|
||||
--8<-- "docs/examples/how-to/containers09.py"
|
||||
```
|
||||
|
||||
1. Align children to the center of the vertical axis.
|
||||
|
||||
Here's the output:
|
||||
|
||||
```{.textual path="docs/examples/how-to/containers09.py"}
|
||||
```
|
||||
|
||||
Note how the container expands on the vertical axis, but fits on the horizontal axis.
|
||||
|
||||
## Other containers
|
||||
|
||||
This how-to covers the most common widgets, but isn't exhausted.
|
||||
Be sure to visit the [container reference][textual.containers] for the full list.
|
||||
There may be new containers added in future versions of Textual.
|
||||
|
||||
## Custom containers
|
||||
|
||||
The builtin [containers][textual.containers] cover a number of common layout patterns, but are unlikely to cover every possible requirement.
|
||||
Fortunately, creating your own is easy.
|
||||
Just like the builtin containers, you can create a container by extending Widget and adding little TCSS.
|
||||
|
||||
Here's a template for a custom container:
|
||||
|
||||
```python
|
||||
class MyContainer(Widget):
|
||||
"""My custom container."""
|
||||
DEFAULT_CSS = """
|
||||
MyContainer {
|
||||
# Your rules here
|
||||
}
|
||||
"""
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
- Containers are compound widgets with preset styles for arranging their children.
|
||||
- [`Horizontal`][textual.containers.Horizontal] and [`Vertical`][textual.containers.Vertical] containers stretch to fill available space.
|
||||
- [`HorizontalGroup`][textual.containers.HorizontalGroup] and [`VerticalGroup`][textual.containers.VerticalGroup] fit to the height of their contents.
|
||||
- [`HorizontalScroll`][textual.containers.HorizontalScroll] and [`VerticalScroll`][textual.containers.VerticalScroll] add automatic scrollbars.
|
||||
- [`Center`][textual.containers.Center], [`Right`][textual.containers.Right], and [`Middle`][textual.containers.Middle] set alignment.
|
||||
- Custom containers are trivial to create.
|
||||
|
||||
@@ -29,7 +29,7 @@ class Container(Widget):
|
||||
"""
|
||||
|
||||
|
||||
class ScrollableContainer(Widget, can_focus=True, inherit_bindings=False):
|
||||
class ScrollableContainer(Widget, can_focus=True):
|
||||
"""A scrollable container with vertical layout, and auto scrollbars on both axis."""
|
||||
|
||||
# We don't typically want to maximize scrollable containers,
|
||||
@@ -118,7 +118,7 @@ class ScrollableContainer(Widget, can_focus=True, inherit_bindings=False):
|
||||
return self.can_maximize
|
||||
|
||||
|
||||
class Vertical(Widget, inherit_bindings=False):
|
||||
class Vertical(Widget):
|
||||
"""An expanding container with vertical layout and no scrollbars."""
|
||||
|
||||
DEFAULT_CSS = """
|
||||
@@ -131,7 +131,7 @@ class Vertical(Widget, inherit_bindings=False):
|
||||
"""
|
||||
|
||||
|
||||
class VerticalGroup(Widget, inherit_bindings=False):
|
||||
class VerticalGroup(Widget):
|
||||
"""A non-expanding container with vertical layout and no scrollbars."""
|
||||
|
||||
DEFAULT_CSS = """
|
||||
@@ -156,7 +156,7 @@ class VerticalScroll(ScrollableContainer):
|
||||
"""
|
||||
|
||||
|
||||
class Horizontal(Widget, inherit_bindings=False):
|
||||
class Horizontal(Widget):
|
||||
"""An expanding container with horizontal layout and no scrollbars."""
|
||||
|
||||
DEFAULT_CSS = """
|
||||
@@ -169,7 +169,7 @@ class Horizontal(Widget, inherit_bindings=False):
|
||||
"""
|
||||
|
||||
|
||||
class HorizontalGroup(Widget, inherit_bindings=False):
|
||||
class HorizontalGroup(Widget):
|
||||
"""A non-expanding container with horizontal layout and no scrollbars."""
|
||||
|
||||
DEFAULT_CSS = """
|
||||
@@ -194,7 +194,7 @@ class HorizontalScroll(ScrollableContainer):
|
||||
"""
|
||||
|
||||
|
||||
class Center(Widget, inherit_bindings=False):
|
||||
class Center(Widget):
|
||||
"""A container which aligns children on the X axis."""
|
||||
|
||||
DEFAULT_CSS = """
|
||||
@@ -206,7 +206,7 @@ class Center(Widget, inherit_bindings=False):
|
||||
"""
|
||||
|
||||
|
||||
class Right(Widget, inherit_bindings=False):
|
||||
class Right(Widget):
|
||||
"""A container which aligns children on the X axis."""
|
||||
|
||||
DEFAULT_CSS = """
|
||||
@@ -218,7 +218,7 @@ class Right(Widget, inherit_bindings=False):
|
||||
"""
|
||||
|
||||
|
||||
class Middle(Widget, inherit_bindings=False):
|
||||
class Middle(Widget):
|
||||
"""A container which aligns children on the Y axis."""
|
||||
|
||||
DEFAULT_CSS = """
|
||||
@@ -230,7 +230,7 @@ class Middle(Widget, inherit_bindings=False):
|
||||
"""
|
||||
|
||||
|
||||
class CenterMiddle(Widget, inherit_bindings=False):
|
||||
class CenterMiddle(Widget):
|
||||
"""A container which aligns its children on both axis."""
|
||||
|
||||
DEFAULT_CSS = """
|
||||
@@ -242,7 +242,7 @@ class CenterMiddle(Widget, inherit_bindings=False):
|
||||
"""
|
||||
|
||||
|
||||
class Grid(Widget, inherit_bindings=False):
|
||||
class Grid(Widget):
|
||||
"""A container with grid layout."""
|
||||
|
||||
DEFAULT_CSS = """
|
||||
@@ -254,7 +254,7 @@ class Grid(Widget, inherit_bindings=False):
|
||||
"""
|
||||
|
||||
|
||||
class ItemGrid(Widget, inherit_bindings=False):
|
||||
class ItemGrid(Widget):
|
||||
"""A container with grid layout and automatic columns."""
|
||||
|
||||
DEFAULT_CSS = """
|
||||
|
||||
Reference in New Issue
Block a user