logo oujood
🔍

Projet Tkinter : calculatrice

Une calculatrice graphique fonctionnelle en moins de 100 lignes. Ce projet consolide grid(), les callbacks, les StringVar et la gestion d'erreurs dans un exemple concret.

OUJOOD.COM

La calculatrice est le projet introductif classique pour Tkinter — pas parce qu'elle est simple, mais parce qu'elle touche à tout : mise en page avec grid(), callbacks multiples, StringVar, gestion d'erreurs et raccourcis clavier. On construit ici une version fonctionnelle avec les quatre opérations de base.

Structure du projet

La calculatrice se compose de trois éléments : un affichage en haut, une grille de boutons chiffrés au centre, et une ligne d'opérateurs. On utilise grid() pour aligner les boutons en colonnes égales.

Code complet

📋 Copier le code

import tkinter as tk

class Calculatrice(tk.Tk):

    def __init__(self):
        super().__init__()
        self.title("Calculatrice")
        self.resizable(False, False)
        self.expression = tk.StringVar(value="0")
        self._en_cours   = ""      # expression en construction
        self._creer_interface()
        self._lier_clavier()

    def _creer_interface(self):
        # Affichage
        affichage = tk.Entry(
            self, textvariable=self.expression,
            font=("Arial", 22), justify="right",
            state="readonly", readonlybackground="#1a1a2e",
            fg="white", bd=0, width=16
        )
        affichage.grid(row=0, column=0, columnspan=4,
                       ipady=12, padx=2, pady=2)

        # Définition des boutons : (texte, ligne, colonne, colspan, couleur_fond)
        boutons = [
            ("C",   1, 0, 1, "#ef5350"), ("±",  1, 1, 1, "#757575"),
            ("%",   1, 2, 1, "#757575"), ("÷",  1, 3, 1, "#f57c00"),
            ("7",   2, 0, 1, "#2d2d44"), ("8",  2, 1, 1, "#2d2d44"),
            ("9",   2, 2, 1, "#2d2d44"), ("×",  2, 3, 1, "#f57c00"),
            ("4",   3, 0, 1, "#2d2d44"), ("5",  3, 1, 1, "#2d2d44"),
            ("6",   3, 2, 1, "#2d2d44"), ("−",  3, 3, 1, "#f57c00"),
            ("1",   4, 0, 1, "#2d2d44"), ("2",  4, 1, 1, "#2d2d44"),
            ("3",   4, 2, 1, "#2d2d44"), ("+",  4, 3, 1, "#f57c00"),
            ("0",   5, 0, 2, "#2d2d44"), (",",  5, 2, 1, "#2d2d44"),
            ("=",   5, 3, 1, "#1565c0"),
        ]

        for texte, ligne, col, colspan, couleur in boutons:
            btn = tk.Button(
                self, text=texte,
                font=("Arial", 16, "bold"),
                bg=couleur, fg="white",
                activebackground=couleur, activeforeground="white",
                relief="flat", bd=0, width=4, height=2,
                command=lambda t=texte: self._appuyer(t)
            )
            btn.grid(row=ligne, column=col, columnspan=colspan,
                     padx=2, pady=2, sticky="nsew")

        # Toutes les colonnes de taille égale
        for i in range(4):
            self.columnconfigure(i, weight=1)

    def _appuyer(self, touche):
        if touche == "C":
            self._en_cours = ""
            self.expression.set("0")

        elif touche == "=":
            self._calculer()

        elif touche == "±":
            try:
                val = float(self._en_cours or "0")
                self._en_cours = str(-val)
                self.expression.set(self._en_cours)
            except ValueError:
                pass

        elif touche == "%":
            try:
                val = float(self._en_cours or "0")
                self._en_cours = str(val / 100)
                self.expression.set(self._en_cours)
            except ValueError:
                pass

        else:
            # Remplacer les symboles affichés par les opérateurs Python
            correspondances = {"×": "*", "÷": "/", "−": "-", ",": "."}
            self._en_cours += correspondances.get(touche, touche)
            self.expression.set(self._en_cours)

    def _calculer(self):
        try:
            resultat = eval(self._en_cours)
            # Afficher sans .0 inutile pour les entiers
            if isinstance(resultat, float) and resultat.is_integer():
                resultat = int(resultat)
            self._en_cours = str(resultat)
            self.expression.set(self._en_cours)
        except ZeroDivisionError:
            self.expression.set("Division par 0")
            self._en_cours = ""
        except Exception:
            self.expression.set("Erreur")
            self._en_cours = ""

    def _lier_clavier(self):
        self.bind("", self._touche_clavier)

    def _touche_clavier(self, event):
        correspondances = {
            "Return": "=", "KP_Enter": "=", "Escape": "C",
            "Delete": "C", "BackSpace": "C",
        }
        touche = correspondances.get(event.keysym, event.char)
        if touche in "0123456789.+-*/=C%":
            self._appuyer(touche)

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

Points clés de l'implémentation

Quelques choix de conception qui valent la peine d'être notés. On utilise eval() pour évaluer l'expression — c'est acceptable dans une application locale sans entrée réseau, mais à éviter dans toute application web ou exposée. Les symboles ×, ÷ et sont remplacés par leurs équivalents Python avant l'évaluation. Le résultat est nettoyé : 9.0 s'affiche 9, pas 9.0.

La structure en classe héritant de tk.Tk évite toute variable globale. Les raccourcis clavier sont liés sur la fenêtre elle-même pour fonctionner sans que l'utilisateur ait besoin de cliquer d'abord sur un widget.

Par carabde | Mis à jour le 30 avril 2025