使用Python設置Word文檔中表格的格式的方法
更新時間:2025年12月01日 09:25:13 作者:溫輕舟
本文介紹了使用PyQt5和python-docx庫開發(fā)的圖形化應用程序,用于對Word文檔中的表格進行格式化設置,該應用程序提供文件操作、基本格式設置、條件格式設置、邊框和背景設置等功能,支持跨平臺運行,并提供詳細的錯誤處理和用戶反饋,需要的朋友可以參考下
一:效果展示:
本項目是基于PyQt5和python-docx庫開發(fā)的圖形化應用程序,用于對Word文檔中的表格進行格式化設置。用戶可以通過直觀的界面調(diào)整表格的各種格式屬性,包括基本格式、條件格式、邊框和背景等



二:功能描述:
1. 核心功能
(1)文件操作模塊
- 打開文件:允許用戶選擇并加載
.docx文件,自動檢測文件中的第一個表格 - 保存文件:將修改后的文檔保存為新文件(在原文件名后添加"-整理"后綴)
- 文件狀態(tài)顯示:在界面頂部顯示當前打開的文件名
(2)基本格式設置
- 行高設置:
- 默認行高:設置表格數(shù)據(jù)行的默認高度(單位:磅)
- 表頭行數(shù):指定表格中表頭的行數(shù)(表頭行高固定為1cm)
- 對齊方式:
- 水平對齊:居中/左對齊/右對齊
- 垂直對齊:居中/頂部/底部
- 字體設置:
- 字體名稱:下拉選擇常見中英文字體(包括系統(tǒng)默認字體)
- 字體大?。?-72磅可調(diào)
- 字體樣式:加粗/斜體復選框
- 字體顏色:通過顏色選擇器設置
(3)條件格式設置
- 條件1設置:
- 應用列:指定要應用條件的列號
- 操作符:>=, >, =, <=, <, <>
- 比較值:數(shù)值比較
- 背景色:滿足條件時單元格的背景顏色
- 條件2設置:
- 應用列:指定要應用條件的列號
- 操作符:>=, >, =, <=, <, <>
- 比較值:支持數(shù)值和文本比較
- 背景色:滿足條件時單元格的背景顏色
(4)邊框和背景設置
- 邊框設置:
- 邊框樣式:單線/虛線/點線/雙線/無線條
- 邊框?qū)挾龋?-24磅可調(diào)
- 邊框顏色:通過顏色選擇器設置
- 應用邊框:可單獨選擇應用左邊框、上邊框、右邊框或下邊框
- 背景設置:
- 背景顏色:通過顏色選擇器設置
- 應用范圍:所有單元格/表頭/數(shù)據(jù)行/特定列
- 列選擇:當選擇 “特定列” 時指定列號
2. 功能實現(xiàn)細節(jié)
(1)表格格式化核心類 - DocxTableEditor
set_cell_border:使用python-docx的底層XML操作設置單元格邊框樣式set_background_color:通過XML操作設置單元格背景顏色set_cell_font:設置單元格內(nèi)文本的字體屬性(名稱、大小、加粗、斜體、顏色)
(2)條件格式實現(xiàn)
- 支持數(shù)值比較(條件1)和文本比較(條件2)
- 只有當用戶選擇了背景顏色時才應用條件格式
- 自動跳過表頭行(根據(jù)表頭行數(shù)設置)
(3)用戶界面特性
- 使用選項卡組織不同功能模塊
- 顏色選擇后實時預覽(標簽顯示顏色并設置背景色)
- 智能字體選擇(包含常見中英文字體并嘗試檢測系統(tǒng)默認字體)
- 詳細的錯誤處理和用戶反饋(通過
QMessageBox)
3. 使用流程
(1)打開文檔:
點擊"打開文件"按鈕選擇包含表格的Word文檔
(2)設置格式
- 在"基本格式"選項卡中設置表格的基礎樣式
- 在"條件格式"選項卡中設置基于單元格值的條件格式
- 在"邊框和背景"選項卡中設置邊框樣式和單元格背景
(3)保存文檔
點擊"保存文件"按鈕將修改保存為新文檔
4. 技術特點
- 跨平臺性:基于
PyQt5開發(fā),可在Windows、macOS和Linux上運行 - 非破壞性編輯:保留原始文檔內(nèi)容,只修改指定格式屬性
- 直觀的用戶界面:通過圖形化控件簡化復雜的表格格式設置
5. 適用場景
- 批量處理報表文檔的格式
- 標準化不同來源的Word表格樣式
- 通過條件格式可突出顯示特定數(shù)據(jù)
三:完整代碼:
import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QPushButton, QFileDialog, QGroupBox, QGridLayout,
QCheckBox, QComboBox, QLineEdit, QSpinBox, QColorDialog,
QMessageBox, QTabWidget, QFormLayout)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QColor
from docx import Document
from docx.shared import Cm, Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_ALIGN_VERTICAL
from docx.oxml import OxmlElement
from docx.oxml.ns import qn, nsdecls
from docx.oxml import parse_xml
class DocxTableEditor:
@staticmethod
def set_cell_border(cell, **kwargs):
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
tcBorders = tcPr.first_child_found_in("w:tcBorders")
if tcBorders is None:
tcBorders = OxmlElement('w:tcBorders')
tcPr.append(tcBorders)
for edge in ('start', 'top', 'end', 'bottom', 'insideH', 'insideV'):
edge_data = kwargs.get(edge)
if edge_data:
tag = 'w:{}'.format(edge)
element = tcBorders.find(qn(tag))
if element is None:
element = OxmlElement(tag)
tcBorders.append(element)
for key in ["sz", "val", "color", "space", "shadow"]:
if key in edge_data:
element.set(qn('w:{}'.format(key)), str(edge_data[key]))
@staticmethod
def set_background_color(cell, rgb_color):
if isinstance(rgb_color, QColor):
rgb_color = rgb_color.name()[1:]
elif isinstance(rgb_color, str) and rgb_color.startswith('#'):
rgb_color = rgb_color[1:]
rgb_color = f"{rgb_color:0>6}"
shading_elm = parse_xml(r'<w:shd {} w:fill="{color_value}"/>'.format(nsdecls('w'), color_value=rgb_color))
cell._tc.get_or_add_tcPr().append(shading_elm)
@staticmethod
def set_cell_font(cell, font_name=None, font_size=None, bold=None, italic=None, color=None):
for paragraph in cell.paragraphs:
for run in paragraph.runs:
if font_name:
run.font.name = font_name
if font_size:
run.font.size = Pt(font_size)
if bold is not None:
run.font.bold = bold
if italic is not None:
run.font.italic = italic
if color:
if isinstance(color, QColor):
run.font.color.rgb = RGBColor(color.red(), color.green(), color.blue())
elif isinstance(color, str):
if color.startswith('#'):
color = color[1:]
try:
r = int(color[0:2], 16)
g = int(color[2:4], 16)
b = int(color[4:6], 16)
run.font.color.rgb = RGBColor(r, g, b)
except (ValueError, IndexError):
run.font.color.rgb = RGBColor(0, 0, 0)
else:
run.font.color.rgb = RGBColor(0, 0, 0)
class TableFormatterApp(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("設置Word文檔表格格式")
self.setGeometry(100, 100, 800, 600)
self.doc = None
self.table = None
self.file_path = ""
self.font_color_label = QLabel("未選擇")
self.cond1_color_label = QLabel("未選擇")
self.cond2_color_label = QLabel("未選擇")
self.border_color_label = QLabel("未選擇")
self.bg_color_label = QLabel("未選擇")
self.init_ui()
def init_ui(self):
main_widget = QWidget()
main_layout = QVBoxLayout()
file_group = QGroupBox("文件操作")
file_layout = QHBoxLayout()
self.file_label = QLabel("未選擇文件")
self.file_label.setAlignment(Qt.AlignCenter)
open_btn = QPushButton("打開文件")
open_btn.clicked.connect(self.open_file)
save_btn = QPushButton("保存文件")
save_btn.clicked.connect(self.save_file)
file_layout.addWidget(self.file_label)
file_layout.addWidget(open_btn)
file_layout.addWidget(save_btn)
file_group.setLayout(file_layout)
tab_widget = QTabWidget()
basic_tab = QWidget()
basic_layout = QVBoxLayout()
row_group = QGroupBox("行高設置")
row_form = QFormLayout()
self.row_height_spin = QSpinBox()
self.row_height_spin.setRange(10, 100)
self.row_height_spin.setValue(30)
self.row_height_spin.setSuffix(" 磅")
self.header_row_spin = QSpinBox()
self.header_row_spin.setRange(0, 10)
self.header_row_spin.setValue(1)
row_form.addRow("默認行高:", self.row_height_spin)
row_form.addRow("表頭行數(shù):", self.header_row_spin)
row_group.setLayout(row_form)
align_group = QGroupBox("對齊方式")
align_layout = QHBoxLayout()
self.align_combo = QComboBox()
self.align_combo.addItems(["居中", "左對齊", "右對齊"])
self.valign_combo = QComboBox()
self.valign_combo.addItems(["居中", "頂部", "底部"])
align_layout.addWidget(QLabel("水平對齊:"))
align_layout.addWidget(self.align_combo)
align_layout.addWidget(QLabel("垂直對齊:"))
align_layout.addWidget(self.valign_combo)
align_group.setLayout(align_layout)
font_group = QGroupBox("字體設置")
font_layout = QFormLayout()
self.font_name_combo = QComboBox()
common_fonts = [
"默認字體",
"宋體", "黑體", "楷體", "仿宋", "微軟雅黑", "Arial", "Times New Roman",
"Calibri", "Courier New", "Verdana", "Tahoma", "Helvetica"
]
self.font_name_combo.addItems(common_fonts)
try:
import matplotlib.font_manager as fm
default_font = fm.FontProperties().get_name()
if default_font not in common_fonts:
self.font_name_combo.insertItem(1, default_font)
except:
pass
self.font_size_spin = QSpinBox()
self.font_size_spin.setRange(8, 72)
self.font_size_spin.setValue(11)
self.bold_check = QCheckBox("加粗")
self.italic_check = QCheckBox("斜體")
font_color_layout = QHBoxLayout()
self.font_color_btn = QPushButton("字體顏色")
self.font_color_btn.clicked.connect(self.choose_font_color)
font_color_layout.addWidget(self.font_color_btn)
font_color_layout.addWidget(self.font_color_label)
font_layout.addRow("字體名稱:", self.font_name_combo)
font_layout.addRow("字體大小:", self.font_size_spin)
font_layout.addRow(self.bold_check)
font_layout.addRow(self.italic_check)
font_layout.addRow("字體顏色:", font_color_layout)
font_group.setLayout(font_layout)
apply_basic_btn = QPushButton("應用基本格式")
apply_basic_btn.clicked.connect(self.apply_basic_formatting)
basic_layout.addWidget(row_group)
basic_layout.addWidget(align_group)
basic_layout.addWidget(font_group)
basic_layout.addWidget(apply_basic_btn)
basic_tab.setLayout(basic_layout)
cond_tab = QWidget()
cond_layout = QVBoxLayout()
cond_group = QGroupBox("條件格式設置")
cond_grid = QGridLayout()
cond_grid.addWidget(QLabel("條件1:"), 0, 0)
self.cond1_col_spin = QSpinBox()
self.cond1_col_spin.setRange(1, 20)
self.cond1_col_spin.setValue(6) # 默認第6列(數(shù)量列)
cond_grid.addWidget(QLabel("列號:"), 0, 1)
cond_grid.addWidget(self.cond1_col_spin, 0, 2)
self.cond1_op_combo = QComboBox()
self.cond1_op_combo.addItems([">=", ">", "=", "<=", "<", "<>"])
cond_grid.addWidget(QLabel("操作符:"), 0, 3)
cond_grid.addWidget(self.cond1_op_combo, 0, 4)
self.cond1_value_spin = QSpinBox()
self.cond1_value_spin.setRange(0, 10000)
self.cond1_value_spin.setValue(85)
cond_grid.addWidget(QLabel("值:"), 0, 5)
cond_grid.addWidget(self.cond1_value_spin, 0, 6)
cond1_color_layout = QHBoxLayout()
self.cond1_color_btn = QPushButton("背景色")
self.cond1_color_btn.clicked.connect(lambda: self.choose_condition_color(1))
cond1_color_layout.addWidget(self.cond1_color_btn)
cond1_color_layout.addWidget(self.cond1_color_label)
cond_grid.addLayout(cond1_color_layout, 0, 7)
cond_grid.addWidget(QLabel("條件2:"), 1, 0)
self.cond2_col_spin = QSpinBox()
self.cond2_col_spin.setRange(1, 20)
cond_grid.addWidget(QLabel("列號:"), 1, 1)
cond_grid.addWidget(self.cond2_col_spin, 1, 2)
self.cond2_op_combo = QComboBox()
self.cond2_op_combo.addItems([">=", ">", "=", "<=", "<", "<>"])
cond_grid.addWidget(QLabel("操作符:"), 1, 3)
cond_grid.addWidget(self.cond2_op_combo, 1, 4)
self.cond2_value_edit = QLineEdit()
self.cond2_value_edit.setPlaceholderText("數(shù)值或文本")
cond_grid.addWidget(QLabel("值:"), 1, 5)
cond_grid.addWidget(self.cond2_value_edit, 1, 6)
cond2_color_layout = QHBoxLayout()
self.cond2_color_btn = QPushButton("背景色")
self.cond2_color_btn.clicked.connect(lambda: self.choose_condition_color(2))
cond2_color_layout.addWidget(self.cond2_color_btn)
cond2_color_layout.addWidget(self.cond2_color_label)
cond_grid.addLayout(cond2_color_layout, 1, 7)
cond_group.setLayout(cond_grid)
apply_cond_btn = QPushButton("應用條件格式")
apply_cond_btn.clicked.connect(self.apply_condition_formatting)
cond_layout.addWidget(cond_group)
cond_layout.addWidget(apply_cond_btn)
cond_tab.setLayout(cond_layout)
border_tab = QWidget()
border_layout = QVBoxLayout()
border_group = QGroupBox("邊框設置")
border_form = QFormLayout()
self.border_style_combo = QComboBox()
self.border_style_combo.addItems(["single", "dashed", "dotted", "double", "none"])
self.border_style_combo.setCurrentText("single")
self.border_width_spin = QSpinBox()
self.border_width_spin.setRange(1, 24)
self.border_width_spin.setValue(4)
self.border_width_spin.setSuffix(" 磅")
border_color_layout = QHBoxLayout()
self.border_color_btn = QPushButton("邊框顏色")
self.border_color_btn.clicked.connect(self.choose_border_color)
border_color_layout.addWidget(self.border_color_btn)
border_color_layout.addWidget(self.border_color_label)
self.border_sides_check = []
side_layout = QHBoxLayout()
sides = ["左邊框", "上邊框", "右邊框", "下邊框"]
for side in sides:
check = QCheckBox(side)
check.setChecked(True)
self.border_sides_check.append(check)
side_layout.addWidget(check)
border_form.addRow("邊框樣式:", self.border_style_combo)
border_form.addRow("邊框?qū)挾?", self.border_width_spin)
border_form.addRow("邊框顏色:", border_color_layout)
border_form.addRow("應用邊框:", side_layout)
border_group.setLayout(border_form)
bg_group = QGroupBox("背景設置")
bg_layout = QHBoxLayout()
bg_color_layout = QHBoxLayout()
self.bg_color_btn = QPushButton("選擇背景色")
self.bg_color_btn.clicked.connect(self.choose_bg_color)
bg_color_layout.addWidget(self.bg_color_btn)
bg_color_layout.addWidget(self.bg_color_label)
self.bg_range_combo = QComboBox()
self.bg_range_combo.addItems(["所有單元格", "表頭", "數(shù)據(jù)行", "特定列"])
self.bg_col_spin = QSpinBox()
self.bg_col_spin.setRange(1, 20)
self.bg_col_spin.setValue(1)
bg_layout.addLayout(bg_color_layout)
bg_layout.addWidget(QLabel("應用范圍:"))
bg_layout.addWidget(self.bg_range_combo)
bg_layout.addWidget(QLabel("列號:"))
bg_layout.addWidget(self.bg_col_spin)
bg_group.setLayout(bg_layout)
apply_border_btn = QPushButton("應用邊框和背景")
apply_border_btn.clicked.connect(self.apply_border_and_background)
border_layout.addWidget(border_group)
border_layout.addWidget(bg_group)
border_layout.addWidget(apply_border_btn)
border_tab.setLayout(border_layout)
tab_widget.addTab(basic_tab, "基本格式")
tab_widget.addTab(cond_tab, "條件格式")
tab_widget.addTab(border_tab, "邊框和背景")
main_layout.addWidget(file_group)
main_layout.addWidget(tab_widget)
main_widget.setLayout(main_layout)
self.setCentralWidget(main_widget)
def open_file(self):
file_path, _ = QFileDialog.getOpenFileName(self, "打開Word文件", "", "Word文件 (*.docx)")
if file_path:
self.file_path = file_path
self.file_label.setText(file_path.split("/")[-1])
try:
self.doc = Document(file_path)
if len(self.doc.tables) > 0:
self.table = self.doc.tables[0]
QMessageBox.information(self, "成功", "文件加載成功!")
else:
QMessageBox.warning(self, "警告", "文件中沒有表格!")
self.table = None
except Exception as e:
QMessageBox.critical(self, "錯誤", f"無法打開文件:\n{str(e)}")
self.table = None
def save_file(self):
if not self.doc:
QMessageBox.warning(self, "警告", "請先打開文件!")
return
if not self.file_path:
save_path, _ = QFileDialog.getSaveFileName(self, "保存Word文件", "", "Word文件 (*.docx)")
if not save_path:
return
else:
save_path = self.file_path.replace(".docx", "-整理.docx")
try:
self.doc.save(save_path)
QMessageBox.information(self, "成功", f"文件已保存到:\n{save_path}")
except Exception as e:
QMessageBox.critical(self, "錯誤", f"保存文件失敗:\n{str(e)}")
def choose_font_color(self):
color = QColorDialog.getColor()
if color.isValid():
self.font_color = color
self.font_color_label.setText(color.name())
self.font_color_label.setStyleSheet(f"background-color: {color.name()}; color: white;")
def choose_condition_color(self, cond_num):
color = QColorDialog.getColor()
if color.isValid():
if cond_num == 1:
self.cond1_color = color.name()[1:]
self.cond1_color_label.setText(color.name())
self.cond1_color_label.setStyleSheet(f"background-color: {color.name()}; color: black;")
else:
self.cond2_color = color.name()[1:]
self.cond2_color_label.setText(color.name())
self.cond2_color_label.setStyleSheet(f"background-color: {color.name()}; color: black;")
def choose_border_color(self):
color = QColorDialog.getColor()
if color.isValid():
self.border_color = color.name()[1:]
self.border_color_label.setText(color.name())
self.border_color_label.setStyleSheet(f"background-color: {color.name()}; color: black;")
def choose_bg_color(self):
color = QColorDialog.getColor()
if color.isValid():
self.bg_color = color.name()[1:]
self.bg_color_label.setText(color.name())
self.bg_color_label.setStyleSheet(f"background-color: {color.name()}; color: black;")
def apply_basic_formatting(self):
if not self.table:
QMessageBox.warning(self, "警告", "請先打開文件!")
return
try:
align_map = {"居中": WD_ALIGN_PARAGRAPH.CENTER, "左對齊": WD_ALIGN_PARAGRAPH.LEFT,
"右對齊": WD_ALIGN_PARAGRAPH.RIGHT}
valign_map = {"居中": WD_ALIGN_VERTICAL.CENTER, "頂部": WD_ALIGN_VERTICAL.TOP, "底部": WD_ALIGN_VERTICAL.BOTTOM}
align = align_map[self.align_combo.currentText()]
valign = valign_map[self.valign_combo.currentText()]
font_name = self.font_name_combo.currentText() if self.font_name_combo.currentText() != "默認字體" else None
font_size = self.font_size_spin.value() if self.font_size_spin.value() > 0 else None
bold = self.bold_check.isChecked()
italic = self.italic_check.isChecked()
header_rows = self.header_row_spin.value()
default_row_height = self.row_height_spin.value()
for i, row in enumerate(self.table.rows):
if i < header_rows:
row.height = Cm(1)
else:
row.height = Pt(default_row_height)
for cell in row.cells:
for paragraph in cell.paragraphs:
paragraph.alignment = align
cell.vertical_alignment = valign
DocxTableEditor.set_cell_font(
cell,
font_name=font_name,
font_size=font_size,
bold=bold,
italic=italic,
color=self.font_color
)
QMessageBox.information(self, "成功", "基本格式應用成功!")
except Exception as e:
QMessageBox.critical(self, "錯誤", f"應用基本格式時出錯:\n{str(e)}")
def apply_condition_formatting(self):
if not self.table:
QMessageBox.warning(self, "警告", "請先打開文件!")
return
try:
cond1_col = self.cond1_col_spin.value() - 1
cond1_op = self.cond1_op_combo.currentText()
cond1_value = self.cond1_value_spin.value()
cond1_color = self.cond1_color if hasattr(self, 'cond1_color') else None
cond2_col = self.cond2_col_spin.value() - 1
cond2_op = self.cond2_op_combo.currentText()
cond2_value = self.cond2_value_edit.text()
cond2_color = self.cond2_color if hasattr(self, 'cond2_color') else None
for row in self.table.rows[self.header_row_spin.value():]:
try:
cell_text = row.cells[cond1_col].text.strip()
if cell_text and cond1_color:
try:
cell_value = float(cell_text)
condition_met = self.evaluate_condition(cell_value, cond1_op, cond1_value)
if condition_met:
DocxTableEditor.set_background_color(row.cells[cond1_col], cond1_color)
except ValueError:
pass
if cond2_value and cond2_color:
cell_text = row.cells[cond2_col].text.strip()
try:
cell_value = float(cell_text)
cond2_value_float = float(cond2_value)
condition_met = self.evaluate_condition(cell_value, cond2_op, cond2_value_float)
except ValueError:
condition_met = self.evaluate_text_condition(cell_text, cond2_op, cond2_value)
if condition_met:
DocxTableEditor.set_background_color(row.cells[cond2_col], cond2_color)
except (ValueError, IndexError):
continue
QMessageBox.information(self, "成功", "條件格式應用成功!")
except Exception as e:
QMessageBox.critical(self, "錯誤", f"應用條件格式時出錯:\n{str(e)}")
def evaluate_condition(self, value, op, compare_value):
if op == ">=":
return value >= compare_value
elif op == ">":
return value > compare_value
elif op == "=":
return value == compare_value
elif op == "<=":
return value <= compare_value
elif op == "<":
return value < compare_value
elif op == "<>":
return value != compare_value
return False
def evaluate_text_condition(self, text, op, compare_text):
if op == "=":
return text == compare_text
elif op == "<>":
return text != compare_text
return False
def apply_border_and_background(self):
if not self.table:
QMessageBox.warning(self, "警告", "請先打開文件!")
return
try:
border_style = self.border_style_combo.currentText()
border_width = self.border_width_spin.value()
border_color = self.border_color
sides = []
if self.border_sides_check[0].isChecked(): sides.append('start')
if self.border_sides_check[1].isChecked(): sides.append('top')
if self.border_sides_check[2].isChecked(): sides.append('end')
if self.border_sides_check[3].isChecked(): sides.append('bottom')
bg_range = self.bg_range_combo.currentText()
bg_col = self.bg_col_spin.value() - 1
header_rows = self.header_row_spin.value()
for i, row in enumerate(self.table.rows):
for j, cell in enumerate(row.cells):
if sides:
border_settings = {}
for side in sides:
border_settings[side] = {
"val": border_style,
"sz": border_width,
"color": border_color
}
DocxTableEditor.set_cell_border(cell, **border_settings)
if self.bg_color:
apply_bg = False
if bg_range == "所有單元格":
apply_bg = True
elif bg_range == "表頭" and i < header_rows:
apply_bg = True
elif bg_range == "數(shù)據(jù)行" and i >= header_rows:
apply_bg = True
elif bg_range == "特定列" and j == bg_col:
apply_bg = True
if apply_bg:
DocxTableEditor.set_background_color(cell, self.bg_color)
QMessageBox.information(self, "成功", "邊框和背景應用成功!")
except Exception as e:
QMessageBox.critical(self, "錯誤", f"應用邊框和背景時出錯:\n{str(e)}")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = TableFormatterApp()
window.show()
sys.exit(app.exec_())
四:代碼分析:
1.DocxTableEditor工具類
class DocxTableEditor:
"""用于操作Word表格樣式的工具類"""
@staticmethod
def set_cell_border(cell, **kwargs):
"""設置單元格邊框樣式
Args:
cell: 表格單元格對象
**kwargs: 邊框參數(shù),如 start/top/end/bottom/insideH/insideV 等邊的樣式
每邊參數(shù)格式: {'val': 'single', 'sz': 4, 'color': 'FF0000'}
"""
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
tcBorders = tcPr.first_child_found_in("w:tcBorders")
# 如果不存在邊框定義則創(chuàng)建
if tcBorders is None:
tcBorders = OxmlElement('w:tcBorders')
tcPr.append(tcBorders)
# 遍歷所有指定的邊
for edge in ('start', 'top', 'end', 'bottom', 'insideH', 'insideV'):
edge_data = kwargs.get(edge)
if edge_data:
tag = 'w:{}'.format(edge)
element = tcBorders.find(qn(tag))
# 如果不存在該邊的定義則創(chuàng)建
if element is None:
element = OxmlElement(tag)
tcBorders.append(element)
# 設置邊框?qū)傩?
for key in ["sz", "val", "color", "space", "shadow"]:
if key in edge_data:
element.set(qn('w:{}'.format(key)), str(edge_data[key]))
@staticmethod
def set_background_color(cell, rgb_color):
"""設置單元格背景色
Args:
cell: 表格單元格對象
rgb_color: 顏色值,可以是QColor對象或十六進制字符串(帶#或不帶)
"""
# 統(tǒng)一顏色格式為6位十六進制字符串
if isinstance(rgb_color, QColor):
rgb_color = rgb_color.name()[1:] # 去掉QColor返回的#前綴
elif isinstance(rgb_color, str) and rgb_color.startswith('#'):
rgb_color = rgb_color[1:]
rgb_color = f"{rgb_color:0>6}" # 確保6位長度
# 創(chuàng)建shading元素并設置填充色
shading_elm = parse_xml(r'<w:shd {} w:fill="{color_value}"/>'.format(
nsdecls('w'), color_value=rgb_color))
cell._tc.get_or_add_tcPr().append(shading_elm)
@staticmethod
def set_cell_font(cell, font_name=None, font_size=None, bold=None, italic=None, color=None):
"""設置單元格內(nèi)文字樣式
Args:
cell: 表格單元格對象
font_name: 字體名稱
font_size: 字體大小(pt)
bold: 是否加粗
italic: 是否斜體
color: 字體顏色(QColor/十六進制字符串)
"""
for paragraph in cell.paragraphs:
for run in paragraph.runs:
if font_name:
run.font.name = font_name
if font_size:
run.font.size = Pt(font_size)
if bold is not None:
run.font.bold = bold
if italic is not None:
run.font.italic = italic
if color:
# 處理不同顏色輸入格式
if isinstance(color, QColor):
run.font.color.rgb = RGBColor(color.red(), color.green(), color.blue())
elif isinstance(color, str):
if color.startswith('#'):
color = color[1:]
try:
r = int(color[0:2], 16)
g = int(color[2:4], 16)
b = int(color[4:6], 16)
run.font.color.rgb = RGBColor(r, g, b)
except (ValueError, IndexError):
run.font.color.rgb = RGBColor(0, 0, 0)
else:
run.font.color.rgb = RGBColor(0, 0, 0)
2. 主窗口初始化 (TableFormatterApp類)
class TableFormatterApp(QMainWindow):
"""主應用程序窗口"""
def __init__(self):
super().__init__()
self.setWindowTitle("設置Word文檔表格格式")
self.setGeometry(100, 100, 800, 600)
self.doc = None # 當前打開的Document對象
self.table = None # 當前操作的表格對象
self.file_path = "" # 當前文件路徑
# 初始化顏色標簽(用于顯示當前選擇的顏色)
self.font_color_label = QLabel("未選擇")
self.cond1_color_label = QLabel("未選擇")
self.cond2_color_label = QLabel("未選擇")
self.border_color_label = QLabel("未選擇")
self.bg_color_label = QLabel("未選擇")
self.init_ui() # 初始化界面
def init_ui(self):
"""初始化用戶界面"""
main_widget = QWidget()
main_layout = QVBoxLayout()
# ========== 文件操作區(qū)域 ==========
file_group = QGroupBox("文件操作")
file_layout = QHBoxLayout()
self.file_label = QLabel("未選擇文件")
self.file_label.setAlignment(Qt.AlignCenter)
open_btn = QPushButton("打開文件")
open_btn.clicked.connect(self.open_file)
save_btn = QPushButton("保存文件")
save_btn.clicked.connect(self.save_file)
file_layout.addWidget(self.file_label)
file_layout.addWidget(open_btn)
file_layout.addWidget(save_btn)
file_group.setLayout(file_layout)
# ========== 選項卡區(qū)域 ==========
tab_widget = QTabWidget()
# 基本格式選項卡
basic_tab = self._create_basic_tab()
# 條件格式選項卡
cond_tab = self._create_cond_tab()
# 邊框和背景選項卡
border_tab = self._create_border_tab()
tab_widget.addTab(basic_tab, "基本格式")
tab_widget.addTab(cond_tab, "條件格式")
tab_widget.addTab(border_tab, "邊框和背景")
# ========== 主布局組裝 ==========
main_layout.addWidget(file_group)
main_layout.addWidget(tab_widget)
main_widget.setLayout(main_layout)
self.setCentralWidget(main_widget)
3. 核心功能方法
def open_file(self):
"""打開Word文件并加載第一個表格"""
file_path, _ = QFileDialog.getOpenFileName(self, "打開Word文件", "", "Word文件 (*.docx)")
if file_path:
self.file_path = file_path
self.file_label.setText(file_path.split("/")[-1])
try:
self.doc = Document(file_path)
if len(self.doc.tables) > 0:
self.table = self.doc.tables[0]
QMessageBox.information(self, "成功", "文件加載成功!")
else:
QMessageBox.warning(self, "警告", "文件中沒有表格!")
self.table = None
except Exception as e:
QMessageBox.critical(self, "錯誤", f"無法打開文件:\n{str(e)}")
self.table = None
def save_file(self):
"""保存修改后的Word文件"""
if not self.doc:
QMessageBox.warning(self, "警告", "請先打開文件!")
return
if not self.file_path:
save_path, _ = QFileDialog.getSaveFileName(self, "保存Word文件", "", "Word文件 (*.docx)")
if not save_path:
return
else:
save_path = self.file_path.replace(".docx", "-整理.docx")
try:
self.doc.save(save_path)
QMessageBox.information(self, "成功", f"文件已保存到:\n{save_path}")
except Exception as e:
QMessageBox.critical(self, "錯誤", f"保存文件失敗:\n{str(e)}")
def apply_basic_formatting(self):
"""應用基本格式設置到表格"""
if not self.table:
QMessageBox.warning(self, "警告", "請先打開文件!")
return
try:
# 獲取對齊方式設置
align_map = {"居中": WD_ALIGN_PARAGRAPH.CENTER,
"左對齊": WD_ALIGN_PARAGRAPH.LEFT,
"右對齊": WD_ALIGN_PARAGRAPH.RIGHT}
valign_map = {"居中": WD_ALIGN_VERTICAL.CENTER,
"頂部": WD_ALIGN_VERTICAL.TOP,
"底部": WD_ALIGN_VERTICAL.BOTTOM}
align = align_map[self.align_combo.currentText()]
valign = valign_map[self.valign_combo.currentText()]
# 獲取字體設置
font_name = self.font_name_combo.currentText() if self.font_name_combo.currentText() != "默認字體" else None
font_size = self.font_size_spin.value() if self.font_size_spin.value() > 0 else None
bold = self.bold_check.isChecked()
italic = self.italic_check.isChecked()
header_rows = self.header_row_spin.value()
default_row_height = self.row_height_spin.value()
# 遍歷表格應用設置
for i, row in enumerate(self.table.rows):
# 設置行高(表頭行固定1cm,其他行使用指定磅值)
if i < header_rows:
row.height = Cm(1)
else:
row.height = Pt(default_row_height)
# 設置單元格格式
for cell in row.cells:
# 設置段落對齊
for paragraph in cell.paragraphs:
paragraph.alignment = align
# 設置垂直對齊
cell.vertical_alignment = valign
# 設置字體
DocxTableEditor.set_cell_font(
cell,
font_name=font_name,
font_size=font_size,
bold=bold,
italic=italic,
color=getattr(self, 'font_color', None) # 使用getattr避免未定義屬性錯誤
)
QMessageBox.information(self, "成功", "基本格式應用成功!")
except Exception as e:
QMessageBox.critical(self, "錯誤", f"應用基本格式時出錯:\n{str(e)}")
def apply_condition_formatting(self):
"""應用條件格式到表格"""
if not self.table:
QMessageBox.warning(self, "警告", "請先打開文件!")
return
try:
# 獲取條件1設置
cond1_col = self.cond1_col_spin.value() - 1 # 轉(zhuǎn)換為0-based索引
cond1_op = self.cond1_op_combo.currentText()
cond1_value = self.cond1_value_spin.value()
cond1_color = getattr(self, 'cond1_color', None)
# 獲取條件2設置
cond2_col = self.cond2_col_spin.value() - 1
cond2_op = self.cond2_op_combo.currentText()
cond2_value = self.cond2_value_edit.text()
cond2_color = getattr(self, 'cond2_color', None)
# 跳過表頭行
for row in self.table.rows[self.header_row_spin.value():]:
try:
# 處理條件1(數(shù)值比較)
cell_text = row.cells[cond1_col].text.strip()
if cell_text and cond1_color:
try:
cell_value = float(cell_text)
if self.evaluate_condition(cell_value, cond1_op, cond1_value):
DocxTableEditor.set_background_color(row.cells[cond1_col], cond1_color)
except ValueError:
pass # 非數(shù)值內(nèi)容跳過
# 處理條件2(支持文本比較)
if cond2_value and cond2_color:
cell_text = row.cells[cond2_col].text.strip()
try:
# 嘗試數(shù)值比較
cell_value = float(cell_text)
cond2_value_float = float(cond2_value)
condition_met = self.evaluate_condition(cell_value, cond2_op, cond2_value_float)
except ValueError:
# 回退到文本比較
condition_met = self.evaluate_text_condition(cell_text, cond2_op, cond2_value)
if condition_met:
DocxTableEditor.set_background_color(row.cells[cond2_col], cond2_color)
except (ValueError, IndexError):
continue # 跳過格式錯誤的單元格
QMessageBox.information(self, "成功", "條件格式應用成功!")
except Exception as e:
QMessageBox.critical(self, "錯誤", f"應用條件格式時出錯:\n{str(e)}")
def evaluate_condition(self, value, op, compare_value):
"""數(shù)值條件判斷"""
if op == ">=":
return value >= compare_value
elif op == ">":
return value > compare_value
elif op == "=":
return value == compare_value
elif op == "<=":
return value <= compare_value
elif op == "<":
return value < compare_value
elif op == "<>":
return value != compare_value
return False
def evaluate_text_condition(self, text, op, compare_text):
"""文本條件判斷"""
if op == "=":
return text == compare_text
elif op == "<>":
return text != compare_text
return False
def apply_border_and_background(self):
"""應用邊框和背景設置"""
if not self.table:
QMessageBox.warning(self, "警告", "請先打開文件!")
return
try:
# 獲取邊框設置
border_style = self.border_style_combo.currentText()
border_width = self.border_width_spin.value()
border_color = getattr(self, 'border_color', None)
# 獲取要設置邊框的邊
sides = []
for idx, check in enumerate(self.border_sides_check):
if check.isChecked():
side_map = ['start', 'top', 'end', 'bottom']
sides.append(side_map[idx])
# 獲取背景設置
bg_range = self.bg_range_combo.currentText()
bg_col = self.bg_col_spin.value() - 1
header_rows = self.header_row_spin.value()
# 遍歷表格應用設置
for i, row in enumerate(self.table.rows):
for j, cell in enumerate(row.cells):
# 應用邊框
if sides and border_color:
border_settings = {}
for side in sides:
border_settings[side] = {
"val": border_style,
"sz": border_width,
"color": border_color
}
DocxTableEditor.set_cell_border(cell, **border_settings)
# 應用背景色
if hasattr(self, 'bg_color') and self.bg_color:
apply_bg = False
# 判斷是否在指定范圍內(nèi)
if bg_range == "所有單元格":
apply_bg = True
elif bg_range == "表頭" and i < header_rows:
apply_bg = True
elif bg_range == "數(shù)據(jù)行" and i >= header_rows:
apply_bg = True
elif bg_range == "特定列" and j == bg_col:
apply_bg = True
if apply_bg:
DocxTableEditor.set_background_color(cell, self.bg_color)
QMessageBox.information(self, "成功", "邊框和背景應用成功!")
except Exception as e:
QMessageBox.critical(self, "錯誤", f"應用邊框和背景時出錯:\n{str(e)}")
以上就是使用Python設置Word文檔中表格的格式的方法的詳細內(nèi)容,更多關于Python Word表格格式設置的資料請關注腳本之家其它相關文章!
相關文章
用Python復現(xiàn)二戰(zhàn)德軍enigma密碼機
大家好,本篇文章主要講的是用Python復現(xiàn)二戰(zhàn)德軍enigma密碼機,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽2022-01-01
淺談pandas用groupby后對層級索引levels的處理方法
今天小編就為大家分享一篇淺談pandas用groupby后對層級索引levels的處理方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-11-11
Scrapy框架爬取Boss直聘網(wǎng)Python職位信息的源碼
今天小編就為大家分享一篇關于Scrapy框架爬取Boss直聘網(wǎng)Python職位信息的源碼,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-02-02

