Python实现Excel批量样式修改器(附完整代码)

2025-09-14 11:50

本文主要是介绍Python实现Excel批量样式修改器(附完整代码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Python实现Excel批量样式修改器(附完整代码)》这篇文章主要为大家详细介绍了如何使用Python实现一个Excel批量样式修改器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一...

前言

一个基于 python tkinter 和 openpyxl 的 Excel 文件批量美化工具,支持拖拽操作和灵活的样式配置。

功能特性

核心功能

  • 批量处理:支持同时处理多个 Excel 文件
  • 拖拽支持:直接拖拽文件到界面即可添加
  • 样式自定义:可自定义表头和数据行的字体、字号、背景色
  • 居中对齐:支持表头和数据行的水平居中设置
  • 背景色控制:可选择是否修改背景色
  • Sheet 选择:支持处理所有 Sheet 或指定特定 Sheet

界面特性

  • 直观的图形用户界面
  • 实时进度显示
  • 详细的操作日志
  • 颜色选择器
  • Sheet 列表查看功能

系统要求

Python 3.6+

Windows 操作系统

依赖库:

  • tkinter (Python 内置)
  • openpyxl
  • tkinterdnd2

安装说明

克隆或下载项目

git clone <repository-url>
cd 13-Excel批量样式修改器

安装依赖

pip install openpyxl tkinterdnd2

运行程序

python main.py

使用指南

基本操作流程

1.启动程序

  • 双击 main.py 或在命令行运行
  • 程序界面将自动打开

2.参数设置

  • 表头行号:设置表头所在的行号(默认第1行)
  • 字体设置:选择表头和数据行的字体类型和大小
  • 背景色设置:点击"选色"按钮选择背景颜色
  • 居中选项:勾选是否需要水平居中
  • 背景色控制:选择是否修改背景色

3.Sheet 选择

  • 处理所有Sheet:默认选项,处理文件中的所有工作表
  • 指定Sheet:输入特定的Sheet名称,多个用逗号分隔
  • 查看Sheet:点击按钮查看文件中所有可用的Sheet列表

4.添加文件

  • 拖拽添加:直接将 Excel 文件拖拽到文件列表区域
  • 手动添加:点击"添加文件"按钮选择单个或多个文件
  • 批量添加:点击"添加目录"按钮选择包含 Excel 文件的文件夹

5.开始处理

  • 点击"开始美化"按钮
  • 观察进度条和日志输出
  • 等待处理完成

高级功能

Sheet 选择功能

  • 查看 Sheet 列表:添加文件后,点击"查看Sheet"按钮可以查看第一个文件中的所有Sheet名称
  • 指定 Sheet 处理:在"Sheet名称"输入框中输入要处理的Sheet名称
  • 多 Sheet 处理:使用逗号分隔多个Sheet名称,如:Sheet1, 数据表, Swww.chinasem.cnummary

样式配置技巧

  • 表头样式:通常使用较大字号和深色背景,便于区分
  • 数据行样式:使用较小字号和浅色背景,保持可读性
  • 颜色搭配:建议使用对比度适中的颜色组合

技术实现

核心技术栈

  • GUI框架:tkinter + tkinterdnd2(拖拽支持)
  • Excel处理:openpyxl
  • 多线程:threading(避免界面冻结)

关键函数说明

beautify_onjse_file()

def beautify_one_file(file_path: str,
                      header_row: int,
                      header_font, header_fill,
                      data_font, data_fill,
                      center_header: bool,
                      center_data: bool,
                      change_header_bg: bool = True,
                      change_data_bg: bool = True,
                      sheet_names: list = None):

核心美化函数,负责处理单个Excel文件的样式修改。

参数说明:

  • file_path:Excel文件路径
  • header_row:表头行号
  • header_font/data_font:字体样式对象
  • header_fill/data_fill:背景填充对象
  • center_header/center_data:是否居中对齐
  • change_header_bg/change_data_bg:是否修改背景色
  • sheet_names:指定处理的Sheet列表

get_sheet_names()

def get_sheet_names(file_path: str):

获取Excel文件中所有Sheet名称的辅助函数。

设计模式

  • MVC模式:界面、逻辑、数据分离
  • 观察者模式:GUI事件响应
  • 工厂模式:样式对象创建

完整代码

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Excel 批量美化小工具
tkinter + openpyxl,支持拖拽
"""

import os
import sys
import threading
from tkinter import *
from tkinter import ttk, filedialog, messagebox
from tkinter.scrolledtext import ScrolledText

try:
    from tkinterdnd2 import DND_FILES, TkinterDnD
except ImportError:
    messagebox.showerror("依赖缺失", "请先 pip install tkinterdnd2")
    sys.exit(1)

from openpyxl import load_workbook
from openpyxl.styles import Alignment, Font, PatternFill


# ---------- 工具函数 ----------
def get_sheet_names(file_path: str):
    """获取Excel文件中所有Sheet的名称"""
    try:
        wb = load_workbook(file_path, read_only=True)
        sheet_names = [ws.title for ws in wb.worksheets]
        wb.close()
        return sheet_names
    except Exception as e:
        return []


def rgb_to_hex(r, g, b):
    """将 rgb 整数转 16 进制字符串"""
    return f"{r:02X}{g:02X}{b:02X}"


def hex_to_rgb(hex_color: str):
    """#RRGGBB 转 (r,g,b)"""
    hex_color = hex_color.lstrip("#")
    return tuple(int(hex_color[i:i + 2], 16) for i in (0, 2, 4))


# ---------- 核心逻辑 ----------
def beautify_one_file(file_path: str,
                      header_row: int,
                      header_font, header_fill,
                      data_font, data_fill,
                      center_header: bool,
                      center_data: bool,
                      change_header_bg: bool = True,
                      change_data_bg: bool = True,
                      sheet_names: list = None):
    """美化单个文件"""
    wb = load_workbook(file_path)
    # 如果指定了sheet_names,只处理指定的Sheet;否则处理所有Sheet
    if sheet_names:
        worksheets = [ws for ws in wb.worksheets if ws.title in sheet_names]
    else:
        worksheets = wb.worksheets
    
    for ws in worksheets:
        max_col = ws.max_column
        # ----- 表头 -----
        for col in range(1, max_col + 1):
            cell = ws.cell(row=header_row, column=col)
            cell.font = header_font
            if change_header_bg:
                cell.fill = header_fill
            if center_header:
                cell.alignment = Alignment(horizontal='center', vertical='center')
        # ----- 数据行 -----
        for row in range(header_row + 1, ws.max_row + 1):
            for col in range(1, max_col + 1):
                cell = ws.cell(row=row, column=col)
                cell.font = data_font
                if change_data_bg:
                    cell.fill = data_fill
                if center_data:
                    cell.alignment = Alignment(horizontal='center', vertical='center')
    wb.save(file_path)


# ---------- GUI ----------
class ExcelBeautifier(TkinterDnD.Tk):
    def __init__(self):
        super().__init__()
        self.title("Excel 批量美化工具")
        self.geometry("700x600")
        self.resizable(False, False)
        self.file_list = []

        # ---- 顶部参数区 ----
        params = LabelFrame(self, text="参数设置", padx=10, pady=10)
        params.pack(fill=X, padx=10, pady=5)

        # 表头行号
        row_frm = Frame(params)
        row_frm.pack(anchor=W)
        Label(row_frm, text="表头所在行号:").pack(side=LEFT)
        self.header_row_var = IntVar(value=1)
        Spinbox(row_frm, from_=1, to_=100, textvariable=self.header_row_var, width=5).pack(side=LEFT)

        # 表头字体/字号/颜色/居中/背景色控制
        self.header_font_name = StringVar(value="微软雅黑")
        self.header_font_size = IntVar(value=12)
        self.header_hex = StringVar(value="#4472C4")  # 默认蓝色
        self.center_header = BooleanVar(value=True)
        self.change_header_bg = BooleanVar(value=True)

        # 数据行字体/字号/颜色/居中/背景色控制
        self.data_font_name = StringVar(value="微软雅黑")
        self.data_font_size = IntVar(value=10)
        self.data_hex = StringVar(value="#FFFFFF")
        self.center_data = BooleanVar(value=False)
        self.change_data_bg = BooleanVar(value=True)

        # Sheet选择模式
        self.sheet_mode = StringVar(value="all")  # "all" 或 "specific"
        self.sheet_names_input = StringVar(value="")

        def _add_line(parent, label, font_name, font_size, hex_var, center_var, bg_var):
            frm = Frame(parent)
            frm.pack(anchor=W, pady=2)
            Label(frm, text=label, width=10, anchor=W).pack(side=LEFT)
            Label(frm, text="字体:").pack(side=LEFT)
            ttk.Combobox(frm, textvariable=font_name, values=["微软雅黑", "宋体", "Arial", "Calibri"], width=10,
                         state="readonly").pack(side=LEFT)
            Label(frm, text="字号:").pack(side=LEFT)
            Spinbox(frm, from_=6, to_=30, textvariable=font_size, width=5).pack(side=LEFT)
            Label(frm, text="背景色:").pack(side=LEFT)
            Entry(frm, textvariable=hex_var, width=8).pack(side=LEFT)
            Button(frm, text="选色", command=lambda: self.choose_color(hex_var)).pack(side=LEFT, padx=2)
            Checkbutton(frm, text="改变背景色", variable=bg_var).pack(side=LEFT, padx=2)
            Checkbutton(frm, text="水平居中", variable=center_var).pack(side=LEFT)

        _add_line(params, "表头:", self.header_font_name, self.header_font_size, self.header_hex, self.center_header, self.change_header_bg)
        _add_line(params, "数据:", self.data_font_name, self.data_font_size, self.data_hex, self.center_data, self.change_data_bg)

        # Sheet选择区域
        sheet_frm = Frame(params)
        sheet_frm.pack(anchor=W, pady=5)
        Label(sheet_frm, text="Sheet选择:", width=10, anchor=W).pack(side=LEFT)
        Radiobutton(sheet_frm, text="处理所有Sheet", variable=self.sheet_mode, value="all",
                   command=self.on_sheet_mode_change).pack(side=LEFT)
        Radiobutton(sheet_frm, text="指定Sheet", variable=self.sheet_mode, value="specific",
                   command=self.on_sheet_mode_change).pack(side=LEFT, padx=10)
        Label(sheet_frm, text="Sheet名称:").pack(side=LEFT)
        self.sheet_entry = Entry(sheet_frm, textvariable=self.shphpeet_names_input, width=20, 
                                state=DISABLED)
        self.sheet_entry.pack(side=LEFT, padx=2)
        Button(sheet_frm, text="查看Sheet", command=self.show_sheets).pack(side=LEFT, padx=2)
        Label(sheet_frm, text="(多个用逗号分隔)", font=("微软雅黑", 8)).pack(side=LEFT)

        # ---- 文件列表区 ----
        list_frame = LabelFrame(self, text="待处理文件(支持拖拽)", padx=10, pady=10)
        list_frame.pack(fill=BOTH, expand=True, padx=10, pady=5)
        self.listbox = Listbox(list_frame, selectmode=EXTENDED)
        self.listbox.pack(side=LEFT, fill=BOTH, expand=True)
       javascript scroll = Scrollbar(list_frame, orient=VERTICAL)
        scroll.pack(side=RIGHT, fill=Y)
        self.listbox.config(yscrollcommand=scroll.set)
        scroll.config(command=self.listbox.yview)

        # 拖拽绑定
        self.listbox.drop_target_register(DND_FILES)
        self.listbox.dnd_bind('<<Drop>>', self.on_drop)

        # ---- 按钮区 ----
        btn_bar = Frame(self)
        btn_bar.pack(fill=X, padx=10, pady=5)
        Button(btn_bar, text="添加文件", command=self.add_files).pack(side=LEFT, padx=2)
        Button(btn_bar, text="添加目录", command=self.add_folder).pack(side=LEFT, padx=2)
        Button(btn_bar, text="移除选中", command=self.remove_selected).pack(side=LEFT, padx=2)
        Button(btn_bar, text="清空列表", command=self.clear_list).pack(side=LEFT, padx=2)
        Button(btn_bar, text="开始美化", command=self.start_task, bg="#4472C4", fg="white").pack(side=RIGHT, padx=2)

        # ---- 日志/进度 ----
        bottom = Frame(self)
        bottom.pack(fill=X, padx=10, pady=5)
        self.log = ScrolledText(bottom, height=8, state=DISABLED)
        self.log.pack(fill=X)
        self.progress = ttk.Progressbar(bottom, orient=HORIZONTAL, mode='determinate')
        self.progress.pack(fill=X, pady=5)

    # ---------- 交互 ----------
    def on_sheet_mode_change(self):
        """Sheet选择模式改变时的回调"""
        if self.sheet_mode.get() == "specific":
            self.sheet_entry.config(state=NORMAL)
        else:
            self.sheet_entry.config(state=DISABLED)
            self.sheet_names_input.set("")  # 清空输入

    def show_sheets(self):
        """显示选中文件的Sheet列表"""
        if not self.file_list:
            messagebox.showinfo("提示", "请先添加Excel文件!")
            return
        
        # 获取第一个文件的Sheet列表作为示例
        file_path = self.file_list[0]
        sheet_names = get_sheet_names(file_path)
        
        if not sheet_names:
            messagebox.showerror("错误", f"无法读取文件:{os.path.basename(file_path)}")
            return
        
        # 显示Sheet列表
        sheet_list = "\n".join([f"• {name}" for name in sheet_names])
        messagebox.showinfo(
            f"Sheet列表 - {os.path.basename(file_path)}",
            f"该文件包含以下Sheet:\n\n{sheet_list}\n\n提示:如需处理多个Sheet,请用逗号分隔"
        )

    def choose_color(self, var: StringVar):
        from tkinter.colorchooser import askcolor
        _, hex_code = askcolor(color=var.get(), parent=self)
        if hex_code:
            var.set(hex_code.upper())

    def on_drop(self, event):
        files = self.tk.splitlist(event.data)
        self.add_file_list(files)

    def add_files(self):
        files = filedialog.askopenfilenames(filetypes=[("Excel 文件", "*.xlsx")])
        self.add_file_list(files)

    def add_folder(self):
        folder = filedialog.askdirectory()
        if not folder:
            return
        files = [os.path.join(folder, f) for f in os.listdir(folder)
                 if f.lower().endswith(".xlsx")]
        self.add_file_list(files)

    def add_file_list(self, files):
        for f in files:
            if f not in self.file_list:
                self.file_list.append(f)
                self.listbox.insert(END, os.path.basename(f))

    def remove_selected(self):
        for idx in reversed(self.listbox.curselection()):
            self.listbox.delete(idx)
            self.file_list.pop(idx)

    def clear_list(self):
        self.listbox.delete(0, END)
        self.file_list.clear()

    def log_msg(self, msg: str):
        self.log.config(state=NORMAL)
        self.log.insert(END, msg + "\n")
        self.log.see(END)
        self.log.config(state=DISABLED)
        self.update()

    # ---------- 任务 ----------
    def start_task(self):
        if not self.file_list:
            messagebox.showwarning("提示", "请先添加待处理文件!")
            return
        # 禁用按钮防止重复点击
        for child in self.winfo_children():
            if isinstance(child, Frame):
                for btn in child.winfo_children():
                    if isinstance(btn, Button):
                        btn.config(state=DISABLED)
        self.progress["maximum"] = len(self.file_list)
        self.progress["value"] = 0
        threading.Thread(target=self.worker, daemon=True).start()

    def worker(self):
        hdr_font = Font(name=self.header_font_name.get(), size=self.header_font_size.get(), bold=True)
        hdr_rgb = hex_to_rgb(self.header_hex.get())
        hdr_fill = PatternFill(start_color=rgb_to_hex(*hdr_rgb), end_color=rgb_to_hex(*hdr_rgb), fill_type="solid")

        dat_font = Font(name=self.data_font_name.get(), size=self.data_font_size.get(), bold=False)
        dat_rgb = hex_to_rgb(self.data_hex.get())
        dat_fill = PatternFill(start_color=rgb_to_hex(*dat_rgb), end_color=rgb_to_hex(*dat_rgb), fill_type="solid")

        # 处理Sheet选择
        sheet_names = None
        if self.sheet_mode.get() == "specific":
            sheet_input = self.sheet_names_input.get().strip()
            if sheet_input:
                sheet_names = [name.strip() for name in sheet_input.split(',') if name.strip()]

        for idx, file_path in enumerate(self.file_list, 1):
            self.log_msg(f"[{idx}/{len(self.file_list)}] 处理中:{os.path.basename(file_path)}")
            try:
                beautify_one_file(
                    file_path,
                    self.header_row_var.get(),
                    hdr_font, hdr_fill,
                    dat_font, dat_fill,
                    self.center_header.get(),
                    self.center_data.get(),
                    self.change_header_bg.get(),
                    self.change_data_bg.get(),
                    sheet_names
                )
                self.log_msg("  完成!")
            except Exception as e:
                self.log_msg(f"  错误:{e}")
            self.progress["value"] = idx

        self.log_msg(">>> 全部任务结束!")
        # 恢复按钮
        for child in self.winfo_children():
            if isinstance(child, Frame):
                for btn in child.winfo_children():
                    if isinstance(btn, Button):
                        btn.config(state=NORMAL)


# ---------- 启动 ----------
if __name__ == "__main__":
    ExcelBeautifier().mainloop()

界面布局

┌─────────────────────────────────────────┐
│                参数设置                   │
├─────────────────────────────────────────┤
│ 表头行号: [1]                 &nbjavascriptsp;         │
│ 表头: [字体] [字号] [背景色] [选项]        │
│ 数据: [字体] [字号] [背景色] [选项]        │
│ Sheet选择: ○全部 ○指定 [输入框] [查看]    │
├─────────────────────────────────────────┤
│            待处理文件列表                 │
│         (支持拖拽添加文件)               │
├─────────────────────────────────────────┤
│ [添加文件] [添加目录] [移除] [清空] [开始] │
├─────────────────────────────────────────┤
│                操作日志                   │
│              [进度条]                    │
└─────────────────────────────────────────┘

效果图

Python实现Excel批量样式修改器(附完整代码)

使用示例

示例1:基础美化

  • 设置表头行号为 1
  • 表头:微软雅黑,12号,蓝色背景,居中
  • 数据:微软雅黑,10号,白色背景,不居中
  • 拖拽Excel文件到列表
  • 点击"开始美化"

示例2:指定Sheet处理

  • 完成基础设置
  • 选择"指定Sheet"单选按钮
  • 在输入框中输入:工作表1, 数据统计
  • 点击"查看Sheet"确认Sheet名称
  • 开始处理

示例3:不修改背景色

  • 完成基础设置
  • 取消勾选"改变背景色"选项
  • 只修改字体样式和对齐方式
  • 开始处理

注意事项

  • 文件备份:处理前建议备份原始文件
  • 文件格式:仅支持 .xlsx 格式的Excel文件
  • 文件占用:确保Excel文件未被其他程序打开
  • Sheet名称:输入Sheet名称时注意大小写和空格
  • 内存使用:处理大量文件时注意内存占用

常见问题

Q: 程序提示"依赖缺失"

A: 请安装 tkinterdnd2:pip install tkinterdnd2

Q: 无法拖拽文件

A: 确保已正确安装 tkinterdnd2 库

Q: 处理时出现错误

A: 检查文件是否被占用,确认文件格式为 .xlsx

Q: Sheet名称输入无效

A: 点击"查看Sheet"按钮确认正确的Sheet名称

Q: 程序界面冻结

A: 大文件处理时属于正常现象,请耐心等待

版本历史

v2.0.0 (最新)

  • 新增Sheet选择功能
  • 新增背景色控制选项
  • 新增Sheet列表查看功能
  • 修复多线程处理问题
  • 优化界面布局

v1.0.0

  • 初始版本发布
  • 基础批量美化功能
  • 拖拽文件支持
  • 样式自定义功能

开发环境设置

  • Fork 项目
  • 创建功能分支
  • 提交更改
  • 创建 Pull Request

代码规范

  • 遵循 PEP 8 编码规范
  • 添加适当的注释和文档
  • 保持代码简洁易读

到此这篇关于Python实现Excel批量样式修改器(附完整代码)的文章就介绍到这了,更多相关Python修改Excel样式内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!

这篇关于Python实现Excel批量样式修改器(附完整代码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1155912

相关文章

MyBatis分页查询实战案例完整流程

《MyBatis分页查询实战案例完整流程》MyBatis是一个强大的Java持久层框架,支持自定义SQL和高级映射,本案例以员工工资信息管理为例,详细讲解如何在IDEA中使用MyBatis结合Page... 目录1. MyBATis框架简介2. 分页查询原理与应用场景2.1 分页查询的基本原理2.1.1 分

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

Nginx部署HTTP/3的实现步骤

《Nginx部署HTTP/3的实现步骤》本文介绍了在Nginx中部署HTTP/3的详细步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录前提条件第一步:安装必要的依赖库第二步:获取并构建 BoringSSL第三步:获取 Nginx

MyBatis Plus实现时间字段自动填充的完整方案

《MyBatisPlus实现时间字段自动填充的完整方案》在日常开发中,我们经常需要记录数据的创建时间和更新时间,传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏,... 目录前言解决目标技术栈实现步骤1. 实体类注解配置2. 创建元数据处理器3. 服务层代码优化填充机制详

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

Python实现批量CSV转Excel的高性能处理方案

《Python实现批量CSV转Excel的高性能处理方案》在日常办公中,我们经常需要将CSV格式的数据转换为Excel文件,本文将介绍一个基于Python的高性能解决方案,感兴趣的小伙伴可以跟随小编一... 目录一、场景需求二、技术方案三、核心代码四、批量处理方案五、性能优化六、使用示例完整代码七、小结一、

Python中 try / except / else / finally 异常处理方法详解

《Python中try/except/else/finally异常处理方法详解》:本文主要介绍Python中try/except/else/finally异常处理方法的相关资料,涵... 目录1. 基本结构2. 各部分的作用tryexceptelsefinally3. 执行流程总结4. 常见用法(1)多个e