Python开发Excel批量写入工具:多文件独立配置与Tkinter界面设计

Python开发Excel批量写入工具:多文件独立配置与Tkinter界面设计


一、工具功能概述

本工具基于Python开发,提供以下核心功能:

  • 📌 多Excel文件批量选择与独立配置
  • 📝 动态获取工作表列表(支持双击配置)
  • 🎯 单元格地址格式自动验证
  • 📥 支持文本内容直接输入/文件导入
  • 📊 实时状态反馈与详细错误报告

二、环境配置与依赖安装

1. 创建虚拟环境

bash 复制代码
python -m venv excel_env
source excel_env/bin/activate  # Linux/Mac
excel_env\Scripts\activate     # Windows

2. 安装依赖库

bash 复制代码
pip install openpyxl pyinstaller

三、工具设计与实现

1. 界面布局设计

2. 核心功能模块

(1) 文件配置区
python 复制代码
# 文件列表展示(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) 动态配置窗口
python 复制代码
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) 内容写入逻辑
python 复制代码
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'
解决:调整组件创建顺序,确保元素先创建后使用

python 复制代码
# 正确顺序示例
self.content_text = tk.Text(...)  # 先创建
self.tree.bind(...)              # 后绑定事件

2. 状态栏丢失问题

现象AttributeError: 'ExcelWriterApp' object has no attribute 'status_var'
修复方案

python 复制代码
# 在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内嵌图片元数据问题 可忽略不影响功能

五、完整实现代码

python 复制代码
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from openpyxl import load_workbook
import os


class ExcelWriterApp:
    def __init__(self, root):
        self.root = root
        self.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.sheetnames
        except 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_msgs

    def 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("错误", "必须填写写入内容")
            return

        success = 0
        errors = []

        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}")
                continue

            try:
                wb = load_workbook(file_path)
                if sheet not in wb.sheetnames:
                    errors.append(f"工作表不存在:{file_path} - {sheet}")
                    continue

                ws = wb[sheet]
                ws[cell] = content
                wb.save(file_path)
                success += 1
            except 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文件

bash 复制代码
pyinstaller --onefile --windowed --name ExcelTool main.py

2. 使用注意事项

  1. 建议提前备份目标Excel文件
  2. 单元格地址需使用大写字母(如"A1")
  3. 支持批量处理最大文件数:无限制(取决于内存)

七、功能扩展建议

  1. 进度显示优化
python 复制代码
# 添加进度条组件
self.progress = ttk.Progressbar(self.root, orient=tk.HORIZONTAL, length=100, mode='determinate')
  1. 配置模板保存
json 复制代码
// 保存格式示例
{
    "files": [
        {"path": "report.xlsx", "sheet": "Data", "cell": "B2"},
        {"path": "data.xlsx", "sheet": "2023", "cell": "C5"}
    ]
}
  1. 跨工作表批量操作
python 复制代码
# 示例: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
相关推荐
心软且酷丶30 分钟前
leetcode:2160. 拆分数位后四位数字的最小和(python3解法,数学相关算法题)
python·算法·leetcode
盛夏绽放2 小时前
Python常用高阶函数全面解析:通俗易懂的指南
前端·windows·python
仟濹3 小时前
Python - 文件部分
python
一点.点3 小时前
李沐动手深度学习(pycharm中运行笔记)——10.多层感知机+从零实现+简介实现
人工智能·笔记·python·深度学习·pycharm
小黄人软件3 小时前
OpenSSL 与 C++ 搭建一个支持 TLS 1.3 的服务器
服务器·开发语言·c++
那雨倾城3 小时前
使用 OpenCV 实现哈哈镜效果
人工智能·python·opencv·计算机视觉
武昌库里写JAVA4 小时前
Vue3编译器:静态提升原理
java·开发语言·spring boot·学习·课程设计
xzdangelliu4 小时前
POI模板生成EXCEL 64000 style in a .xlsx Workbook
java·excel·poi
编程乐趣4 小时前
推荐一个Excel与实体映射导入导出的C#开源库
开源·c#·.net·excel
日晞4 小时前
深浅拷贝?
开发语言·前端·javascript