from tkinter import Frame, messagebox import tkinter.font as tkFont from pandas import DataFrame from ttkbootstrap import * import ttkbootstrap as ttk from ttkbootstrap.constants import * import pandas as pd import pymysql from ttkbootstrap.toast import ToastNotification from BaseWindow import BaseWindow def get_text_content(text): return text.get("0.0", "end").replace("\n", " ") class LoadElement(Frame): def __init__(self, master, table_name): super().__init__(master) self.master = master self.table_name = table_name self.data = [] self.conn = pymysql.connect(user="root", password="cyh0110", database="SCT", host="127.0.0.1", port=3306) self.data_frame = pd.read_sql(f"select * from {self.table_name} limit 0", self.conn) self.font_style = tkFont.Font(family="Lucida Grande", size=20) self.button_font = tkFont.Font(family="Lucida Grande", size=10) self.create_widget() self.select_value(None) self.create_tree_widget() def select_value(self, event): self.table_name = self.select_stringVar.get() def get_table(self) -> DataFrame: TableList = pd.read_sql("show tables", self.conn) return TableList def create_widget(self): data_frame = self.get_table() tables = [i[0] for i in data_frame.values.tolist()] style = ttk.Style() # 设置字体和字体大小 style.configure('TCombobox', font=('Arial', 100)) self.select_stringVar = StringVar() self.select_stringVar.set(self.table_name) self.combo = ttk.Combobox(self, width=10, height=1, textvariable=self.select_stringVar, font=self.font_style, style="TCombobox") self.combo["values"] = tables self.combo.bind('<>', self.select_value) self.combo.grid(column=0, row=0) Button(self, text="装载", width=10, command=self.load).grid(column=1, row=0, padx=5) def create_tree_widget(self): frame = Frame(self, width=50, height=220) frame.grid(row=1, column=0, columnspan=2, sticky=NSEW, pady=5) frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(0, weight=1) columns = self.data_frame.keys().tolist() style = ttk.Style() style.configure("Custom.Treeview.Heading", font=("宋体", 15)) style.configure("Custom.Treeview", rowheight=30, font=("宋体", 15)) tree = ttk.Treeview(frame, columns=columns, show="headings", style="Custom.Treeview", selectmode=BROWSE) # 根据dataFrame结构生成表 for i in columns: tree.heading(column=i, text=i) for i in columns: tree.column(i, anchor=CENTER, width=80) if columns.index(i) == 1 or columns.index(i) == 0: tree.column(i, anchor=CENTER, width=120) for row in self.data_frame.itertuples(): tree.insert(parent="", index=END, values=[row[i] for i in range(1, len(row))]) y_scrollbar = ttk.Scrollbar(self, orient='vertical', command=tree.yview) x_scrollbar = ttk.Scrollbar(frame, orient="horizontal", command=tree.xview) tree.configure(yscrollcommand=y_scrollbar.set) tree.config(height=6) tree.grid(row=0, column=0, columnspan=2, sticky=NSEW, pady=5) y_scrollbar.grid(row=1, column=3, sticky='ns') x_scrollbar.grid(row=2, column=0, columnspan=2, sticky='ew') frame.grid_propagate(False) def load(self): # 加载数据 self.data_frame = pd.read_sql(f"select * from {self.table_name}", self.conn) self.create_tree_widget() class FormElement(Frame): def __init__(self, master): super().__init__(master) self.master = master self.data = [] self.conn = pymysql.connect(user="root", password="cyh0110", database="SCT", host="127.0.0.1", port=3306) self.font_style = tkFont.Font(family="Lucida Grande", size=20) self.button_font = tkFont.Font(family="Lucida Grande", size=10) self.default_query_sql = "select * from student" self.create_form() self.create_treeview(pd.read_sql(self.default_query_sql, con=self.conn)) def create_form(self): self.sid_var = IntVar() self.sname_var = IntVar() self.sclass_var = IntVar() self.ssex_var = IntVar() self.sage_var = IntVar() self.score_var = IntVar() self.courseId_var = IntVar() self.cname_var = IntVar() self.credit_var = IntVar() self.chours_var = IntVar() Label(self, text="学生/student", font=("Lucida Grande", 20), style="inverse").grid(row=0, column=0, sticky=W) Label(self, text="学号", font=self.font_style).grid(row=1, column=0, sticky=E) Checkbutton(self, onvalue=1, offvalue=0, variable=self.sid_var).grid(row=1, column=1, sticky=W) self.sid = Entry(self, width=20, font=self.font_style) self.sid.grid(row=1, column=2, sticky=W) Label(self, text="姓名", font=self.font_style).grid(row=1, column=3, sticky=E) Checkbutton(self, onvalue=1, offvalue=0, variable=self.sname_var).grid(row=1, column=4, sticky=W) self.sname = Entry(self, width=20, font=self.font_style) self.sname.grid(row=1, column=5, sticky=W) Label(self, text="班级", font=self.font_style).grid(row=2, column=0, sticky=E) Checkbutton(self, onvalue=1, offvalue=0, variable=self.sclass_var).grid(row=2, column=1, sticky=W) self.sclass = Entry(self, width=20, font=self.font_style) self.sclass.grid(row=2, column=2, sticky=W) Label(self, text="性别", font=self.font_style).grid(row=2, column=3, sticky=E) Checkbutton(self, onvalue=1, offvalue=0, variable=self.ssex_var).grid(row=2, column=4, sticky=W) self.ssex = Entry(self, width=20, font=self.font_style) self.ssex.grid(row=2, column=5, sticky=W, pady=10) Label(self, text="年龄自", font=self.font_style).grid(row=3, column=0, sticky=E) Checkbutton(self, onvalue=1, offvalue=0, variable=self.sage_var).grid(row=3, column=1, sticky=W) self.start_age = Entry(self, width=20, font=self.font_style) self.start_age.grid(row=3, column=2, sticky=W) Label(self, text="到", font=self.font_style).grid(row=3, column=3, sticky=E) Label(self, text="", font=self.font_style).grid(row=3, column=4, sticky=W) self.end_age = Entry(self, width=20, font=self.font_style) self.end_age.grid(row=3, column=5, sticky=W, pady=10) Label(self, text="课程/course", font=("Lucida Grande", 20), style="inverse").grid(row=4, column=0, sticky=W) Label(self, text="课号", font=self.font_style).grid(row=5, column=0, sticky=E) Checkbutton(self, onvalue=1, offvalue=0, variable=self.courseId_var).grid(row=5, column=1, sticky=W) self.course_id = Entry(self, width=20, font=self.font_style) self.course_id.grid(row=5, column=2, sticky=W) Label(self, text="课名", font=self.font_style).grid(row=5, column=3, sticky=E) Checkbutton(self, onvalue=1, offvalue=0, variable=self.cname_var).grid(row=5, column=4, sticky=W) self.course_name = Entry(self, width=20, font=self.font_style) self.course_name.grid(row=5, column=5, sticky=W, pady=10) Label(self, text="选课/sc", font=("Lucida Grande", 20), style="inverse").grid(row=6, column=0, sticky=W) Label(self, text="成绩大于", font=self.font_style).grid(row=7, column=0, sticky=E) Checkbutton(self, onvalue=1, offvalue=0, variable=self.score_var).grid(row=7, column=1, sticky=W) self.sc_start = Entry(self, width=20, font=self.font_style) self.sc_start.grid(row=7, column=2, sticky=W) Label(self, text="小于", font=self.font_style).grid(row=7, column=3, sticky=E) Label(self, text="", font=self.font_style).grid(row=7, column=4, sticky=W) self.sc_end = Entry(self, width=20, font=self.font_style) self.sc_end.grid(row=7, column=5, sticky=W, pady=10) Button(self, text="\n\n构造SQL\n\n", command=self.make_sql, width=8, ).grid(column=8, row=0, rowspan=8) self.sql_text = Text(self, height=3, font=self.font_style, width=75) self.sql_text.grid(row=8, column=0, rowspan=2, columnspan=7, sticky=W) Button(self, text="\n执行SQL\n", command=self.execute_sql, width=8, ).grid(column=8, row=8, rowspan=2, padx=10) self.sql_text.insert(1.0, self.default_query_sql) def execute_sql(self): cursor = self.conn.cursor() try: sql = get_text_content(self.sql_text).lower().strip() cursor.execute(sql) if sql.startswith("select"): data_frame = pd.read_sql(sql, con=self.conn) self.create_treeview(data_frame) ToastNotification(message="语句执行成功", title="提示", duration=1500, position=(int(self.winfo_screenwidth() / 2) - 150, 80, "ne"), bootstyle="success", icon="").show_toast() except pymysql.Error as e: messagebox.showerror(str(e.args[0]), str(e.args[1])) finally: cursor.close() def create_treeview(self, data_frame): frame = Frame(self, height=400) frame.grid(row=10, column=0, columnspan=10, rowspan=5, sticky=NSEW) frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(0, weight=1) columns = data_frame.keys().tolist() tree = ttk.Treeview(frame, columns=columns, show="headings", style="mystyle.Treeview", height=50, selectmode=BROWSE) style = ttk.Style() style.configure("Treeview.Heading", font=self.font_style) style.configure("Treeview", rowheight=30, font=self.font_style, borderwidth=1) # 根据dataFrame结构生成表 for i in columns: tree.heading(column=i, text=i) for i in columns: tree.column(i, anchor=CENTER, minwidth=100, width=100) for row in data_frame.itertuples(): tree.insert(parent="", index=END, values=[row[i] for i in range(1, len(row))]) tree.grid(row=0, column=0, sticky=NSEW, pady=10) y_scrollbar = ttk.Scrollbar(frame, orient='vertical', command=tree.yview) tree.configure(yscrollcommand=y_scrollbar.set) y_scrollbar.grid(row=0, column=1, sticky='ns') frame.grid_propagate(False) def make_sql(self): sql = "select * from student where 1=1" if self.course_id and self.course_name and self.sc_start and self.sc_end != "": sql = "select * from student s join sc on sc.sid=s.sid join course c on c.cid=sc.cid" if self.sid.get() != "": sql += f" and (s.sid like '{self.sid.get()}')" if self.sname.get() != "": sql += f" and (s.sname like '{self.sname.get()}')" if self.sclass.get() != "": sql += f" and (s.sclass like '{self.sclass.get()}')" if self.ssex.get() != "": sql += f" and (s.ssex like '{self.ssex.get()}')" if self.start_age.get() != "": sql += f" and (s.sage > '{self.start_age.get()}')" if self.end_age.get() != "": sql += f" and (s.sage < '{self.end_age.get()}')" if self.course_id.get() != "": sql += f" and (c.cid like '{self.course_id.get()}')" if self.course_name.get() != "": sql += f" and (c.cname like '{self.course_name.get()}')" if self.sc_start.get() != "": sql += f" and (sc.score > {self.sc_start.get()})" if self.sc_end.get() != "": sql += f" and (sc.score < {self.sc_end.get()})" else: if self.sid.get() != "": sql += f" and (sid like '{self.sid.get()}')" if self.sname.get() != "": sql += f" and (sname like '{self.sname.get()}')" if self.sclass.get() != "": sql += f" and (sclass like '{self.sclass.get()}')" if self.start_age.get() != "": sql += f" and (sage > '{self.start_age.get()}')" if self.end_age.get() != "": sql += f" and (sage < '{self.end_age.get()}')" if sql == "select * from student where 1=1": sql = "select * from student" if (self.sid_var and self.ssex_var and self.sage_var and self.sclass_var and self.sname_var and self.score_var and self.cname_var and self.credit_var and self.chours_var == 0): pass else: data = [] data.append("s.sid")if self.sid_var.get() == 1 else "" data.append("s.sname")if self.sname_var.get() == 1 else "" data.append("s.ssex")if self.ssex_var.get() == 1 else "" data.append("s.sage")if self.sage_var.get() == 1 else "" data.append("s.sclass")if self.sclass_var.get() == 1 else "" data.append("sc.score")if self.score_var.get() == 1 else "" data.append("c.cid")if self.courseId_var.get() == 1 else "" data.append("c.cname")if self.cname_var.get() == 1 else "" data.append("c.credit")if self.credit_var.get() == 1 else "" data.append("c.chours")if self.chours_var.get() == 1 else "" sql = sql.replace("select *", f"select {', '.join(data)} ") sql = sql.replace("1=1 and", "") self.sql_text.delete(0.0, END) self.sql_text.insert(1.0, sql) class StuSys_X4(BaseWindow): def __init__(self, master, attr): super().__init__(master, attr) self.create_left_plate() self.create_right_plate() def create_left_plate(self): self.left_frame = Frame(self.master, height=self.attr["height"]) self.left_frame.pack(side=LEFT, anchor=NW, pady=10, padx=10) load_element1 = LoadElement(self.left_frame, "student") load_element1.pack(side=TOP, pady=10) load_element2 = LoadElement(self.left_frame, "course") load_element2.pack(side=TOP, pady=10) load_element2 = LoadElement(self.left_frame, "sc") load_element2.pack(side=TOP, pady=10) def create_right_plate(self): self.right_frame = Frame(self.master, height=self.attr["height"]) self.right_frame.pack(side=LEFT, anchor=NW, pady=10, padx=10) form_element = FormElement(self.right_frame) form_element.pack(side=TOP, pady=10, anchor=NE) if __name__ == '__main__': style = "morph" root = Window(themename=style) screenwidth = root.winfo_screenwidth() screenheight = root.winfo_screenheight() root.columnconfigure(0, weight=1) root.rowconfigure(1, weight=1) root_attr = { "width": screenwidth * 0.83, "height": screenheight * 0.85, } # 配置界面大小 alignstr = '%dx%d+%d+%d' % (root_attr['width'], root_attr['height'], (screenwidth - root_attr['width']) / 2, (screenheight - root_attr['height']) / 2) root.geometry(alignstr) root.resizable(width=False, height=False) # 禁止用户调整界面大小 app = StuSys_X4(root, root_attr) app.create_left_plate() app.create_right_plate() ttk.Style().configure("TButton", font="-size 18") root.mainloop()