求助:在Tkinter中展示MySQL条件查询的带表头表格
解决MySQL查询结果在Tkinter表格展示的问题
我帮你修复了代码中的多个问题,现在可以在Report标签页以带字段名的表格形式展示符合条件的MySQL数据了。先看完整的修正代码,再给你拆解关键改进点:
import tkinter as tk from tkinter import ttk, messagebox from tkcalendar import DateEntry import MySQLdb as mydb import datetime # 初始化主窗口 root = tk.Tk() root.title("Procurement System") tabcontrol = ttk.Notebook(root) tab1 = ttk.Frame(tabcontrol) tab2 = ttk.Frame(tabcontrol) tabcontrol.add(tab1, text="Entry Form") tabcontrol.add(tab2, text="Report") tabcontrol.pack(expand=1, fill='both') # 数据库连接 conn = mydb.connect(host='localhost', user='root', passwd='root', database='operator') mycur = conn.cursor() # 全局变量:存储选中的日期 selected_date = None # ------------------------ 标签页1:数据录入 ------------------------ partno = tk.StringVar() cname = tk.StringVar() quantity = tk.IntVar(value=0) # 默认值设为0 cpu = tk.DoubleVar() def dateentry_view(): global selected_date def print_sel(): global selected_date selected_date = cal.get_date() # 更新标签显示选中的日期 date_label.config(text=f"Selected Date: {selected_date.strftime('%Y-%m-%d')}") top.destroy() top = tk.Toplevel(tab1) top.title("Select Date") cal = DateEntry(top, width=12, background='darkblue', foreground='white', borderwidth=2) cal.pack(pady=10) ttk.Button(top, text="OK", command=print_sel).pack(pady=5) def savedata(): global selected_date if not selected_date: messagebox.showwarning("Warning", "Please select a procurement date first!") return # 获取输入值 part_no_val = partno.get().strip() comp_name_val = cname.get().strip() qty_val = quantity.get() cpu_val = cpu.get() # 验证输入 if not all([part_no_val, comp_name_val, qty_val > 0, cpu_val > 0]): messagebox.showerror("Error", "Please fill all fields correctly (quantity and cost must be positive)!") return total_cost = qty_val * cpu_val dt_str = selected_date.strftime('%Y-%m-%d') # 插入数据 try: insert_sql = """INSERT INTO PROCUREMENT_FORM (DATE_OF_PROCUREMENT,PART_NO,COMPONENT_NAME,QUANTITY,COST_PER_UNIT,TOTAL_COST) VALUES (%s,%s,%s,%s,%s,%s)""" mycur.execute(insert_sql, (dt_str, part_no_val, comp_name_val, qty_val, cpu_val, total_cost)) conn.commit() messagebox.showinfo("Success", "Data saved successfully!") # 清空输入 partno.set("") cname.set("") quantity.set(0) cpu.set(0.0) selected_date = None date_label.config(text="Selected Date: None") except Exception as e: messagebox.showerror("Database Error", f"Failed to save data: {str(e)}") conn.rollback() # 日期选择按钮和标签 ttk.Button(tab1, text='Select Procurement Date', command=dateentry_view).grid(row=0, column=0, padx=20, pady=20) date_label = tk.Label(tab1, text="Selected Date: None", font=('Arial', 10)) date_label.grid(row=0, column=1, padx=20, pady=20) # 录入表单控件 labels = ["Part No:", "Component name:", "Quantity:", "Cost per unit:"] row_idx = 1 for lbl_text in labels: ttk.Label(tab1, text=lbl_text, font=('Arial', 10)).grid(row=row_idx, column=0, padx=20, pady=10, sticky='w') row_idx +=1 etext2 = ttk.Entry(tab1, textvariable=partno) etext3 = ttk.Entry(tab1, textvariable=cname) etext4 = ttk.Entry(tab1, textvariable=quantity) etext5 = ttk.Entry(tab1, textvariable=cpu) etext2.grid(row=1, column=1, padx=20, pady=10) etext3.grid(row=2, column=1, padx=20, pady=10) etext4.grid(row=3, column=1, padx=20, pady=10) etext5.grid(row=4, column=1, padx=20, pady=10) # 数量增减按钮 ttk.Button(tab1, text="+", command=lambda: quantity.set(quantity.get() + 1)).grid(row=3, column=2, padx=5) ttk.Button(tab1, text="-", command=lambda: quantity.set(max(0, quantity.get() - 1))).grid(row=3, column=3, padx=5) # 保存按钮 ttk.Button(tab1, text="Save", command=savedata).grid(row=5, column=1, pady=20) # ------------------------ 标签页2:数据查询与表格展示 ------------------------ pno = tk.StringVar() # 创建Treeview表格(带表头) columns = ("date", "part_no", "comp_name", "qty", "cost_unit", "total_cost") tree = ttk.Treeview(tab2, columns=columns, show="headings") # 设置表头 tree.heading("date", text="Procurement Date") tree.heading("part_no", text="Part No") tree.heading("comp_name", text="Component Name") tree.heading("qty", text="Quantity") tree.heading("cost_unit", text="Cost Per Unit") tree.heading("total_cost", text="Total Cost") # 设置列宽 tree.column("date", width=120) tree.column("part_no", width=100) tree.column("comp_name", width=150) tree.column("qty", width=80) tree.column("cost_unit", width=100) tree.column("total_cost", width=100) tree.pack(expand=1, fill='both', padx=20, pady=20) def getfromdb(): part_no_query = pno.get().strip() if not part_no_query: messagebox.showwarning("Warning", "Please enter a part number to search!") return # 清空表格旧数据 for item in tree.get_children(): tree.delete(item) try: # 查询数据(包含所有字段,包括TOTAL_COST) select_sql = """SELECT DATE_OF_PROCUREMENT,PART_NO,COMPONENT_NAME,QUANTITY,COST_PER_UNIT,TOTAL_COST FROM PROCUREMENT_FORM WHERE PART_NO LIKE %s""" # 使用%通配符支持模糊查询,比如输入"ABC"会匹配所有包含ABC的零件号 mycur.execute(select_sql, (f"%{part_no_query}%",)) rows = mycur.fetchall() if not rows: messagebox.showinfo("Info", "No matching part number found!") return # 将查询结果插入表格 for row in rows: # 日期格式转换,让显示更友好 formatted_date = row[0].strftime('%Y-%m-%d') if isinstance(row[0], datetime.date) else row[0] tree.insert("", tk.END, values=(formatted_date, row[1], row[2], row[3], row[4], row[5])) except Exception as e: messagebox.showerror("Database Error", f"Failed to fetch data: {str(e)}") # 查询控件 ttk.Label(tab2, text="Enter Part No (supports partial search):", font=('Arial', 10)).pack(pady=5) entry1 = ttk.Entry(tab2, textvariable=pno, width=30) entry1.pack(pady=5) ttk.Button(tab2, text="Get Details", command=getfromdb).pack(pady=10) # 关闭窗口时关闭数据库连接 def on_closing(): mycur.close() conn.close() root.destroy() root.protocol("WM_DELETE_WINDOW", on_closing) root.mainloop()
关键改进点说明:
- 修复窗口初始化问题:移除了重复的
root=tk.Tk()和root.withdraw(),避免窗口管理混乱,统一使用一个主窗口。 - 日期选择与传递:用全局变量
selected_date存储选中的日期,确保savedata函数能正确获取用户选择的采购日期,而不是创建新的日期控件。 - 数据录入验证:添加了输入验证(必填字段、数量和成本为正数),并在保存成功后清空表单,提升用户体验。
- 表格展示优化:使用
ttk.Treeview控件实现带表头的表格,这是Tkinter中展示结构化数据的标准组件,支持列排序、滚动等功能。 - 查询逻辑修复:
- 移除了重复创建Entry控件的冗余代码,直接获取用户输入的零件号
- 支持模糊查询(通过
%{part_no_query}%),用户可以输入部分零件号进行搜索 - 查询前清空表格旧数据,避免数据重叠
- 处理数据库异常,给出友好的错误提示
- 资源管理:添加了窗口关闭时的数据库连接关闭逻辑,避免资源泄漏。
- 布局优化:改用
grid和pack布局替代place,让控件布局更稳定、自适应窗口大小。
内容的提问来源于stack exchange,提问作者hardcoder
相关产品推荐
相关产品推荐

