# encoding: utf-8 from tkinter import * from tkinter import messagebox from PIL import Image, ImageTk import math from time import sleep from dbUtil import DbUtil class Message(Canvas): # todo: 日志消息类 def __init__(self, master, **kwargs): super().__init__(master, **kwargs) self.message = [] self.master = master self.scrollbar = Scrollbar(master, orient="vertical", command=self.yview) self.scrollbar.pack(side="right", fill=BOTH) self.config(yscrollcommand=self.scrollbar.set) def show_message(self, message, color="white"): # todo: 添加日志消息 self.message.append({"message": message, "color": color}) num = 0 self.delete("message") for function in self.message: self.create_text(20, 25 * num + 10, anchor="nw", text=function["message"], font=("", 15), fill=function["color"], tags="message") num += 1 self.update() self.configure(scrollregion=self.bbox("all")) self.scrollbar.set(1.0, 1.0) self.yview_moveto(1.0) class AddFractal(Toplevel): def __init__(self, master, _type, fractal_id=None, *args, **kwargs): super().__init__(*args, **kwargs) self.transient(root) self.master = master self.type = _type self.fractal_id = fractal_id self.cv = Canvas(self, width=screen_width * 0.5, height=screen_height * 0.7) self.cv.place(x=0, y=0, anchor=NW) self.label_width, self.label_height = 140, 40 self.top_window_back_img = ImageTk.PhotoImage( Image.open("./images/大背景@3x.jpg").resize((int(screen_width * 0.5), int(screen_height * 0.7)))) self.save_img = ImageTk.PhotoImage(Image.open("./images/保存@3x.png").resize((100, self.label_height))) self.update_img = ImageTk.PhotoImage(Image.open("./images/修改@3x.png").resize((100, self.label_height))) self.add_var_img = ImageTk.PhotoImage(Image.open("./images/添加变量@3x.png").resize((100, self.label_height))) self.cv.create_image(0, 0, image=self.top_window_back_img, anchor=NW) self.var_data_dict = {} self.init_window() if self.type == "update": self.load_fractal_data() def load_fractal_data(self): fractal = DbUtil.query_fractal_by_id(self.fractal_id).iloc[0] self.fractal_name.insert(0, str(fractal["name"])) self.fractal_e_name.insert(0, str(fractal["e_name"])) self.basic_pattern.insert(0.0, "\n".join(str(fractal["basic_pattern"]).split("\n")[:-1])) self.function_code.insert(0.0, "\n".join(str(fractal["function_code"]).split("\n")[:-1])) self.basic_execute_function.insert(0, str(fractal["basic_pattern"]).split("\n")[-1]) self.function_code_execute_function.insert(0, str(fractal["function_code"]).split("\n")[-1]) fractal_var = DbUtil.query_fractal_var_by_id(self.fractal_id) for i in fractal_var.itertuples(index=False): self.var_tree.insert("end", f"{i[2]} : {i[0]} = {i[1]}") def create_label(self, x, y, img, label_text, entry_width=200): self.cv.create_image(x, y, image=img, anchor=NW) self.cv.create_text(x + self.label_width / 2, y + self.label_height / 2, text=label_text, font=("黑体", 12), fill="black") entry = Entry(self.cv, font=("Arial", 18, "bold")) entry.place(x=x + self.label_width, y=y, width=entry_width, height=40, anchor=NW) return entry def add_var(self): """ todo: 添加一个变量 :return: """ fractal_comment = self.fractal_comment.get() fractal_var_name = self.fractal_var_name.get() fractal_var_value = self.fractal_var_value.get() if fractal_var_name.strip() == "" and fractal_var_value.strip() == "" and fractal_comment.strip() == "": messagebox.showwarning("提示", "变量名称,变量注释和变量值不能为空!") return if fractal_var_name in self.var_data_dict: messagebox.showerror("提示", "该变量已经存在!") self.fractal_comment.delete(0, "end"), self.fractal_var_name.delete(0, "end"), self.fractal_var_value.delete(0, "end") return self.var_data_dict[fractal_var_name] = (fractal_comment, fractal_var_value) self.var_tree.insert("end", f"{fractal_comment} : {fractal_var_name} = {fractal_var_value}") self.fractal_comment.delete(0, "end"), self.fractal_var_name.delete(0, "end"), self.fractal_var_value.delete(0, "end") def save(self): fractal_name = self.fractal_name.get() fractal_e_name = self.fractal_e_name.get() basic_execute_function = self.basic_execute_function.get() function_code_execute_function = self.function_code_execute_function.get() function_code = self.function_code.get(0.0, "end") basic_pattern = self.basic_pattern.get(0.0, "end") if fractal_name.strip() == "" \ and fractal_e_name == "" \ and basic_execute_function.strip() == ""\ and basic_pattern.strip() == ""\ and function_code.strip() == ""\ and function_code_execute_function.strip() == "": messagebox.showwarning("提示", "值不能为空!") return function_code = function_code + "\n" + function_code_execute_function basic_pattern = basic_pattern + "\n" + basic_execute_function if self.type == "update": DbUtil.update_to_fractal(self.fractal_id, fractal_name, fractal_e_name, basic_pattern, function_code) for key, data in self.var_data_dict.items(): DbUtil.insert_to_var(key, data[1], data[0], self.fractal_id) self.master.master.message.show_message("更新成功!") else: id = DbUtil.insert_to_fractal(fractal_name, fractal_e_name, basic_pattern, function_code) for key, data in self.var_data_dict.items(): DbUtil.insert_to_var(key, data[1], data[0], id) self.master.master.message.show_message("添加成功!") self.destroy() self.master.master.flush() def init_window(self): self.label_img = ImageTk.PhotoImage( Image.open("./images/文字背景@3x.png").resize((self.label_width, self.label_height))) self.fractal_name = self.create_label(50, 30, self.label_img, "分形名称") self.fractal_e_name = self.create_label(50, 30 + self.label_height + 15, self.label_img, "分形英文名称") self.fractal_comment = self.create_label(50, 30 + (self.label_height + 15) * 2, self.label_img, "变量注释") self.fractal_var_name = self.create_label(50, 30 + (self.label_height + 15) * 3, self.label_img, "变量名称") self.fractal_var_value = self.create_label(50, 30 + (self.label_height + 15) * 4, self.label_img, "变量值") self.basic_execute_function = self.create_label(50, 30 + (self.label_height + 15) * 5, self.label_img, "基本图案调用函数") self.function_code_execute_function = self.create_label(50 + 15 + self.label_width + 300 + 30, 30 + (self.label_height + 15) * 5, self.label_img, "分形树调用函数", entry_width=250) Button(self.cv, image=self.add_var_img, command=self.add_var, bd=0, relief="solid", bg="#f7f7f7", highlightthickness=0, ).place(x=50 + 15 + self.label_width + 200, y=30 + (self.label_height + 15) * 4, width=100, height=self.label_height, anchor=NW) Button(self.cv, image=self.save_img if self.type == "add" else self.update_img, command=self.save, bd=0, relief="solid", bg="#f7f7f7", highlightthickness=0, ).place(x=50 + 15 + self.label_width + 200, y=30 + (self.label_height + 15) * 7 - 15 + 300 - self.label_height, width=100, height=self.label_height, anchor=NW) list_frame = Frame(self.cv) list_frame.place(x=50 + 15 + self.label_width + 300 + 30, y=30, height=(self.label_height + 15) * 5 - 15, width=400) self.var_tree = Listbox(list_frame, font=("Arial", 14), bg="#bce7f7", highlightthickness=0, highlightcolor="#bce7f7") self.var_tree.pack(side="left", fill="both", expand=True) scrollbar = Scrollbar(list_frame, command=self.var_tree.yview) scrollbar.pack(side="right", fill="y") self.var_tree.config(yscrollcommand=scrollbar.set) self.basic_label_image = ImageTk.PhotoImage(Image.open("./images/文字背景@3x.png").resize((self.label_width + 200, 30))) self.cv.create_image(50, (self.label_height + 15) * 7 - 15, image=self.basic_label_image, anchor=NW) self.cv.create_text(50 + (self.label_width + 200) / 2, (self.label_height + 15) * 7, text="基本图案绘制函数", font=("黑体", 14)) self.basic_pattern = Text(self.cv, font=("Arial", 14), bg="#bce7f7", highlightthickness=0,) self.basic_pattern.place(x=50, y=(self.label_height + 15) * 7 + 15, width=self.label_width + 200, height=300) self.function_code_label_image = ImageTk.PhotoImage(Image.open("./images/文字背景@3x.png").resize((400, 30))) self.cv.create_image(50 + 15 + self.label_width + 300 + 30, (self.label_height + 15) * 7 - 15, image=self.function_code_label_image, anchor=NW) self.cv.create_text(50 + 15 + self.label_width + 300 + 30 + 400 / 2, (self.label_height + 15) * 7, text="分形树绘制函数", font=("黑体", 14)) self.function_code = Text(self.cv, font=("Arial", 14), bg="#bce7f7", highlightthickness=0, ) self.function_code.place(x=50 + 15 + self.label_width + 300 + 30, y=(self.label_height + 15) * 7 + 15, width=400, height=300) class SelectFractalFrame(Frame): # todo: 右上方分形图案单选框类 def __init__(self, master, *args, ** kwargs): super().__init__(master, *args, **kwargs) self.db = DbUtil() self.width = int(self.cget("width")) self.height = int(self.cget("height")) self.img = ImageTk.PhotoImage(Image.open("./images/上部背景@3x.png").resize( (int(self.width), self.height))) Label(self, width=self.width, height=self.height, image=self.img).place(x=0, y=0, anchor=NW) Label(self, text="分形图案类型", font=("黑体", 14, "bold"), bg="#f7f7f7", ).place(x=10, y=10) self.button_img = ImageTk.PhotoImage(Image.open("./images/新增分形图案类型@3x.png").resize((120, 36))) Button(self, image=self.button_img, bd=0, relief="solid", bg="#f7f7f7", highlightthickness=0, command=self.add_fractal_tree).place(x=280, y=8) self.update_button_img = ImageTk.PhotoImage(Image.open("./images/修改分形图案@3x.png").resize((120, 36))) Button(self, image=self.update_button_img, bd=0, relief="solid", bg="#f7f7f7", highlightthickness=0, command=self.update_fractal_tree).place(x=150, y=8) self.select_frame = Frame(self, width=self.width, height=self.height * 0.8, bg="#f7f7f7") self.select_frame.place(x=0, y=self.height * 0.2) self.create_select_menu() def add_fractal_tree(self): screen_width = root.winfo_screenwidth() # winfo方法来获取当前电脑屏幕大小 screen_height = root.winfo_screenheight() x, y = int(screen_width - screen_width * 0.5) // 2, int(screen_height - screen_height * 0.6) // 2 top_window = AddFractal(self, "add", width=screen_width * 0.5, height=screen_height * 0.7) top_window.geometry(f'{int(screen_width * 0.5)}x{int(screen_height * 0.7)}+{x}+{y}') top_window.mainloop() def update_fractal_tree(self): screen_width = root.winfo_screenwidth() # winfo方法来获取当前电脑屏幕大小 screen_height = root.winfo_screenheight() x, y = int(screen_width - screen_width * 0.5) // 2, int(screen_height - screen_height * 0.6) // 2 top_window = AddFractal(self, "update", width=screen_width * 0.5, height=screen_height * 0.7, fractal_id=self.master.chose_fractal.get()) top_window.geometry(f'{int(screen_width * 0.5)}x{int(screen_height * 0.7)}+{x}+{y}') top_window.mainloop() def create_select_menu(self): # todo: 创建分形图案单选框 data_frame = self.db.execute("select * from fractal") yscro = Scrollbar(self.select_frame, orient=VERTICAL) yscro.place(x=self.width - 20, y=0, height=self.height * 0.8, width=20, anchor='nw') canvas = Canvas(self.select_frame, width=self.width - 20, height=self.height * 0.8, bg="#f7f7f7") canvas.place(x=0, y=0, anchor='nw') f2 = Frame(canvas, bg="#f7f7f7", width=self.width * 0.8, height=self.height * 0.8) canvas.create_window((0, 0), window=f2, anchor=NW) self.master.chose_fractal = IntVar() self.master.chose_fractal.set(data_frame.loc[0:]["id"].tolist()[0]) for data in data_frame.itertuples(index=False): f_id, name, e_name, basic_pattern, function_code = data[0], data[1], data[2], data[3], data[4] Radiobutton(f2, text=f"{name} {e_name}", value=f_id, command=lambda message=f"{name} {e_name}": self.master.update_select(message), variable=self.master.chose_fractal, font=("", 18), bg="#f7f7f7").pack(ipadx=10, anchor="w") canvas.update() canvas.config(scrollregion=canvas.bbox("all"), yscrollcommand=yscro.set) # 设置画布的滚动区域 yscro.config(command=canvas.yview) class FormFractalFrame(Frame): # todo: 右下方变量填写类 def __init__(self, master, *args, **kwargs): super().__init__(master, *args, **kwargs) self.db = DbUtil() self.width = int(self.cget("width")) self.height = int(self.cget("height")) self.var_dict = {} self.img = ImageTk.PhotoImage(Image.open("./images/上部背景@3x.png").resize( (int(self.width), self.height))) Label(self, width=self.width, height=self.height, image=self.img).place(x=0, y=0, anchor=NW) Label(self, text="分形参数设置", font=("黑体", 14, "bold"), bg="#f7f7f7", ).place(x=10, y=10) self.create_form() self.button_img = ImageTk.PhotoImage(Image.open("./images/基本图案绘制@3x.png").resize((90, 36))) Button(self, image=self.button_img, bd=0, relief="solid", bg="#f7f7f7", highlightthickness=0, command=self.master.basic_tree_canvas.draw_basic_tree).place(x=10, y=self.height - 50) self.button2_img = ImageTk.PhotoImage(Image.open("./images/绘制参数更新@3x.png").resize((90, 36))) Button(self, image=self.button2_img, bd=0, relief="solid", bg="#f7f7f7", highlightthickness=0, command=self.update_fractal_var).place(x=100 + 5, y=self.height - 50) self.button3_img = ImageTk.PhotoImage(Image.open("./images/绘制@3x.png").resize((70, 36))) Button(self, image=self.button3_img, bd=0, relief="solid", bg="#f7f7f7", highlightthickness=0, command=self.master.fractal_tree_canvas.draw_fractal_tree).place(x=100 * 2 + 5, y=self.height - 50) self.button4_img = ImageTk.PhotoImage(Image.open("./images/删除图案@3x.png").resize((90, 36))) Button(self, image=self.button4_img, bd=0, relief="solid", bg="#f7f7f7", highlightthickness=0, command=self.delete_fractal).place(x=95 * 3, y=self.height - 50) def delete_fractal(self): """ 删除分形树 :return: """ result = messagebox.askquestion("确认框", "您确定要执行此操作吗?") if not result == "yes": return fractal_id = self.master.chose_fractal.get() DbUtil.delete_fractal(fractal_id) self.master.flush() self.master.message.show_message("删除成功!") def update_fractal_var(self): # todo: 绘制参数更新 try: for key, value in self.var_dict.items(): sql = "update fractal_var set value='{}' where fractal_id={} and name='{}'".format(value.get(), self.master.chose_fractal.get(), key) self.db.update(sql) self.master.message.show_message("参数更新成功!") except Exception as E: self.master.message.show_message(f"{E}", "red") def create_form(self): # todo: 分形图案变量生成 data_frame = self.db.query_fractal_var_by_id(self.master.chose_fractal.get()) self.select_frame = Frame(self, width=self.width, height=self.height * 0.6, bg="#f7f7f7") self.select_frame.place(x=0, y=self.height * 0.2) yscro = Scrollbar(self.select_frame, orient=VERTICAL) yscro.place(x=self.width - 20, y=0, height=self.height * 0.6, width=20, anchor='nw') canvas = Canvas(self.select_frame, width=self.width - 20, height=self.height * 0.6, bg="#f7f7f7") canvas.place(x=0, y=0, anchor='nw') f2 = Frame(canvas, bg="#f7f7f7", width=self.width * 0.8, height=self.height * 0.6) canvas.create_window((0, 0), window=f2, anchor=NW) self.var_dict = {} for data in data_frame.itertuples(): index, name, value, comment, value_type = data[0], data[1], data[2], data[3], data[4] Label(f2, text=f"{comment}:{name}=", width=20, font=("黑体", 14, "bold"), anchor=W, bg="#f7f7f7").grid(row=index, column=0, padx=10, pady=10) self.var_dict[name] = Entry(f2, font=("黑体", 14, "bold")) self.var_dict[name].insert(0, value) self.var_dict[name].grid(row=index, column=1, pady=10) self.master.message.show_message(f"\t{comment}:{name} = {value}") canvas.update() canvas.config(scrollregion=canvas.bbox("all"), yscrollcommand=yscro.set) # 设置画布的滚动区域 yscro.config(command=canvas.yview) class BasicTree(Canvas): # todo: 基本图案绘制画布类 def __init__(self, master, *args, **kwargs): super().__init__(master, *args, **kwargs) self.db = DbUtil() self.width = int(self.cget("width")) self.height = int(self.cget("height")) self.background_img = ImageTk.PhotoImage(Image.open("./images/全览图@3x.png").resize((self.width + 20, self.height + 20))) self.create_image(-5, -5, image=self.background_img, anchor=NW) def draw_basic_tree(self): # todo: 绘制基本图案 self.delete("all") data_frame = self.db.query_fractal_by_id(self.master.chose_fractal.get()) params = { "canvas": self } try: exec(data_frame["basic_pattern"].tolist()[0], params) self.master.message.show_message(f"基本图案绘制成功!") except Exception as E: self.master.message.show_message(f"{E}", color="red") class FractalTreeCanvas(Canvas): # todo: 绘制分形树画布 def __init__(self, master, *args, **kwargs): super().__init__(master, *args, **kwargs) self.db = DbUtil() self.width = int(self.cget("width")) self.height = int(self.cget("height")) def draw_fractal_tree(self): # todo: 绘制分形树 try: self.delete("all") data_frame = self.db.query_fractal_by_id(self.master.chose_fractal.get()) fractal_var = self.db.query_fractal_var_by_id(self.master.chose_fractal.get()) params = {fractal_var["name"].tolist()[i]: eval(fractal_var["value"].tolist()[i]) for i in range(len(fractal_var["name"].tolist()))} params["canvas"] = self params["math"] = math params["sleep"] = sleep exec(data_frame["function_code"].tolist()[0], params) self.master.message.show_message("分形树绘制成功!") except Exception as E: self.master.message.show_message(f"{E}", "red") class FractalTree(Canvas): def __init__(self, master, *args, **kwargs): super().__init__(master, *args, **kwargs) self.db = DbUtil() self.width = int(self.cget("width")) self.height = int(self.cget("height")) self.background_image = ImageTk.PhotoImage(Image.open("./images/大背景@3x.jpg").resize((self.width, self.height))) self.create_image(0, 0, image=self.background_image, anchor=NW) self.chose_fractal = 1 self.function_code = "" self.fractal_var = {} self.init_window() def update_select(self, message): # todo: 切换分形图案 self.message.show_message(f"选择了{message},参数如下:") self.form_fractal_frame.create_form() def flush(self): self.select_fractal_frame.create_select_menu() self.form_fractal_frame.create_form() def init_window(self): """ 初始化窗口,创建窗口并布局 :return: """ # 创建下方消息显示框 message_frame = Frame(self, width=self.width - 60, height=self.height * 0.2) message_frame.place(x=15, y=self.height * 0.8 + 15, anchor=NW) self.message = Message(message_frame, width=self.width - 60, height=self.height * 0.2 - 30) self.message.pack(anchor=NW) self.message.configure(bg="#85bbd1") # 分形树画布 self.fractal_tree_canvas = FractalTreeCanvas(self, width=self.width * 0.73 - 10, height=self.height * 0.8 + 12, highlightthickness=0, bg="#b5e6f5") self.fractal_tree_canvas.place(x=0, y=0, anchor=NW) # 基本图形绘制框 self.basic_tree_canvas = BasicTree(self, width=150, height=150, bg="#e0eaf5", bd=0) self.basic_tree_canvas.place(x=15, y=self.height * 0.8 - 150, anchor=NW) # 创建左上方分形图案选择框 self.select_fractal_frame = SelectFractalFrame(self, width=self.width * 0.27 - 10, height=int((self.height * 0.8) / 2) - 10) self.select_fractal_frame.place(x=self.width * 0.73, y=10, anchor=NW) # 创建左下方输入框 self.form_fractal_frame = FormFractalFrame(self, width=self.width * 0.27 - 10, height=int((self.height * 0.8) / 2)) self.form_fractal_frame.place(x=self.width * 0.73, y=self.height * 0.8 / 2 + 10, anchor=NW) if __name__ == '__main__': # 创建主窗口 root = Tk() root.title('分形树') screen_width = root.winfo_screenwidth() # winfo方法来获取当前电脑屏幕大小 screen_height = root.winfo_screenheight() root_attr = { "width": screen_width * 0.8, "height": screen_height * 0.8, } size = '%dx%d+%d+%d' % (root_attr['width'], root_attr['height'], (screen_width - root_attr['width']) / 2, (screen_height - root_attr['height']) / 2 - 30) root.geometry(size) tree = FractalTree(root, width=root_attr["width"], height=root_attr["height"]) tree.place(x=0, y=0, anchor=NW) root.mainloop()