(Python)tkinter连接MySQL进行学生数据管理

报错问题可能是:

1.缺少依赖

2.数据库账户密码没配置对,我自己用的是root root

更新ui布局

update-ui.py

python 复制代码
import tkinter as tk
from tkinter import ttk, messagebox, font
import mysql.connector
from mysql.connector import Error
from datetime import datetime


class StudentManagementSystem:
    def __init__(self, root):
        self.root = root
        self.root.title("学生信息管理系统")
        self.root.geometry("1100x600")

        # 设置窗口图标(如果有图标文件)
        try:
            self.root.iconbitmap('icon.ico')
        except:
            pass

        # 设置字体
        self.title_font = font.Font(family="微软雅黑", size=16, weight="bold")
        self.button_font = font.Font(family="微软雅黑", size=10)
        self.label_font = font.Font(family="微软雅黑", size=10)
        self.table_font = font.Font(family="微软雅黑", size=9)

        # 设置颜色
        self.bg_color = "#f0f0f0"
        self.button_bg = "#4CAF50"
        self.button_fg = "white"
        self.button_hover = "#45a049"
        self.search_bg = "#2196F3"
        self.search_hover = "#1976D2"
        self.delete_bg = "#f44336"
        self.delete_hover = "#d32f2f"

        # 配置主窗口背景色
        self.root.configure(bg=self.bg_color)

        # 数据库连接配置
        self.db_config = {
            'host': 'localhost',
            'user': 'root',
            'password': 'root',
            'database': 'student_management',
            'charset': 'utf8mb4',
            'use_unicode': True,
            'collation': 'utf8mb4_unicode_ci'
        }

        # 初始化数据库连接
        self.connection = None
        self.connect_db()
        self.create_table_if_not_exists()

        # 创建GUI
        self.create_widgets()
        self.load_data()

        # 中心化窗口
        self.center_window()

    def center_window(self):
        """将窗口居中显示"""
        self.root.update_idletasks()
        width = self.root.winfo_width()
        height = self.root.winfo_height()
        x = (self.root.winfo_screenwidth() // 2) - (width // 2)
        y = (self.root.winfo_screenheight() // 2) - (height // 2)
        self.root.geometry(f'{width}x{height}+{x}+{y}')

    def connect_db(self):
        """连接到MySQL数据库"""
        try:
            self.connection = mysql.connector.connect(**self.db_config)
            if self.connection.is_connected():
                cursor = self.connection.cursor()
                cursor.execute("SET NAMES utf8mb4")
                cursor.execute("SET CHARACTER SET utf8mb4")
                cursor.execute("SET character_set_connection=utf8mb4")
                cursor.close()
                print("成功连接到MySQL数据库,字符集已设置为utf8mb4")
        except Error as e:
            messagebox.showerror("数据库连接错误", f"无法连接到数据库: {str(e)}")
            self.root.quit()

    def create_table_if_not_exists(self):
        """如果表不存在则创建表"""
        try:
            cursor = self.connection.cursor()
            cursor.execute("""
                           CREATE TABLE IF NOT EXISTS students
                           (
                               student_id
                               VARCHAR
                           (
                               10
                           ) PRIMARY KEY,
                               name VARCHAR
                           (
                               50
                           ) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
                               gender VARCHAR
                           (
                               2
                           ) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
                               birth_date DATE,
                               major VARCHAR
                           (
                               50
                           ) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
                               total_credits INT,
                               remarks TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
                               ) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
                           """)
            self.connection.commit()
            print("表已创建/验证,字符集为utf8mb4")
        except Error as e:
            messagebox.showerror("数据库错误", f"创建表失败: {str(e)}")

    def create_widgets(self):
        """创建GUI组件"""
        # 标题框架
        title_frame = tk.Frame(self.root, bg=self.bg_color)
        title_frame.pack(fill=tk.X, pady=(20, 10))

        # 标题标签
        title_label = tk.Label(
            title_frame,
            text="学生信息管理系统",
            font=self.title_font,
            bg=self.bg_color,
            fg="#333333"
        )
        title_label.pack()

        # 按钮框架
        button_frame = tk.Frame(self.root, bg=self.bg_color)
        button_frame.pack(fill=tk.X, pady=10, padx=20)

        # 创建按钮样式
        style = ttk.Style()
        style.theme_use('clam')

        # 按钮定义
        button_configs = [
            ("查询", self.query_student, self.search_bg, self.search_hover),
            ("插入", self.insert_student, self.button_bg, self.button_hover),
            ("修改", self.update_student, "#FF9800", "#F57C00"),
            ("删除", self.delete_student, self.delete_bg, self.delete_hover),
            ("刷新", self.load_data, "#9C27B0", "#7B1FA2"),
        ]

        for text, command, bg_color, hover_color in button_configs:
            btn = self.create_button(button_frame, text, command, bg_color, hover_color)
            btn.pack(side=tk.LEFT, padx=5, ipady=5, ipadx=15)

        # 搜索框架
        search_frame = tk.Frame(self.root, bg=self.bg_color)
        search_frame.pack(fill=tk.X, pady=10, padx=20)

        search_label = tk.Label(
            search_frame,
            text="学号/姓名搜索:",
            font=self.label_font,
            bg=self.bg_color,
            fg="#333333"
        )
        search_label.pack(side=tk.LEFT, padx=(0, 10))

        self.search_var = tk.StringVar()
        self.search_entry = tk.Entry(
            search_frame,
            textvariable=self.search_var,
            width=40,
            font=self.label_font,
            relief=tk.GROOVE,
            bd=2
        )
        self.search_entry.pack(side=tk.LEFT, padx=(0, 10))

        # 绑定回车键搜索
        self.search_entry.bind('<Return>', lambda e: self.search_data())

        search_btn = self.create_button(search_frame, "搜索", self.search_data, self.search_bg, self.search_hover)
        search_btn.pack(side=tk.LEFT, ipady=5, ipadx=15)

        # 状态标签
        self.status_label = tk.Label(
            self.root,
            text="就绪",
            font=font.Font(family="微软雅黑", size=9),
            bg=self.bg_color,
            fg="#666666",
            anchor=tk.W
        )
        self.status_label.pack(fill=tk.X, padx=20, pady=(5, 10))

        # 表格框架
        table_frame = tk.Frame(self.root, bg=self.bg_color)
        table_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=(0, 20))

        # 创建表格
        columns = ("学号", "姓名", "性别", "出生时间", "专业", "总学分", "备注")
        self.tree = ttk.Treeview(
            table_frame,
            columns=columns,
            show="headings",
            height=18,
            selectmode="browse"
        )

        # 配置表格样式
        style.configure("Treeview",
                        font=self.table_font,
                        rowheight=25,
                        background="#ffffff",
                        fieldbackground="#ffffff",
                        foreground="#000000")

        style.configure("Treeview.Heading",
                        font=font.Font(family="微软雅黑", size=10, weight="bold"),
                        background="#e1e1e1",
                        foreground="#333333",
                        relief=tk.FLAT)

        style.map("Treeview.Heading", background=[('active', '#d1d1d1')])

        # 设置列标题和宽度
        column_widths = {
            "学号": 100,
            "姓名": 100,
            "性别": 60,
            "出生时间": 120,
            "专业": 120,
            "总学分": 80,
            "备注": 200
        }

        for col in columns:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=column_widths[col], anchor="center")

        # 设置隔行变色
        self.tree.tag_configure('oddrow', background='#f9f9f9')
        self.tree.tag_configure('evenrow', background='#ffffff')

        # 垂直滚动条
        scrollbar = ttk.Scrollbar(
            table_frame,
            orient="vertical",
            command=self.tree.yview
        )
        self.tree.configure(yscrollcommand=scrollbar.set)

        # 布局
        self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # 绑定事件
        self.tree.bind('<Double-Button-1>', self.on_double_click)

        # 右键菜单
        self.create_context_menu()

    def create_button(self, parent, text, command, bg_color, hover_color):
        """创建自定义样式的按钮"""

        def on_enter(e):
            btn['background'] = hover_color

        def on_leave(e):
            btn['background'] = bg_color

        btn = tk.Button(
            parent,
            text=text,
            command=command,
            font=self.button_font,
            bg=bg_color,
            fg="white",
            activebackground=hover_color,
            activeforeground="white",
            relief=tk.RAISED,
            bd=1,
            cursor="hand2"
        )

        btn.bind("<Enter>", on_enter)
        btn.bind("<Leave>", on_leave)

        return btn

    def create_context_menu(self):
        """创建右键菜单"""
        self.context_menu = tk.Menu(self.root, tearoff=0)
        self.context_menu.add_command(label="查看详情", command=self.show_details)
        self.context_menu.add_command(label="修改信息", command=self.update_student)
        self.context_menu.add_separator()
        self.context_menu.add_command(label="删除学生", command=self.delete_student)

        # 绑定右键事件
        self.tree.bind("<Button-3>", self.show_context_menu)

    def show_context_menu(self, event):
        """显示右键菜单"""
        item = self.tree.identify_row(event.y)
        if item:
            self.tree.selection_set(item)
            self.context_menu.post(event.x_root, event.y_root)

    def load_data(self):
        """从数据库加载数据到表格"""
        # 清空表格
        for item in self.tree.get_children():
            self.tree.delete(item)

        try:
            cursor = self.connection.cursor()
            cursor.execute("SELECT * FROM students ORDER BY student_id")
            rows = cursor.fetchall()

            # 插入数据到表格
            for i, row in enumerate(rows):
                # 格式化日期
                birth_date = row[3]
                if birth_date:
                    birth_date_str = birth_date.strftime('%Y/%m/%d')
                else:
                    birth_date_str = ""

                # 处理None值
                values = list(row)
                for j in range(len(values)):
                    if values[j] is None:
                        values[j] = ""

                values[3] = birth_date_str

                # 设置隔行颜色
                tag = 'evenrow' if i % 2 == 0 else 'oddrow'
                self.tree.insert("", tk.END, values=values, tags=(tag,))

            cursor.close()

            # 更新状态
            self.status_label.config(text=f"共 {len(rows)} 条记录")
            print(f"加载了 {len(rows)} 条记录")
        except Error as e:
            messagebox.showerror("数据库错误", f"加载数据失败: {str(e)}")

    def search_data(self):
        """搜索学生信息"""
        search_text = self.search_var.get().strip()
        if not search_text:
            messagebox.showwarning("搜索提示", "请输入搜索内容")
            return

        # 清空表格
        for item in self.tree.get_children():
            self.tree.delete(item)

        try:
            cursor = self.connection.cursor()
            query = """
                    SELECT * \
                    FROM students
                    WHERE student_id LIKE %s \
                       OR name LIKE %s
                    ORDER BY student_id \
                    """
            search_pattern = f"%{search_text}%"
            cursor.execute(query, (search_pattern, search_pattern))
            rows = cursor.fetchall()

            if rows:
                for i, row in enumerate(rows):
                    # 格式化日期
                    birth_date = row[3]
                    if birth_date:
                        birth_date_str = birth_date.strftime('%Y/%m/%d')
                    else:
                        birth_date_str = ""

                    # 处理None值
                    values = list(row)
                    for j in range(len(values)):
                        if values[j] is None:
                            values[j] = ""

                    values[3] = birth_date_str

                    # 设置隔行颜色
                    tag = 'evenrow' if i % 2 == 0 else 'oddrow'
                    self.tree.insert("", tk.END, values=values, tags=(tag,))

                self.status_label.config(text=f"找到 {len(rows)} 条记录")
                messagebox.showinfo("搜索结果", f"找到 {len(rows)} 条记录")
            else:
                self.status_label.config(text="未找到相关记录")
                messagebox.showinfo("搜索结果", "未找到相关记录")

            cursor.close()
        except Error as e:
            messagebox.showerror("数据库错误", f"搜索失败: {str(e)}")

    def show_details(self):
        """显示选中学生的详细信息"""
        selected_item = self.tree.selection()
        if selected_item:
            values = self.tree.item(selected_item[0])['values']
            details_window = tk.Toplevel(self.root)
            details_window.title("学生详细信息")
            details_window.geometry("400x300")
            details_window.configure(bg=self.bg_color)

            # 中心化窗口
            details_window.update_idletasks()
            width = details_window.winfo_width()
            height = details_window.winfo_height()
            x = (details_window.winfo_screenwidth() // 2) - (width // 2)
            y = (details_window.winfo_screenheight() // 2) - (height // 2)
            details_window.geometry(f'{width}x{height}+{x}+{y}')

            # 创建详情内容
            details = [
                ("学号:", values[0]),
                ("姓名:", values[1]),
                ("性别:", values[2]),
                ("出生时间:", values[3]),
                ("专业:", values[4]),
                ("总学分:", values[5]),
                ("备注:", values[6] if values[6] else "无")
            ]

            for i, (label, value) in enumerate(details):
                tk.Label(details_window, text=label, font=self.label_font,
                         bg=self.bg_color, fg="#333333", anchor="e").grid(
                    row=i, column=0, padx=20, pady=10, sticky="e"
                )
                tk.Label(details_window, text=value, font=self.label_font,
                         bg=self.bg_color, fg="#666666", anchor="w").grid(
                    row=i, column=1, padx=(0, 20), pady=10, sticky="w"
                )

    def insert_student(self):
        """打开插入学生窗口"""
        InsertWindow(self)

    def query_student(self):
        """查询特定学生信息"""
        QueryWindow(self)

    def delete_student(self):
        """删除选中的学生"""
        selected_item = self.tree.selection()
        if not selected_item:
            messagebox.showwarning("删除提示", "请先选择要删除的学生")
            return

        # 获取选中的学生学号
        student_id = self.tree.item(selected_item[0])['values'][0]
        student_name = self.tree.item(selected_item[0])['values'][1]

        # 确认删除
        confirm = messagebox.askyesno("确认删除",
                                      f"确定要删除学生 {student_name} (学号: {student_id}) 吗?",
                                      icon='warning')
        if confirm:
            try:
                cursor = self.connection.cursor()
                cursor.execute("DELETE FROM students WHERE student_id = %s", (student_id,))
                self.connection.commit()

                # 从表格中移除
                self.tree.delete(selected_item[0])

                # 更新状态
                self.status_label.config(text=f"已删除学生 {student_name}")
                messagebox.showinfo("删除成功", f"已删除学生 {student_name}")
                cursor.close()
            except Error as e:
                messagebox.showerror("数据库错误", f"删除失败: {str(e)}")

    def update_student(self):
        """修改选中的学生信息"""
        selected_item = self.tree.selection()
        if not selected_item:
            messagebox.showwarning("修改提示", "请先选择要修改的学生")
            return

        # 获取选中的学生信息
        values = self.tree.item(selected_item[0])['values']
        UpdateWindow(self, values)

    def on_double_click(self, event):
        """双击表格行时显示详细信息"""
        selected_item = self.tree.selection()
        if selected_item:
            values = self.tree.item(selected_item[0])['values']
            self.show_details()

    def __del__(self):
        """关闭数据库连接"""
        if self.connection and self.connection.is_connected():
            self.connection.close()
            print("数据库连接已关闭")


class InsertWindow:
    """插入学生信息窗口"""

    def __init__(self, parent):
        self.parent = parent
        self.window = tk.Toplevel(parent.root)
        self.window.title("插入学生信息")
        self.window.geometry("500x450")
        self.window.configure(bg=parent.bg_color)

        # 中心化窗口
        self.window.update_idletasks()
        width = self.window.winfo_width()
        height = self.window.winfo_height()
        x = (self.window.winfo_screenwidth() // 2) - (width // 2)
        y = (self.window.winfo_screenheight() // 2) - (height // 2)
        self.window.geometry(f'{width}x{height}+{x}+{y}')

        # 创建标题
        title_label = tk.Label(
            self.window,
            text="新增学生信息",
            font=self.parent.title_font,
            bg=self.parent.bg_color,
            fg="#333333"
        )
        title_label.pack(pady=(20, 30))

        # 创建表单框架
        form_frame = tk.Frame(self.window, bg=self.parent.bg_color)
        form_frame.pack(padx=40)

        self.create_widgets(form_frame)

        # 创建按钮框架
        button_frame = tk.Frame(self.window, bg=self.parent.bg_color)
        button_frame.pack(pady=30)

        # 插入按钮
        insert_btn = self.parent.create_button(
            button_frame,
            "插入",
            self.insert,
            self.parent.button_bg,
            self.parent.button_hover
        )
        insert_btn.pack(side=tk.LEFT, padx=10, ipady=5, ipadx=20)

        # 取消按钮
        cancel_btn = self.parent.create_button(
            button_frame,
            "取消",
            self.window.destroy,
            self.parent.delete_bg,
            self.parent.delete_hover
        )
        cancel_btn.pack(side=tk.LEFT, padx=10, ipady=5, ipadx=20)

    def create_widgets(self, parent):
        """创建表单组件"""
        # 字段定义
        fields = [
            ("学号:", "id_entry"),
            ("姓名:", "name_entry"),
            ("性别:", "gender_var"),  # 特别注意:这是单选按钮,不是输入框
            ("出生时间 (YYYY/MM/DD):", "birth_entry", "1997/02/10"),
            ("专业:", "major_entry", "计算机"),
            ("总学分:", "credits_entry", "50"),
            ("备注:", "remarks_entry")
        ]

        row = 0
        for field in fields:
            label_text = field[0]
            field_name = field[1]
            default_value = field[2] if len(field) > 2 else ""

            # 标签
            label = tk.Label(
                parent,
                text=label_text,
                font=self.parent.label_font,
                bg=self.parent.bg_color,
                fg="#333333",
                anchor="e"
            )
            label.grid(row=row, column=0, padx=10, pady=10, sticky="e")

            # 如果是性别字段,创建单选按钮
            if field_name == "gender_var":
                gender_frame = tk.Frame(parent, bg=self.parent.bg_color)
                gender_frame.grid(row=row, column=1, padx=10, pady=10, sticky="w")

                self.gender_var = tk.StringVar(value="男")
                tk.Radiobutton(gender_frame, text="男", variable=self.gender_var,
                               value="男", font=self.parent.label_font,
                               bg=self.parent.bg_color, selectcolor=self.parent.bg_color).pack(side=tk.LEFT, padx=10)
                tk.Radiobutton(gender_frame, text="女", variable=self.gender_var,
                               value="女", font=self.parent.label_font,
                               bg=self.parent.bg_color, selectcolor=self.parent.bg_color).pack(side=tk.LEFT, padx=10)
                row += 1
                continue

            # 对于其他字段,创建输入框
            entry = tk.Entry(
                parent,
                width=30,
                font=self.parent.label_font,
                relief=tk.GROOVE,
                bd=2
            )
            entry.grid(row=row, column=1, padx=10, pady=10, sticky="w")

            if default_value:
                entry.insert(0, default_value)

            # 保存引用
            setattr(self, field_name, entry)
            row += 1

    def insert(self):
        """插入新学生到数据库"""
        # 获取输入值
        student_id = self.id_entry.get().strip()
        name = self.name_entry.get().strip()
        gender = self.gender_var.get()
        birth_date = self.birth_entry.get().strip()
        major = self.major_entry.get().strip()
        credits = self.credits_entry.get().strip()
        remarks = self.remarks_entry.get().strip()

        # 验证输入
        if not student_id or not name:
            messagebox.showwarning("输入错误", "学号和姓名不能为空")
            return

        # 验证学号是否已存在
        try:
            cursor = self.parent.connection.cursor()
            cursor.execute("SELECT student_id FROM students WHERE student_id = %s", (student_id,))
            if cursor.fetchone():
                messagebox.showwarning("输入错误", f"学号 {student_id} 已存在")
                cursor.close()
                return
            cursor.close()
        except Error as e:
            messagebox.showerror("数据库错误", f"验证学号失败: {str(e)}")
            return

        # 插入数据
        try:
            cursor = self.parent.connection.cursor()

            # 转换日期格式
            if birth_date:
                try:
                    birth_date_obj = datetime.strptime(birth_date, '%Y/%m/%d')
                except ValueError:
                    try:
                        birth_date_obj = datetime.strptime(birth_date, '%Y-%m-%d')
                    except ValueError:
                        messagebox.showwarning("日期格式错误", "请使用YYYY/MM/DD或YYYY-MM-DD格式")
                        return
            else:
                birth_date_obj = None

            # 转换学分
            try:
                credits_int = int(credits) if credits else 0
            except ValueError:
                credits_int = 0

            # 执行插入
            insert_query = """
                           INSERT INTO students (student_id, name, gender, birth_date, major, total_credits, remarks)
                           VALUES (%s, %s, %s, %s, %s, %s, %s) \
                           """
            insert_values = (student_id, name, gender, birth_date_obj, major, credits_int, remarks if remarks else None)

            cursor.execute(insert_query, insert_values)
            self.parent.connection.commit()
            cursor.close()

            messagebox.showinfo("插入成功", f"学生 {name} 已成功添加")

            # 刷新主窗口数据
            self.parent.load_data()

            # 关闭窗口
            self.window.destroy()

        except Error as e:
            messagebox.showerror("数据库错误", f"插入失败: {str(e)}")


class QueryWindow:
    """查询学生信息窗口"""

    def __init__(self, parent):
        self.parent = parent
        self.window = tk.Toplevel(parent.root)
        self.window.title("查询学生信息")
        self.window.geometry("400x200")
        self.window.configure(bg=parent.bg_color)

        # 中心化窗口
        self.window.update_idletasks()
        width = self.window.winfo_width()
        height = self.window.winfo_height()
        x = (self.window.winfo_screenwidth() // 2) - (width // 2)
        y = (self.window.winfo_screenheight() // 2) - (height // 2)
        self.window.geometry(f'{width}x{height}+{x}+{y}')

        # 创建标题
        title_label = tk.Label(
            self.window,
            text="查询学生信息",
            font=self.parent.title_font,
            bg=self.parent.bg_color,
            fg="#333333"
        )
        title_label.pack(pady=(30, 20))

        # 查询输入框
        input_frame = tk.Frame(self.window, bg=self.parent.bg_color)
        input_frame.pack(pady=10)

        tk.Label(input_frame, text="请输入学号:", font=self.parent.label_font,
                 bg=self.parent.bg_color, fg="#333333").pack(side=tk.LEFT, padx=5)

        self.query_id_entry = tk.Entry(
            input_frame,
            width=25,
            font=self.parent.label_font,
            relief=tk.GROOVE,
            bd=2
        )
        self.query_id_entry.pack(side=tk.LEFT, padx=5)

        # 绑定回车键
        self.query_id_entry.bind('<Return>', lambda e: self.query())

        # 按钮框架
        btn_frame = tk.Frame(self.window, bg=self.parent.bg_color)
        btn_frame.pack(pady=20)

        query_btn = self.parent.create_button(
            btn_frame,
            "查询",
            self.query,
            self.parent.search_bg,
            self.parent.search_hover
        )
        query_btn.pack(side=tk.LEFT, padx=10, ipady=5, ipadx=15)

        cancel_btn = self.parent.create_button(
            btn_frame,
            "取消",
            self.window.destroy,
            self.parent.delete_bg,
            self.parent.delete_hover
        )
        cancel_btn.pack(side=tk.LEFT, padx=10, ipady=5, ipadx=15)

    def query(self):
        """查询学生信息"""
        student_id = self.query_id_entry.get().strip()
        if not student_id:
            messagebox.showwarning("查询提示", "请输入学号")
            return

        try:
            cursor = self.parent.connection.cursor()
            cursor.execute("SELECT * FROM students WHERE student_id = %s", (student_id,))
            row = cursor.fetchone()

            if row:
                # 格式化日期
                birth_date = row[3]
                if birth_date:
                    birth_date_str = birth_date.strftime('%Y/%m/%d')
                else:
                    birth_date_str = ""

                # 显示查询结果
                details = f"学号: {row[0]}\n姓名: {row[1]}\n性别: {row[2]}\n出生时间: {birth_date_str}\n专业: {row[4]}\n总学分: {row[5]}\n备注: {row[6] if row[6] else '无'}"
                messagebox.showinfo("查询结果", details)
            else:
                messagebox.showinfo("查询结果", f"未找到学号为 {student_id} 的学生")

            cursor.close()
        except Error as e:
            messagebox.showerror("数据库错误", f"查询失败: {str(e)}")


class UpdateWindow:
    """修改学生信息窗口"""

    def __init__(self, parent, values):
        self.parent = parent
        self.original_id = values[0]  # 保存原始学号
        self.window = tk.Toplevel(parent.root)
        self.window.title("修改学生信息")
        self.window.geometry("500x450")
        self.window.configure(bg=parent.bg_color)

        # 中心化窗口
        self.window.update_idletasks()
        width = self.window.winfo_width()
        height = self.window.winfo_height()
        x = (self.window.winfo_screenwidth() // 2) - (width // 2)
        y = (self.window.winfo_screenheight() // 2) - (height // 2)
        self.window.geometry(f'{width}x{height}+{x}+{y}')

        # 创建标题
        title_label = tk.Label(
            self.window,
            text="修改学生信息",
            font=self.parent.title_font,
            bg=self.parent.bg_color,
            fg="#333333"
        )
        title_label.pack(pady=(20, 30))

        # 创建表单框架
        form_frame = tk.Frame(self.window, bg=self.parent.bg_color)
        form_frame.pack(padx=40)

        self.create_widgets(form_frame, values)

        # 创建按钮框架
        button_frame = tk.Frame(self.window, bg=self.parent.bg_color)
        button_frame.pack(pady=30)

        # 更新按钮
        update_btn = self.parent.create_button(
            button_frame,
            "更新",
            self.update,
            "#FF9800",
            "#F57C00"
        )
        update_btn.pack(side=tk.LEFT, padx=10, ipady=5, ipadx=20)

        # 取消按钮
        cancel_btn = self.parent.create_button(
            button_frame,
            "取消",
            self.window.destroy,
            self.parent.delete_bg,
            self.parent.delete_hover
        )
        cancel_btn.pack(side=tk.LEFT, padx=10, ipady=5, ipadx=20)

    def create_widgets(self, parent, values):
        """创建表单组件"""
        # 字段定义
        fields = [
            ("学号:", "id_entry"),
            ("姓名:", "name_entry"),
            ("性别:", "gender_var"),  # 特别注意:这是单选按钮,不是输入框
            ("出生时间 (YYYY/MM/DD):", "birth_entry", "1997/02/10"),
            ("专业:", "major_entry", "计算机"),
            ("总学分:", "credits_entry", "50"),
            ("备注:", "remarks_entry")
        ]

        row = 0
        for field in fields:
            label_text = field[0]
            field_name = field[1]
            default_value = field[2] if len(field) > 2 else ""

            # 标签
            label = tk.Label(
                parent,
                text=label_text,
                font=self.parent.label_font,
                bg=self.parent.bg_color,
                fg="#333333",
                anchor="e"
            )
            label.grid(row=row, column=0, padx=10, pady=10, sticky="e")

            # 如果是性别字段,创建单选按钮
            if field_name == "gender_var":
                gender_frame = tk.Frame(parent, bg=self.parent.bg_color)
                gender_frame.grid(row=row, column=1, padx=10, pady=10, sticky="w")

                gender_value = values[2] if values[2] else "男"
                self.gender_var = tk.StringVar(value=gender_value)
                tk.Radiobutton(gender_frame, text="男", variable=self.gender_var,
                               value="男", font=self.parent.label_font,
                               bg=self.parent.bg_color, selectcolor=self.parent.bg_color).pack(side=tk.LEFT, padx=10)
                tk.Radiobutton(gender_frame, text="女", variable=self.gender_var,
                               value="女", font=self.parent.label_font,
                               bg=self.parent.bg_color, selectcolor=self.parent.bg_color).pack(side=tk.LEFT, padx=10)
                row += 1
                continue

            # 对于其他字段,创建输入框
            entry = tk.Entry(
                parent,
                width=30,
                font=self.parent.label_font,
                relief=tk.GROOVE,
                bd=2
            )
            entry.grid(row=row, column=1, padx=10, pady=10, sticky="w")

            # 根据字段名设置默认值
            if field_name == "id_entry":
                entry.insert(0, values[0])
            elif field_name == "name_entry":
                entry.insert(0, values[1])
            elif field_name == "birth_entry":
                entry.insert(0, values[3])
            elif field_name == "major_entry":
                entry.insert(0, values[4])
            elif field_name == "credits_entry":
                entry.insert(0, str(values[5]))
            elif field_name == "remarks_entry":
                entry.insert(0, values[6] if values[6] else "")
            elif default_value:
                entry.insert(0, default_value)

            # 保存引用
            setattr(self, field_name, entry)
            row += 1

    def update(self):
        """更新学生信息"""
        # 获取输入值
        student_id = self.id_entry.get().strip()
        name = self.name_entry.get().strip()
        gender = self.gender_var.get()
        birth_date = self.birth_entry.get().strip()
        major = self.major_entry.get().strip()
        credits = self.credits_entry.get().strip()
        remarks = self.remarks_entry.get().strip()

        # 验证输入
        if not student_id or not name:
            messagebox.showwarning("输入错误", "学号和姓名不能为空")
            return

        # 如果学号已修改,检查新学号是否已存在
        if student_id != self.original_id:
            try:
                cursor = self.parent.connection.cursor()
                cursor.execute("SELECT student_id FROM students WHERE student_id = %s", (student_id,))
                if cursor.fetchone():
                    messagebox.showwarning("输入错误", f"学号 {student_id} 已存在")
                    cursor.close()
                    return
                cursor.close()
            except Error as e:
                messagebox.showerror("数据库错误", f"验证学号失败: {str(e)}")
                return

        # 更新数据
        try:
            cursor = self.parent.connection.cursor()

            # 转换日期格式
            if birth_date:
                try:
                    birth_date_obj = datetime.strptime(birth_date, '%Y/%m/%d')
                except ValueError:
                    try:
                        birth_date_obj = datetime.strptime(birth_date, '%Y-%m-%d')
                    except ValueError:
                        messagebox.showwarning("日期格式错误", "请使用YYYY/MM/DD或YYYY-MM-DD格式")
                        return
            else:
                birth_date_obj = None

            # 转换学分
            try:
                credits_int = int(credits) if credits else 0
            except ValueError:
                credits_int = 0

            # 执行更新
            update_query = """
                           UPDATE students
                           SET student_id    = %s, \
                               name          = %s, \
                               gender        = %s, \
                               birth_date    = %s, \
                               major         = %s, \
                               total_credits = %s, \
                               remarks       = %s
                           WHERE student_id = %s \
                           """
            update_values = (student_id, name, gender, birth_date_obj, major, credits_int,
                             remarks if remarks else None, self.original_id)

            cursor.execute(update_query, update_values)
            self.parent.connection.commit()
            cursor.close()

            messagebox.showinfo("更新成功", f"学生 {name} 的信息已更新")

            # 刷新主窗口数据
            self.parent.load_data()

            # 关闭窗口
            self.window.destroy()

        except Error as e:
            messagebox.showerror("数据库错误", f"更新失败: {str(e)}")


def main():
    root = tk.Tk()
    app = StudentManagementSystem(root)
    root.mainloop()


if __name__ == "__main__":
    main()

创建数据库sql:

python 复制代码
-- 删除原有数据库
DROP DATABASE IF EXISTS student_management;

-- 创建新数据库,指定字符集
CREATE DATABASE student_management 
CHARACTER SET utf8mb4 
COLLATE utf8mb4_unicode_ci;

USE student_management;

-- 创建表,指定字符集
CREATE TABLE students (
    student_id VARCHAR(10) PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    gender VARCHAR(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
    birth_date DATE,
    major VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
    total_credits INT,
    remarks TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

运行效果:

python代码:

python 复制代码
import tkinter as tk
from tkinter import ttk, messagebox
import mysql.connector
from mysql.connector import Error
from datetime import datetime


class StudentManagementSystem:
    def __init__(self, root):
        self.root = root
        self.root.title("学生信息管理系统")
        self.root.geometry("1000x500")

        # 数据库连接配置
        self.db_config = {
            'host': 'localhost',
            'user': 'root',  # 修改为你的MySQL用户名
            'password': 'root',  # 修改为你的MySQL密码
            'database': 'student_management'
        }

        # 初始化数据库连接
        self.connection = None
        self.connect_db()
        self.create_table_if_not_exists()

        # 创建GUI
        self.create_widgets()
        self.load_data()

    def connect_db(self):
        """连接到MySQL数据库"""
        try:
            self.connection = mysql.connector.connect(**self.db_config)
            if self.connection.is_connected():
                print("成功连接到MySQL数据库")
        except Error as e:
            messagebox.showerror("数据库连接错误", f"无法连接到数据库: {str(e)}")
            self.root.quit()

    def create_table_if_not_exists(self):
        """如果表不存在则创建表"""
        try:
            cursor = self.connection.cursor()
            cursor.execute("""
                           CREATE TABLE IF NOT EXISTS students
                           (
                               student_id
                               VARCHAR
                           (
                               10
                           ) PRIMARY KEY,
                               name VARCHAR
                           (
                               50
                           ) NOT NULL,
                               gender VARCHAR
                           (
                               2
                           ),
                               birth_date DATE,
                               major VARCHAR
                           (
                               50
                           ),
                               total_credits INT,
                               remarks TEXT
                               )
                           """)
            self.connection.commit()
            print("表已准备好")
        except Error as e:
            messagebox.showerror("数据库错误", f"创建表失败: {str(e)}")

    def create_widgets(self):
        """创建GUI组件"""
        # 按钮框架
        btn_frame = tk.Frame(self.root)
        btn_frame.pack(pady=10)

        # 按钮
        tk.Button(btn_frame, text="查询", command=self.query_student, width=10).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="插入", command=self.insert_student, width=10).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="删除", command=self.delete_student, width=10).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="修改", command=self.update_student, width=10).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="刷新", command=self.load_data, width=10).pack(side=tk.LEFT, padx=5)

        # 搜索框架
        search_frame = tk.Frame(self.root)
        search_frame.pack(pady=5)

        tk.Label(search_frame, text="学号/姓名搜索:").pack(side=tk.LEFT, padx=5)
        self.search_var = tk.StringVar()
        self.search_entry = tk.Entry(search_frame, textvariable=self.search_var, width=30)
        self.search_entry.pack(side=tk.LEFT, padx=5)
        tk.Button(search_frame, text="搜索", command=self.search_data, width=10).pack(side=tk.LEFT, padx=5)

        # 表格框架
        table_frame = tk.Frame(self.root)
        table_frame.pack(pady=10, padx=20, fill=tk.BOTH, expand=True)

        # 创建表格
        columns = ("学号", "姓名", "性别", "出生时间", "专业", "总学分", "备注")
        self.tree = ttk.Treeview(table_frame, columns=columns, show="headings", height=15)

        # 设置列标题和宽度
        column_widths = {"学号": 80, "姓名": 80, "性别": 60, "出生时间": 100, "专业": 100, "总学分": 80, "备注": 150}
        for col in columns:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=column_widths[col])

        # 垂直滚动条
        scrollbar = ttk.Scrollbar(table_frame, orient="vertical", command=self.tree.yview)
        self.tree.configure(yscrollcommand=scrollbar.set)

        # 布局
        self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # 绑定双击事件
        self.tree.bind('<Double-Button-1>', self.on_double_click)

    def load_data(self):
        """从数据库加载数据到表格"""
        # 清空表格
        for item in self.tree.get_children():
            self.tree.delete(item)

        try:
            cursor = self.connection.cursor()
            cursor.execute("SELECT * FROM students ORDER BY student_id")
            rows = cursor.fetchall()

            # 插入数据到表格
            for row in rows:
                # 格式化日期
                birth_date = row[3]
                if birth_date:
                    birth_date_str = birth_date.strftime('%Y/%m/%d')
                else:
                    birth_date_str = ""

                # 处理None值
                values = list(row)
                for i in range(len(values)):
                    if values[i] is None:
                        values[i] = ""

                values[3] = birth_date_str
                self.tree.insert("", tk.END, values=values)

            cursor.close()
            print(f"加载了 {len(rows)} 条记录")
        except Error as e:
            messagebox.showerror("数据库错误", f"加载数据失败: {str(e)}")

    def search_data(self):
        """搜索学生信息"""
        search_text = self.search_var.get().strip()
        if not search_text:
            messagebox.showwarning("搜索提示", "请输入搜索内容")
            return

        # 清空表格
        for item in self.tree.get_children():
            self.tree.delete(item)

        try:
            cursor = self.connection.cursor()
            query = """
                    SELECT * \
                    FROM students
                    WHERE student_id LIKE %s \
                       OR name LIKE %s
                    ORDER BY student_id \
                    """
            search_pattern = f"%{search_text}%"
            cursor.execute(query, (search_pattern, search_pattern))
            rows = cursor.fetchall()

            if rows:
                for row in rows:
                    # 格式化日期
                    birth_date = row[3]
                    if birth_date:
                        birth_date_str = birth_date.strftime('%Y/%m/%d')
                    else:
                        birth_date_str = ""

                    # 处理None值
                    values = list(row)
                    for i in range(len(values)):
                        if values[i] is None:
                            values[i] = ""

                    values[3] = birth_date_str
                    self.tree.insert("", tk.END, values=values)

                messagebox.showinfo("搜索结果", f"找到 {len(rows)} 条记录")
            else:
                messagebox.showinfo("搜索结果", "未找到相关记录")

            cursor.close()
        except Error as e:
            messagebox.showerror("数据库错误", f"搜索失败: {str(e)}")

    def insert_student(self):
        """打开插入学生窗口"""
        InsertWindow(self)

    def query_student(self):
        """查询特定学生信息"""
        QueryWindow(self)

    def delete_student(self):
        """删除选中的学生"""
        selected_item = self.tree.selection()
        if not selected_item:
            messagebox.showwarning("删除提示", "请先选择要删除的学生")
            return

        # 获取选中的学生学号
        student_id = self.tree.item(selected_item[0])['values'][0]
        student_name = self.tree.item(selected_item[0])['values'][1]

        # 确认删除
        confirm = messagebox.askyesno("确认删除", f"确定要删除学生 {student_name} (学号: {student_id}) 吗?")
        if confirm:
            try:
                cursor = self.connection.cursor()
                cursor.execute("DELETE FROM students WHERE student_id = %s", (student_id,))
                self.connection.commit()

                # 从表格中移除
                self.tree.delete(selected_item[0])

                messagebox.showinfo("删除成功", f"已删除学生 {student_name}")
                cursor.close()
            except Error as e:
                messagebox.showerror("数据库错误", f"删除失败: {str(e)}")

    def update_student(self):
        """修改选中的学生信息"""
        selected_item = self.tree.selection()
        if not selected_item:
            messagebox.showwarning("修改提示", "请先选择要修改的学生")
            return

        # 获取选中的学生信息
        values = self.tree.item(selected_item[0])['values']
        UpdateWindow(self, values)

    def on_double_click(self, event):
        """双击表格行时显示详细信息"""
        selected_item = self.tree.selection()
        if selected_item:
            values = self.tree.item(selected_item[0])['values']
            details = f"学号: {values[0]}\n姓名: {values[1]}\n性别: {values[2]}\n出生时间: {values[3]}\n专业: {values[4]}\n总学分: {values[5]}\n备注: {values[6]}"
            messagebox.showinfo("学生详细信息", details)

    def __del__(self):
        """关闭数据库连接"""
        if self.connection and self.connection.is_connected():
            self.connection.close()
            print("数据库连接已关闭")


class InsertWindow:
    """插入学生信息窗口"""

    def __init__(self, parent):
        self.parent = parent
        self.window = tk.Toplevel(parent.root)
        self.window.title("插入学生信息")
        self.window.geometry("400x350")

        self.create_widgets()

    def create_widgets(self):
        tk.Label(self.window, text="学号:").grid(row=0, column=0, padx=10, pady=10, sticky="e")
        self.id_entry = tk.Entry(self.window, width=30)
        self.id_entry.grid(row=0, column=1, padx=10, pady=10)

        tk.Label(self.window, text="姓名:").grid(row=1, column=0, padx=10, pady=10, sticky="e")
        self.name_entry = tk.Entry(self.window, width=30)
        self.name_entry.grid(row=1, column=1, padx=10, pady=10)

        tk.Label(self.window, text="性别:").grid(row=2, column=0, padx=10, pady=10, sticky="e")
        self.gender_var = tk.StringVar(value="男")
        gender_frame = tk.Frame(self.window)
        gender_frame.grid(row=2, column=1, padx=10, pady=10, sticky="w")
        tk.Radiobutton(gender_frame, text="男", variable=self.gender_var, value="男").pack(side=tk.LEFT)
        tk.Radiobutton(gender_frame, text="女", variable=self.gender_var, value="女").pack(side=tk.LEFT)

        tk.Label(self.window, text="出生时间 (YYYY/MM/DD):").grid(row=3, column=0, padx=10, pady=10, sticky="e")
        self.birth_entry = tk.Entry(self.window, width=30)
        self.birth_entry.grid(row=3, column=1, padx=10, pady=10)
        self.birth_entry.insert(0, "1990/01/01")

        tk.Label(self.window, text="专业:").grid(row=4, column=0, padx=10, pady=10, sticky="e")
        self.major_entry = tk.Entry(self.window, width=30)
        self.major_entry.grid(row=4, column=1, padx=10, pady=10)
        self.major_entry.insert(0, "计算机")

        tk.Label(self.window, text="总学分:").grid(row=5, column=0, padx=10, pady=10, sticky="e")
        self.credits_entry = tk.Entry(self.window, width=30)
        self.credits_entry.grid(row=5, column=1, padx=10, pady=10)
        self.credits_entry.insert(0, "50")

        tk.Label(self.window, text="备注:").grid(row=6, column=0, padx=10, pady=10, sticky="e")
        self.remarks_entry = tk.Entry(self.window, width=30)
        self.remarks_entry.grid(row=6, column=1, padx=10, pady=10)

        # 按钮
        btn_frame = tk.Frame(self.window)
        btn_frame.grid(row=7, column=0, columnspan=2, pady=20)

        tk.Button(btn_frame, text="插入", command=self.insert, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(btn_frame, text="取消", command=self.window.destroy, width=10).pack(side=tk.LEFT, padx=10)

    def insert(self):
        """插入新学生到数据库"""
        # 获取输入值
        student_id = self.id_entry.get().strip()
        name = self.name_entry.get().strip()
        gender = self.gender_var.get()
        birth_date = self.birth_entry.get().strip()
        major = self.major_entry.get().strip()
        credits = self.credits_entry.get().strip()
        remarks = self.remarks_entry.get().strip()

        # 验证输入
        if not student_id or not name:
            messagebox.showwarning("输入错误", "学号和姓名不能为空")
            return

        # 验证学号是否已存在
        try:
            cursor = self.parent.connection.cursor()
            cursor.execute("SELECT student_id FROM students WHERE student_id = %s", (student_id,))
            if cursor.fetchone():
                messagebox.showwarning("输入错误", f"学号 {student_id} 已存在")
                cursor.close()
                return
            cursor.close()
        except Error as e:
            messagebox.showerror("数据库错误", f"验证学号失败: {str(e)}")
            return

        # 插入数据
        try:
            cursor = self.parent.connection.cursor()

            # 转换日期格式
            if birth_date:
                try:
                    birth_date_obj = datetime.strptime(birth_date, '%Y/%m/%d')
                except ValueError:
                    try:
                        birth_date_obj = datetime.strptime(birth_date, '%Y-%m-%d')
                    except ValueError:
                        messagebox.showwarning("日期格式错误", "请使用YYYY/MM/DD或YYYY-MM-DD格式")
                        return
            else:
                birth_date_obj = None

            # 转换学分
            try:
                credits_int = int(credits) if credits else 0
            except ValueError:
                credits_int = 0

            # 执行插入
            cursor.execute("""
                           INSERT INTO students (student_id, name, gender, birth_date, major, total_credits, remarks)
                           VALUES (%s, %s, %s, %s, %s, %s, %s)
                           """,
                           (student_id, name, gender, birth_date_obj, major, credits_int, remarks if remarks else None))

            self.parent.connection.commit()
            cursor.close()

            messagebox.showinfo("插入成功", f"学生 {name} 已成功添加")

            # 刷新主窗口数据
            self.parent.load_data()

            # 关闭窗口
            self.window.destroy()

        except Error as e:
            messagebox.showerror("数据库错误", f"插入失败: {str(e)}")


class QueryWindow:
    """查询学生信息窗口"""

    def __init__(self, parent):
        self.parent = parent
        self.window = tk.Toplevel(parent.root)
        self.window.title("查询学生信息")
        self.window.geometry("300x150")

        self.create_widgets()

    def create_widgets(self):
        tk.Label(self.window, text="请输入学号:").pack(pady=10)

        self.query_id_entry = tk.Entry(self.window, width=30)
        self.query_id_entry.pack(pady=5)

        btn_frame = tk.Frame(self.window)
        btn_frame.pack(pady=20)

        tk.Button(btn_frame, text="查询", command=self.query, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(btn_frame, text="取消", command=self.window.destroy, width=10).pack(side=tk.LEFT, padx=10)

    def query(self):
        """查询学生信息"""
        student_id = self.query_id_entry.get().strip()
        if not student_id:
            messagebox.showwarning("查询提示", "请输入学号")
            return

        try:
            cursor = self.parent.connection.cursor()
            cursor.execute("SELECT * FROM students WHERE student_id = %s", (student_id,))
            row = cursor.fetchone()

            if row:
                # 格式化日期
                birth_date = row[3]
                if birth_date:
                    birth_date_str = birth_date.strftime('%Y/%m/%d')
                else:
                    birth_date_str = ""

                # 显示查询结果
                details = f"学号: {row[0]}\n姓名: {row[1]}\n性别: {row[2]}\n出生时间: {birth_date_str}\n专业: {row[4]}\n总学分: {row[5]}\n备注: {row[6] if row[6] else '无'}"
                messagebox.showinfo("查询结果", details)
            else:
                messagebox.showinfo("查询结果", f"未找到学号为 {student_id} 的学生")

            cursor.close()
        except Error as e:
            messagebox.showerror("数据库错误", f"查询失败: {str(e)}")


class UpdateWindow:
    """修改学生信息窗口"""

    def __init__(self, parent, values):
        self.parent = parent
        self.original_id = values[0]  # 保存原始学号
        self.window = tk.Toplevel(parent.root)
        self.window.title("修改学生信息")
        self.window.geometry("400x350")

        self.create_widgets(values)

    def create_widgets(self, values):
        tk.Label(self.window, text="学号:").grid(row=0, column=0, padx=10, pady=10, sticky="e")
        self.id_entry = tk.Entry(self.window, width=30)
        self.id_entry.grid(row=0, column=1, padx=10, pady=10)
        self.id_entry.insert(0, values[0])

        tk.Label(self.window, text="姓名:").grid(row=1, column=0, padx=10, pady=10, sticky="e")
        self.name_entry = tk.Entry(self.window, width=30)
        self.name_entry.grid(row=1, column=1, padx=10, pady=10)
        self.name_entry.insert(0, values[1])

        tk.Label(self.window, text="性别:").grid(row=2, column=0, padx=10, pady=10, sticky="e")
        self.gender_var = tk.StringVar(value=values[2] if values[2] else "男")
        gender_frame = tk.Frame(self.window)
        gender_frame.grid(row=2, column=1, padx=10, pady=10, sticky="w")
        tk.Radiobutton(gender_frame, text="男", variable=self.gender_var, value="男").pack(side=tk.LEFT)
        tk.Radiobutton(gender_frame, text="女", variable=self.gender_var, value="女").pack(side=tk.LEFT)

        tk.Label(self.window, text="出生时间 (YYYY/MM/DD):").grid(row=3, column=0, padx=10, pady=10, sticky="e")
        self.birth_entry = tk.Entry(self.window, width=30)
        self.birth_entry.grid(row=3, column=1, padx=10, pady=10)
        self.birth_entry.insert(0, values[3])

        tk.Label(self.window, text="专业:").grid(row=4, column=0, padx=10, pady=10, sticky="e")
        self.major_entry = tk.Entry(self.window, width=30)
        self.major_entry.grid(row=4, column=1, padx=10, pady=10)
        self.major_entry.insert(0, values[4])

        tk.Label(self.window, text="总学分:").grid(row=5, column=0, padx=10, pady=10, sticky="e")
        self.credits_entry = tk.Entry(self.window, width=30)
        self.credits_entry.grid(row=5, column=1, padx=10, pady=10)
        self.credits_entry.insert(0, values[5])

        tk.Label(self.window, text="备注:").grid(row=6, column=0, padx=10, pady=10, sticky="e")
        self.remarks_entry = tk.Entry(self.window, width=30)
        self.remarks_entry.grid(row=6, column=1, padx=10, pady=10)
        self.remarks_entry.insert(0, values[6])

        # 按钮
        btn_frame = tk.Frame(self.window)
        btn_frame.grid(row=7, column=0, columnspan=2, pady=20)

        tk.Button(btn_frame, text="更新", command=self.update, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(btn_frame, text="取消", command=self.window.destroy, width=10).pack(side=tk.LEFT, padx=10)

    def update(self):
        """更新学生信息"""
        # 获取输入值
        student_id = self.id_entry.get().strip()
        name = self.name_entry.get().strip()
        gender = self.gender_var.get()
        birth_date = self.birth_entry.get().strip()
        major = self.major_entry.get().strip()
        credits = self.credits_entry.get().strip()
        remarks = self.remarks_entry.get().strip()

        # 验证输入
        if not student_id or not name:
            messagebox.showwarning("输入错误", "学号和姓名不能为空")
            return

        # 如果学号已修改,检查新学号是否已存在
        if student_id != self.original_id:
            try:
                cursor = self.parent.connection.cursor()
                cursor.execute("SELECT student_id FROM students WHERE student_id = %s", (student_id,))
                if cursor.fetchone():
                    messagebox.showwarning("输入错误", f"学号 {student_id} 已存在")
                    cursor.close()
                    return
                cursor.close()
            except Error as e:
                messagebox.showerror("数据库错误", f"验证学号失败: {str(e)}")
                return

        # 更新数据
        try:
            cursor = self.parent.connection.cursor()

            # 转换日期格式
            if birth_date:
                try:
                    birth_date_obj = datetime.strptime(birth_date, '%Y/%m/%d')
                except ValueError:
                    try:
                        birth_date_obj = datetime.strptime(birth_date, '%Y-%m-%d')
                    except ValueError:
                        messagebox.showwarning("日期格式错误", "请使用YYYY/MM/DD或YYYY-MM-DD格式")
                        return
            else:
                birth_date_obj = None

            # 转换学分
            try:
                credits_int = int(credits) if credits else 0
            except ValueError:
                credits_int = 0

            # 执行更新
            cursor.execute("""
                           UPDATE students
                           SET student_id    = %s,
                               name          = %s,
                               gender        = %s,
                               birth_date    = %s,
                               major         = %s,
                               total_credits = %s,
                               remarks       = %s
                           WHERE student_id = %s
                           """,
                           (student_id, name, gender, birth_date_obj, major, credits_int, remarks if remarks else None,
                            self.original_id))

            self.parent.connection.commit()
            cursor.close()

            messagebox.showinfo("更新成功", f"学生 {name} 的信息已更新")

            # 刷新主窗口数据
            self.parent.load_data()

            # 关闭窗口

            self.window.destroy()

        except Error as e:
            messagebox.showerror("数据库错误", f"更新失败: {str(e)}")


def main():
    root = tk.Tk()
    app = StudentManagementSystem(root)
    root.mainloop()


if __name__ == "__main__":
    main()

参考帖子收费:

(Python)tkinter连接MySQL进行学生数据管理_tinkter可以访问数据库吗-CSDN博客

相关推荐
行走在电子领域的工匠3 小时前
台达ST:自定义串行通讯传送与接收指令COMRS程序范例二
开发语言
8***23553 小时前
SQL Server2022版+SSMS安装教程(保姆级)
后端·python·flask
小熊officer3 小时前
mysql创建用户以及赋予权限
数据库·mysql
Sally_xy3 小时前
Python 虚拟环境
开发语言·chrome·python
张np3 小时前
java基础-List接口
java·开发语言
serve the people4 小时前
tensorflow tf.function 的两种执行模式(计算图执行 vs Eager 执行)的关键差异
人工智能·python·tensorflow
拾贰_C4 小时前
[python ]anaconda
开发语言·python
serve the people4 小时前
tensorflow中的计算图是什么
人工智能·python·tensorflow
子午4 小时前
【动物识别系统】Python+TensorFlow+Django+人工智能+深度学习+卷积神经网络算法
人工智能·python·深度学习