Textual
PythonでモダンなTUIアプリケーションを構築するためのフレームワーク。CSS、DOM、リアクティブなプログラミングモデルを採用し、Web開発の概念をターミナル環境に持ち込んでいます。
GitHub概要
Textualize/textual
The lean application framework for Python. Build sophisticated user interfaces with a simple Python API. Run your apps in the terminal and a web browser.
スター30,007
ウォッチ174
フォーク932
作成日:2021年4月8日
言語:Python
ライセンス:MIT License
トピックス
cliframeworkpythonrichterminaltui
スター履歴
データ取得日時: 2025/7/25 06:22
フレームワーク
Textual
概要
TextualはPythonでモダンなTUI(テキストベースユーザーインターフェース)アプリケーションを構築するための革新的なフレームワークです。Web開発の概念(CSS、DOM、リアクティブプログラミング)をターミナル環境に持ち込み、直感的で高性能なTUIアプリケーションの開発を可能にします。
詳細
Textualは2021年にTextualize社によって開発され、PythonのTUI開発に新しいパラダイムを提供しました。従来のcursesベースのアプローチとは異なり、モダンなWeb開発のベストプラクティスを採用しています。
主要な特徴
- CSS-like スタイリング: CSS風の構文でアプリケーションの見た目をカスタマイズ
- DOM構造: HTMLのようなDOM(Document Object Model)でUI階層を管理
- リアクティブ属性: データの変更が自動的にUIに反映される仕組み
- 豊富なウィジェット: ボタン、入力フィールド、テーブル、ツリーなど多様な組み込みウィジェット
- イベント駆動: メッセージベースのイベントシステム
- アニメーション: スムーズなアニメーション効果
- テーマシステム: カスタマイズ可能なテーマとカラースキーム
- Web展開: ターミナルアプリをWebブラウザでも実行可能
アーキテクチャ
Textualのアーキテクチャは以下の主要コンポーネントで構成されています:
- App: アプリケーションのエントリーポイント
- Screen: 画面全体を表す特別なWidget
- Widget: UI要素の基底クラス
- MessagePump: イベント処理の基盤
- Compositor: レンダリングシステム
- CSS Engine: スタイリングエンジン
メリット・デメリット
メリット
- モダンなWeb開発の知識を活用できる
- 高性能なレンダリングとアニメーション
- 豊富なドキュメントとコミュニティサポート
- クロスプラットフォーム対応(Linux、macOS、Windows)
- Webブラウザでの実行も可能
- 豊富な組み込みウィジェット
- 直感的なCSS風スタイリング
- 強力な開発ツール(デバッグコンソール、ライブリロードなど)
デメリット
- 比較的新しいフレームワークのため学習リソースが限定的
- 大規模アプリケーションでの実績がまだ少ない
- Richライブラリへの依存
- 軽量なアプリケーションには機能過多の場合がある
主要リンク
書き方の例
from textual.app import App, ComposeResult
from textual.containers import Container
from textual.widgets import Button, Header, Footer, Static
class CounterApp(App):
\"\"\"A simple counter app.\"\"\"
CSS_PATH = "counter.tcss"
def __init__(self):
super().__init__()
self.counter = 0
def compose(self) -> ComposeResult:
\"\"\"Create child widgets for the app.\"\"\"
yield Header()
yield Footer()
yield Container(
Static(f"Count: {self.counter}", id="counter"),
Button("Increment", id="increment"),
Button("Decrement", id="decrement"),
id="app-grid",
)
def on_button_pressed(self, event: Button.Pressed) -> None:
\"\"\"Event handler called when a button is pressed.\"\"\"
if event.button.id == "increment":
self.counter += 1
elif event.button.id == "decrement":
self.counter -= 1
# Update the counter display
counter_widget = self.query_one("#counter", Static)
counter_widget.update(f"Count: {self.counter}")
if __name__ == "__main__":
app = CounterApp()
app.run()
CSSファイル (counter.tcss):
#app-grid {
display: grid;
grid-size: 1 3;
grid-rows: 1fr;
margin: 1 2;
min-height: 0;
}
#counter {
content-align: center middle;
text-style: bold;
}
Button {
margin: 1 2;
}