在UI界面顶部生成菜单栏选项:一级目录<Excel文件处理>,点击该目录生成二级目录<宏模块加载分析>、二级目录<文件合并统计分析>。点击二级目录<宏模块加载分析>时加载出如下UI界面:import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import os
import win32com.client as win32
import time
from datetime import datetime
import threading
import re
class VBAExecutorApp:
def __init__(self, root):
self.root = root
self.root.title("WPS Excel宏执行器")
self.root.geometry("600x280")
self.root.resizable(True, True)
self.style = ttk.Style()
# 配置按钮样式
self.style.configure("Run.TButton",
foreground="white",
background="#4CAF50",
font=("Arial", 10, "bold"),
padding=6)
self.style.map("Run.TButton",
foreground=[('disabled', 'gray')],
background=[('disabled', '#CCCCCC')])
# 创建网格布局
self.root.columnconfigure((0, 1, 2), weight=1)
self.root.rowconfigure((0, 1, 2), weight=1)
# 第一行标题
self.create_label("日志文件选择:", 0, 0, "黑体", 12)
self.create_label("分析模块选择:", 0, 1, "黑体", 12)
self.create_label("宏主程序读取:", 0, 2, "黑体", 12)
# 第二行文件选择
self.excel_path = tk.StringVar()
self.bas_path = tk.StringVar()
self.create_file_entry(1, 0, self.excel_path, [("Excel文件", "*.xls *.xlsx")])
self.create_file_entry(1, 1, self.bas_path, [("BAS文件", "*.bas")])
# 宏函数下拉框
self.macro_var = tk.StringVar()
self.macro_combobox = ttk.Combobox(
self.root,
textvariable=self.macro_var,
state="readonly",
height=8
)
self.macro_combobox.grid(row=1, column=2, padx=5, pady=2, sticky="ew")
# 第三行按钮
self.run_button = ttk.Button(
self.root,
text="执行宏命令分析",
command=self.start_execution,
width=23,
style="Run.TButton"
)
self.run_button.grid(row=2, column=0, padx=5, pady=(7, 8), sticky="ew")
# 添加悬停效果绑定
self.run_button.bind("<Enter>", self.on_enter)
self.run_button.bind("<Leave>", self.on_leave)
self.run_button.bind("<ButtonPress-1>", self.on_press)
self.run_button.bind("<ButtonRelease-1>", self.on_release)
# 进度条容器
progress_container = ttk.Frame(self.root)
progress_container.grid(row=2, column=1, columnspan=2, padx=5, pady=0, sticky="ew")
progress_container.columnconfigure(0, weight=1)
progress_container.columnconfigure(1, weight=0)
# 进度条
self.progress_var = tk.DoubleVar()
self.progress_bar = ttk.Progressbar(
progress_container,
variable=self.progress_var,
maximum=100,
mode="determinate",
length=200
)
self.progress_bar.grid(row=0, column=0,ipadx=30,ipady=7,padx=(0, 0), sticky="ew")
# 百分比标签
self.percent_label = ttk.Label(
progress_container,
text="0%",
font=("Arial", 12),
width=5
)
self.percent_label.grid(row=0, column=1, ipadx=2,ipady=7,padx=(10, 0),sticky="e")
# 绑定事件
self.bas_path.trace_add("write", self.parse_bas_file)
self.progress_var.trace_add("write", self.update_percent_label)
def update_percent_label(self, *args):
"""更新百分比标签显示"""
progress_value = self.progress_var.get()
self.percent_label.config(text=f"{int(progress_value)}%")
# 根据进度改变标签颜色
if progress_value < 30:
self.percent_label.config(foreground="red")
elif progress_value < 70:
self.percent_label.config(foreground="orange")
else:
self.percent_label.config(foreground="green")
# 关键修改:当进度达到100%时重新启用按钮
if progress_value == 100:
self.run_button.config(state=tk.NORMAL)
def create_label(self, text, row, column, font, size):
label = tk.Label(
self.root, text=text,
font=(font, size), anchor="w"
)
label.grid(row=row, column=column, padx=0, pady=(25, 0), sticky="w")
return label
def create_file_entry(self, row, column, text_var, filetypes):
frame = ttk.Frame(self.root)
frame.grid(row=row, column=column, padx=5, pady=2, sticky="ew")
frame.columnconfigure(1, weight=1)
entry = ttk.Entry(frame, textvariable=text_var)
entry.grid(row=0, column=0, sticky="ew", padx=(0, 2))
browse = ttk.Button(frame, text="浏览", command=lambda: self.browse_file(text_var, filetypes))
browse.grid(row=0, column=1, padx=(0, 0))
def browse_file(self, text_var, filetypes):
file_path = filedialog.askopenfilename(filetypes=filetypes)
if file_path:
text_var.set(file_path)
def parse_bas_file(self, *args):
bas_path = self.bas_path.get()
if not bas_path or not os.path.exists(bas_path):
return
try:
# 尝试使用UTF-8和GBK解码
try:
with open(bas_path, "r", encoding="utf-8") as f:
content = f.read()
except UnicodeDecodeError:
with open(bas_path, "r", encoding="gbk") as f:
content = f.read()
# 查找Main_开头的宏函数
macro_pattern = r"Sub\s+(Main_\w+)\s*\(\)"
macros = re.findall(macro_pattern, content)
if macros:
self.macro_combobox["values"] = macros
if self.macro_combobox["values"]:
self.macro_combobox.current(0)
except Exception as e:
messagebox.showerror("错误", f"解析BAS文件失败: {str(e)}")
def start_execution(self):
"""关键修改:点击后立即禁用按钮"""
if not self.excel_path.get() or not self.bas_path.get():
messagebox.showerror("错误", "请先选择需要分析的文件或宏模块")
return
# 禁用按钮防止重复点击
self.run_button.config(state=tk.DISABLED)
self.progress_var.set(0) # 重置进度条
# 在后台线程中执行宏
threading.Thread(target=self.execute_macro, daemon=True).start()
def on_enter(self, event):
self.style.configure("Run.TButton", background="#45a049")
def on_leave(self, event):
self.style.configure("Run.TButton", background="#4CAF50")
def on_press(self, event):
self.style.configure("Run.TButton", background="#2E7D32")
def on_release(self, event):
self.style.configure("Run.TButton", background="#45a049")
def execute_macro(self):
try:
# 初始化WPS Excel
excel = win32.gencache.EnsureDispatch("Excel.Application")
excel.Visible = False
excel.DisplayAlerts = False
# 打开Excel文件
wb = excel.Workbooks.Open(os.path.abspath(self.excel_path.get()))
self.update_progress(20)
# 导入BAS文件
vb_project = wb.VBProject
vb_project.VBComponents.Import(os.path.abspath(self.bas_path.get()))
self.update_progress(40)
# 执行宏
macro_name = self.macro_var.get()
excel.Application.Run(macro_name)
self.update_progress(70)
time.sleep(1) # 模拟执行时间
# 另存为新文件
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
save_path = filedialog.asksaveasfilename(
defaultextension=".xlsx",
filetypes=[("Excel文件", "*.xlsx"), ("Excel 97-2003", "*.xls")],
initialfile=f"{self.macro_combobox["values"]}{timestamp}"
)
if save_path:
wb.SaveAs(save_path)
self.update_progress(90)
messagebox.showinfo("成功", f"文件已保存至: {save_path}")
wb.Close(False)
excel.Quit()
self.update_progress(100) # 关键点:设置进度为100%
except Exception as e:
messagebox.showerror("执行错误", f"宏执行失败: {str(e)}")
self.update_progress(100) # 出错时也设置进度为100%
finally:
# 确保进度达到100%(update_progress(100)会启用按钮)
if self.progress_var.get() < 100:
self.update_progress(100)
def update_progress(self, value):
"""更新进度条值(线程安全)"""
# 使用after确保在主线程更新UI
self.root.after(0, lambda: self.progress_var.set(value))
self.root.update_idletasks()
if __name__ == "__main__":
root = tk.Tk()
app = VBAExecutorApp(root)
root.mainloop()
最新发布