Python Textual Text User Interface Library
Textual is a TUI (Text User Interface) library for Python, a sister project to and dependent on Rich, which supports Rich's Renderable class and has its own interactive component, the Widget class. Complex user interfaces can be built using a simple Python API to run in shell tools or browsers.
Textual runs on Linux, macOS and Windows.
Textual requires Python 3.7 or later.
Textual Principle
- Textual uses Rich to render rich text, so anything Rich can render can be used in Textual.
- Textual's event handling is asynchronous (using the async and await keywords). widgets (UI components) can be updated independently and communicate with each other via messaging.
- Textual has more in common with modern web development in that layouts are done in CSS and themes can be customized in CSS. Other techniques are borrowed from JS frameworks such as Vue and Reactive.
Install Textual
pip install textual
If you plan to develop a text application, you should also install the development tools using the following command:
pip install textual-dev
After installing Textual, run the following command to see what it can do:
python -m textual
Run results:
Widgets
Button #Button
Checkbox #Checkbox
Collapsible #stowed/folded
ContentSwitcher#Content Switcher
DataTable#DataTable
Digits
DirectoryTree #DirectoryTree
Footer
Header#Header
Input#Input
Label#Label
ListView#List
LoadingIndicator#Loading Indicator
Log#Log
MarkdownViewer#Markdown Viewer
Markdown#Markdown
OptionList#Option List
Placeholder#Placeholder
Pretty#Formatting
ProgressBar#Progress Bar
RadioButton#Radio Button
RadioSet#CheckButton
RichLog#rich log
Rule#Split Line
Select#Select
SelectionList#Selection List
Sparkline#Bar Chart
Static# static files
Switch#Switch
Tabs#
TabbedContent tab content
TextArea#Text Area
Tree#Tree
Textual applies styles to widgets using CSS.
Example of a countdown
from time import monotonic from import App, ComposeResult from import ScrollableContainer from import reactive from import Button, Footer, Header, Static class TimeDisplay(Static): """A widget to display elapsed time.""" start_time = reactive(monotonic) time = reactive(0.0) total = reactive(0.0) def on_mount(self) -> None: """Event handler called when widget is added to the app.""" self.update_timer = self.set_interval(1 / 60, self.update_time, pause=True) def update_time(self) -> None: """Method to update time to current.""" = + (monotonic() - self.start_time) def watch_time(self, time: float) -> None: """Called when the time attribute changes.""" minutes, seconds = divmod(time, 60) hours, minutes = divmod(minutes, 60) (f"{hours:02,.0f}:{minutes:02.0f}:{seconds:05.2f}") def start(self) -> None: """Method to start (or resume) time updating.""" self.start_time = monotonic() self.update_timer.resume() def stop(self) -> None: """Method to stop the time display updating.""" self.update_timer.pause() += monotonic() - self.start_time = def reset(self) -> None: """Method to reset the time display to zero.""" = 0 = 0 class Stopwatch(Static): """A stopwatch widget.""" def on_button_pressed(self, event: ) -> None: """Event handler called when a button is pressed.""" button_id = time_display = self.query_one(TimeDisplay) if button_id == "start": time_display.start() self.add_class("started") elif button_id == "stop": time_display.stop() self.remove_class("started") elif button_id == "reset": time_display.reset() def compose(self) -> ComposeResult: """Create child widgets of a stopwatch.""" yield Button("Start", , variant="success") yield Button("Stop", , variant="error") yield Button("Reset", ) yield TimeDisplay() class StopwatchApp(App): """A Textual app to manage stopwatches.""" CSS_PATH = "" BINDINGS = [("d", "toggle_dark", "Toggle dark mode")] def compose(self) -> ComposeResult: """Called to add widgets to the app.""" yield Header() yield Footer() yield ScrollableContainer(Stopwatch(), Stopwatch(), Stopwatch()) def action_toggle_dark(self) -> None: """An action to toggle dark mode.""" = not if __name__ == "__main__": app = StopwatchApp() ()
css style
Stopwatch { layout: horizontal; background: $boost; height: 5; margin: 1; min-width: 50; padding: 1; } TimeDisplay { content-align: center middle; text-opacity: 60%; height: 3; } Button { width: 16; } #start { dock: left; } #stop { dock: left; display: none; } #reset { dock: right; } .started { text-style: bold; background: $success; color: $text; } .started TimeDisplay { text-opacity: 100%; } .started #start { display: none } .started #stop { display: block } .started #reset { visibility: hidden }
operational effect
Other examples can be found on github
Refer to the documentation:
Project github:/Textualize/textual
Official Documentation:/
Above is the Python Textual text user interface library to use the principle of exploration of the details, more information about the Python Textual library please pay attention to my other related articles!