🛠
Practice Projects · ★★★★
curses · textual · Widgets · Keyboard events
Project 16 — TUI App with curses / textual
Build a terminal user interface (TUI) for one of your earlier projects. Use curses for low-level control or the modern textual framework for high-level widgets.
TUIcursestextualterminal UIwidgets
Duration
⏱ 4 hours
Level
📊 Advanced Applied
Prerequisite
🎯 Advanced track
OUTCOME
A full TUI application with menus, input fields, and keyboard navigation
What you'll learn
- 1Set up a curses or textual application skeleton
- 2Render windows, panels, and text widgets
- 3Handle keyboard input and navigation
- 4Port an existing CLI app to TUI
Option A: curses (stdlib)
python
import curses
def main(stdscr):
curses.curs_set(0)
stdscr.clear()
h, w = stdscr.getmaxyx()
stdscr.addstr(h//2, w//2-10, "Hello from curses!")
stdscr.addstr(h-1, 0, "Press q to quit")
stdscr.refresh()
while True:
key = stdscr.getch()
if key == ord("q"):
break
curses.wrapper(main)Option B: textual (third-party)
python
from textual.app import App, ComposeResult
from textual.widgets import Header, Footer, Button, Label
class MyApp(App):
def compose(self) -> ComposeResult:
yield Header()
yield Label("Hello, Textual!")
yield Button("Click me", id="btn")
yield Footer()
def on_button_pressed(self, event: Button.Pressed) -> None:
self.query_one(Label).update("Button was pressed!")
if __name__ == "__main__":
MyApp().run()Suggested project: TUI To-Do
- Main pane: task list with arrow-key navigation
- Status bar: task count and current filter
- Keybindings: a=add, d=delete, space=toggle done, q=quit, /=search
- Input dialog: popup for task title
📝 Exercises
Try them yourself first, then open the solution to compare.
Exercise 1
Build a TUI app
Goal: Port your to-do app (Project 5) to a TUI using curses or textual.
Requirements
- Task list with keyboard navigation
- Add/delete/toggle done via keybindings
- Status bar with count
- Search/filter pane
Grading
- · Renders correctly in terminal — 30%
- · Keyboard navigation — 30%
- · CRUD operations — 30%
- · No crashes on resize — 10%
Example code / lecture materials
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗