logo oujood
🔍

Organiser les fichiers d'une application Tkinter

Une application Tkinter qui grandit mérite une structure de fichiers réfléchie. Voici comment séparer l'interface, la logique et les ressources sans se compliquer la vie.

OUJOOD.COM

Un script Python unique suffit pour une petite application. Dès qu'on dépasse quelques centaines de lignes ou qu'on veut réutiliser des parties du code ailleurs, répartir le projet en fichiers séparés devient une nécessité. La structure décrite ici est minimaliste mais suffisante pour la majorité des projets Tkinter de taille moyenne.

Structure de base recommandée

Voici une organisation typique pour une application Tkinter de taille moyenne :

📋 Copier le code

mon_application/
│
├── main.py              # point d'entrée — lance l'application
├── app.py               # classe Application principale (hérite de tk.Tk)
│
├── vues/                # les écrans / panneaux de l'interface
│   ├── __init__.py
│   ├── vue_principale.py
│   └── vue_parametres.py
│
├── logique/             # traitement des données, sans aucun import tkinter
│   ├── __init__.py
│   └── traitement.py
│
└── ressources/          # images, icônes, fichiers de données
    └── icone.png

La règle la plus importante : le dossier logique/ ne doit contenir aucun import Tkinter. La logique métier — calculs, lecture de fichiers, traitement de données — doit pouvoir tourner indépendamment de l'interface. Cela facilite les tests et permet de remplacer Tkinter par une autre interface (web, CLI) sans retoucher la logique.

main.py — point d'entrée

📋 Copier le code

# main.py
from app import Application

if __name__ == "__main__":
    app = Application()
    app.mainloop()

main.py est volontairement minimal. Sa seule responsabilité : importer et lancer. Le garde if __name__ == "__main__" empêche le lancement automatique si ce fichier est importé par un autre module.

app.py — classe principale

📋 Copier le code

# app.py
import tkinter as tk
from tkinter import messagebox
from vues.vue_principale import VuePrincipale
from vues.vue_parametres import VueParametres

class Application(tk.Tk):

    def __init__(self):
        super().__init__()
        self.title("Mon application")
        self.geometry("600x400")
        self.protocol("WM_DELETE_WINDOW", self._quitter)
        self._vue_active = None
        self._afficher_vue(VuePrincipale)

    def _afficher_vue(self, classe_vue):
        if self._vue_active:
            self._vue_active.destroy()
        self._vue_active = classe_vue(self)
        self._vue_active.pack(fill="both", expand=True)

    def aller_parametres(self):
        self._afficher_vue(VueParametres)

    def aller_principale(self):
        self._afficher_vue(VuePrincipale)

    def _quitter(self):
        if messagebox.askokcancel("Quitter", "Fermer l'application ?"):
            self.destroy()

vues/vue_principale.py — un écran

📋 Copier le code

# vues/vue_principale.py
import tkinter as tk
from logique.traitement import calculer_total

class VuePrincipale(tk.Frame):

    def __init__(self, parent):
        super().__init__(parent)
        self._parent = parent
        self._creer_widgets()

    def _creer_widgets(self):
        tk.Label(self, text="Vue principale", font=("Arial", 14, "bold")).pack(pady=20)

        self.champ = tk.Entry(self, width=20)
        self.champ.pack()

        tk.Button(self, text="Calculer", command=self._calculer).pack(pady=8)
        self.label_res = tk.Label(self, text="")
        self.label_res.pack()

        tk.Button(self, text="Paramètres",
                  command=self._parent.aller_parametres).pack(pady=10)

    def _calculer(self):
        try:
            valeur = float(self.champ.get())
            resultat = calculer_total(valeur)  # appel à la logique
            self.label_res.config(text=f"Total : {resultat:.2f}")
        except ValueError:
            self.label_res.config(text="Valeur invalide")

La vue appelle calculer_total() depuis le module logique — elle ne sait pas comment le calcul est fait, elle reçoit juste le résultat. Pour naviguer vers un autre écran, elle appelle self._parent.aller_parametres() — la vue délègue la navigation à l'application. Ce principe de séparation des responsabilités est la base de toute architecture maintenable, que ce soit avec Tkinter, Pandas ou NumPy en arrière-plan.

Par carabde | Mis à jour le 30 avril 2025