第九周总结
完成了一个Python实验(餐厅点餐子系统),以下是实验代码。
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import pymysql
from PIL import Image, ImageTk
import config
import io
import warnings
忽略图片处理警告
warnings.filterwarnings("ignore", message="iCCP: known incorrect sRGB profile")
class RestaurantApp:
"""餐厅点餐系统主应用"""
def __init__(self, root):
self.root = root
self.root.title("餐厅点餐系统")
self.current_image = None
# 数据库连接
self.conn = pymysql.connect(**config.DB_CONFIG)
self.cursor = self.conn.cursor()
self.create_widgets()
self.load_menu()
def create_widgets(self):
"""创建主界面"""
self.notebook = ttk.Notebook(self.root)
self.notebook.pack(fill='both', expand=True)
# 创建三个功能标签页
self.management_frame = ttk.Frame(self.notebook)
self.notebook.add(self.management_frame, text='菜单管理')
self.order_frame = ttk.Frame(self.notebook)
self.notebook.add(self.order_frame, text='点餐')
self.order_management_frame = ttk.Frame(self.notebook)
self.notebook.add(self.order_management_frame, text='订单管理')
# 初始化各标签页界面
self.create_management_ui()
self.create_order_ui()
self.create_order_management_ui()
def create_management_ui(self):
"""创建菜单管理界面"""
# 左侧控制按钮
control_frame = ttk.Frame(self.management_frame, width=200)
control_frame.pack(side='left', fill='y')
ttk.Button(control_frame, text="添加菜品", command=self.add_dish).pack(pady=5, fill='x')
ttk.Button(control_frame, text="删除菜品", command=self.delete_dish).pack(pady=5, fill='x')
ttk.Button(control_frame, text="修改菜品", command=self.update_dish).pack(pady=5, fill='x')
# 右侧显示区域
display_frame = ttk.Frame(self.management_frame)
display_frame.pack(side='right', fill='both', expand=True)
# 菜品列表
self.tree = ttk.Treeview(
display_frame,
columns=('id', 'name', 'price', 'cooking_time'),
show='headings'
)
self.tree.heading('id', text='编号')
self.tree.heading('name', text='菜名')
self.tree.heading('price', text='价格')
self.tree.heading('cooking_time', text='烹饪时间')
self.tree.pack(fill='both', expand=True)
# 图片显示区域
self.image_frame = ttk.Frame(display_frame)
self.image_frame.pack(pady=10)
self.image_label = ttk.Label(self.image_frame)
self.image_label.pack()
# 绑定选择事件
self.tree.bind("<<TreeviewSelect>>", self.show_selected_image)
def create_order_ui(self):
"""创建点餐界面"""
# 左侧菜单列表
menu_frame = ttk.Frame(self.order_frame)
menu_frame.pack(side='left', fill='both', expand=True)
# 菜品列表
list_frame = ttk.Frame(menu_frame)
list_frame.pack(fill='both', expand=True)
self.order_tree = ttk.Treeview(
list_frame,
columns=('id', 'name', 'price'),
show='headings',
height=15
)
self.order_tree.heading('id', text='编号')
self.order_tree.heading('name', text='菜名')
self.order_tree.heading('price', text='价格')
self.order_tree.pack(fill='both', expand=True)
# 菜品图片预览
self.order_image_frame = ttk.Frame(menu_frame)
self.order_image_frame.pack(fill='both', expand=True)
self.order_image_label = ttk.Label(self.order_image_frame)
self.order_image_label.pack()
# 绑定选择事件
self.order_tree.bind("<<TreeviewSelect>>", self.show_order_image)
# 右侧订单区域
order_control_frame = ttk.Frame(self.order_frame)
order_control_frame.pack(side='right', fill='both', expand=True)
# 数量选择
ttk.Label(order_control_frame, text="数量:").pack()
self.quantity = ttk.Spinbox(order_control_frame, from_=1, to=10)
self.quantity.pack()
ttk.Button(order_control_frame, text="添加到订单", command=self.add_to_order).pack(pady=5)
# 订单列表
self.current_order = ttk.Treeview(
order_control_frame,
columns=('name', 'price', 'quantity', 'total'),
show='headings'
)
self.current_order.heading('name', text='菜名')
self.current_order.heading('price', text='单价')
self.current_order.heading('quantity', text='数量')
self.current_order.heading('total', text='小计')
self.current_order.pack(fill='both', expand=True)
# 总价显示
self.total_label = ttk.Label(order_control_frame, text="总价:0.00元")
self.total_label.pack()
ttk.Button(order_control_frame, text="提交订单", command=self.submit_order).pack(pady=5)
def create_order_management_ui(self):
"""创建订单管理界面"""
main_frame = ttk.Frame(self.order_management_frame)
main_frame.pack(fill='both', expand=True, padx=10, pady=10)
# 订单列表
self.orders_tree = ttk.Treeview(
main_frame,
columns=('order_id', 'total', 'time', 'items'),
show='headings'
)
self.orders_tree.heading('order_id', text='订单号')
self.orders_tree.heading('total', text='总金额')
self.orders_tree.heading('time', text='下单时间')
self.orders_tree.heading('items', text='菜品详情')
self.orders_tree.pack(fill='both', expand=True)
# 滚动条
scrollbar = ttk.Scrollbar(main_frame, orient=tk.VERTICAL, command=self.orders_tree.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.orders_tree.configure(yscrollcommand=scrollbar.set)
# 删除按钮
ttk.Button(
main_frame,
text="删除选中订单",
command=self.delete_order
).pack(pady=5)
self.load_orders()
# ----------------- 数据库操作方法 -----------------
def load_menu(self):
"""加载菜单数据"""
self.tree.delete(*self.tree.get_children())
self.order_tree.delete(*self.order_tree.get_children())
self.cursor.execute("SELECT id, name, price, cooking_time FROM menu")
for row in self.cursor.fetchall():
self.tree.insert('', 'end', values=row)
self.order_tree.insert('', 'end', values=row[:3])
def show_selected_image(self, event):
"""显示选中菜品的图片"""
selected = self.tree.selection()
if selected:
dish_id = self.tree.item(selected[0])['values'][0]
self.show_image(dish_id)
def show_order_image(self, event):
"""在点餐界面显示选中菜品的图片"""
selected = self.order_tree.selection()
if selected:
dish_id = self.order_tree.item(selected[0])['values'][0]
self.show_image_in_label(dish_id, self.order_image_label)
def show_image(self, dish_id):
"""显示菜品图片"""
self.show_image_in_label(dish_id, self.image_label)
def show_image_in_label(self, dish_id, label):
"""在指定标签中显示菜品图片"""
self.cursor.execute("SELECT image FROM menu WHERE id=%s", (dish_id,))
result = self.cursor.fetchone()
if result and result[0]:
try:
image = Image.open(io.BytesIO(result[0]))
image.thumbnail((300, 300))
photo = ImageTk.PhotoImage(image)
label.config(image=photo)
label.image = photo
except:
label.config(image='')
else:
label.config(image='')
def add_dish(self):
"""打开添加菜品窗口"""
AddDishWindow(self)
def delete_dish(self):
"""删除选中的菜品"""
selected = self.tree.selection()
if not selected:
return
dish_id = self.tree.item(selected[0])['values'][0]
try:
self.cursor.execute("DELETE FROM menu WHERE id=%s", (dish_id,))
self.conn.commit()
self.load_menu()
messagebox.showinfo("提示", "删除成功!")
except Exception as e:
messagebox.showerror("错误", f"删除失败: {str(e)}")
def update_dish(self):
"""打开修改菜品窗口"""
selected = self.tree.selection()
if not selected:
return
values = self.tree.item(selected[0])['values']
UpdateDishWindow(self, values)
# ----------------- 点餐功能方法 -----------------
def add_to_order(self):
"""添加菜品到订单"""
selected = self.order_tree.selection()
if not selected:
return
dish_id = self.order_tree.item(selected[0])['values'][0]
try:
quantity = int(self.quantity.get())
if quantity < 1:
raise ValueError
except:
messagebox.showerror("错误", "请输入有效数量(1-10)")
return
try:
self.cursor.execute("SELECT name, price FROM menu WHERE id=%s", (dish_id,))
name, price = self.cursor.fetchone()
price = float(price)
total = price * quantity
# 检查是否已存在相同菜品
exists = False
for child in self.current_order.get_children():
values = self.current_order.item(child)['values']
if values[0] == name:
exists = True
new_quantity = values[2] + quantity
new_total = new_quantity * price
self.current_order.item(child, values=(name, price, new_quantity, new_total))
break
if not exists:
self.current_order.insert('', 'end', values=(name, price, quantity, total))
self.update_total()
except Exception as e:
messagebox.showerror("错误", f"添加失败: {str(e)}")
def update_total(self):
"""更新订单总价"""
total = 0.0
for child in self.current_order.get_children():
total += float(self.current_order.item(child)['values'][3])
self.total_label.config(text=f"总价:{total:.2f}元")
def submit_order(self):
"""提交订单"""
if not self.current_order.get_children():
messagebox.showwarning("提示", "订单为空!")
return
try:
self.conn.begin()
# 插入主订单
total = float(self.total_label.cget("text")[3:-1])
self.cursor.execute("INSERT INTO orders (total) VALUES (%s)", (total,))
order_id = self.cursor.lastrowid
# 插入订单详情
for child in self.current_order.get_children():
values = self.current_order.item(child)['values']
dish_id = self.get_dish_id_by_name(values[0])
quantity = values[2]
price = values[1]
self.cursor.execute(
"INSERT INTO order_details (order_id, dish_id, quantity, price) VALUES (%s, %s, %s, %s)",
(order_id, dish_id, quantity, price)
)
self.conn.commit()
messagebox.showinfo("成功", f"订单提交成功!订单号:{order_id},总金额:¥{total:.2f}")
self.current_order.delete(*self.current_order.get_children())
self.total_label.config(text="总价:0.00元")
self.load_orders()
except Exception as e:
self.conn.rollback()
messagebox.showerror("错误", f"提交失败: {str(e)}")
def get_dish_id_by_name(self, dish_name):
"""根据菜品名称获取ID"""
self.cursor.execute("SELECT id FROM menu WHERE name = %s", (dish_name,))
result = self.cursor.fetchone()
return result[0] if result else None
# ----------------- 订单管理方法 -----------------
def load_orders(self):
"""加载历史订单"""
self.orders_tree.delete(*self.orders_tree.get_children())
try:
self.cursor.execute("""
SELECT o.order_id, o.total, o.order_time,
GROUP_CONCAT(CONCAT(m.name, ' × ', od.quantity))
FROM orders o
JOIN order_details od ON o.order_id = od.order_id
JOIN menu m ON od.dish_id = m.id
GROUP BY o.order_id
ORDER BY o.order_time DESC
""")
for row in self.cursor.fetchall():
order_id, total, time, items = row
self.orders_tree.insert('', 'end', values=(
order_id, f"¥{total:.2f}", time.strftime("%Y-%m-%d %H:%M:%S"), items
))
except Exception as e:
messagebox.showerror("错误", f"加载订单失败: {str(e)}")
def delete_order(self):
"""删除选中的订单"""
selected = self.orders_tree.selection()
if not selected:
return
order_id = self.orders_tree.item(selected[0])['values'][0]
if messagebox.askyesno("确认", f"确定要删除订单 {order_id} 吗?"):
try:
self.cursor.execute("DELETE FROM orders WHERE order_id = %s", (order_id,))
self.conn.commit()
self.load_orders()
messagebox.showinfo("成功", "订单已删除")
except Exception as e:
self.conn.rollback()
messagebox.showerror("错误", f"删除失败: {str(e)}")
class AddDishWindow(tk.Toplevel):
"""添加菜品窗口"""
def __init__(self, parent):
super().__init__(parent.root)
self.parent = parent
self.title("添加菜品")
self.temp_image = None
self.image_data = None
# 创建UI元素
ttk.Label(self, text="菜名:").grid(row=0, column=0)
self.name = ttk.Entry(self)
self.name.grid(row=0, column=1)
ttk.Label(self, text="价格:").grid(row=1, column=0)
self.price = ttk.Entry(self)
self.price.grid(row=1, column=1)
ttk.Label(self, text="烹饪时间:").grid(row=2, column=0)
self.cooking_time = ttk.Entry(self)
self.cooking_time.grid(row=2, column=1)
ttk.Label(self, text="图片:").grid(row=3, column=0)
ttk.Button(self, text="选择图片", command=self.select_image).grid(row=3, column=1)
# 图片预览区域
self.preview_frame = ttk.Frame(self)
self.preview_frame.grid(row=4, columnspan=2, pady=10)
self.preview_label = ttk.Label(self.preview_frame)
self.preview_label.pack()
ttk.Button(self, text="提交", command=self.submit).grid(row=5, columnspan=2)
def select_image(self):
"""选择并处理图片"""
path = filedialog.askopenfilename()
if path:
try:
img = Image.open(path)
# 处理图片格式问题
if "icc_profile" in img.info:
del img.info["icc_profile"]
if img.mode in ("RGBA", "P"):
img = img.convert("RGB")
# 生成预览
preview_img = img.copy()
preview_img.thumbnail((200, 200))
self.temp_image = ImageTk.PhotoImage(preview_img)
self.preview_label.config(image=self.temp_image)
# 保存图片数据
img_byte_arr = io.BytesIO()
img.save(img_byte_arr, format='PNG' if path.lower().endswith('.png') else 'JPEG')
self.image_data = img_byte_arr.getvalue()
except Exception as e:
messagebox.showerror("错误", f"图片处理失败: {str(e)}")
self.image_data = None
def submit(self):
"""提交菜品数据"""
if not self.image_data:
messagebox.showerror("错误", "请选择菜品图片")
return
try:
self.parent.cursor.execute(
"INSERT INTO menu (name, price, image, cooking_time) VALUES (%s, %s, %s, %s)",
(self.name.get(), float(self.price.get()), self.image_data, int(self.cooking_time.get()))
)
self.parent.conn.commit()
self.parent.load_menu()
self.destroy()
except Exception as e:
messagebox.showerror("错误", str(e))
class UpdateDishWindow(AddDishWindow):
"""修改菜品窗口"""
def __init__(self, parent, values):
super().__init__(parent)
self.title("修改菜品")
self.dish_id = values[0]
# 填充现有数据
self.name.insert(0, values[1])
self.price.insert(0, values[2])
self.cooking_time.insert(0, values[3])
# 加载现有图片
self.parent.cursor.execute("SELECT image FROM menu WHERE id=%s", (self.dish_id,))
image_data = self.parent.cursor.fetchone()[0]
if image_data:
try:
image = Image.open(io.BytesIO(image_data))
image.thumbnail((200, 200))
self.temp_image = ImageTk.PhotoImage(image)
self.preview_label.config(image=self.temp_image)
except:
pass
def submit(self):
"""提交修改"""
try:
# 如果未选择新图片,则使用原有图片
if not self.image_data:
self.parent.cursor.execute("SELECT image FROM menu WHERE id=%s", (self.dish_id,))
self.image_data = self.parent.cursor.fetchone()[0]
self.parent.cursor.execute(
"UPDATE menu SET name=%s, price=%s, image=%s, cooking_time=%s WHERE id=%s",
(self.name.get(), float(self.price.get()), self.image_data, int(self.cooking_time.get()), self.dish_id)
)
self.parent.conn.commit()
self.parent.load_menu()
self.destroy()
except Exception as e:
messagebox.showerror("错误", str(e))
if name == "main":
root = tk.Tk()
app = RestaurantApp(root)
root.mainloop()
app.conn.close()

浙公网安备 33010602011771号