Python中用Tkinter展示MySQL数据遇卡顿:程序无响应求助
问题分析与修复方案
核心问题
- 主线程阻塞:Tkinter的UI事件循环依赖主线程,
show_new_window函数中直接在主线程执行数据库查询、创建大量按钮的操作,会阻塞事件循环,导致窗口卡顿甚至无响应。 - 不符合预期的展示方式:你希望在当前窗口展示记录,但代码用
Toplevel创建了新窗口,且用按钮逐行展示数据的方式效率极低,数据量大时卡顿会更严重。
修复步骤与优化代码
修复后的完整代码
# Import the required Libraries import tkinter as tk from tkinter import ttk, filedialog import mysql.connector import xlrd from threading import Thread def browse_button(): filename = filedialog.askopenfilename(filetypes=[("Excel Files", "*.xls *.xlsx")]) folder_path.set(filename) # 选择文件后自动执行Excel导入数据库逻辑 import_excel_to_db(filename) def import_excel_to_db(filename): # 数据库连接与数据导入 conn = mysql.connector.connect(user='root', password='', host='localhost', database='magnetico') try: book = xlrd.open_workbook(filename) sheet = book.sheet_by_name("Order Details") cursor = conn.cursor() # 跳过表头行,批量插入提升效率 for row_idx in range(1, sheet.nrows): row = sheet.row_values(row_idx) cursor.execute("INSERT INTO perorder (mp_task_nr, batch_id, dropoff_sequence, id_user_payout_type, task_status, city, fleet, id_user, Name, Vendor, order_date, UID, KM, total_amount, Remarks) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", row) conn.commit() print("数据导入成功") except Exception as e: print(f"导入失败: {str(e)}") conn.rollback() finally: cursor.close() conn.close() def fetch_report_data(): # 子线程执行数据库查询,避免阻塞主线程 conn = mysql.connector.connect(user='root', password='', host='localhost', database='magnetico') try: mycursor = conn.cursor() mycursor.execute("SELECT id_user, Vendor, KM FROM perorder") result = mycursor.fetchall() # 查询完成后通知主线程更新UI app.after(0, update_report_ui, result) except Exception as e: print(f"查询失败: {str(e)}") finally: mycursor.close() conn.close() def update_report_ui(data): # 清空现有数据,插入新查询结果 for item in report_tree.get_children(): report_tree.delete(item) for row in data: report_tree.insert('', tk.END, values=row) def show_report(): # 启动子线程执行查询 Thread(target=fetch_report_data, daemon=True).start() # 主窗口初始化 app = tk.Tk() app.geometry("900x800") app.title("发票应用") folder_path = tk.StringVar() # 页面元素布局 heading = tk.Label(app, text="点击按钮浏览文件", font=("Helvetica", 16)) heading.grid(row=0, column=1, columnspan=2, pady=10) lbl1 = tk.Label(app, textvariable=folder_path) lbl1.grid(row=1, column=1, padx=10, pady=10, sticky=tk.NSEW) button2 = tk.Button(app, text="Browse", command=browse_button) button2.grid(row=1, column=2, padx=10, pady=10, sticky=tk.NSEW) button = tk.Button(app, text="Report", command=show_report) button.grid(row=2, column=2, padx=10, pady=10, sticky=tk.NSEW) # 主窗口内创建表格用于展示报告数据 report_frame = ttk.Frame(app) report_frame.grid(row=3, column=1, columnspan=2, padx=10, pady=10, sticky=tk.NSEW) # 定义表格列 columns = ("ID用户", "供应商", "公里数") report_tree = ttk.Treeview(report_frame, columns=columns, show="headings") # 设置表头与列宽 for col in columns: report_tree.heading(col, text=col) report_tree.column(col, width=150) # 添加滚动条 scrollbar = ttk.Scrollbar(report_frame, orient=tk.VERTICAL, command=report_tree.yview) report_tree.configure(yscroll=scrollbar.set) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) report_tree.pack(fill=tk.BOTH, expand=True) # 配置窗口自适应布局 app.columnconfigure(1, weight=1) app.columnconfigure(2, weight=1) app.rowconfigure(3, weight=1) app.mainloop()
关键改进说明
- 修复Excel导入逻辑:原代码中导入数据库的代码放在
mainloop()之后,永远不会执行,现在移到Browse按钮回调中,选择文件后自动导入。 - 用Treeview替代按钮展示数据:高效展示结构化数据,符合你“在当前窗口展示”的需求,避免大量按钮导致的卡顿。
- 子线程执行数据库操作:将查询逻辑放在子线程中,避免阻塞主线程的UI事件循环,彻底解决卡顿问题。
- 批量插入优化:导入Excel时统一提交事务,提升数据导入效率。
内容的提问来源于stack exchange,提问作者Mateo
相关产品推荐
相关产品推荐

