import os
import win32com.client
import tkinter as tk
from tkinter import ttk
from ttkbootstrap import Style
from tkinter import filedialog, messagebox
from threading import Thread
class ExcelToPDFConverter:
def __init__(self, master):
self.master = master
self.master.title("Excel转PDF工具 - 专业版")
self.master.geometry("600x400")
# 应用ttkbootstrap主题
self.style = Style(theme='morph')
self.style.configure('TButton', font=('微软雅黑', 10))
# 界面组件
self.create_widgets()
self.running = False
def create_widgets(self):
"""创建界面组件"""
# 文件选择区域
frame_files = ttk.Frame(self.master)
frame_files.pack(pady=10, padx=20, fill='x')
self.btn_select = ttk.Button(
frame_files,
text="选择Excel文件",
command=self.select_files,
style='primary'
)
self.btn_select.pack(side='left', padx=5)
self.lbl_files = ttk.Label(frame_files, text="未选择文件")
self.lbl_files.pack(side='left', fill='x', expand=True)
# 输出目录区域
frame_output = ttk.Frame(self.master)
frame_output.pack(pady=10, padx=20, fill='x')
self.btn_output = ttk.Button(
frame_output,
text="选择保存位置",
command=self.select_output,
style='info'
)
self.btn_output.pack(side='left', padx=5)
self.lbl_output = ttk.Label(frame_output, text="未选择目录")
self.lbl_output.pack(side='left', fill='x', expand=True)
# 进度条
self.progress = ttk.Progressbar(
self.master,
orient='horizontal',
mode='determinate'
)
self.progress.pack(pady=15, padx=20, fill='x')
# 日志区域
self.log_text = tk.Text(
self.master,
height=8,
state='disabled',
font=('Consolas', 9)
)
self.log_text.pack(pady=10, padx=20, fill='both', expand=True)
# 操作按钮
frame_btn = ttk.Frame(self.master)
frame_btn.pack(pady=10)
self.btn_start = ttk.Button(
frame_btn,
text="开始转换",
command=self.start_conversion,
style='success'
)
self.btn_start.pack(side='left', padx=10)
self.btn_clear = ttk.Button(
frame_btn,
text="清空日志",
command=self.clear_log,
style='warning'
)
self.btn_clear.pack(side='left', padx=10)
def select_files(self):
"""选择Excel文件"""
files = filedialog.askopenfilenames(
filetypes=[("Excel文件", "*.xls *.xlsx")]
)
if files:
self.file_paths = files
self.lbl_files.config(text=f"已选择 {len(files)} 个文件")
def select_output(self):
"""选择输出目录"""
folder = filedialog.askdirectory()
if folder:
self.output_folder = folder
self.lbl_output.config(text=folder)
def log_message(self, msg):
"""记录日志"""
self.log_text.config(state='normal')
self.log_text.insert('end', msg + '\n')
self.log_text.see('end')
self.log_text.config(state='disabled')
def clear_log(self):
"""清空日志"""
self.log_text.config(state='normal')
self.log_text.delete(1.0, 'end')
self.log_text.config(state='disabled')
def start_conversion(self):
"""启动转换线程"""
if not hasattr(self, 'file_paths'):
messagebox.showwarning("警告", "请先选择Excel文件")
return
if not hasattr(self, 'output_folder'):
messagebox.showwarning("警告", "请选择输出目录")
return
if not self.running:
self.running = True
Thread(target=self.convert_files).start()
def convert_files(self):
"""执行转换"""
total = len(self.file_paths)
excel = win32com.client.Dispatch("Excel.Application")
excel.Visible = False
excel.DisplayAlerts = False
try:
for i, file_path in enumerate(self.file_paths, 1):
if not self.running:
break
self.progress['value'] = (i / total) * 100
self.master.title(f"转换中... {i}/{total}")
try:
# 转换逻辑
workbook = excel.Workbooks.Open(file_path)
file_name = os.path.splitext(os.path.basename(file_path))[0]
output_path = os.path.join(self.output_folder, f"{file_name}.pdf")
workbook.ExportAsFixedFormat(0, output_path)
self.log_message(f"✓ 成功: {file_name}")
except Exception as e:
self.log_message(f"✗ 失败: {os.path.basename(file_path)} - {str(e)}")
finally:
if 'workbook' in locals():
workbook.Close(False)
messagebox.showinfo("完成", "所有文件转换完成!")
finally:
excel.Quit()
self.running = False
self.master.title("Excel转PDF工具 - 专业版")
self.progress['value'] = 0
if __name__ == "__main__":
# 安装依赖:pip install ttkbootstrap pywin32
root = tk.Tk()
app = ExcelToPDFConverter(root)
root.mainloop()