Python實現(xiàn)Excel批量樣式修改器(附完整代碼)
前言
一個基于 Python tkinter 和 openpyxl 的 Excel 文件批量美化工具,支持拖拽操作和靈活的樣式配置。
功能特性
核心功能
- 批量處理:支持同時處理多個 Excel 文件
- 拖拽支持:直接拖拽文件到界面即可添加
- 樣式自定義:可自定義表頭和數(shù)據(jù)行的字體、字號、背景色
- 居中對齊:支持表頭和數(shù)據(jù)行的水平居中設(shè)置
- 背景色控制:可選擇是否修改背景色
- Sheet 選擇:支持處理所有 Sheet 或指定特定 Sheet
界面特性
- 直觀的圖形用戶界面
- 實時進(jìn)度顯示
- 詳細(xì)的操作日志
- 顏色選擇器
- Sheet 列表查看功能
系統(tǒng)要求
Python 3.6+
Windows 操作系統(tǒng)
依賴庫:
tkinter(Python 內(nèi)置)openpyxltkinterdnd2
安裝說明
克隆或下載項目
git clone <repository-url> cd 13-Excel批量樣式修改器
安裝依賴
pip install openpyxl tkinterdnd2
運行程序
python main.py
使用指南
基本操作流程
1.啟動程序
- 雙擊
main.py或在命令行運行 - 程序界面將自動打開
2.參數(shù)設(shè)置
- 表頭行號:設(shè)置表頭所在的行號(默認(rèn)第1行)
- 字體設(shè)置:選擇表頭和數(shù)據(jù)行的字體類型和大小
- 背景色設(shè)置:點擊"選色"按鈕選擇背景顏色
- 居中選項:勾選是否需要水平居中
- 背景色控制:選擇是否修改背景色
3.Sheet 選擇
- 處理所有Sheet:默認(rèn)選項,處理文件中的所有工作表
- 指定Sheet:輸入特定的Sheet名稱,多個用逗號分隔
- 查看Sheet:點擊按鈕查看文件中所有可用的Sheet列表
4.添加文件
- 拖拽添加:直接將 Excel 文件拖拽到文件列表區(qū)域
- 手動添加:點擊"添加文件"按鈕選擇單個或多個文件
- 批量添加:點擊"添加目錄"按鈕選擇包含 Excel 文件的文件夾
5.開始處理
- 點擊"開始美化"按鈕
- 觀察進(jìn)度條和日志輸出
- 等待處理完成
高級功能
Sheet 選擇功能
- 查看 Sheet 列表:添加文件后,點擊"查看Sheet"按鈕可以查看第一個文件中的所有Sheet名稱
- 指定 Sheet 處理:在"Sheet名稱"輸入框中輸入要處理的Sheet名稱
- 多 Sheet 處理:使用逗號分隔多個Sheet名稱,如:
Sheet1, 數(shù)據(jù)表, Summary
樣式配置技巧
- 表頭樣式:通常使用較大字號和深色背景,便于區(qū)分
- 數(shù)據(jù)行樣式:使用較小字號和淺色背景,保持可讀性
- 顏色搭配:建議使用對比度適中的顏色組合
技術(shù)實現(xiàn)
核心技術(shù)棧
- GUI框架:tkinter + tkinterdnd2(拖拽支持)
- Excel處理:openpyxl
- 多線程:threading(避免界面凍結(jié))
關(guān)鍵函數(shù)說明
beautify_one_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):
核心美化函數(shù),負(fù)責(zé)處理單個Excel文件的樣式修改。
參數(shù)說明:
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名稱的輔助函數(shù)。
設(shè)計模式
- MVC模式:界面、邏輯、數(shù)據(jù)分離
- 觀察者模式:GUI事件響應(yīng)
- 工廠模式:樣式對象創(chuàng)建
完整代碼
#!/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
# ---------- 工具函數(shù) ----------
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 整數(shù)轉(zhuǎn) 16 進(jìn)制字符串"""
return f"{r:02X}{g:02X}{b:02X}"
def hex_to_rgb(hex_color: str):
"""#RRGGBB 轉(zhuǎn) (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')
# ----- 數(shù)據(jù)行 -----
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 = []
# ---- 頂部參數(shù)區(qū) ----
params = LabelFrame(self, text="參數(shù)設(shè)置", 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") # 默認(rèn)藍(lán)色
self.center_header = BooleanVar(value=True)
self.change_header_bg = BooleanVar(value=True)
# 數(shù)據(jù)行字體/字號/顏色/居中/背景色控制
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, "數(shù)據(jù):", self.data_font_name, self.data_font_size, self.data_hex, self.center_data, self.change_data_bg)
# Sheet選擇區(qū)域
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.sheet_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)
# ---- 文件列表區(qū) ----
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)
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)
# ---- 按鈕區(qū) ----
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)
# ---- 日志/進(jìn)度 ----
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選擇模式改變時的回調(diào)"""
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()
# ---------- 任務(wù) ----------
def start_task(self):
if not self.file_list:
messagebox.showwarning("提示", "請先添加待處理文件!")
return
# 禁用按鈕防止重復(fù)點擊
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(">>> 全部任務(wù)結(jié)束!")
# 恢復(fù)按鈕
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()
界面布局
┌─────────────────────────────────────────┐
│ 參數(shù)設(shè)置 │
├─────────────────────────────────────────┤
│ 表頭行號: [1] │
│ 表頭: [字體] [字號] [背景色] [選項] │
│ 數(shù)據(jù): [字體] [字號] [背景色] [選項] │
│ Sheet選擇: ○全部 ○指定 [輸入框] [查看] │
├─────────────────────────────────────────┤
│ 待處理文件列表 │
│ (支持拖拽添加文件) │
├─────────────────────────────────────────┤
│ [添加文件] [添加目錄] [移除] [清空] [開始] │
├─────────────────────────────────────────┤
│ 操作日志 │
│ [進(jìn)度條] │
└─────────────────────────────────────────┘
效果圖

使用示例
示例1:基礎(chǔ)美化
- 設(shè)置表頭行號為 1
- 表頭:微軟雅黑,12號,藍(lán)色背景,居中
- 數(shù)據(jù):微軟雅黑,10號,白色背景,不居中
- 拖拽Excel文件到列表
- 點擊"開始美化"
示例2:指定Sheet處理
- 完成基礎(chǔ)設(shè)置
- 選擇"指定Sheet"單選按鈕
- 在輸入框中輸入:
工作表1, 數(shù)據(jù)統(tǒng)計 - 點擊"查看Sheet"確認(rèn)Sheet名稱
- 開始處理
示例3:不修改背景色
- 完成基礎(chǔ)設(shè)置
- 取消勾選"改變背景色"選項
- 只修改字體樣式和對齊方式
- 開始處理
注意事項
- 文件備份:處理前建議備份原始文件
- 文件格式:僅支持
.xlsx格式的Excel文件 - 文件占用:確保Excel文件未被其他程序打開
- Sheet名稱:輸入Sheet名稱時注意大小寫和空格
- 內(nèi)存使用:處理大量文件時注意內(nèi)存占用
常見問題
Q: 程序提示"依賴缺失"
A: 請安裝 tkinterdnd2:pip install tkinterdnd2
Q: 無法拖拽文件
A: 確保已正確安裝 tkinterdnd2 庫
Q: 處理時出現(xiàn)錯誤
A: 檢查文件是否被占用,確認(rèn)文件格式為 .xlsx
Q: Sheet名稱輸入無效
A: 點擊"查看Sheet"按鈕確認(rèn)正確的Sheet名稱
Q: 程序界面凍結(jié)
A: 大文件處理時屬于正?,F(xiàn)象,請耐心等待
版本歷史
v2.0.0 (最新)
- 新增Sheet選擇功能
- 新增背景色控制選項
- 新增Sheet列表查看功能
- 修復(fù)多線程處理問題
- 優(yōu)化界面布局
v1.0.0
- 初始版本發(fā)布
- 基礎(chǔ)批量美化功能
- 拖拽文件支持
- 樣式自定義功能
開發(fā)環(huán)境設(shè)置
- Fork 項目
- 創(chuàng)建功能分支
- 提交更改
- 創(chuàng)建 Pull Request
代碼規(guī)范
- 遵循 PEP 8 編碼規(guī)范
- 添加適當(dāng)?shù)淖⑨尯臀臋n
- 保持代碼簡潔易讀
到此這篇關(guān)于Python實現(xiàn)Excel批量樣式修改器(附完整代碼)的文章就介紹到這了,更多相關(guān)Python修改Excel樣式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何更改pycharm緩存路徑和虛擬內(nèi)存分頁文件位置(c盤爆紅)
這篇文章主要介紹了如何更改pycharm緩存路徑和虛擬內(nèi)存分頁文件位置(c盤爆紅)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-05-05
詳解python架構(gòu)?PyNeuraLogic超越Transformers
這篇文章主要為大家介紹了python使用?PyNeuraLogic超越Transformers示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
Python threading模塊condition原理及運行流程詳解
這篇文章主要介紹了Python threading模塊condition原理及運行流程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10
Python使用sqlalchemy模塊連接數(shù)據(jù)庫操作示例
這篇文章主要介紹了Python使用sqlalchemy模塊連接數(shù)據(jù)庫操作,結(jié)合實例形式分析了sqlalchemy模塊的安裝及連接、調(diào)用數(shù)據(jù)庫相關(guān)操作技巧,需要的朋友可以參考下2019-03-03

