import tkinter as tk from tkinter import messagebox from Pile import Pile_chaine as Pile from math import * from expression import * class ValeurSaisie: """classe d'une valeur saise par l'utilisateur""" def __init__(self, valeur, master): self.valeur = valeur self.label_valeur = tk.Label(master, text=valeur) self.label_valeur.pack(side="bottom") def __del__(self): """suppression du label""" self.label_valeur.destroy() class Interface(tk.Frame): """interface de la calculatrice""" def __init__(self, master): self.master = master tk.Frame.__init__(self, master) self.etat = tk.Label(self.master, text="notation postfixée (polonaise inversée) -- mode interactif", fg="gray42") self.etat.pack() self.etat_affichage = "post-int" self.stack = Pile() self.create_menu_bar() self.frame_stack = tk.Frame(self.master) self.frame_stack.pack(padx=10, pady=10) self.affichage_expression = tk.Label(self.master, text="", bg="red") self.affichage_expression.pack() frame_saisie = tk.Frame(self.master, padx=5, pady=5) frame_saisie.pack() self.saisie_expression = tk.Entry(frame_saisie) self.saisie_expression.pack(side="left") self.saisie_expression.bind("", lambda e : self.entrer()) self.saisie_expression.bind("", lambda e : self.entrer()) btn_entrer = tk.Button(frame_saisie, text='entrer', command=self.entrer) btn_entrer.pack() commandes = tk.LabelFrame(self.master, text="commandes", padx=5, pady=5) commandes.pack(fill="both") effacer = tk.LabelFrame(commandes, text="effacer", padx=5, pady=5) effacer.pack(fill="both") btn_effacer_tt = tk.Button(effacer, text='tout effacer', command=self.effacer_tt) btn_effacer_tt.pack(side="left") btn_effacer_dernier = tk.Button(effacer, text='effacer la dernière valeur', command=self.effacer_dernier) btn_effacer_dernier.pack(side="left") fonctions = tk.LabelFrame(commandes, text="fonctions", padx=5, pady=5) fonctions.pack(fill="both") btn_sinus = tk.Button(fonctions, text='sin', command=lambda : self.evaluer("sin",1)) btn_sinus.pack(side="left") btn_sinus = tk.Button(fonctions, text='cos', command=lambda : self.evaluer("cos",1)) btn_sinus.pack(side="left") btn_sinus = tk.Button(fonctions, text='tan', command=lambda : self.evaluer("tan",1)) btn_sinus.pack(side="left") btn_pow = tk.Button(fonctions, text='^', command=lambda : self.evaluer("^",2)) btn_pow.pack(side="right") def create_menu_bar(self): menu_bar = tk.Menu(self) menu_file = tk.Menu(menu_bar, tearoff=0) menu_file.add_command(label="Quitter", command=self.master.destroy) menu_bar.add_cascade(label="Fichier", menu=menu_file) menu_affichage = tk.Menu(menu_bar, tearoff=0) menu_mode = tk.Menu(menu_bar, tearoff=0) menu_affichage.add_command(label="préfixe (polonaise)", command=lambda : self.change_affichage("pre")) menu_affichage.add_command(label="infixe", command=lambda : self.change_affichage("inf")) menu_mode.add_command(label="mode interactif", command=lambda : self.change_affichage("post-int")) menu_mode.add_command(label="mode expression", command=lambda : self.change_affichage("post-expr")) menu_affichage.add_cascade(label="postfixe (polonaise inversée)", menu=menu_mode) menu_bar.add_cascade(label="Notation", menu=menu_affichage) menu_help = tk.Menu(menu_bar, tearoff=0) menu_help.add_command(label="Aide", command=self.aide) menu_help.add_command(label="À propos", command=self.about) menu_bar.add_cascade(label="Aide", menu=menu_help) self.master.config(menu=menu_bar) def change_affichage(self, affichage): """change le mode d'affichage et efface les calculs en cours""" self.etat_affichage = affichage etat_text = {"pre":"notation préfixée (polonaise)", "inf":"notation infixée", "post-int":"notation postfixée (polonaise inversée) -- mode interactif", "post-expr": "notation postfixée (polonaise inversée) -- mode expression" } self.etat.config(text=etat_text[affichage]) self.affichage_expression.config(text="") self.effacer_tt() self.saisie_expression.delete(0 ,'end') def do_something(self): pass def aide(self): """affiche l'aide""" messagebox.showinfo("Aide", "...") def about(self): """à propos de cette application""" messagebox.showinfo("À propos", "Ceci est une calculatrice.") def evaluer(self, op, nb_arg): """affiche une erreur s'il n'y a pas assez d'arguments ; application de l'operation aux nb_arg dernières valeurs du stack ; si nb_arg == -1 alors toutes les valeurs du stack sont utilisées""" if nb_arg == -1: if self.stack.est_vide(): messagebox.showerror("Pas assez d'arguments", "Il n'y a pas d'arguments") return lst_val = [] while not self.stack.est_vide(): lst_val.append(self.stack.depiler().valeur) if op == "somme": res = 0 for val in lst_val: res += val if op == "produit": res = 1 for val in lst_val: res *= val if self.stack.taille() < nb_arg: if nb_arg - self.stack.taille() == 1: messagebox.showerror("Pas assez d'arguments", "Il manque 1 argument") else: messagebox.showerror("Pas assez d'arguments", "Il manque "+str(nb_arg - self.stack.taille())+" arguments") return if nb_arg == 1: val = self.stack.depiler().valeur if op == "sin": res = sin(val) if op == "cos": res = cos(val) if op == "tan": res = tan(val) if op == "!": res = factorial(val) elif nb_arg == 2: droite = self.stack.depiler().valeur gauche = self.stack.depiler().valeur if op == "+": res = gauche + droite if op == "-": res = gauche - droite if op == "*": res = gauche * droite if op == "/": res = gauche / droite if op == "^": res = gauche ** droite elif nb_arg == 3: terme3 = self.stack.depiler().valeur terme2 = self.stack.depiler().valeur terme1 = self.stack.depiler().valeur if op == "moy3": res = (terme1 + terme2 + terme3)/3 self.stack.empiler(ValeurSaisie(res, self.frame_stack)) def entrer(self): """si dans mode npi: si dans interactif alors ajoute nv terme si dans expression alors evalue l'expression""" #completer les différents cas pour les autres notations if self.etat_affichage == "post-int": self.entrer_terme_dans_stack() if self.etat_affichage == "post-expr": self.evaluer_prepostfixe() if self.etat_affichage == "pre": self.evaluer_prepostfixe() def evaluer_prepostfixe(self): """evalue la chaine de caractère dans le champ de saisie comme une expression en notation polonaise ou npi selon l'affichage""" #simplifier les conditions (plus tard) - ça m'a l'air pas mal expr = self.saisie_expression.get() if self.etat_affichage == "pre": expr = expr[::-1] expr = expr.split() try: arbre_expr = npi2tree(expr) self.affichage_expression.config(text = str(arbre_expr) + "=" + str(arbre_expr.evalue())) except IndexError: messagebox.showerror("Erreur","Erreur") def entrer_terme_dans_stack(self): """si nombre : ajoute une nouvelle valeur dans le stack ajoute un label avec cette valeur si fonction : appelle la fonction évaluer""" valeur_a_ajouter = self.saisie_expression.get().replace(" ", "") if valeur_a_ajouter != "": if "." in valeur_a_ajouter: valeur_a_ajouter = float(valeur_a_ajouter) self.stack.empiler(ValeurSaisie(valeur_a_ajouter, self.frame_stack)) elif valeur_a_ajouter in ["sin","cos","tan","!"]: self.evaluer(valeur_a_ajouter,1) elif valeur_a_ajouter in ["+","-","/","*","^"]: self.evaluer(valeur_a_ajouter,2) elif valeur_a_ajouter in ["moy3"]: self.evaluer(valeur_a_ajouter,3) elif valeur_a_ajouter in ["somme","produit"]: self.evaluer(valeur_a_ajouter,-1) elif valeur_a_ajouter == "pi": self.stack.empiler(ValeurSaisie(pi, self.frame_stack)) else: try: valeur_a_ajouter = int(valeur_a_ajouter) self.stack.empiler(ValeurSaisie(valeur_a_ajouter, self.frame_stack)) except ValueError: messagebox.showerror("Saisie invalide", "Vous n'avez pas entré un nombre, ou la fonction est inconnue") self.saisie_expression.delete(0 ,'end') def effacer_tt(self): """supprime tout le contenu de la pile (et les labels associés)""" while not self.stack.est_vide(): self.stack.depiler() self.frame_stack.config(height = 1) def effacer_dernier(self): """supprime la dernière valeur entrée (et le label associés)""" if not self.stack.est_vide(): self.stack.depiler() if __name__ == "__main__": root = tk.Tk() root.title("Calculatrice") root.geometry("350x500") hello_frame = Interface(root) hello_frame.mainloop()