From 1b91e9e7b0d6b74a2738cf9164215f5989dcd534 Mon Sep 17 00:00:00 2001 From: "bollet.c" <> Date: Sat, 17 Feb 2024 23:51:20 +0100 Subject: [PATCH] =?UTF-8?q?erreurs=20fonctionnelles=20;=20changement=20de?= =?UTF-8?q?=20mode=20possible=20sauf=20infixe=20(pas=20d=C3=A9velopp=C3=A9?= =?UTF-8?q?)=20;=20ajout=20op=C3=A9rateurs=20;=20menu=20;=20ajout=20consta?= =?UTF-8?q?nte=20(pi)=20;=20pas=20de=20gestion=20des=20overflow=20;=20nomb?= =?UTF-8?q?res=20d=C3=A9cimaux=20et=20n=C3=A9gatifs=20fonctionnels?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- expression.py | 25 +++++- test_interface.py | 225 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 199 insertions(+), 51 deletions(-) diff --git a/expression.py b/expression.py index dbbea1e..cf715d6 100644 --- a/expression.py +++ b/expression.py @@ -1,4 +1,5 @@ from Pile import Pile_chaine as Pile +from math import * class Expression: def __init__(self, racine, gauche, droit): @@ -8,7 +9,16 @@ class Expression: self.droit = droit def evalue(self): - """renvoie la valeur de l'expression""" + """renvoie la valeur de l'expression + si 1 seul argument alors on prend le fils gauche""" + #fonction unaires + if self.racine == "sin": + return sin(self.gauche.evalue()) + if self.racine == "cos": + return cos(self.gauche.evalue()) + if self.racine == "tan": + return tan(self.gauche.evalue()) + #fonctions binaires if self.racine == "+": return self.gauche.evalue() + self.droit.evalue() if self.racine == "-": @@ -17,16 +27,21 @@ class Expression: return self.gauche.evalue() * self.droit.evalue() if self.racine == "/": return self.gauche.evalue() / self.droit.evalue() + if self.racine == "^": + return self.gauche.evalue() ** self.droit.evalue() + if "." in self.racine: + return float(self.racine) return int(self.racine) def __str__(self): """affiche l'expression""" #temporaire - if self.racine in ["+", "*", "-", "/"]: + if self.racine in ["+", "*", "-", "/", "^"]: return "(" + str(self.gauche) + self.racine + str(self.droit) + ")" - + if self.racine in ["sin","cos","tan"]: + return self.racine + "(" + str(self.gauche) + ")" return str(self.racine) @@ -34,8 +49,10 @@ def npi2tree(liste_en_npi): """conversion d'une liste en NPI en un arbre""" pile_expr = Pile() for element in liste_en_npi: - if element in ["+", "*","-","/"]: + if element in ["+", "*","-","/", "^"]: pile_expr.empiler(Expression(element, pile_expr.depiler(),pile_expr.depiler())) + elif element in ["sin","cos","tan"]: + pile_expr.empiler(Expression(element, pile_expr.depiler(),None)) else: pile_expr.empiler(Expression(element, None, None)) return pile_expr.sommet() \ No newline at end of file diff --git a/test_interface.py b/test_interface.py index 236dd9d..f25957b 100644 --- a/test_interface.py +++ b/test_interface.py @@ -1,6 +1,8 @@ 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""" @@ -8,7 +10,7 @@ class ValeurSaisie: self.valeur = valeur self.label_valeur = tk.Label(master, text=valeur) - self.label_valeur.pack() + self.label_valeur.pack(side="bottom") def __del__(self): """suppression du label""" @@ -20,66 +22,146 @@ class Interface(tk.Frame): 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.saisie_expression = tk.Entry(self.master) - self.saisie_expression.pack() + 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()) - self.saisie_expression.bind("+", lambda e : self.evaluer("+",2)) - self.saisie_expression.bind("-", lambda e : self.evaluer("-",2)) - self.saisie_expression.bind("*", lambda e : self.evaluer("*",2)) - self.saisie_expression.bind("/", lambda e : self.evaluer("/",2)) + btn_entrer = tk.Button(frame_saisie, text='entrer', command=self.entrer) + btn_entrer.pack() - commandes = tk.LabelFrame(self.master, text="commandes", padx=20, pady=20) + commandes = tk.LabelFrame(self.master, text="commandes", padx=5, pady=5) commandes.pack(fill="both") + - btn_calculer = tk.Button(commandes, text='évaluer', command=self.entrer) - btn_calculer.pack(side="left") - btn_effacer = tk.Button(commandes, text='effacer', command=self.effacer) - btn_effacer.pack(side="left") + 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") - btn_sinus = tk.Button(commandes, text='sin', command=lambda : self.evaluer("sin",1)) + 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(commandes, text='cos', command=lambda : self.evaluer("cos",1)) + btn_sinus = tk.Button(fonctions, text='cos', command=lambda : self.evaluer("cos",1)) btn_sinus.pack(side="left") - btn_sinus = tk.Button(commandes, text='tan', command=lambda : self.evaluer("tan",1)) + btn_sinus = tk.Button(fonctions, text='tan', command=lambda : self.evaluer("tan",1)) btn_sinus.pack(side="left") - btn_pow = tk.Button(commandes, text='^', command=lambda : self.evaluer("^",2)) - btn_pow.pack(side="right") + btn_pow = tk.Button(fonctions, text='^', command=lambda : self.evaluer("^",2)) + btn_pow.pack(side="right") - self.affichage_expression = tk.Label(self.master) - self.affichage_expression.pack() + 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) - self.frame_stack = tk.Frame(self.master, bg="gray") - self.frame_stack.pack(padx=10, pady=10) + 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")) - self.error_log = tk.Label(self.master, fg="red") - self.error_log.pack() + 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 evaluer(self, op, nb_arg): - """application de l'operation aux nb_arg dernières valeurs du stack""" - self.entrer() + 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: - try: - droite = self.stack.depiler().valeur - gauche = self.stack.depiler().valeur - except IndexError: - self.error_log.config(text="Il manque un argument") - + droite = self.stack.depiler().valeur + gauche = self.stack.depiler().valeur + if op == "+": res = gauche + droite if op == "-": @@ -90,32 +172,81 @@ class Interface(tk.Frame): 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)) - #https://stackoverflow.com/questions/11541262/basic-query-regarding-bindtags-in-tkinter/11542200#11542200 - return "break" - def entrer(self): - """ajoute une nouvelle valeur dans le stack - ajoute un label avec cette valeur""" + """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: - valeur_a_ajouter = int(valeur_a_ajouter) - - self.stack.empiler(ValeurSaisie(valeur_a_ajouter, self.frame_stack)) + 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(self): - """supprime tout le contenu de la pile et les labels associés""" + + 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__":