Python开发Excel批量写入工具:多文件独立配置与Tkinter界面设计
Python开发Excel批量写入工具:多文件独立配置与Tkinter界面设计
一、工具功能概述
本工具基于Python开发,提供以下核心功能:
- 📌 多Excel文件批量选择与独立配置
- 📝 动态获取工作表列表(支持双击配置)
- 🎯 单元格地址格式自动验证
- 📥 支持文本内容直接输入/文件导入
- 📊 实时状态反馈与详细错误报告
二、环境配置与依赖安装
1. 创建虚拟环境
python -m venv excel_env
source excel_env/bin/activate # Linux/Mac
excel_env\Scripts\activate # Windows
2. 安装依赖库
pip install openpyxl pyinstaller
三、工具设计与实现
1. 界面布局设计
2. 核心功能模块
(1) 文件配置区
# 文件列表展示(Treeview组件)
self.tree = ttk.Treeview(main_frame, columns=("File", "Sheet", "Cell"), show="headings",height=8
)
self.tree.heading("File", text="文件路径")
self.tree.heading("Sheet", text="工作表")
self.tree.heading("Cell", text="单元格")
(2) 动态配置窗口
def on_item_double_click(self, event):"""双击触发配置弹窗"""item = self.tree.selection()[0]file_path = self.tree.item(item, "values")[0]# 自动读取工作表列表wb = load_workbook(file_path, read_only=True)sheets = wb.sheetnames# 创建带组合框的配置窗口sheet_combobox = ttk.Combobox(config_window, values=sheets)cell_entry = ttk.Entry(config_window)
(3) 内容写入逻辑
def write_to_excel(self):content = self.content_text.get("1.0", tk.END).strip()for item in self.tree.get_children():file_path, sheet, cell = self.tree.item(item, "values")try:wb = load_workbook(file_path)ws = wb[sheet]ws[cell] = content # 核心写入操作wb.save(file_path)except Exception as e:# 详细错误记录...
四、关键问题解决方案
1. 组件初始化顺序错误
现象:AttributeError: 'ExcelWriterApp' object has no attribute 'content_text'
解决:调整组件创建顺序,确保元素先创建后使用
# 正确顺序示例
self.content_text = tk.Text(...) # 先创建
self.tree.bind(...) # 后绑定事件
2. 状态栏丢失问题
现象:AttributeError: 'ExcelWriterApp' object has no attribute 'status_var'
修复方案:
# 在setup_ui中明确初始化
self.status_var = tk.StringVar()
self.status_bar = ttk.Label(...)
self.status_var.set("就绪")
3. 常见警告处理
警告类型 | 原因 | 解决方案 |
---|---|---|
Qt版本警告 | Tkinter依赖的Qt库版本检测 | 添加环境变量:os.environ["QT_LOGGING_RULES"] = "qt.qpa.*=false" |
libpng警告 | Excel内嵌图片元数据问题 | 可忽略不影响功能 |
五、完整实现代码
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from openpyxl import load_workbook
import osclass ExcelWriterApp:def __init__(self, root):self.root = rootself.root.title("Excel 单元格写入工具")self.file_configs = {} # 存储文件配置的字典 {file_path: (sheet, cell)}self.setup_ui()def setup_ui(self):# 主容器main_frame = ttk.Frame(self.root)main_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)# 文件选择区file_selector_frame = ttk.LabelFrame(main_frame, text="文件配置")file_selector_frame.pack(fill=tk.X, pady=5)ttk.Button(file_selector_frame, text="添加文件", command=self.select_files).pack(side=tk.LEFT, padx=5)# 文件列表树状视图self.tree = ttk.Treeview(main_frame, columns=("File", "Sheet", "Cell"), show="headings", height=8)self.tree.heading("File", text="文件路径")self.tree.heading("Sheet", text="工作表")self.tree.heading("Cell", text="单元格")self.tree.pack(fill=tk.BOTH, expand=True)# 内容输入区content_frame = ttk.LabelFrame(main_frame, text="内容配置")content_frame.pack(fill=tk.X, pady=5)self.content_text = tk.Text(content_frame, height=6, width=50)self.content_text.pack(side=tk.LEFT, padx=5, pady=5)btn_frame = ttk.Frame(content_frame)btn_frame.pack(side=tk.RIGHT, padx=5)ttk.Button(btn_frame, text="导入内容", command=self.import_content).pack(pady=2)ttk.Button(btn_frame, text="执行写入", command=self.write_to_excel).pack(pady=2)# 绑定双击事件编辑配置self.tree.bind("<Double-1>", self.on_item_double_click)# 状态栏初始化(添加在界面底部)self.status_var = tk.StringVar()self.status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)# 初始化状态self.status_var.set("就绪")def on_item_double_click(self, event):"""双击条目弹出配置窗口"""item = self.tree.selection()[0]file_path = self.tree.item(item, "values")[0]config_window = tk.Toplevel(self.root)config_window.title("文件配置")# 获取该文件的工作表列表try:wb = load_workbook(file_path, read_only=True)sheets = wb.sheetnamesexcept Exception as e:messagebox.showerror("错误", f"读取文件失败:{str(e)}")return# 工作表选择ttk.Label(config_window, text="选择工作表:").grid(row=0, column=0, padx=5, pady=5)sheet_combobox = ttk.Combobox(config_window, values=sheets)sheet_combobox.grid(row=0, column=1, padx=5, pady=5)sheet_combobox.set(self.tree.item(item, "values")[1])# 单元格输入ttk.Label(config_window, text="输入单元格:").grid(row=1, column=0, padx=5, pady=5)cell_entry = ttk.Entry(config_window)cell_entry.grid(row=1, column=1, padx=5, pady=5)cell_entry.insert(0, self.tree.item(item, "values")[2])# 保存按钮def save_config():new_sheet = sheet_combobox.get()new_cell = cell_entry.get().upper()self.tree.item(item, values=(file_path, new_sheet, new_cell))config_window.destroy()ttk.Button(config_window, text="保存配置", command=save_config).grid(row=2, columnspan=2, pady=5)def select_files(self):files = filedialog.askopenfilenames(filetypes=[("Excel Files", "*.xlsx"), ("All Files", "*.*")])if files:for f in files:if f not in self.file_configs:# 自动获取第一个工作表作为默认值try:wb = load_workbook(f, read_only=True)default_sheet = wb.sheetnames[0]except:default_sheet = "Sheet1"self.tree.insert("", "end", values=(f, default_sheet, "A1"))self.file_configs[f] = (default_sheet, "A1")def validate_inputs(self):"""验证所有输入的有效性"""error_msgs = []# 清除旧的高亮显示for widget in [self.sheet_entry, self.cell_entry, self.content_text]:widget.config(background="white")if not self.selected_files:error_msgs.append("请至少选择一个Excel文件")self.file_btn.config(background="#ffcccc")sheet_name = self.sheet_entry.get().strip()if not sheet_name:error_msgs.append("必须填写工作表名称")self.sheet_entry.config(background="#ffcccc")cell = self.cell_entry.get().strip()if not cell or not cell[0].isalpha() or not cell[1:].isdigit():error_msgs.append("单元格格式不正确(示例:A1/B2)")self.cell_entry.config(background="#ffcccc")if not self.content_text.get("1.0", tk.END).strip():error_msgs.append("必须填写写入内容")self.content_text.config(background="#ffcccc")return error_msgsdef import_content(self):file_path = filedialog.askopenfilename(title="选择文本文件",filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")],)if file_path:with open(file_path, "r", encoding="utf-8") as f:content = f.read()self.content_text.delete(1.0, tk.END)self.content_text.insert(tk.END, content)def write_to_excel(self):content = self.content_text.get("1.0", tk.END).strip()if not content:messagebox.showerror("错误", "必须填写写入内容")returnsuccess = 0errors = []for item in self.tree.get_children():file_path, sheet, cell = self.tree.item(item, "values")# 单元格格式验证if not (cell[0].isalpha() and cell[1:].isdigit()):errors.append(f"无效单元格格式:{file_path} - {cell}")continuetry:wb = load_workbook(file_path)if sheet not in wb.sheetnames:errors.append(f"工作表不存在:{file_path} - {sheet}")continuews = wb[sheet]ws[cell] = contentwb.save(file_path)success += 1except Exception as e:errors.append(f"{os.path.basename(file_path)} 错误:{str(e)}")# 显示结果result = [f"成功写入文件数:{success}",f"失败文件数:{len(errors)}","\n错误详情:" + "\n".join(errors[:3]) + ("..." if len(errors) > 3 else ""),]messagebox.showinfo("执行结果", "\n".join(result))# 重置选择self.selected_files = []self.status_var.set("就绪")if __name__ == "__main__":root = tk.Tk()app = ExcelWriterApp(root)root.mainloop()
六、工具打包与使用
1. 打包为EXE文件
pyinstaller --onefile --windowed --name ExcelTool main.py
2. 使用注意事项
- 建议提前备份目标Excel文件
- 单元格地址需使用大写字母(如"A1")
- 支持批量处理最大文件数:无限制(取决于内存)
七、功能扩展建议
- 进度显示优化
# 添加进度条组件
self.progress = ttk.Progressbar(self.root, orient=tk.HORIZONTAL, length=100, mode='determinate')
- 配置模板保存
// 保存格式示例
{"files": [{"path": "report.xlsx", "sheet": "Data", "cell": "B2"},{"path": "data.xlsx", "sheet": "2023", "cell": "C5"}]
}
- 跨工作表批量操作
# 示例:A1:C10区域写入
for row in ws.iter_rows(min_row=1, max_row=10, min_col=1, max_col=3):for cell in row:cell.value = content