Textual
Mise à jour :
On a parfois besoin d’une interface utilisateur sans vouloir lancer un navigateur ou une application graphique. Dans un terminal, notamment en SSH ou dans un environnement serveur, une interface texte bien pensée peut faire toute la différence. C’est là que le framework Python Textual entre en jeu.
Présentation de Textual
Le terminal est souvent vu comme un outil brut, réservé aux commandes et scripts simples. Pourtant, il peut devenir un véritable espace d’interaction graphique — sans souris, sans navigateur, sans interface graphique lourde. Textual transforme ce potentiel en réalité. Développé par l’équipe derrière la bibliothèque Rich, ce framework Python permet de créer des interfaces utilisateur textuelles modernes et dynamiques, directement dans le terminal.
Textual, c’est plus qu’un simple habillage : c’est une architecture pensée pour construire des applications modulaires, interactives, stylisées, avec des composants réutilisables et des mises en page flexibles. Il est conçu pour des développeurs Python qui souhaitent offrir à leurs utilisateurs une expérience fluide en ligne de commande, sans sacrifier le confort.
Textual vs Rich
Avant Textual, il y avait Rich. Cette bibliothèque Python permettait d’afficher des textes formatés, des tableaux, des barres de progression ou encore du code colorisé dans le terminal. Elle est toujours au cœur de Textual, mais sert désormais de moteur d’affichage.
Rich | Textual |
---|---|
Affichage statique | Interface dynamique (TUI) |
Tableaux, couleurs, logs | Widgets, layout, événements |
Pour des scripts et logs enrichis | Pour des applications terminal complètes |
Textual s’appuie sur Rich mais va beaucoup plus loin : il gère le layout, les interactions clavier, la navigation, le styling CSS, et même les animations. Il peut être utilisé pour construire des outils internes, des dashboards, des explorateurs de fichiers ou encore des clients API interactifs.
Exemples d’usages courants :
- Applications SSH interactives
- Interfaces de configuration
- Gestionnaires de tâches en ligne de commande
- Tableaux de bord pour services (ex : monitoring)
Fonctionnement et concepts fondamentaux de Textual
Avant d’explorer des widgets avancés ou projets complexes, il est essentiel de bien comprendre les bases de l’architecture de Textual: comment une app est structurée, comment les événements fonctionnent, et comment déclencher des mises à jour réactives.
Classe App
: Le cœur de l’application
Tout commence par hériter de textual.app.App
. C’est elle qui lance le mode
« application terminal » et gère la boucle principale.
from textual.app import App
class MyApp(App): pass
if __name__ == "__main__": MyApp().run()
run()
active le mode applicatif (gestion des entrées clavier, affichage interactif).Ctrl+Q
(par défaut) quitte proprement ce mode
Méthode compose()
: structure de l’interface
Dans compose()
, vous yieldtez les widgets que vous voulez afficher. Elle
définit l’arborescence du DOM Textual :
def compose(self): yield Header() yield Button("Cliquez") yield Container(Label("Hello"))
Cette démarche rappelle React/Vue, avec une structure déclarative, et permet l’injection efficace de composants.
Mise en page et styles
Textual utilise un système de mise en page basé sur des conteneurs et
des layouts. Vous pouvez organiser vos widgets en utilisant des conteneurs comme
Container
, Grid
, Dock
, etc. Chaque conteneur peut avoir un style
personnalisé grâce à TCSS (Textual CSS), un langage de style inspiré de CSS.
Les styles sont définis dans des fichiers .tcss
, et vous pouvez les appliquer
aux widgets en utilisant des sélecteurs CSS. Par exemple :
Footer { height: 1; background: $DARK_GRAY; color: $WHITE;}
Containers
Les containers sont des éléments qui regroupent d’autres widgets. Ils permettent de structurer l’interface et de gérer la disposition des widgets qu’ils contiennent. Textual propose plusieurs types de containers :
Container
: un conteneur de base qui peut contenir n’importe quel widget.Grid
: un conteneur qui organise les widgets en grille.Dock
: un conteneur qui permet de fixer des widgets à des bords (haut, bas, gauche, droite).Scroll
: un conteneur qui permet de faire défiler son contenu si celui-ci dépasse la taille du conteneur.Split
: un conteneur qui divise l’espace en plusieurs zones redimensionnables.
Widgets : les composants de base
Chaque élément de l’interface est un widget. Textual propose de nombreux
widgets prêts à l’emploi, comme Label
, Button
, Input
, DataTable
, etc.
Vous pouvez aussi créer vos propres widgets en héritant de Widget
.
Vous pouvez aussi créer des widgets personnalisés en héritant de la classe
Widget
.
Événements et actions
Les interactions utilisateur sont gérées par des événements. Chaque widget peut déclencher des événements, comme un clic de souris ou une touche du clavier.
Ces événements peuvent être capturés et gérés pour déclencher des actions dans l’application.
from textual.widgets import Button
button = Button("Cliquez-moi")
@button.on_clickdef on_button_click(event): print("Bouton cliqué !")
Les événements sont gérés de manière asynchrone, ce qui permet de créer des interfaces réactives. Vous pouvez aussi définir des raccourcis clavier pour exécuter des actions spécifiques.
Création d’une application Textual
Maintenant que vous avez une vue d’ensemble des concepts de base, voyons comment créer une application Textual simple. Nous allons structurer le projet, installer les dépendances nécessaires, et écrire un exemple d’application.
Une application Textual repose sur une organisation claire du code, qui permet de séparer les composants, les styles et la logique. Même pour une application simple, structurer correctement le projet vous évitera des difficultés à mesure que le code grandit.
Arborescence recommandée
Voici une structure typique pour un projet Textual :
mon_app/├── app.py # Point d’entrée de l’application├── widgets/ # Composants personnalisés│ └── mon_widget.py├── screens/ # Écrans ou vues│ └── accueil.py├── styles/ # Fichiers de style (TCSS)│ └── default.tcss└── utils/ # Fonctions utilitaires └── base.py
Cette architecture permet de bien séparer :
- la logique de l’application (
app.py
) - les composants réutilisables (
widgets/
) - les styles (
styles/
) - les écrans ou interfaces utilisateur (
screens/
)
Pour créer cette structure, vous pouvez utiliser les commandes suivantes :
mkdir mon_appcd mon_apptouch app.pymkdir widgets screens styles utilstouch widgets/mon_widget.py screens/accueil.py styles/default.tcss utils/base.py
Installation de Textual
Pour commencer à utiliser Textual, il vous faut un environnement Python récent et quelques bonnes pratiques de base. L’installation est simple et rapide, grâce à pip, le gestionnaire de paquets Python.
Prérequis
- Python 3.8 ou plus : Textual utilise des fonctionnalités modernes du langage, donc une version récente de Python est indispensable.
- Un terminal compatible avec les caractères Unicode et les couleurs 24 bits (la plupart des terminaux modernes : GNOME Terminal, iTerm2, Windows Terminal…).
- Optionnel, mais recommandé : un environnement virtuel pour isoler vos dépendances.
Étapes d’installation
- Créer un environnement virtuel
python3 -m venv .venvsource .venv/bin/activate # Linux/macOS.venv\Scripts\activate # Windows
- Installer Textual avec pip
pip install textual
Cette commande installe également Rich, qui est une dépendance directe de Textual.
- Vérifier l’installation
Pour vérifier que Textual est bien installé, vous pouvez exécuter la commande suivante :
python -m textual
Vous devriez obtenir une interface de démonstration de Textual avec des exemples de widgets et de styles. Cela confirme que l’installation s’est bien déroulée.
Exemple d’application simple
Pour illustrer l’utilisation de Textual, voici un exemple d’application très simple et facile à comprendre. Cette application crée une interface avec un titre, un champ de saisie, un bouton et une zone d’affichage des résultats.
Voici les fichiers nécessaires pour cet exemple :
-
Fichier
app.py
:from textual.app import App, ComposeResultfrom textual.widgets import Header, Footer, Label, Input, Buttonfrom textual.containers import Verticalclass CalculatriceApp(App):"""Une application Textual simple pour calculer le carré d'un nombre."""CSS_PATH = "styles/default.tcss"def compose(self) -> ComposeResult:"""Créer les widgets de l'application."""yield Header()yield Vertical(Label("Calculatrice de carré", id="title"),Label("Entrez un nombre :"),Input(placeholder="Ex: 5", id="number_input"),Button("Calculer le carré", id="calculate_btn"),Label("Résultat : ", id="result"),id="main_container")yield Footer()async def on_button_pressed(self, event: Button.Pressed) -> None:"""Gérer le clic sur le bouton."""if event.button.id == "calculate_btn":# Récupérer la valeur saisieinput_widget = self.query_one("#number_input", Input)number_text = input_widget.value# Calculer le carrétry:number = float(number_text)result = number ** 2# Afficher le résultatresult_label = self.query_one("#result", Label)result_label.update(f"Résultat : {number}² = {result}")except ValueError:# Gérer les erreurs de saisieresult_label = self.query_one("#result", Label)result_label.update("Erreur : Veuillez entrer un nombre valide")async def on_input_submitted(self, event: Input.Submitted) -> None:"""Gérer la validation par Entrée dans le champ de saisie."""if event.input.id == "number_input":# Déclencher le calcul quand on appuie sur Entréebutton = self.query_one("#calculate_btn", Button)await self.on_button_pressed(Button.Pressed(button))if __name__ == "__main__":app = CalculatriceApp()app.run() -
Fichier
styles/default.tcss
:#main_container {padding: 2;width: 50;height: 100%;align: center middle;}#title {text-align: center;text-style: bold;color: cyan;margin-bottom: 1;}Input {margin: 1 0;}Button {margin: 1 0;width: 100%;}#result {margin-top: 1;text-align: center;color: yellow;text-style: bold;}
Ce code crée une application Textual simple qui :
- Affiche un titre en haut
- Demande à l’utilisateur d’entrer un nombre
- Calcule et affiche le carré de ce nombre quand on clique sur le bouton
- Gère les erreurs de saisie
Structure de l’application :
-
CalculatriceApp
: La classe principale héritant deApp
compose()
: Définit la structure de l’interface avec les widgetson_button_pressed()
: Gère le clic sur le bouton “Calculer”on_input_submitted()
: Permet d’utiliser la touche Entrée pour calculer
-
Widgets utilisés :
Header
etFooter
: En-tête et pied de page automatiquesLabel
: Pour afficher du texte (titre, instructions, résultat)Input
: Pour la saisie utilisateurButton
: Pour déclencher le calculVertical
: Conteneur pour organiser les widgets verticalement
Cette application démontre les concepts de base de Textual de manière simple et compréhensible.
Exécution de l’application
Pour lancer l’application, assurez-vous d’être dans le répertoire du projet et exécutez la commande suivante :
python app.py
Vous devriez voir une interface utilisateur s’afficher dans votre terminal, avec
un en-tête, un message centré et un pied de page. Vous pouvez interagir avec
l’application en utilisant les touches fléchées pour naviguer, et quitter
l’application avec Ctrl+C
.
Plus loin
Une fois que vous avez compris les bases de Textual, vous pouvez explorer des fonctionnalités plus avancées :
- Widgets avancés : Textual propose de nombreux widgets comme des tableaux, des graphiques, des menus déroulants, etc.
- Animations : Vous pouvez ajouter des animations pour rendre l’interface plus dynamique.
- Gestion des événements : Textual permet de gérer les événements de manière asynchrone, ce qui permet de créer des interfaces réactives.
- Thèmes et styles : Vous pouvez personnaliser l’apparence de votre application avec des thèmes et des styles CSS.
- Tests et débogage : Textual propose des outils pour tester et déboguer vos applications, facilitant le développement.
- Intégration avec d’autres bibliothèques : Vous pouvez combiner Textual avec d’autres bibliothèques Python pour ajouter des fonctionnalités supplémentaires, comme la gestion de bases de données, l’accès à des API, etc.
- Extensions et plugins : Textual permet de créer des extensions pour ajouter des fonctionnalités personnalisées à votre application.
Je vais créer un projet plus complexe pour illustrer ces concepts avancés, que je vous présenterai prochainement. Dans l’idée , une interface qui permet de :
- lancer des commandes système en arrière plan,
- de visualiser les résultats en temps réel dans un terminal interactif.
- d’afficher le contenu d’un fichier de logs en temps réel.
Ce projet vous permettra de voir comment utiliser les widgets avancés, la gestion des événements et les animations pour créer une application terminal riche et interactive.
En attendant, vous pouvez également consulter la documentation officielle de Textual ↗ pour découvrir toutes les possibilités offertes par ce framework.
Conclusion
Textual est un framework puissant pour créer des interfaces utilisateur modernes dans le terminal. Il permet de transformer des applications en ligne de commande en véritables interfaces graphiques, tout en restant dans l’environnement familier du terminal.
Grâce à Textual, vous pouvez désormais développer des applications terminales riches et ergonomiques, offrant une expérience utilisateur fluide et agréable.