Python GUI 界面设计
获取用户输入的SOURCE_DIR、TARGET_DIR和DATE,并包含路径自动校正、日期验证功能和多线程实现任务功能。
框架设计灵活,根据实际需求替换main_processing_function中的处理逻辑,而不需要修改GUI部分的代码。
import tkinter as tk
from tkinter import ttk, messagebox
import re
import os
import sys
from datetime import datetime, timedelta
import calendar
import threading
class PathDateInputApp:
def __init__(self, root):
self.root = root
self.root.title("数据处理工具")
self.root.geometry("500x250")
self.root.resizable(True, True)
# 设置协议,当窗口关闭时调用safe_exit
self.root.protocol("WM_DELETE_WINDOW", self.safe_exit)
# 设置主框架
main_frame = ttk.Frame(root, padding="20")
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# 配置网格权重
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
main_frame.columnconfigure(1, weight=1)
# 创建输入字段
ttk.Label(main_frame, text="源路径:").grid(row=0, column=0, sticky=tk.W, pady=5)
self.source_dir = ttk.Entry(main_frame, width=50)
self.source_dir.grid(row=0, column=1, sticky=(tk.W, tk.E), pady=5, padx=(10, 0))
ttk.Label(main_frame, text="目标路径:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.target_dir = ttk.Entry(main_frame, width=50)
self.target_dir.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=5, padx=(10, 0))
# 添加示例文本
ttk.Label(main_frame, text="路径示例: C:\\Users\\J\\input", foreground="gray").grid(row=2, column=0, columnspan=2, pady=5, sticky=tk.W)
ttk.Label(main_frame, text="日期 (YYYYMMDD):").grid(row=3, column=0, sticky=tk.W, pady=5)
self.date_entry = ttk.Entry(main_frame, width=50)
self.date_entry.grid(row=3, column=1, sticky=(tk.W, tk.E), pady=5, padx=(10, 0))
# 添加示例文本
ttk.Label(main_frame, text="日期示例: 20250630", foreground="gray").grid(row=4, column=0, columnspan=2, pady=5, sticky=tk.W)
# 按钮框架
button_frame = ttk.Frame(main_frame)
button_frame.grid(row=5, column=0, columnspan=2, pady=20)
# 定义处理按钮并保存到self.process_button
self.process_button = ttk.Button(button_frame, text="处理", command=self.process_data)
self.process_button.pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="清除", command=self.clear_fields).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="退出", command=self.safe_exit).pack(side=tk.LEFT, padx=5)
# 状态栏
self.status_var = tk.StringVar()
self.status_var.set("就绪")
status_bar = ttk.Label(root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
status_bar.grid(row=1, column=0, sticky=(tk.W, tk.E))
# 处理线程
self.processing_thread = None
self.is_processing = False
def normalize_path(self, path):
"""自动校正路径格式"""
# 移除引号
path = re.sub(r'^["\']|["\']$', '', path.strip())
# 统一斜杠格式
path = path.replace('/', '\\')
path = path.replace('\\\\', '\\')
return path
def validate_date(self, date_str):
"""验证日期格式和有效性"""
# 检查格式
if not re.match(r'^\d{8}$', date_str):
return False, "日期必须为YYYYMMDD格式"
try:
# 尝试解析日期
year = int(date_str[:4])
month = int(date_str[4:6])
day = int(date_str[6:8])
date_obj = datetime(year, month, day)
# 检查是否为月末
last_day = calendar.monthrange(year, month)[1]
if day != last_day:
return False, f"日期不是月末,最后一天是{last_day}"
return True, date_obj
except ValueError as e:
return False, f"无效日期: {str(e)}"
def process_data(self):
"""处理数据的主函数"""
# 如果正在处理中,则不执行新的处理
if self.is_processing:
return
# 获取输入值
source_dir = self.source_dir.get()
target_dir = self.target_dir.get()
date_str = self.date_entry.get()
# 验证输入
if not all([source_dir, target_dir, date_str]):
messagebox.showerror("错误", "所有字段均为必填")
return
# 校正路径
try:
source_dir = self.normalize_path(source_dir)
target_dir = self.normalize_path(target_dir)
except Exception as e:
messagebox.showerror("错误", f"路径校正失败: {str(e)}")
return
# 验证日期
is_valid, date_result = self.validate_date(date_str)
if not is_valid:
messagebox.showerror("错误", date_result)
return
# 更新状态
self.status_var.set("处理中...")
self.process_button.config(state="disabled")
self.is_processing = True
# 在新线程中运行处理函数,避免界面冻结
self.processing_thread = threading.Thread(
target=self.run_processing,
args=(source_dir, target_dir, date_result),
daemon=True
)
self.processing_thread.start()
# 定期检查处理是否完成
self.check_processing_status()
def run_processing(self, source_dir, target_dir, date_obj):
"""在新线程中运行处理函数"""
try:
# 调用主处理函数
result = main_processing_function(source_dir, target_dir, date_obj)
# 使用线程安全的方式更新GUI
self.root.after(0, lambda: self.processing_complete(True, result))
except Exception as e:
# 使用线程安全的方式更新GUI
self.root.after(0, lambda: self.processing_complete(False, str(e)))
def check_processing_status(self):
"""定期检查处理状态"""
if self.is_processing and self.processing_thread.is_alive():
# 如果仍在处理中,继续检查
self.root.after(100, self.check_processing_status)
elif self.is_processing:
# 如果线程已结束但状态未更新,强制更新
self.processing_complete(False, "处理被中断")
def processing_complete(self, success, message):
"""处理完成后的回调函数"""
self.is_processing = False
self.process_button.config(state="normal")
if success:
messagebox.showinfo("成功", f"处理成功完成!\n{message}")
self.status_var.set("就绪")
else:
messagebox.showerror("错误", f"处理失败: {message}")
self.status_var.set("发生错误")
def clear_fields(self):
"""清除所有输入字段"""
self.source_dir.delete(0, tk.END)
self.target_dir.delete(0, tk.END)
self.date_entry.delete(0, tk.END)
self.status_var.set("字段已清除")
def safe_exit(self):
"""安全退出应用程序"""
if self.is_processing:
if messagebox.askyesno("确认退出",
"正在处理中,确定要退出吗?"):
self.root.destroy()
sys.exit(0)
else:
self.root.destroy()
sys.exit(0)
# 主要处理函数 - 可以替换为实际的处理逻辑
def main_processing_function(source_dir, target_dir, date_obj):
"""
主要处理函数 - 替换为实际的数据处理逻辑
参数:
source_dir (str): 源目录路径
target_dir (str): 目标目录路径
date_obj (datetime): 日期对象
返回:
str: 处理结果信息
"""
# 这里可以替换为实际的数据处理代码
result = f"从 {source_dir} 到 {target_dir} 的数据已处理,日期为 {date_obj.strftime('%Y-%m-%d')}"
# 模拟处理时间
import time
time.sleep(2)
return result
def main():
"""主函数"""
root = tk.Tk()
app = PathDateInputApp(root)
root.mainloop()
if __name__ == "__main__":
main()
功能说明
-
路径自动校正:
- 移除路径字符串开头和结尾的引号
- 将正斜杠(/)和双反斜杠(\\)统一转换为单反斜杠(\)
- 处理各种不规范的路径输入格式
-
日期验证:
- 检查日期格式是否为YYYYMMDD
- 验证日期是否有效(如2月30日会被拒绝)
- 检查日期是否为该月的最后一天
-
GUI界面:
- 示例文本提示用户正确格式
- 状态栏显示当前操作状态
- 响应式布局,窗口可调整大小
-
自由替换主要处理函数:
main_processing_function可以替换为实际的数据处理逻辑- 提供了清晰的参数说明和返回格式
9万+

被折叠的 条评论
为什么被折叠?



