win10程序(十四)pdf转docx简易版
‘’‘
这是一个使用Python和Tkinter开发的PDF转DOCX转换工具,具有美观的糖果色界面和批量转换功能。
## 功能特点
- 批量选择和转换PDF文件
- 糖果色主题的友好界面
- 实时转换进度显示
- 详细的转换日志记录
- 简单易用的操作方式
’‘’
# -*- coding: utf-8 -*-
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import os
import threading
import time
import sys
# 检查依赖项
try:
from pdf2docx import Converter
DEPENDENCY_AVAILABLE = True
except ImportError:
DEPENDENCY_AVAILABLE = False
print("警告: 未找到pdf2docx模块,请运行 'pip install pdf2docx' 来安装")
class PDFtoDOCXConverter:
def __init__(self, root):
self.root = root
self.root.title("PDF转DOCX转换器")
self.root.geometry("1000x600") # 调整窗口大小以适应内容
self.root.resizable(True, True) # 允许调整窗口大小
# 设置糖果色主题
self.colors = {
'primary': '#FF6B6B', # 珊瑚粉
'secondary': '#4ECDC4', # 薄荷绿
'accent1': '#FFD166', # 芒果黄
'accent2': '#06D6A0', # 青柠绿
'accent3': '#118AB2', # 天空蓝
'background': '#F7F9FC', # 浅灰白
'text': '#2D3142', # 深灰蓝
'light_text': '#6C757D' # 浅灰色
}
# 设置背景颜色
self.root.configure(bg=self.colors['background'])
# 存储选择的文件
self.selected_files = []
# 创建界面
self.create_widgets()
def create_widgets(self):
# 创建主框架
main_frame = tk.Frame(self.root, bg=self.colors['background'])
main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
# 创建左侧控制面板
control_frame = tk.Frame(main_frame, bg=self.colors['background'], width=300)
control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=10)
# 添加按钮
self.create_buttons(control_frame)
# 创建右侧文件列表和日志区域
content_frame = tk.Frame(main_frame, bg=self.colors['background'])
content_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=10)
# 文件列表区域
files_frame = tk.LabelFrame(content_frame, text="待转换文件",
font=("微软雅黑", 12),
bg=self.colors['background'],
fg=self.colors['text'])
files_frame.pack(fill=tk.BOTH, expand=True, pady=10)
# 文件列表
self.create_file_list(files_frame)
# 日志区域
log_frame = tk.LabelFrame(content_frame, text="转换日志",
font=("微软雅黑", 12),
bg=self.colors['background'],
fg=self.colors['text'])
log_frame.pack(fill=tk.BOTH, expand=True, pady=10)
# 日志文本框
self.create_log_text(log_frame)
def create_buttons(self, parent):
# 选择文件按钮
select_btn = tk.Button(parent, text="选择PDF文件",
font=("微软雅黑", 14),
bg=self.colors['accent1'],
fg=self.colors['text'],
command=self.select_files,
relief=tk.RAISED,
bd=0,
height=2,
width=20)
select_btn.pack(pady=15)
select_btn.bind("<Enter>", lambda e: select_btn.config(bg="#FFE066"))
select_btn.bind("<Leave>", lambda e: select_btn.config(bg=self.colors['accent1']))
# 转换按钮
convert_btn = tk.Button(parent, text="开始转换",
font=("微软雅黑", 14),
bg=self.colors['accent2'],
fg="white",
command=self.start_conversion,
relief=tk.RAISED,
bd=0,
height=2,
width=20)
convert_btn.pack(pady=15)
convert_btn.bind("<Enter>", lambda e: convert_btn.config(bg="#06E6A0"))
convert_btn.bind("<Leave>", lambda e: convert_btn.config(bg=self.colors['accent2']))
# 清空列表按钮
clear_btn = tk.Button(parent, text="清空列表",
font=("微软雅黑", 14),
bg=self.colors['accent3'],
fg="white",
command=self.clear_files,
relief=tk.RAISED,
bd=0,
height=2,
width=20)
clear_btn.pack(pady=15)
clear_btn.bind("<Enter>", lambda e: clear_btn.config(bg="#119AB2"))
clear_btn.bind("<Leave>", lambda e: clear_btn.config(bg=self.colors['accent3']))
def create_file_list(self, parent):
# 创建滚动条
scrollbar = tk.Scrollbar(parent)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# 创建列表框
self.file_listbox = tk.Listbox(parent,
font=("微软雅黑", 10),
bg="white",
fg=self.colors['text'],
selectbackground=self.colors['accent1'],
selectforeground=self.colors['text'],
width=70,
height=10,
yscrollcommand=scrollbar.set)
self.file_listbox.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
scrollbar.config(command=self.file_listbox.yview)
def create_log_text(self, parent):
# 创建滚动条
scrollbar = tk.Scrollbar(parent)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# 创建文本框
self.log_text = tk.Text(parent,
font=("微软雅黑", 10),
bg="white",
fg=self.colors['text'],
width=70,
height=8,
yscrollcommand=scrollbar.set,
state=tk.DISABLED)
self.log_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
scrollbar.config(command=self.log_text.yview)
def select_files(self):
files = filedialog.askopenfilenames(
title="选择PDF文件",
filetypes=[("PDF文件", "*.pdf"), ("所有文件", "*.*")]
)
if files:
for file in files:
if file not in self.selected_files:
self.selected_files.append(file)
self.file_listbox.insert(tk.END, os.path.basename(file))
self.log("已添加 {} 个文件".format(len(files)))
def clear_files(self):
if self.selected_files:
self.selected_files.clear()
self.file_listbox.delete(0, tk.END)
self.log("文件列表已清空")
else:
messagebox.showinfo("提示", "文件列表已为空")
def start_conversion(self):
if not self.selected_files:
messagebox.showwarning("警告", "请先选择PDF文件")
return
# 选择输出目录
output_dir = filedialog.askdirectory(title="选择输出目录")
if not output_dir:
return
# 禁用转换按钮防止重复点击
for widget in self.root.winfo_children():
if isinstance(widget, tk.Frame) and widget.winfo_children():
for child in widget.winfo_children():
if isinstance(child, tk.Frame) and child.winfo_children():
for btn in child.winfo_children():
if isinstance(btn, tk.Button) and btn["text"] == "开始转换":
btn.config(state=tk.DISABLED)
# 在新线程中开始转换
self.total_files = len(self.selected_files)
self.current_file = 0
thread = threading.Thread(target=self.convert_files, args=(output_dir,))
thread.daemon = True
thread.start()
def convert_files(self, output_dir):
self.log("开始转换文件...")
# 确保输出目录存在
if not os.path.exists(output_dir):
try:
os.makedirs(output_dir)
self.log(f"已创建输出目录: {output_dir}")
except Exception as e:
self.log(f"创建输出目录失败: {str(e)}")
# 在主线程中显示错误消息
self.root.after(0, lambda: messagebox.showerror("错误", f"创建输出目录失败: {str(e)}"))
# 重新启用转换按钮
self.root.after(0, self._enable_convert_button)
return
success_count = 0
fail_count = 0
for i, pdf_path in enumerate(self.selected_files):
self.current_file = i + 1
filename = os.path.basename(pdf_path)
docx_filename = os.path.splitext(filename)[0] + ".docx"
docx_path = os.path.join(output_dir, docx_filename)
try:
self.log(f"转换中: {filename}")
# 检查文件是否存在且可读
if not os.path.exists(pdf_path):
raise FileNotFoundError(f"文件不存在: {pdf_path}")
# 创建转换器并转换
cv = Converter(pdf_path)
cv.convert(docx_path, start=0, end=None)
cv.close()
self.log(f"转换完成: {docx_filename}")
success_count += 1
except Exception as e:
error_msg = f"转换失败: {filename} - {str(e)}"
self.log(error_msg)
fail_count += 1
finally:
# 仅记录当前进度到日志
self.log(f"进度: {self.current_file}/{self.total_files}")
# 转换完成
summary = f"转换完成!成功: {success_count}, 失败: {fail_count}"
self.log(summary)
# 重新启用转换按钮
self.root.after(0, self._enable_convert_button)
# 在主线程中显示完成消息
self.root.after(0, lambda: messagebox.showinfo("完成", summary))
def _enable_convert_button(self):
"""重新启用转换按钮的辅助方法"""
for widget in self.root.winfo_children():
if isinstance(widget, tk.Frame) and widget.winfo_children():
for child in widget.winfo_children():
if isinstance(child, tk.Frame) and child.winfo_children():
for btn in child.winfo_children():
if isinstance(btn, tk.Button) and btn["text"] == "开始转换":
btn.config(state=tk.NORMAL)
break
def log(self, message):
timestamp = time.strftime("%H:%M:%S")
log_message = f"[{timestamp}] {message}\n"
self.log_text.config(state=tk.NORMAL)
self.log_text.insert(tk.END, log_message)
self.log_text.see(tk.END) # 自动滚动到底部
self.log_text.config(state=tk.DISABLED)
def check_dependencies():
"""检查程序所需的依赖项"""
if not DEPENDENCY_AVAILABLE:
root = tk.Tk()
root.withdraw() # 隐藏主窗口
messagebox.showerror(
"缺少依赖项",
"未找到pdf2docx模块!\n\n请按照以下步骤安装依赖:\n1. 打开命令提示符\n2. 运行: pip install pdf2docx\n3. 然后重新启动程序"
)
root.destroy()
return False
return True
if __name__ == "__main__":
# 调试输出
print("程序启动中...")
# 先检查依赖项
if check_dependencies():
try:
print("依赖项检查通过,创建窗口...")
root = tk.Tk()
print("窗口创建成功,初始化应用...")
app = PDFtoDOCXConverter(root)
print("应用初始化完成,启动主循环...")
root.mainloop()
except Exception as e:
print(f"程序运行出错: {str(e)}")
import traceback
traceback.print_exc()
# 创建一个简单的错误提示窗口
error_root = tk.Tk()
error_root.title("错误")
error_root.geometry("400x200")
error_label = tk.Label(
error_root,
text=f"程序运行出错:\n{str(e)}",
font=("微软雅黑", 10),
justify=tk.LEFT,
wraplength=380
)
error_label.pack(pady=20)
ok_btn = tk.Button(
error_root,
text="确定",
command=error_root.destroy,
width=10
)
ok_btn.pack(pady=10)
error_root.mainloop()
