You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

411 lines
21 KiB

# 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.65, height=screen_height * 0.8)
self.width, self.height = int(screen_width * 0.65), int(screen_height * 0.8)
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.65), int(screen_height * 0.8))))
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.cv.create_image(0, 0, image=self.top_window_back_img, anchor=NW)
self.var_data_dict = {}
if self.type == "update":
fractal = DbUtil.query_fractal_by_id(self.fractal_id).iloc[0]
self.is_default = fractal["is_default"]
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])
self.var_tree.insert(0.0, "\n".join(str(fractal["vars"]).split("\n")[:-1]))
if self.is_default == 0:
self.fractal_name.config(state="readonly")
self.fractal_e_name.config(state="readonly")
self.basic_pattern.config(state="disabled")
self.basic_execute_function.config(state="readonly")
self.function_code_execute_function.config(state="readonly")
self.var_tree.config(state="disabled")
self.function_code.config(state="disabled")
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 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")
vars = self.var_tree.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, vars)
self.master.master.message.show_message("更新成功!")
else:
id = DbUtil.insert_to_fractal(fractal_name, fractal_e_name, basic_pattern, function_code, vars)
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(35, 30, self.label_img, "分形名称", int((self.width - 100) / 2 - 140))
self.fractal_e_name = self.create_label(35 + int((self.width - 100) / 2) + 30, 30, self.label_img,
"分形英文名称", int((self.width - 100) / 2 - 140))
self.basic_execute_function = self.create_label(35, 30 + (self.label_height + 15) * 1, self.label_img,
"基本图案调用函数", int((self.width - 100) / 2 - 140))
self.function_code_execute_function = self.create_label(35 + int((self.width - 100) / 2) + 30,
30 + (self.label_height + 15) * 1, self.label_img,
"分形树调用函数",
entry_width=int((self.width - 100) / 2 - 140))
if self.is_default != 0:
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=(self.width - 100) / 2, y=self.height - 60, width=100,
height=self.label_height, anchor=NW)
self.basic_label_image = ImageTk.PhotoImage(
Image.open("./images/文字背景@3x.png").resize((int((self.width - 100) / 2), 30)))
# 分形树绘制表单
self.cv.create_image(35 + int((self.width - 100) / 2) + 30, 30 + (self.label_height + 15) * 2,
image=self.basic_label_image, anchor=NW)
self.cv.create_text(35 + int((self.width - 100) / 2) + 30 + int((self.width - 100) / 4),
30 + (self.label_height + 15) * 2 + 15, text="分形图案绘制函数", font=("黑体", 14))
self.function_code = Text(self.cv, font=("Arial", 14), bg="#bce7f7", highlightthickness=0,
highlightcolor="#bce7f7",
spacing1=5, spacing2=3, spacing3=3, wrap="none")
self.function_code.place(x=35 + int((self.width - 100) / 2) + 30, y=30 + (self.label_height + 15) * 2 + 30,
height=self.height - 250, width=int((self.width - 100) / 2))
# 基本图形绘制表单
self.cv.create_image(35, 30 + (self.label_height + 15) * 2, image=self.basic_label_image, anchor=NW)
self.cv.create_text(35 + int((self.width - 100) / 4), 30 + (self.label_height + 15) * 2 + 15,
text="基本图案绘制函数", font=("黑体", 14))
self.basic_pattern = Text(self.cv, font=("Arial", 14), bg="#bce7f7", highlightthickness=0,
spacing1=5, spacing2=3, spacing3=3, wrap="none", undo=True)
self.basic_pattern.place(x=35, y=30 + (self.label_height + 15) * 2 + 30, width=int((self.width - 100) / 2),
height=285)
# 初始变量表单
self.cv.create_image(35, 30 + (self.label_height + 15) * 2 + 30 + 285 + 15, image=self.basic_label_image,
anchor=NW)
self.cv.create_text(35 + int((self.width - 100) / 4), 30 + (self.label_height + 15) * 2 + 30 + 285 + 30,
text="初始变量",
font=("黑体", 14))
self.var_tree = Text(self.cv, font=("Arial", 14), bg="#bce7f7", highlightthickness=0, highlightcolor="#bce7f7",
spacing1=10, spacing2=5, spacing3=5, wrap="none")
self.var_tree.place(x=35, y=30 + (self.label_height + 15) * 2 + 30 + 280 + 45,
height=290, width=int((self.width - 100) / 2))
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.65) // 2, int(screen_height - screen_height * 0.8) // 2
top_window = AddFractal(self, "add", width=screen_width * 0.65, height=screen_height * 0.8)
top_window.geometry(f'{int(screen_width * 0.65)}x{int(screen_height * 0.8)}+{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.65) // 2, int(screen_height - screen_height * 0.8) // 2
top_window = AddFractal(self, "update", width=screen_width * 0.65, height=screen_height * 0.8,
fractal_id=self.master.chose_fractal.get())
top_window.geometry(f'{int(screen_width * 0.65)}x{int(screen_height * 0.8)}+{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=lambda params=self.var_dict: self.master.fractal_tree_canvas.draw_fractal_tree(params)).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: 绘制参数更新
data_frame = self.db.query_fractal_by_id(self.master.chose_fractal.get()).iloc[0]
params = {
"self": self,
"var_text": self.var_text.get(0.0, END).strip()
}
self.var_text.delete(0.0, END)
exec(data_frame["vars"], params)
def create_form(self):
# todo: 分形图案变量生成
data_frame = self.db.query_fractal_by_id(self.master.chose_fractal.get()).iloc[0]
self.var_text = Text(self, font=("Arial", 14), bg="#f7f7f7", highlightthickness=0, highlightcolor="#f7f7f7",
spacing1=10, spacing2=5, spacing3=5, wrap="none")
self.var_text.place(x=0, y=self.height * 0.2, width=self.width, height=self.height * 0.6)
params = {
"self": self,
"var_text": self.var_text.get(0.0, END)
}
exec(data_frame["vars"], params)
class BasicTree(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_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, params):
try:
self.delete("all")
data_frame = self.db.query_fractal_by_id(self.master.chose_fractal.get())
params = {key: value for key, value in params.items()}
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()