Python GUI设计界面框架应用(一)

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()

功能说明

  1. 路径自动校正

    • 移除路径字符串开头和结尾的引号
    • 将正斜杠(/)和双反斜杠(\\)统一转换为单反斜杠(\)
    • 处理各种不规范的路径输入格式
  2. 日期验证

    • 检查日期格式是否为YYYYMMDD
    • 验证日期是否有效(如2月30日会被拒绝)
    • 检查日期是否为该月的最后一天
  3. GUI界面

    • 示例文本提示用户正确格式
    • 状态栏显示当前操作状态
    • 响应式布局,窗口可调整大小
  4. 自由替换主要处理函数

    • main_processing_function 可以替换为实际的数据处理逻辑
    • 提供了清晰的参数说明和返回格式

学习和参考的操作手册

  1. tkinter模块教程 - Python图形编程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值