Browse Source

erreurs fonctionnelles ; changement de mode possible sauf infixe (pas développé) ; ajout opérateurs ; menu ; ajout constante (pi) ; pas de gestion des overflow ; nombres décimaux et négatifs fonctionnels

master
bollet.c 7 months ago
parent
commit
1b91e9e7b0
  1. 25
      expression.py
  2. 225
      test_interface.py

25
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()

225
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("<Return>", lambda e : self.entrer())
self.saisie_expression.bind("<KP_Enter>", 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__":

Loading…
Cancel
Save