Skip to content

Commit 923a3b2

Browse files
authored
Merge pull request #642 from realpython/python-textual
Sample code for the article on Textual
2 parents b955c14 + 66eb6fb commit 923a3b2

19 files changed

+398
-0
lines changed

python-textual/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Python Textual: Build Beautiful UIs in the Terminal
2+
3+
This folder provides the code examples for the Real Python tutorial [Python Textual: Build Beautiful UIs in the Terminal](https://realpython.com/python-textual/).
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from textual.app import App
2+
from textual.widgets import Button, Input
3+
4+
5+
class ButtonsAndInputsApp(App):
6+
def compose(self):
7+
# Buttons
8+
yield Button("Click me!")
9+
yield Button("Primary!", variant="primary")
10+
yield Button.success("Success!")
11+
yield Button.warning("Warning!")
12+
yield Button.error("Error!")
13+
# Inputs
14+
yield Input(placeholder="Type your text here")
15+
yield Input(placeholder="Password", password=True)
16+
yield Input(
17+
placeholder="Type a number here",
18+
type="number",
19+
tooltip="Digits only please!",
20+
)
21+
22+
23+
if __name__ == "__main__":
24+
app = ButtonsAndInputsApp()
25+
app.run()

python-textual/events.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# from textual import on
2+
from textual.app import App
3+
from textual.widgets import Button, Digits, Footer
4+
5+
6+
class EventsApp(App):
7+
CSS_PATH = "events.tcss"
8+
BINDINGS = [
9+
("q", "quit", "Quit"),
10+
("b", "toggle_border", "Toggle border"),
11+
]
12+
13+
presses_count = 0
14+
double_border = False
15+
16+
def compose(self):
17+
yield Button(
18+
"Click me!",
19+
id="button",
20+
)
21+
digits = Digits("0", id="digits")
22+
digits.border_subtitle = "Button presses"
23+
yield digits
24+
yield Footer()
25+
26+
def action_toggle_border(self):
27+
self.double_border = not self.double_border
28+
digits = self.query_one("#digits")
29+
if self.double_border:
30+
digits.styles.border = ("double", "yellow")
31+
else:
32+
digits.styles.border = ("solid", "white")
33+
34+
def on_button_pressed(self, event):
35+
if event.button.id == "button":
36+
self.presses_count += 1
37+
digits = self.query_one("#digits")
38+
digits.update(f"{self.presses_count}")
39+
40+
# @on(Button.Pressed, "#button")
41+
# def button_pressed(self, event):
42+
# self.presses_count += 1
43+
# digits = self.query_one("#digits")
44+
# digits.update(f"{self.presses_count}")
45+
46+
47+
if __name__ == "__main__":
48+
app = EventsApp()
49+
app.run()

python-textual/events.tcss

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Button {
2+
background: $secondary;
3+
border: solid $primary;
4+
margin: 2 2;
5+
}
6+
7+
Button:hover {
8+
border: round white;
9+
}
10+
11+
#digits {
12+
color: green;
13+
border: solid white;
14+
padding: 1;
15+
width: 30;
16+
}

python-textual/grid.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from textual.app import App
2+
from textual.containers import Grid
3+
from textual.widgets import Static
4+
5+
6+
class GridLayoutExample(App):
7+
def compose(self):
8+
grid = Grid()
9+
grid.styles.grid_size_rows = rows = 6
10+
grid.styles.grid_size_columns = cols = 4
11+
with grid:
12+
for row in range(rows):
13+
for col in range(cols):
14+
static = Static(f"Static ({row=}, {col=})")
15+
static.styles.border = ("solid", "green")
16+
static.styles.width = "1fr"
17+
static.styles.height = "1fr"
18+
yield static
19+
20+
21+
if __name__ == "__main__":
22+
app = GridLayoutExample()
23+
app.run()

python-textual/grid.tcss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Grid {
2+
grid_size: 4 6;
3+
}
4+
5+
Static {
6+
height: 1fr;
7+
width: 1fr;
8+
border: solid green;
9+
}

python-textual/grid_with_tcss.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from textual.app import App
2+
from textual.containers import Grid
3+
from textual.widgets import Static
4+
5+
6+
class GridLayoutWithTCSS(App):
7+
CSS_PATH = "grid.tcss"
8+
9+
def compose(self):
10+
with Grid():
11+
for row in range(6):
12+
for col in range(4):
13+
yield Static(f"Static ({row=}, {col=})")
14+
15+
16+
if __name__ == "__main__":
17+
app = GridLayoutWithTCSS()
18+
app.run()

python-textual/hello_textual.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from textual.app import App
2+
from textual.widgets import Static
3+
4+
5+
class HelloTextualApp(App):
6+
def compose(self):
7+
yield Static("Hello, Textual!")
8+
9+
10+
if __name__ == "__main__":
11+
app = HelloTextualApp()
12+
app.run()
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from textual.app import App
2+
from textual.containers import Horizontal
3+
from textual.widgets import Static
4+
5+
NUM_BOXES = 4
6+
7+
8+
class HorizontalLayoutExample(App):
9+
def compose(self):
10+
with Horizontal():
11+
for i in range(NUM_BOXES):
12+
static = Static(f"Static {i+1}")
13+
static.styles.border = ("solid", "green")
14+
static.styles.width = "10%"
15+
yield static
16+
17+
18+
if __name__ == "__main__":
19+
app = HorizontalLayoutExample()
20+
app.run()
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from textual.app import App
2+
from textual.containers import HorizontalScroll
3+
from textual.widgets import Static
4+
5+
NUM_BOXES = 20
6+
7+
8+
class HorizontalScrollExample(App):
9+
def compose(self):
10+
with HorizontalScroll():
11+
for i in range(NUM_BOXES):
12+
static = Static(f"Static {i+1}")
13+
static.styles.border = ("solid", "green")
14+
static.styles.width = "10%"
15+
yield static
16+
17+
18+
if __name__ == "__main__":
19+
app = HorizontalScrollExample()
20+
app.run()

0 commit comments

Comments
 (0)