← Back to Python series
🛠
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 ↗