You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:在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()

关键改进点说明:

  1. 修复窗口初始化问题:移除了重复的root=tk.Tk()和root.withdraw(),避免窗口管理混乱,统一使用一个主窗口。
  2. 日期选择与传递:用全局变量selected_date存储选中的日期,确保savedata函数能正确获取用户选择的采购日期,而不是创建新的日期控件。
  3. 数据录入验证:添加了输入验证(必填字段、数量和成本为正数),并在保存成功后清空表单,提升用户体验。
  4. 表格展示优化:使用ttk.Treeview控件实现带表头的表格,这是Tkinter中展示结构化数据的标准组件,支持列排序、滚动等功能。
  5. 查询逻辑修复:
    • 移除了重复创建Entry控件的冗余代码,直接获取用户输入的零件号
    • 支持模糊查询(通过%{part_no_query}%),用户可以输入部分零件号进行搜索
    • 查询前清空表格旧数据,避免数据重叠
    • 处理数据库异常,给出友好的错误提示
  6. 资源管理:添加了窗口关闭时的数据库连接关闭逻辑,避免资源泄漏。
  7. 布局优化:改用grid和pack布局替代place,让控件布局更稳定、自适应窗口大小。

内容的提问来源于stack exchange,提问作者hardcoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:23:05