diff --git a/main.py b/main.py index 2030fe3..ba547dd 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,6 @@ from data_structure import * import customtkinter as ctk +import math class Expression: """manipule les expression sous forme d'arbre""" @@ -51,31 +52,33 @@ class App(ctk.CTk): super().__init__() self.grid_columnconfigure(0, weight=0) - # Calcul Frame - - self.calcul_frame = ctk.CTkFrame(self,corner_radius=0, fg_color="transparent") - - self.screen = ctk.CTkTextbox(self.calcul_frame) - self.screen.pack(padx=20, pady=20, fill="both", expand=True) - self.numbers = [] - for i, val in enumerate(["(", ")", "/", "^", 7,8,9,"*", 4, 5, 6, "-", 1, 2, 3, "+", "clear", 0, '.', "exe"]): # add numbers button self.numbers.append(ctk.CTkButton(self, text=val)) if val == "clear": - self.numbers[i]._command = self.textbox_clear - elif val == "exe": - self.numbers[i]._command = self.calculate + self.numbers[i]._command = self.clear_screen else: self.numbers[i]._command = lambda x=val: self.add_value(x) - self.numbers[i].grid(row=1+i//4, column=i%4+1, sticky="NSEW", padx=5, pady=5) + self.numbers[i].grid(row=5+i//4, column=i%4+1, sticky="NSEW", padx=5, pady=5) + + # Calcul Frame + + self.calcul_frame = ctk.CTkFrame(self,corner_radius=0, fg_color="transparent") + + self.calcul_screen = ctk.CTkLabel(self.calcul_frame, text="hello") + self.calcul_screen.pack(fill="both", expand=True) + self.calcul_entry = ctk.CTkEntry(self.calcul_frame) + self.calcul_entry.pack(fill="both", expand=True) # Fonction Frame - self.fonction_frame = ctk.CTkFrame(self, corner_radius=0, fg_color="transparent") + self.fonction_frame = ctk.CTkFrame(self, fg_color="transparent") self.fonction_screen = ctk.CTkCanvas(self.fonction_frame) - self.fonction_screen.pack(padx=20, pady=20, fill="both", expand=True) + self.fonction_screen.pack(fill="both", expand=True) + self.fonction_entry = ctk.CTkEntry(self.fonction_frame) + self.fonction_entry.pack(fill="both", expand=True) + # navigation menu @@ -100,6 +103,7 @@ class App(ctk.CTk): self.appearance_mode_menu = ctk.CTkOptionMenu(self.navigation_frame, values=["Light", "Dark", "System"], command=self.change_appearance_mode_event) self.appearance_mode_menu.grid(row=4, column=0, padx=20, pady=20, sticky="s") + self.mode = 'Calcul' # select default frame self.select_frame_by_name("Calcul") @@ -111,11 +115,20 @@ class App(ctk.CTk): # show selected frame if name == "Calcul": - self.calcul_frame.grid(columnspan=4, column=1, row=0, sticky="nsew") + self.mode = "Calcul" + self.calcul_frame.grid(padx=20, pady=20,columnspan=4, column=1, rowspan=5, row=0, sticky="nsew") + self.numbers[-1]._command = self.calculate + else: self.calcul_frame.grid_forget() if name == "Fonction": - self.fonction_frame.grid(columnspan=4, column=1, row=0, sticky="nsew") + self.mode = "Fonction" + self.fonction_frame.grid(columnspan=4, column=1, row=0, padx=20, pady=20, sticky="nsew") + self.fonction_frame.update() + self.fonction_screen_width = self.fonction_screen.winfo_width() + self.numbers[-1]._command = self.draw_graph + self.fonction_screen_height = self.fonction_screen.winfo_height() + print(self.fonction_screen_height) else: self.fonction_frame.grid_forget() @@ -123,20 +136,94 @@ class App(ctk.CTk): ctk.set_appearance_mode(new_appearance_mode) def add_value(self, value) -> None: - self.screen.insert('end', value) - - def textbox_clear(self): - self.screen.delete("0.0", "end") + if self.mode == 'Fonction': + self.fonction_entry.insert("end", value) + else: + self.calcul_entry.insert("end", value) - def draw_framing(self): - pass + def clear_screen(self) -> None: + if self.mode == "Calcul": + self.calcul_screen.configure(text="") + else: + self.fonction_screen.delete('all') + + def draw_framing(self, min_x, max_x, min_y, max_y): + ratio = self.fonction_screen_height / self.fonction_screen_width # longueur par largeur du canvas + + # position du max dans l'interval + abscisse = max_y / (abs(min_y)+abs(max_y)) + ordonnee = max_x / (abs(min_x)+abs(max_x)) + + + for i in range(20):# dessin des lignes verticales + if i == int(20*ordonnee): + self.fonction_screen.create_line(0 + i * self.fonction_screen_width/20, 0, 0 + i * self.fonction_screen_width/20, self.fonction_screen_height, fill='red', width=4) + text = self.fonction_screen.create_text(0 + i * self.fonction_screen_width/20, 10, text=max_y) + rect = self.fonction_screen.create_rectangle(self.fonction_screen.bbox(text),fill="white") + self.fonction_screen.tag_lower(rect, text) + + text = self.fonction_screen.create_text(0 + i * self.fonction_screen_width/20, self.fonction_screen_height - 10, text=min_y) + rect = self.fonction_screen.create_rectangle(self.fonction_screen.bbox(text),fill="white") + self.fonction_screen.tag_lower(rect, text) + else: + self.fonction_screen.create_line(0 + i * self.fonction_screen_width/20, 0, 0 + i * self.fonction_screen_width/20, self.fonction_screen_height, fill='red') + coo_abscisse = self.fonction_screen_height * ordonnee % 20 -6 # décalage modulo 20 par rapport à l'origine + nb_abscisse_lines = math.ceil(20*ratio)+1 # nombres de lignes horizontales à tracer + for i in range(nb_abscisse_lines): # dessin des lignes verticales + if i == int(nb_abscisse_lines * abscisse): # tracer de l'axe des abscisses + self.fonction_screen.create_line(0, 0 + i * self.fonction_screen_width/20 - coo_abscisse, self.fonction_screen_width, 0 + i * self.fonction_screen_width/20 - coo_abscisse, fill='red', width=4) + text = self.fonction_screen.create_text(15, 0 + i * self.fonction_screen_width/20 - coo_abscisse, text=min_x) + rect = self.fonction_screen.create_rectangle(self.fonction_screen.bbox(text),fill="white") + self.fonction_screen.tag_lower(rect, text) + + text = self.fonction_screen.create_text(self.fonction_screen_width - 15, 0 + i * self.fonction_screen_width/20 - coo_abscisse, text=max_x) + rect = self.fonction_screen.create_rectangle(self.fonction_screen.bbox(text),fill="white") + self.fonction_screen.tag_lower(rect, text) + else: + self.fonction_screen.create_line(0, 0 + i * self.fonction_screen_width/20 - coo_abscisse, self.fonction_screen_width, 0 + i * self.fonction_screen_width/20 - coo_abscisse, fill='red') def calculate(self) -> None: - exp = list(self.screen.get("0.0", "end").strip()) + exp = list(self.calcul_entry.get()) exp = inf2npi(exp) result = npi2tree(exp).evalue() - self.textbox_clear() - self.screen.insert("end", result) + self.calcul_screen.configure(text=result) + + def draw_graph(self): + self.fonction_screen.delete('all') + self.fonction_points = npi2tree(inf2npi(parse_string_to_list(self.fonction_entry.get()))).valeurs_de_fonction() + max_y = max(self.fonction_points,key=lambda item:item[1])[1] + min_y = min(self.fonction_points,key=lambda item:item[1])[1] + self.draw_framing(-100, 100, min_y, max_y) + for x, y in self.fonction_points: + image_x = self.fonction_screen_width / 2 + x * (self.fonction_screen_width/len(self.fonction_points)) + image_y = self.fonction_screen_height - (y - min_y) * self.fonction_screen_height / (abs(max_y)+abs(min_y)) - 3 + self.fonction_screen.create_rectangle(image_x, image_y, image_x, image_y) + + +def parse_string_to_list(text: str) -> list: + text = list(text) + result = [] + elem = "" + for char in text: + if char.isdigit(): + elem += char + elif char == 'x': + result.append(char) + else: + if len(elem) != 0: + result.append(elem) + elem = "" + result.append(char) + if len(elem) != 0: + result.append(elem) + elem = "" + + return result + + + + + def npi2tree(expr: list) -> Expression: @@ -189,10 +276,7 @@ def inf2npi(expr: list) -> list: return output # [3, '-', 6, '*', 4, '+', 3] -exp = inf2npi(list('x^2')) -print(npi2tree(exp).evalue(2)) - -print(npi2tree(exp).valeurs_de_fonction()) - +print(parse_string_to_list('x')) +print(inf2npi(parse_string_to_list('x'))) gui = App() gui.mainloop() \ No newline at end of file