ux: add custom result dialog with visual success/failure icons

- Add ResultDialog class with green checkmark (✓) for success
- Add red X (✕) icon for failure/partial failure
- Center result dialog on screen
- Use color-coded backgrounds (green/red) for better visual feedback
- Replace standard messagebox for more intuitive result display

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-02-09 16:00:15 +08:00
parent 192443c3b9
commit 2496694f05

View File

@@ -16,6 +16,118 @@ from tkinter import ttk, messagebox
from typing import List, Dict, Any, Optional
class ResultDialog(tk.Toplevel):
"""自定义结果对话框,带有成功/失败图标"""
def __init__(self, parent, title: str, message: str, success: bool = True):
"""初始化结果对话框
Args:
parent: 父窗口
title: 对话框标题
message: 显示的消息
success: 是否成功(成功显示绿色勾,失败显示红色叉)
"""
super().__init__(parent)
self.title(title)
self.resizable(False, False)
# 使窗口模态
self.transient(parent)
self.grab_set()
# 计算居中位置
self.update_idletasks()
width = 400
height = 150
screen_width = self.winfo_screenwidth()
screen_height = self.winfo_screenheight()
x = (screen_width - width) // 2
y = (screen_height - height) // 2
self.geometry(f"{width}x{height}+{x}+{y}")
# 主容器
main_frame = ttk.Frame(self, padding=20)
main_frame.pack(fill=tk.BOTH, expand=True)
# 图标和消息容器
content_frame = ttk.Frame(main_frame)
content_frame.pack(fill=tk.BOTH, expand=True)
# 图标标签
if success:
# 成功图标:绿色勾勾
icon_label = tk.Label(
content_frame,
text="",
font=("Arial", 48),
fg="#22c55e", # 绿色
bg="#f0fdf4" # 浅绿背景
)
icon_label.pack(side=tk.LEFT, padx=(0, 20))
# 背景框
icon_frame = tk.Frame(
content_frame,
bg="#f0fdf4",
width=80,
height=80
)
icon_frame.place(x=0, y=0)
icon_frame.pack_propagate(False)
icon_label = tk.Label(
icon_frame,
text="",
font=("Arial", 48),
fg="#22c55e",
bg="#f0fdf4"
)
icon_label.place(relx=0.5, rely=0.5, anchor="center")
else:
# 失败图标:红色叉叉
icon_frame = tk.Frame(
content_frame,
bg="#fef2f2", # 浅红背景
width=80,
height=80
)
icon_frame.pack_propagate(False)
icon_frame.pack(side=tk.LEFT, padx=(0, 20))
icon_label = tk.Label(
icon_frame,
text="",
font=("Arial", 48),
fg="#ef4444", # 红色
bg="#fef2f2"
)
icon_label.place(relx=0.5, rely=0.5, anchor="center")
# 消息标签
msg_label = tk.Label(
content_frame,
text=message,
font=("Microsoft YaHei UI", 10),
justify=tk.LEFT,
wraplength=280
)
msg_label.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# 确定按钮
button_frame = ttk.Frame(main_frame)
button_frame.pack(fill=tk.X, pady=(10, 0))
ttk.Button(
button_frame,
text="确定",
command=self.destroy,
width=10
).pack(side=tk.RIGHT)
# 等待窗口关闭
self.wait_window()
class EditableTreeview(ttk.Treeview):
"""可编辑的 Treeview 组件
@@ -231,6 +343,16 @@ class MaterialTypeManagementDialog(tk.Toplevel):
self.title(title)
self.geometry("900x650")
# 使窗口居中
self.update_idletasks() # 确保窗口已创建
width = self.winfo_width()
height = self.winfo_height()
screen_width = self.winfo_screenwidth()
screen_height = self.winfo_screenheight()
x = (screen_width - width) // 2
y = (screen_height - height) // 2
self.geometry(f"{width}x{height}+{x}+{y}")
# 使窗口模态
self.transient(parent)
self.grab_set()
@@ -463,6 +585,9 @@ class MaterialTypeManagementDialog(tk.Toplevel):
def _load_data(self):
"""从数据库加载数据"""
try:
# 保存当前的负责人选中状态
previously_selected_managers = self._get_selected_managers()
from db.materials_to_be_deleted_dao import MaterialsTypeToBeDeletedDAO
dao = MaterialsTypeToBeDeletedDAO()
@@ -474,6 +599,25 @@ class MaterialTypeManagementDialog(tk.Toplevel):
# 重新创建筛选复选框
self._create_filter_checkboxes()
# 恢复之前的负责人选中状态
if previously_selected_managers:
# 清空全选
self.select_all_var.set(False)
for var in self.manager_checkboxes.values():
var.set(False)
# 恢复之前选中的负责人
for manager in previously_selected_managers:
if manager in self.manager_checkboxes:
self.manager_checkboxes[manager].set(True)
# 检查是否全部选中
all_selected = all(
self.manager_checkboxes.get(m, tk.BooleanVar(value=False)).get()
for m in self.managers
)
self.select_all_var.set(all_selected)
# 刷新显示
self._apply_filter()
self._update_status()
@@ -888,12 +1032,14 @@ class MaterialTypeManagementDialog(tk.Toplevel):
if stats['update_failed'] > 0:
result_parts.append(f"更新失败:{stats['update_failed']}")
result_msg = "保存完成!\n\n" + "\n".join(result_parts)
result_msg = "\n".join(result_parts)
if (stats['insert_failed'] + stats['delete_failed'] + stats['update_failed']) > 0:
messagebox.showwarning("完成(部分失败)", result_msg)
# 使用自定义对话框显示结果
has_failures = (stats['insert_failed'] + stats['delete_failed'] + stats['update_failed']) > 0
if has_failures:
ResultDialog(self, "保存完成(部分失败)", result_msg, success=False)
else:
messagebox.showinfo("成功", result_msg)
ResultDialog(self, "保存成功", result_msg, success=True)
# 重新加载数据
self._load_data()