diff --git a/BaseWindow.py b/BaseWindow.py new file mode 100644 index 0000000..d2d5f67 --- /dev/null +++ b/BaseWindow.py @@ -0,0 +1,17 @@ +import tkinter.font as tkFont +import tkinter +from tkinter import * +from tkinter import ttk, messagebox + +import pymysql + + +class BaseWindow(Frame): + def __init__(self, master, attr): + super().__init__(master) + self.attr = attr + self.master = master + self.font_style = tkFont.Font(family="Lucida Grande", size=20) + self.button_font = tkFont.Font(family="Lucida Grande", size=10) + self.conn = pymysql.connect(user="root", password="Wyz010810", database="SCT", host="127.0.0.1", port=3306) + # self.conn = pymysql.connect(user="root", password="123123", database="stu_sys", host="127.0.0.1", port=3306) diff --git a/Pymysql_Sample.py b/Pymysql_Sample.py new file mode 100644 index 0000000..8a54c92 --- /dev/null +++ b/Pymysql_Sample.py @@ -0,0 +1,17 @@ +import pymysql + +if __name__ == '__main__': + # 建立数据库连接的语句connection + connection = pymysql.connect(user="root", password="Wyz010810", database="SCT", host="127.0.0.1", port=3306) + cursor = connection.cursor() # 创建游标 + sql = "select * from student" # SQL语句字符串 + # 为了防止SQL注入等安全问题,可以使用参数化查询。 + try: + cursor.execute(sql) # 执行SQL语句 + ResultList = cursor.fetchall() # 获取游标中的数据 + print(ResultList) # Student[(S#,Sname,Sage,...),...] + except pymysql.Error as e: # 捕获报错信息 + print("MySQL Error:", e) # 打印报错信息 + finally: + cursor.close() # 关闭游标 + connection.close() # 关闭数据库连接 diff --git a/README.md b/README.md index 5a632a6..374bfdc 100644 --- a/README.md +++ b/README.md @@ -1,2 +1 @@ -# DatabaseThinkingandRelationalDatabase - +# DatabaseThinkingandRelationalDatabase \ No newline at end of file diff --git a/X1/StuSys_X1_1.py b/X1/StuSys_X1_1.py new file mode 100644 index 0000000..47232d1 --- /dev/null +++ b/X1/StuSys_X1_1.py @@ -0,0 +1,57 @@ +import pymysql + + +def create_database(conn): + cursor = conn.cursor() # 创建游标 + cursor.execute("DROP DATABASE IF EXISTS SCT") + # 创建数据库 + cursor.execute("CREATE DATABASE SCT CHARACTER SET utf8 COLLATE utf8_general_ci") + cursor.close() # 关闭游标 + +def create_table(conn): + cursor = conn.cursor() # 创建游标 + cursor.execute("USE SCT") # 指定数据库 + # 创建student数据表 + cursor.execute(""" + CREATE TABLE IF NOT EXISTS student + ( + sid CHAR(8) PRIMARY KEY, + sname CHAR(10), + ssex CHAR(2), + sage INTEGER, + sclass CHAR(6) + ) + """) + # 创建Course数据表 + cursor.execute(""" + CREATE TABLE IF NOT EXISTS course + ( + cid CHAR(4) PRIMARY KEY, + cname CHAR(30), + credit FLOAT(1), + chours INTEGER, + t CHAR(3) + ) + """) + # 创建SC数据表 + cursor.execute(""" + CREATE TABLE IF NOT EXISTS sc + ( + sid CHAR(8), + cid CHAR(4), + score FLOAT(1), + CONSTRAINT sc_course_cid_fk + FOREIGN KEY (cid) REFERENCES course (cid), + CONSTRAINT sc_student_sid_fk + FOREIGN KEY (sid) REFERENCES student (sid) + ) + """) + cursor.close() + + +if __name__ == '__main__': + # conn = pymysql.connect(user="root", password="123456", database="SCT", host="127.0.0.1", port=3306) + conn = pymysql.connect(user="root", password="Wyz010810", host="127.0.0.1", port=3306) + create_database(conn) + create_table(conn) + conn.close() # 关闭数据库连接 diff --git a/X1/StuSys_X1_3.py b/X1/StuSys_X1_3.py new file mode 100644 index 0000000..e29ab4e --- /dev/null +++ b/X1/StuSys_X1_3.py @@ -0,0 +1,86 @@ +# encoding: utf8 +import time +import pymysql +import random + +last_names = "李,王,张,刘,陈,杨,黄,赵,周,吴,徐,孙,朱,马,胡,郭,林,何,高,梁,郑,罗,宋,谢,唐,韩,曹,许,邓,萧,冯,曾,程,蔡,彭,潘,袁,于,董,余,苏,叶,吕,魏,蒋,田,杜,丁,沈,姜,范,江,傅,钟,卢,汪,戴,崔,任,陆,廖,姚,方,金,邱,夏,谭,韦,贾,邹,石,熊,孟,秦,阎,薛,侯,雷,白,龙,段,郝,孔,邵,史,毛,常,万,顾,赖,武,康,贺,严,尹,钱,施,牛,洪,龚" +last_names_list = last_names.split(",") +course_names = "语文、数学、外语、历史、思想政治、地理、 化学、物理、生物、体育、美术、音乐、技术、微积分、体育、毛泽东思想概论、思想道德修养、高等数学、线性代数、概率论与数理统计、离散数学、计算机原理、人工智能、程序设计基础、面向对象程序设计、数字逻辑电路、电路电子技术、数据结构与算法、WEB程序设计、计算机组成与结构、操作系统、数据库系统原理、编译原理、计算机网络" +course_names_list = course_names.split("、") + +# 随机生成10000条学生表数据 +def student_random_record(conn, cursor): + """ + # 随机生成10000条学生表数据 + :return: + """ + year = time.localtime().tm_year # 获取当前系统时间的年份 + num = 1 + class_num = 1 + class_id = 1 + for i in range(10000): + sid = "%d" % year + "%04d" % num + sname = random.choice(last_names_list) + sid + ssex = random.choice(["男", "女"]) + sage = random.randint(15, 35) + sclass = "%d" % year + "%02d" % class_id + sql = f"INSERT INTO student VALUES ('{sid}', '{sname}', '{ssex}', {sage}, '{sclass}')" + cursor.execute(sql) + sid_list.append(sid) + if num == 2500: # 每年学生数2500 + year += 1 + num = 1 + class_id = 1 + if class_num == 30: # 班级学生数30 + class_id += 1 + class_num = 1 + num += 1 + class_num += 1 + conn.commit() + + +def course_random_record(conn, cursor): + """ + 随机生成1000条课程表数据 + :return: + """ + hours = [i for i in range(8, 192 + 1, 8)] + for i in range(1000): + cid = "%03d" % (i + 1) + cname = random.choice(course_names_list)# course_names_list为样例课程名列表 + hour = random.choice(hours) + credit = round(hour / 16, 2) + sql = f"INSERT INTO course (cid, cname, credit, chours) VALUES ('{cid}', '{cname}', {credit}, {hour})" + cursor.execute(sql) + cid_list.append(cid) + conn.commit() + + +def sc_random_record(conn, cursor): + """ + 随机生成10000 * 30条以上选课表数据 + :return: + """ + for sid in sid_list: + year = int(sid[:4]) # 取sid的前四位学年 + for i in range((year - time.localtime().tm_year + 1) * 16): # 学习课程按学年有16、32、48、64门按学年递增分布 + cid = random.choice(cid_list) + score = random.randint(0, 101) + sql = f"INSERT INTO sc(sid, cid, score) VALUES ('{sid}', '{cid}', {score})" + cursor.execute(sql) + conn.commit() + + +if __name__ == '__main__': + # 创建mysql连接 + conn = pymysql.connect(user="root", password="Wyz010810", database="SCT", host="127.0.0.1", port=3306) + # 创建游标 + cursor = conn.cursor() + sid_list = [] # 用于存储生成的sid + cid_list = [] # 用于存储生成的cid + student_random_record(conn, cursor) + course_random_record(conn, cursor) + sc_random_record(conn, cursor) + # 关闭数据库连接 + cursor.close() + conn.close() \ No newline at end of file diff --git a/X1/StuSys_X1_4.py b/X1/StuSys_X1_4.py new file mode 100644 index 0000000..c9d5682 --- /dev/null +++ b/X1/StuSys_X1_4.py @@ -0,0 +1,31 @@ +import pymysql + +# 创建mysql连接(连接并打开数据库) +conn = pymysql.connect(user="root", password="Wyz010810", database="SCT", host="127.0.0.1", port=3306) +cursor = conn.cursor() # 游标的定义、打开 +# 字符串型SQL语句的执行 +SQLString = "INSERT INTO student VALUES ('20220001', '张三', '男', 20, '01')" +cursor.execute(SQLString) +SQLString = "INSERT INTO course VALUES ('1001', '数据库', 3, 48, 'T01')" +cursor.execute(SQLString) +SQLString = "INSERT INTO sc VALUES ('20230001', '1001', 85)" +cursor.execute(SQLString) +conn.commit() + +def query_data(table_name): + """ + 游标数据的读写处理,读写游标数据 + :param table_name: 表名称 + :return: 游标数据 + """ + SQLString = f"SELECT * FROM {table_name}" + cursor.execute(SQLString) # 执行查询sql语句 + data = cursor.fetchall() # 获取游标中的数据 + return data + +StudentList = query_data("student") +CourseList = query_data("course") +SCList = query_data("sc") +# 关闭数据库连接 +cursor.close() +conn.close() \ No newline at end of file diff --git a/X2/StuSys_X2_bootstrap.py b/X2/StuSys_X2_bootstrap.py new file mode 100644 index 0000000..6a1f77e --- /dev/null +++ b/X2/StuSys_X2_bootstrap.py @@ -0,0 +1,214 @@ +from tkinter import Frame +import tkinter.font as tkFont + +from ttkbootstrap import * +import ttkbootstrap as ttk +from ttkbootstrap.constants import * + +import pandas as pd +import pymysql +from ttkbootstrap.tableview import Tableview + +from BaseWindow import BaseWindow + + +def get_text_content(text): + return text.get("0.0", "end").replace("\n", " ") + +conn = pymysql.connect(user="root", password="Wyz010810", database="SCT", host="127.0.0.1", port=3306) + +class LoadElement(Frame): + def __init__(self, master, table_name): + super().__init__(master) + self.master = master + self.table_name = table_name + self.TableList = pd.read_sql(f"select * from {self.table_name} limit 0", 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.create_tree_widget() + + def create_widget(self): + # 创建装载按钮 + label = Label(self, width=10, font=self.font_style, text=self.table_name, style="inverse-secondary") + label.grid(column=0, row=0) + Button(self, text="装载", width=10, command=self.load).grid(column=1, row=0, padx=5, sticky=NSEW) + + 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.TableList.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.TableList.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): + """ + 加载数据 + :return: + """ + SQLString = f"select * from {self.table_name}" + # 执行SQL语句 并返回列表数据 + self.TableList = pd.read_sql(SQLString, conn) + # 调用X2界面函数将self.TableList数据展示出来 + 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="Wyz010810", 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() + fields_mapping = {'sid': '学号', 'sname': '姓名', 'ssex': '性别', 'sage': '年龄', 'sclass': '班级'} + self.create_treeview(pd.read_sql(self.default_query_sql, con=self.conn), fields_mapping) + + + def create_form(self): + # 创建表单区域 + self.sql_text = Text(self, width=75, height=4, font=self.font_style) + self.sql_text.grid(row=0, column=0, rowspan=2) + Button(self, text="\n\n执行SQL\n\n", command=self.execute_sql, width=7, style=INFO, compound=TOP).grid(column=1, row=0, rowspan=2, padx=10) + self.sql_text.insert(1.0, self.default_query_sql) + + def execute_sql(self): + """ + 执行sql方法 + :return: + """ + # 获取text组件中用户输入的值 + sql = get_text_content(self.sql_text).lower().strip() + print(sql) + + def create_treeview(self, data_frame,fields_mapping): + """ + 创建数据列表展示组件 + :param data_frame: + :return: + """ + frame = Frame(self, height=700) # 创建一个 Frame (框架) 组件,作为树形视图的容器 + 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() + # 使用字段名映射将列名转换为中文 + columns = [fields_mapping.get(col, col) for col in 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(): # 循环遍历 DataFrame 的每一行,并将数据插入到树形视图中 + 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) # 禁止框架自动调整其大小以适应其中的内容 + + +class StuSys_X2(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__': +# """ +# minty, lumen, sandstone, yeti, pulse, united, morph, journal, darkly, superhero, solar +# cyborg, vapor, simplex, cerculean, +# """ +# 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_X2(root, root_attr) +# +# ttk.Style().configure("TButton", font="-size 18") +# root.mainloop() + + +if __name__ == '__main__': + """ + minty, lumen, sandstone, yeti, pulse, united, morph, journal, darkly, superhero, solar + cyborg, vapor, simplex, cerculean, + """ + 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, + "width": screenwidth * 0.61, + "height": screenheight * 0.63, + } + 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_X2(root, root_attr) + + ttk.Style().configure("TButton", font="-size 18") + root.mainloop() \ No newline at end of file diff --git a/X2/__pycache__/StuSys_X2_bootstrap.cpython-37.pyc b/X2/__pycache__/StuSys_X2_bootstrap.cpython-37.pyc new file mode 100644 index 0000000..d8cb4a0 Binary files /dev/null and b/X2/__pycache__/StuSys_X2_bootstrap.cpython-37.pyc differ diff --git a/X2/__pycache__/StuSys_X2_bootstrap.cpython-39.pyc b/X2/__pycache__/StuSys_X2_bootstrap.cpython-39.pyc new file mode 100644 index 0000000..de4214c Binary files /dev/null and b/X2/__pycache__/StuSys_X2_bootstrap.cpython-39.pyc differ diff --git a/X3/StuSys_X3_bootstrap.py b/X3/StuSys_X3_bootstrap.py new file mode 100644 index 0000000..8ae3ecb --- /dev/null +++ b/X3/StuSys_X3_bootstrap.py @@ -0,0 +1,129 @@ +from tkinter import Frame +import tkinter.font as tkFont + +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 +from X2.StuSys_X2_bootstrap import LoadElement + + +def get_text_content(text): + return text.get("0.0", "end").replace("\n", " ") + + + + +class FormElement(Frame): + def __init__(self, master): + super().__init__(master) + self.master = master + self.data = [] + self.conn = pymysql.connect(user="root", password="Wyz010810", 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.sql_text = Text(self, width=75, height=6, font=self.font_style) + self.sql_text.grid(row=0, column=0, rowspan=2) + Button(self, text="\n\n执行SQL\n\n", command=self.execute_sql, width=8, + ).grid(column=1, row=0, rowspan=2, padx=10) + self.sql_text.insert(1.0, self.default_query_sql) + + def sql_query(self, SQLString): + SQLResultList = pd.read_sql(SQLString, self.conn) + return SQLResultList + + def execute_sql(self): + # 执行sql并将sql执行后查询的数据展示 + sql = get_text_content(self.sql_text).lower().strip() + if sql.startswith("select"): + data_frame = self.sql_query(sql) + self.create_treeview(data_frame) + ToastNotification(message="语句执行成功", + title="提示", + duration=1500, + position=(int(self.winfo_screenwidth() / 2) - 150, 80, "ne"), + bootstyle="success", + icon="").show_toast() + + def create_treeview(self, data_frame): + frame = Frame(self, height=700) + 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) + + +class StuSys_X3(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__': + """ + minty, lumen, sandstone, yeti, pulse, united, morph, journal, darkly, superhero, solar + cyborg, vapor, simplex, cerculean, + """ + 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_X3(root, root_attr) + + ttk.Style().configure("TButton", font="-size 18") + root.mainloop() diff --git a/X4/StuSys_X4_bootstrap.py b/X4/StuSys_X4_bootstrap.py new file mode 100644 index 0000000..7015a2c --- /dev/null +++ b/X4/StuSys_X4_bootstrap.py @@ -0,0 +1,199 @@ +from tkinter import Frame +import tkinter.font as tkFont + +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 +from X2.StuSys_X2_bootstrap import LoadElement + + +def get_text_content(text): + return text.get("0.0", "end").replace("\n", " ") + + +class FormElement(Frame): + def __init__(self, master): + super().__init__(master) + self.master = master + self.data = [] + self.conn = pymysql.connect(user="root", password="Wyz010810", 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): + """ + 创建表单 + :return: + """ + self.sid_var = IntVar()# 学号 + self.sname_var = IntVar()# 姓名 + self.sclass_var = IntVar()# 班级 + self.ssex_var = IntVar()# 性别 + self.sage_var = IntVar()# 年龄 + Label(self, text="学号", font=self.font_style).grid(row=0, column=0, sticky=W) + # 创建复选框,表示选择条件的选择状态,并将变量进行关联 + Checkbutton(self, onvalue=1, offvalue=0, variable=self.sid_var).grid(row=0, column=1, sticky=W) + self.sid = Entry(self, width=20, font=self.font_style) # 条件输入文本框 + self.sid.grid(row=0, column=2, sticky=W) + + # ... 其他字段部分的创建类似,以下省略 + Label(self, text="姓名", font=self.font_style).grid(row=0, column=3, sticky=W) + Checkbutton(self, onvalue=1, offvalue=0, variable=self.sname_var).grid(row=0, column=4, sticky=W) + self.sname = Entry(self, width=20, font=self.font_style) # 选择条件文本框 + self.sname.grid(row=0, column=5, sticky=W) + + Label(self, text="班级", font=self.font_style).grid(row=1, column=0, sticky=W) + Checkbutton(self, onvalue=1, offvalue=0, variable=self.sclass_var).grid(row=1, column=1, sticky=W) + self.sclass = Entry(self, width=20, font=self.font_style) + self.sclass.grid(row=1, column=2, sticky=W) + Label(self, text="性别", font=self.font_style).grid(row=1, column=3, sticky=W) + Checkbutton(self, onvalue=1, offvalue=0, variable=self.ssex_var).grid(row=1, column=4, sticky=W) + self.ssex = Entry(self, width=20, font=self.font_style) + self.ssex.grid(row=1, column=5, sticky=W, pady=10) + Label(self, text="年龄自", font=self.font_style).grid(row=2, column=0, sticky=W) + + Checkbutton(self, onvalue=1, offvalue=0, variable=self.sage_var).grid(row=2, column=1, sticky=W) + self.start_age = Entry(self, width=20, font=self.font_style) + self.start_age.grid(row=2, column=2, sticky=W) + Label(self, text="到", font=self.font_style).grid(row=2, column=3, sticky=W) + Label(self, text="", font=self.font_style).grid(row=2, column=4, sticky=W) + self.end_age = Entry(self, width=20, font=self.font_style) + self.end_age.grid(row=2, 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=3) + + self.sql_text = Text(self, height=3, font=self.font_style, width=75) + self.sql_text.grid(row=4, column=0, rowspan=2, columnspan=7, sticky=W) + Button(self, text="\n执行SQL\n", command=self.execute_sql, width=8, + ).grid(column=8, row=4, rowspan=2, padx=10) + self.sql_text.insert(1.0, self.default_query_sql) + + def execute_sql(self): + sql = get_text_content(self.sql_text).lower().strip() + 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() +#"" + def create_treeview(self, data_frame): + frame = Frame(self, height=600) + 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): + """ + 获取用户输入,进行条件判断,进行SQLString的构造 + :return: + """ + # 根据表单条件生成sql语句 + SQLString = "select * from student where 1=1" + if self.sid.get() != "": + SQLString += f" and (sid like '{self.sid.get()}')" + if self.sname.get() != "": + SQLString += f" and (sname like '{self.sname.get()}')" + if self.sclass.get() != "": + SQLString += f" and (sclass like '{self.sclass.get()}')" + if self.ssex.get() != "": + SQLString += f" and (ssex like '{self.ssex.get()}')" + if self.start_age.get() != "": + SQLString += f" and (sage > '{self.start_age.get()}')" + if self.end_age.get() != "": + SQLString += f" and (sage < '{self.end_age.get()}')" + if SQLString == "select * from student where 1=1": + SQLString = "select * from student" + SQLString = SQLString.replace("1=1 and", "") + if (self.sid_var and self.ssex_var and self.sage_var and self.sclass_var and self.sname_var == 0): + pass + else: + data = [] + data.append("sid")if self.sid_var.get() == 1 else "" + data.append("sname")if self.sname_var.get() == 1 else "" + data.append("ssex")if self.ssex_var.get() == 1 else "" + data.append("sage")if self.sage_var.get() == 1 else "" + data.append("sclass")if self.sclass_var.get() == 1 else "" + SQLString = SQLString.replace("select *", f"select {', '.join(data)} ") + self.sql_text.delete(0.0, END) + self.sql_text.insert(1.0, SQLString) + + +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, fill=BOTH) + form_element = FormElement(self.right_frame) + form_element.pack(side=TOP, pady=10, anchor=NE, fill=BOTH) + + +if __name__ == '__main__': + """ + minty, lumen, sandstone, yeti, pulse, united, morph, journal, darkly, superhero, solar + cyborg, vapor, simplex, cerculean, + """ + 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) + + ttk.Style().configure("TButton", font="-size 18") + root.mainloop() diff --git a/X5/StuSys_X5_11.py b/X5/StuSys_X5_11.py new file mode 100644 index 0000000..7e968b8 --- /dev/null +++ b/X5/StuSys_X5_11.py @@ -0,0 +1,248 @@ +from tkinter import Frame +import tkinter.font as tkFont + +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 +from X2.StuSys_X2_bootstrap import LoadElement + + +def get_text_content(text): + return text.get("0.0", "end").replace("\n", " ") + + +class FormElement(Frame): + def __init__(self, master): + super().__init__(master) + self.master = master + self.data = [] + self.conn = pymysql.connect(user="root", password="Wyz010810", 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() + + # 表明标签:学生/student + 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) + # 配置并创建一个"构造SQL"按钮 + Button(self, text="\n\n构造SQL\n\n", command=self.make_sql, width=8, + ).grid(column=8, row=0, rowspan=8) + # 创建一个"执行SQL"按钮,用于执行文本框中的SQL命令 + 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) + # 插入默认的查询SQL + self.sql_text.insert(1.0, self.default_query_sql) + + def execute_sql(self): + sql = get_text_content(self.sql_text).lower().strip() + 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() + + 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查询以包含多个表 + 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)# 插入新构造的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__': + """ + minty, lumen, sandstone, yeti, pulse, united, morph, journal, darkly, superhero, solar + cyborg, vapor, simplex, cerculean, + """ + 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) + + ttk.Style().configure("TButton", font="-size 18") + root.mainloop() diff --git a/X5/StuSys_X5_12.py b/X5/StuSys_X5_12.py new file mode 100644 index 0000000..725cb89 --- /dev/null +++ b/X5/StuSys_X5_12.py @@ -0,0 +1,301 @@ +from tkinter import Frame +import tkinter.font as tkFont + +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="Wyz010810", 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 create_widget(self): + data_frame = pd.read_sql("show tables", self.conn) + tables = [i[0] for i in data_frame.values.tolist()] + style = ttk.Style() + self.select_stringVar = StringVar() + self.select_stringVar.set(self.table_name) + combo = ttk.Combobox(self, width=10, textvariable=self.select_stringVar,font=self.font_style, style="TCombobox") + combo["values"] = tables + combo.bind('<>', self.select_value) + 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="Wyz010810", 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): + sql = get_text_content(self.sql_text).lower().strip() + 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() + + 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__': + """ + minty, lumen, sandstone, yeti, pulse, united, morph, journal, darkly, superhero, solar + cyborg, vapor, simplex, cerculean, + """ + 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) + + ttk.Style().configure("TButton", font="-size 18") + root.mainloop() diff --git a/X5/StuSys_X5_13.py b/X5/StuSys_X5_13.py new file mode 100644 index 0000000..d9b7a54 --- /dev/null +++ b/X5/StuSys_X5_13.py @@ -0,0 +1,315 @@ +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 + +import warnings +warnings.simplefilter(action='ignore', category=UserWarning) + +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="Wyz010810", 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="Wyz010810", 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() diff --git a/X5/StuSys_X5_14.py b/X5/StuSys_X5_14.py new file mode 100644 index 0000000..2debb56 --- /dev/null +++ b/X5/StuSys_X5_14.py @@ -0,0 +1,309 @@ +import uuid +from tkinter import messagebox +import tkinter.font as tkFont + +from ttkbootstrap import * +import ttkbootstrap as ttk +from ttkbootstrap.constants import * + +import pandas as pd +import pymysql + +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="Wyz010810", 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 create_widget(self): + data_frame = pd.read_sql("show tables", self.conn) + 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) + combo = ttk.Combobox(self, width=10, height=1, textvariable=self.select_stringVar, font=self.font_style, + style="TCombobox") + combo["values"] = tables + combo.bind('<>', self.select_value) + combo.grid(column=0, row=0) + Button(self, text="装载", width=9, command=self.load).grid(column=1, row=0, padx=5) + + def create_tree_widget(self): + # 创建画布,用于展示装载后的数据 + frame = Frame(self, width=50, height=250) + 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, node): + super().__init__(master) + self.node = node + self.data = [] + self.conn = pymysql.connect(user="root", password="Wyz010810", 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.table_names = [] + self.form_content = {} + self.get_table_names() + self.table_name = self.table_names[0] + self.default_query_sql = f"SELECT * FROM {self.table_name}" + self.create_form() + self.select_table(None) + self.create_treeview(pd.read_sql(self.default_query_sql, con=self.conn)) + + def get_table_names(self): + """ + 获取该数据库下所有的表 + :return: + """ + data_frame = pd.read_sql("show tables", self.conn) + self.table_names = [i[0] for i in data_frame.values.tolist()] + + def select_table(self, event): + """ + 当下拉框选择表之后,触发该函数,并将tableName改为选择的tableName + :param event: + :return: + """ + for value in self.form_content.values(): + value[0].grid_forget() + value[2].grid_forget() + value[3].grid_forget() + self.form_content.clear() + self.table_name = self.select_table_name.get() + self.create_form() + self.sql_text.delete(0.0, END) + self.sql_text.insert(1.0, f"SELECT * FROM {self.table_name}") + + def get_field_names(self): + """ + 获取所有数据表的所有字段 + :return: 返回表内的所有字段 + """ + data_frame = pd.read_sql(f"desc {self.table_name}", self.conn) + """ + field_names = [] + for field in data_frame["Field"]: + field_names.append(f"{self.table_name}.{field}") + return field_names + """ + return data_frame["Field"].values.tolist() + + def create_form(self): + """ + 创建表单区域,根据数据表自动生成表单 + :return: + """ + self.select_table_name = StringVar() + self.select_table_name.set(self.table_name) + combo = ttk.Combobox(self, width=8, height=1, textvariable=self.select_table_name, font=self.font_style, + style="TCombobox") + combo["values"] = self.table_names + combo.bind('<>', self.select_table) + combo.grid(column=0, row=0, sticky=W) + fields = self.get_field_names() + num_fields = len(fields) + num_rows = (num_fields + 1) // 2 + for i in range(num_rows): + for j in range(2): + field_idx = i * 2 + j + if field_idx >= num_fields: + break + field_name = fields[field_idx] + label = Label(self, text=field_name, font=self.font_style) + label.grid(row=i + 1, column=j * 2, padx=5, pady=5, sticky=W) + checkbutton_var = IntVar() + checkbutton = Checkbutton(self, text='', variable=checkbutton_var) + checkbutton.grid(row=i + 1, column=j * 2, padx=5, pady=5, sticky=E) + entry = Entry(self, font=self.font_style) + entry.grid(row=i + 1, column=j * 2 + 1, padx=5, pady=5, sticky=W) + self.form_content[field_name] = (entry, checkbutton_var, label, checkbutton) + style = Style() + style.configure("custom.TButton", padding=(10, 40, 10, 40)) + Button(self, text="构造SQL", command=self.make_sql, width=8, style="custom.TButton" + ).grid(column=8, row=0, rowspan=8) + + self.sql_text = Text(self, height=3, font=self.font_style, width=62) + 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() + sql = get_text_content(self.sql_text).lower().strip() + try: + cursor.execute(sql) + if sql.startswith("select"): + data_frame = pd.read_sql(sql, con=self.conn) + self.create_treeview(data_frame) + self.node.message.insert(0, f"{sql}执行成功!共查询到{len(data_frame)}条数据-{uuid.uuid4()}-true") + return + self.node.message.insert(0, f"{sql}执行成功!-{uuid.uuid4()}-true") + except pymysql.Error as e: + messagebox.showerror(str(e.args[0]), str(e.args[1])) + self.node.message.insert(0, f"{sql}执行失败!{e}-{uuid.uuid4()}-false") + finally: + cursor.close() + self.node.update_message() + + def create_treeview(self, data_frame): + frame = Frame(self, height=580) + frame.grid(row=10, column=0, columnspan=10, rowspan=5, sticky=NSEW, pady=10) + frame.grid_columnconfigure(0, weight=1) + frame.grid_rowconfigure(0, weight=1) + unique_columns = data_frame.columns[~data_frame.columns.duplicated()] + columns = unique_columns.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 = f"SELECT * FROM {self.table_name}" + conditions = [] + select_fields = [] + for field, (entry, checkbox_var, i, j) in self.form_content.items(): + if entry.get(): + conditions.append("{} like '{}'".format(field, entry.get())) + if checkbox_var.get() == 1: + select_fields.append("{}".format(field)) + if conditions: + sql = "SELECT * FROM {} WHERE {}".format(self.table_name, " AND ".join(conditions)) + if select_fields: + sql = sql.replace("*", ",".join(select_fields)) + 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() + self.message = [] + + def create_left_plate(self): + self.left_frame = Frame(self.master, height=self.attr["height"]) + self.right_frame = Frame(self.master, height=self.attr["height"]) + self.right_frame.pack(side=RIGHT, anchor=NW, pady=10, padx=10) + 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) + message_frame = Frame(self.right_frame, width=50, height=180) + message_frame.pack(side=TOP, pady=10, fill=BOTH) + self.canvas = Canvas(message_frame, width=280, height=1000, bg="#f0f5fa") + self.canvas.configure(background="#f0f5fa") + y_scrollbar = Scrollbar(message_frame, orient="vertical", command=self.canvas.yview) + x_scrollbar = Scrollbar(message_frame, orient="horizontal", command=self.canvas.xview) + y_scrollbar.pack(side=RIGHT, fill=BOTH) + x_scrollbar.pack(side=BOTTOM, fill=BOTH) + self.canvas.pack(side=TOP, fill=BOTH) + self.canvas.configure(yscrollcommand=y_scrollbar.set) + self.canvas.configure(xscrollcommand=x_scrollbar.set) + + def update_message(self): + self.canvas.delete(ALL) + for message in self.message: + index = self.message.index(message) + self.canvas.create_text(0, 20 * index, anchor="nw", + text=message.split("-")[0], font=("", 15), fill="black" if message.split("-")[-1] == "true" else "red") + self.canvas.update() + self.canvas.configure(scrollregion=self.canvas.bbox("all")) + + 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, self) + form_element.pack(side=TOP, pady=10, anchor=NE) + + +if __name__ == '__main__': + """ + minty, lumen, sandstone, yeti, pulse, united, morph, journal, darkly, superhero, solar + cyborg, vapor, simplex, cerculean, + """ + 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.88, + "height": screenheight * 0.90, + } + 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) + ttk.Style().configure("TButton", font="-size 18") + root.mainloop() diff --git a/X5/StuSys_X5_15.py b/X5/StuSys_X5_15.py new file mode 100644 index 0000000..5716eb4 --- /dev/null +++ b/X5/StuSys_X5_15.py @@ -0,0 +1,335 @@ +import uuid +import random +from tkinter import messagebox +import tkinter.font as tkFont + +from ttkbootstrap import * +import ttkbootstrap as ttk +from ttkbootstrap.constants import * + +import pandas as pd +import pymysql + +from BaseWindow import BaseWindow + + +import warnings +warnings.simplefilter(action='ignore', category=UserWarning) + +# 添加第三个任务 + + +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="Wyz010810", 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 create_widget(self): + data_frame = pd.read_sql("show tables", self.conn) + 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) + combo = ttk.Combobox(self, width=10, height=1, textvariable=self.select_stringVar, font=self.font_style, + style="TCombobox") + combo["values"] = tables + combo.bind('<>', self.select_value) + combo.grid(column=0, row=0) + Button(self, text="装载", width=9, command=self.load).grid(column=1, row=0, padx=5) + + def create_tree_widget(self): + # 创建画布,用于展示装载后的数据 + frame = Frame(self, width=50, height=250) + 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, node): + super().__init__(master) + self.node = node + self.data = [] + self.conn = pymysql.connect(user="root", password="Wyz010810", 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.table_names = [] + self.form_content = {} + self.get_table_names() + self.table_name = self.table_names[0] + self.default_query_sql = f"SELECT * FROM {self.table_name}" + self.create_form() + self.select_table(None) + self.create_treeview(pd.read_sql(self.default_query_sql, con=self.conn)) + + def get_table_names(self): + """ + 获取该数据库下所有的表 + :return: + """ + data_frame = pd.read_sql("show tables", self.conn) + self.table_names = [i[0] for i in data_frame.values.tolist()] + + def select_table(self, event): + """ + 当下拉框选择表之后,触发该函数,并将tableName改为选择的tableName + :param event: + :return: + """ + for value in self.form_content.values(): + value[0].grid_forget() + value[2].grid_forget() + value[3].grid_forget() + self.form_content.clear() + self.table_name = self.select_table_name.get() + self.create_form() + self.sql_text.delete(0.0, END) + self.sql_text.insert(1.0, f"SELECT * FROM {self.table_name}") + + def get_field_names(self): + """ + 获取所有数据表的所有字段 + :return: 返回表内的所有字段 + """ + data_frame = pd.read_sql(f"desc {self.table_name}", self.conn) + """ + field_names = [] + for field in data_frame["Field"]: + field_names.append(f"{self.table_name}.{field}") + return field_names + """ + return data_frame["Field"].values.tolist() + + def create_form(self): + """ + 创建表单区域,根据数据表自动生成表单 + :return: + """ + self.select_table_name = StringVar() + self.select_table_name.set(self.table_name) + combo = ttk.Combobox(self, width=8, height=1, textvariable=self.select_table_name, font=self.font_style, + style="TCombobox") + combo["values"] = self.table_names + combo.bind('<>', self.select_table) + combo.grid(column=0, row=0, sticky=W) + fields = self.get_field_names() + num_fields = len(fields) + num_rows = (num_fields + 1) // 2 + for i in range(num_rows): + for j in range(2): + field_idx = i * 2 + j + if field_idx >= num_fields: + break + field_name = fields[field_idx] + label = Label(self, text=field_name, font=self.font_style) + label.grid(row=i + 1, column=j * 2, padx=5, pady=5, sticky=W) + checkbutton_var = IntVar() + checkbutton = Checkbutton(self, text='', variable=checkbutton_var) + checkbutton.grid(row=i + 1, column=j * 2, padx=5, pady=5, sticky=E) + entry = Entry(self, font=self.font_style) + entry.grid(row=i + 1, column=j * 2 + 1, padx=5, pady=5, sticky=W) + self.form_content[field_name] = (entry, checkbutton_var, label, checkbutton) + style = Style() + style.configure("custom.TButton", padding=(10, 40, 10, 40)) + Button(self, text="构造SQL", command=self.make_sql, width=8, style="custom.TButton" + ).grid(column=8, row=0, rowspan=8) + + self.sql_text = Text(self, height=3, font=self.font_style, width=62) + 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() + # 获取文本框中的sql语句 + sql = get_text_content(self.sql_text).lower().strip() + try: + cursor.execute(sql) + # 如果是查询语句 + if sql.startswith("select"): + data_frame = pd.read_sql(sql, con=self.conn) + self.create_treeview(data_frame) + self.node.message.insert(0, f"{sql}执行成功!共查询到{len(data_frame)}条数据-{uuid.uuid4()}-true") # uuid标识事件的唯一性 + return + # 如果不是查询语句 + self.node.message.insert(0, f"{sql}执行成功!-{uuid.uuid4()}-true") + except pymysql.Error as e: + messagebox.showerror(str(e.args[0]), str(e.args[1])) + self.node.message.insert(0, f"{sql}执行失败!{e}-{uuid.uuid4()}-false") + finally: + cursor.close() + self.node.update_message() + + def create_treeview(self, data_frame): + frame = Frame(self, height=580) + frame.grid(row=10, column=0, columnspan=10, rowspan=5, sticky=NSEW, pady=10) + frame.grid_columnconfigure(0, weight=1) + frame.grid_rowconfigure(0, weight=1) + unique_columns = data_frame.columns[~data_frame.columns.duplicated()] + columns = unique_columns.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 = f"SELECT * FROM {self.table_name}" + conditions = [] + select_fields = [] + + condition_statements = [ + "{} LIKE '{}'", + "{} = '{}'", + "NOT ({} != '{}')", + "{} IN ('{}')" + ] + + for field, (entry, checkbox_var, i, j) in self.form_content.items(): + if entry.get(): + + # conditions.append("{} like '{}'".format(field, entry.get())) + # conditions.append("{} = '{}'".format(field, entry.get())) + # conditions.append("NOT ({} != '{}')".format(field, entry.get())) + # conditions.append("{} IN ('{}')".format(field, entry.get())) + conditions.append(random.choice(condition_statements).format(field, entry.get())) + + if checkbox_var.get() == 1: + select_fields.append("{}".format(field)) + if conditions: + sql = "SELECT * FROM {} WHERE {}".format(self.table_name, " AND ".join(conditions)) + print(sql) + if select_fields: + sql = sql.replace("*", ",".join(select_fields)) + 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() + self.message = [] + + def create_left_plate(self): + self.left_frame = Frame(self.master, height=self.attr["height"]) + self.right_frame = Frame(self.master, height=self.attr["height"]) + self.right_frame.pack(side=RIGHT, anchor=NW, pady=10, padx=10) + 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) + message_frame = Frame(self.right_frame, width=50, height=180) + message_frame.pack(side=TOP, pady=10, fill=BOTH) + self.canvas = Canvas(message_frame, width=280, height=1000, bg="#f0f5fa") + self.canvas.configure(background="#f0f5fa") + y_scrollbar = Scrollbar(message_frame, orient="vertical", command=self.canvas.yview) + x_scrollbar = Scrollbar(message_frame, orient="horizontal", command=self.canvas.xview) + y_scrollbar.pack(side=RIGHT, fill=BOTH) + x_scrollbar.pack(side=BOTTOM, fill=BOTH) + self.canvas.pack(side=TOP, fill=BOTH) + self.canvas.configure(yscrollcommand=y_scrollbar.set) + self.canvas.configure(xscrollcommand=x_scrollbar.set) + + def update_message(self): + self.canvas.delete(ALL) + for message in self.message: + index = self.message.index(message) + self.canvas.create_text(0, 20 * index, anchor="nw", + text=message.split("-")[0], font=("", 15), fill="black" if message.split("-")[-1] == "true" else "red") + self.canvas.update() + self.canvas.configure(scrollregion=self.canvas.bbox("all")) + + 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, self) + form_element.pack(side=TOP, pady=10, anchor=NE) + + +if __name__ == '__main__': + """ + minty, lumen, sandstone, yeti, pulse, united, morph, journal, darkly, superhero, solar + cyborg, vapor, simplex, cerculean, + """ + 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.88, + "height": screenheight * 0.90, + } + 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) + ttk.Style().configure("TButton", font="-size 18") + root.mainloop() diff --git a/X5/StuSys_X5_final.py b/X5/StuSys_X5_final.py new file mode 100644 index 0000000..af14913 --- /dev/null +++ b/X5/StuSys_X5_final.py @@ -0,0 +1,382 @@ +import uuid +import random +from tkinter import messagebox +import tkinter.font as tkFont + +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 + +import warnings +warnings.simplefilter(action='ignore', category=UserWarning) + + +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="123123", database="stu_sys", host="127.0.0.1", port=3306) + self.conn = pymysql.connect(user="root", password="Wyz010810", 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.data_frame = pd.DataFrame([]) # 创建一个空的 DataFrame。而不是执行获得并限制返回数量为0 + + # 定义字体和按钮的格式 + 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() + + # 获取下拉框中的table_name以供后续装载等使用 + def select_value(self, event): + self.table_name = self.select_stringVar.get() + + # 固定的版本 + def create_widget_label(self): + # 不再需要查询数据库获取表名,也不需要创建下拉框 + # data_frame = pd.read_sql("show tables", self.conn) + # tables = [i[0] for i in data_frame.values.tolist()] + + style = ttk.Style() + # 设置 Label 的字体和字体大小 + style.configure('TLabel', font=('Arial', 20)) # 根据需要调整字体大小 + + # 创建 Label 控件以显示表名 + label = ttk.Label(self, text=self.table_name, font=self.font_style, style='TLabel') + label.grid(column=0, row=0) + # 创建装载按钮 + Button(self, text="装载", width=9, command=self.load).grid(column=1, row=0, padx=5) + + # 创建小控件,包括下拉按钮以及装载按钮 + def create_widget(self): + data_frame = pd.read_sql("show tables", self.conn) + 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) + combo = ttk.Combobox(self, width=10, height=1, textvariable=self.select_stringVar, font=self.font_style, + style="TCombobox") + combo["values"] = tables + combo.bind('<>', self.select_value) + combo.grid(column=0, row=0) + Button(self, text="装载", width=9, command=self.load).grid(column=1, row=0, padx=5) + + # 创建一个带有滚动条并定义好样式的树形视图控件,用于显示查询结果 + def create_tree_widget(self): + # 创建画布,用于展示装载后的数据 + frame = Frame(self, width=50, height=250) + 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, node): + super().__init__(master) + self.node = node + self.data = [] # 好像没用到 + # self.conn = pymysql.connect(user="root", password="123123", database="stu_sys", host="127.0.0.1", port=3306) + self.conn = pymysql.connect(user="root", password="Wyz010810", 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.table_names = [] # 用于存储下拉表单的数据库表名 + self.form_content = {} + self.get_table_names() + self.table_name = self.table_names[0] + self.default_query_sql = f"SELECT * FROM {self.table_name}" + self.create_form() + self.select_table(None) + self.create_treeview(pd.read_sql(self.default_query_sql, con=self.conn)) + + + def select_table(self, event): + """ + 当下拉框选择表之后,触发该函数,并将tableName改为选择的tableName + :param event: + :return: + """ + for value in self.form_content.values(): + value[0].grid_forget() + value[2].grid_forget() + value[3].grid_forget() + self.form_content.clear() + self.table_name = self.select_table_name.get() + self.create_form() + self.sql_text.delete(0.0, END) + self.sql_text.insert(1.0, f"SELECT * FROM {self.table_name}") + + def get_table_names(self): + """ + 获取该数据库下所有的表 + :return: + """ + data_frame = pd.read_sql("show tables", self.conn) + self.table_names = [i[0] for i in data_frame.values.tolist()] + + def get_field_names(self): + """ + 获取所有数据表的所有字段 + :return: 返回表内的所有字段 + """ + data_frame = pd.read_sql(f"desc {self.table_name}", self.conn) + """ + field_names = [] + for field in data_frame["Field"]: + field_names.append(f"{self.table_name}.{field}") + return field_names + """ + return data_frame["Field"].values.tolist() + + def create_form(self): + """ + 创建表单区域,根据数据表自动生成表单 + :return: + """ + self.select_table_name = StringVar() # 初始化一个StringVar对象,用于存储当前选中的表名 + self.select_table_name.set(self.table_name) # 设置默认表名 + combo = ttk.Combobox(self, width=8, height=1, textvariable=self.select_table_name, font=self.font_style, + style="TCombobox") # 创建一个下拉选择框,允许用户选择一个数据表 + combo["values"] = self.table_names # 设置下拉选项为所有表名 + combo.bind('<>', self.select_table) # 绑定选择事件处理函数 + combo.grid(column=0, row=0, sticky=W) # 放置组件 + # 获取当前表的所有字段名 + fields = self.get_field_names() + num_fields = len(fields) + num_rows = (num_fields + 1) // 2 # 计算需要的行数,以每行放置两个字段 + # 根据字段生成表单元素 + for i in range(num_rows): + for j in range(2): # 每行两列布局 + field_idx = i * 2 + j + if field_idx >= num_fields: + break # 如果字段索引超出范围,则退出循环 + field_name = fields[field_idx] # 获取字段名称 + # 为每个字段创建一个标签 + label = Label(self, text=field_name, font=self.font_style) + label.grid(row=i + 1, column=j * 2, padx=20, pady=5, sticky=W) + # 创建一个复选框,可能用于指示选择状态 + checkbutton_var = IntVar() + checkbutton = Checkbutton(self, text='', variable=checkbutton_var) + checkbutton.grid(row=i + 1, column=j * 2, padx=0, pady=5, sticky=E) + # 创建一个文本输入框,用于输入或显示字段值 + entry = Entry(self, font=self.font_style, width=12) + # entry = Entry(self, font=self.font_style) + entry.grid(row=i + 1, column=j * 2 + 1, padx=5, pady=5, sticky=W) + # 存储表单组件引用,以便后续使用 + self.form_content[field_name] = (entry, checkbutton_var, label, checkbutton) + # 配置并创建一个"构造SQL"按钮 + style = Style() + style.configure("custom.TButton", padding=(10, 40, 10, 40)) + Button(self, text="构造SQL", command=self.make_sql, width=8, style="custom.TButton" + ).grid(column=8, row=0, rowspan=8) + # 创建一个文本框,用于显示或编辑SQL命令 + self.sql_text = Text(self, height=3, font=self.font_style, width=46) + self.sql_text.grid(row=8, column=0, rowspan=2, columnspan=7, sticky=W) + # 创建一个"执行SQL"按钮,用于执行文本框中的SQL命令 + Button(self, text="\n执行SQL\n", command=self.execute_sql, width=8, + ).grid(column=8, row=8, rowspan=2, padx=10) + # 插入默认的查询SQL + self.sql_text.insert(1.0, self.default_query_sql) + + def execute_sql(self): + cursor = self.conn.cursor() + sql = get_text_content(self.sql_text).lower().strip() # 获取文本框中的sql语句 + try: + cursor.execute(sql) + # 如果是查询语句 + if sql.startswith("select"): + data_frame = pd.read_sql(sql, con=self.conn) + self.create_treeview(data_frame) + self.node.message.insert(0, f"{sql}执行成功!共查询到{len(data_frame)}条数据-{uuid.uuid4()}-true") # uuid标识事件的唯一性 + return + # 如果不是查询语句 + self.node.message.insert(0, f"{sql}执行成功!-{uuid.uuid4()}-true") + except pymysql.Error as e: + # 如果执行过程中遇到pymysql相关错误,则弹出错误信息框 + messagebox.showerror(str(e.args[0]), str(e.args[1])) + self.node.message.insert(0, f"{sql}执行失败!{e}-{uuid.uuid4()}-false") + finally: + cursor.close() + self.node.update_message() + + # 创建一个带有滚动条并定义好样式的树形视图控件,用于显示查询结果 + def create_treeview(self, data_frame): + frame = Frame(self, height=580) + frame.grid(row=10, column=0, columnspan=10, rowspan=5, sticky=NSEW, pady=10) + # 设置框架的列和行能够随窗口大小调整而伸缩。 + frame.grid_columnconfigure(0, weight=1) + frame.grid_rowconfigure(0, weight=1) + unique_columns = data_frame.columns[~data_frame.columns.duplicated()] + columns = unique_columns.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 = f"SELECT * FROM {self.table_name}" + conditions = [] + select_fields = [] + + condition_statements = [ + "{} LIKE '{}'", + "{} = '{}'", + "NOT ({} != '{}')", + "{} IN ('{}')" + ] + + for field, (entry, checkbox_var, i, j) in self.form_content.items(): + if entry.get(): + + # conditions.append("{} like '{}'".format(field, entry.get())) + # conditions.append("{} = '{}'".format(field, entry.get())) + # conditions.append("NOT ({} != '{}')".format(field, entry.get())) + # conditions.append("{} IN ('{}')".format(field, entry.get())) + conditions.append(random.choice(condition_statements).format(field, entry.get())) + + if checkbox_var.get() == 1: + select_fields.append("{}".format(field)) + if conditions: + sql = "SELECT * FROM {} WHERE {}".format(self.table_name, " AND ".join(conditions)) + print(sql) + if select_fields: + sql = sql.replace("*", ",".join(select_fields)) + 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() + self.message = [] + + # 这里创建了左边的三个小的查询的表 + 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) + # ...course与sc的装载表的创建方式类似 + load_element2 = LoadElement(self.left_frame, "course") + load_element2.pack(side=TOP, pady=10) + load_element3 = LoadElement(self.left_frame, "sc") + load_element3.pack(side=TOP, pady=10) + + # 以下是消息框部分的内容 + + # 创建右侧框架并打包定位 + self.right_frame = Frame(self.master, height=self.attr["height"]) + self.right_frame.pack(side=RIGHT, anchor=NW, pady=10, padx=10) + + # 创建消息框架和画布,可能用于显示信息或更复杂的交互元素 + message_frame = Frame(self.right_frame, width=50, height=180) + message_frame.pack(side=TOP, pady=10, fill=BOTH) + self.canvas = Canvas(message_frame, width=280, height=1000, bg="#f0f5fa") + self.canvas.configure(background="#f0f5fa") + # 配置滚动条 + y_scrollbar = Scrollbar(message_frame, orient="vertical", command=self.canvas.yview) + x_scrollbar = Scrollbar(message_frame, orient="horizontal", command=self.canvas.xview) + y_scrollbar.pack(side=RIGHT, fill=BOTH) + x_scrollbar.pack(side=BOTTOM, fill=BOTH) + self.canvas.pack(side=TOP, fill=BOTH) + self.canvas.configure(yscrollcommand=y_scrollbar.set) + self.canvas.configure(xscrollcommand=x_scrollbar.set) + + # 在查询后调用这个函数,更新查询记录部分 + def update_message(self): + self.canvas.delete(ALL) + for message in self.message: + index = self.message.index(message) + self.canvas.create_text(0, 20 * index, anchor="nw", + text=message.split("-")[0], font=("", 15), + fill="black" if message.split("-")[-1] == "true" else "red") + self.canvas.update() + self.canvas.configure(scrollregion=self.canvas.bbox("all")) + + 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, self) + form_element.pack(side=TOP, pady=10, anchor=NE) + +if __name__ == '__main__': + """ + minty, lumen, sandstone, yeti, pulse, united, morph, journal, darkly, superhero, solar + cyborg, vapor, simplex, cerculean, + """ + 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.88, + "height": screenheight * 0.90, + } + 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) + ttk.Style().configure("TButton", font="-size 18") + root.mainloop() diff --git a/X5/basic.png b/X5/basic.png new file mode 100644 index 0000000..c0012fe Binary files /dev/null and b/X5/basic.png differ diff --git a/draft.py b/draft.py new file mode 100644 index 0000000..33a7c3e --- /dev/null +++ b/draft.py @@ -0,0 +1,63 @@ +import pymysql + +# 创建名为SCT的数据库 +def create_database(): + cursor = conn.cursor() # 创建游标 + cursor.execute("DROP DATABASE IF EXISTS SCT") + # 创建数据库 + cursor.execute("CREATE DATABASE SCT CHARACTER SET utf8 COLLATE utf8_general_ci") + cursor.close() # 关闭游标 + +# 创建数据库表 +def create_table(): + cursor = conn.cursor() # 创建游标 + cursor.execute("USE SCT") # 指定数据库 + # 创建student数据表 + cursor.execute(""" + CREATE TABLE IF NOT EXISTS student + ( + sid CHAR(8) PRIMARY KEY, + sname CHAR(10), + ssex CHAR(2), + sage INTEGER, + sclass CHAR(6) + ) + """) + # 创建Course数据表 + cursor.execute(""" + CREATE TABLE IF NOT EXISTS course + ( + cid CHAR(4) PRIMARY KEY, + cname CHAR(30), + credit FLOAT(1), + chours INTEGER, + t CHAR(3) + ) + """) + # 创建SC数据表 + cursor.execute(""" + CREATE TABLE IF NOT EXISTS sc + ( + sid CHAR(8), + cid CHAR(4), + score FLOAT(1), + CONSTRAINT sc_course_cid_fk + FOREIGN KEY (cid) REFERENCES course (cid), + CONSTRAINT sc_student_sid_fk + FOREIGN KEY (sid) REFERENCES student (sid) + ) + """) + cursor.close() + +sql = """ +INSERT INTO student VALUES ('20200001', '张三','男',20,'01') +UPDATE student SET SClass = '02' WHERE S# = '20200001' +DELETE FROM student WHERE S# = '20200001' +SELECT * FROM student +""" + +if __name__ == '__main__': + conn = pymysql.connect(user="root", password="123456", host="127.0.0.1", port=3306) + create_database() + create_table() + conn.close() # 关闭链接