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

313 lines
13 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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 ttkbootstrap.toast import ToastNotification
from BaseWindow import BaseWindow
def get_text_content(text):
return text.get("0.0", "end").replace("\n", " ")
class LoadElement(Frame):
def __init__(self, master, table_name):
super().__init__(master)
self.master = master
self.table_name = table_name
self.data = []
self.conn = pymysql.connect(user="root", password="cyh0110", database="SCT", host="127.0.0.1", port=3306)
self.data_frame = pd.read_sql(f"select * from {self.table_name} limit 0", self.conn)
self.font_style = tkFont.Font(family="Lucida Grande", size=20)
self.button_font = tkFont.Font(family="Lucida Grande", size=10)
self.create_widget()
self.select_value(None)
self.create_tree_widget()
def select_value(self, event):
self.table_name = self.select_stringVar.get()
def 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('<<ComboboxSelected>>', 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=180)
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="cyh0110", database="SCT", host="127.0.0.1", port=3306)
self.font_style = tkFont.Font(family="Lucida Grande", size=20)
self.button_font = tkFont.Font(family="Lucida Grande", size=10)
self.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)
return data_frame["Field"].tolist()
def create_form(self):
"""
创建表单区域,根据数据表自动生成表单
:return:
"""
self.select_table_name = StringVar()
self.select_table_name.set(self.table_name)
combo = ttk.Combobox(self, width=10, height=1, textvariable=self.select_table_name, font=self.font_style,
style="TCombobox")
combo["values"] = self.table_names
combo.bind('<<ComboboxSelected>>', 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=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()
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)
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 = 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.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.left_frame, width=50, height=180)
message_frame.pack(side=TOP, pady=10, fill=BOTH)
self.canvas = Canvas(message_frame, width=50, height=180, 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,
"""
from pycallgraph2 import PyCallGraph
from pycallgraph2.output import GraphvizOutput
from pycallgraph2 import Config
from pycallgraph2 import GlobbingFilter
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)
output = GraphvizOutput(font_size=30)
output.output_file = "basic.png"
output.group_font_size = 40
config = Config()
config.trace_filter = GlobbingFilter(include=[
'StuSys_X4.*',
'FormElement.*',
'LoadElement.*',
])
with PyCallGraph(output=output, config=config):
app = StuSys_X4(root, root_attr)
ttk.Style().configure("TButton", font="-size 18")
root.mainloop()