最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Python設(shè)置Word文檔中表格的格式的方法

 更新時間:2025年12月01日 09:25:13   作者:溫輕舟  
本文介紹了使用PyQt5和python-docx庫開發(fā)的圖形化應(yīng)用程序,用于對Word文檔中的表格進行格式化設(shè)置,該應(yīng)用程序提供文件操作、基本格式設(shè)置、條件格式設(shè)置、邊框和背景設(shè)置等功能,支持跨平臺運行,并提供詳細(xì)的錯誤處理和用戶反饋,需要的朋友可以參考下

一:效果展示:

本項目是基于PyQt5python-docx庫開發(fā)的圖形化應(yīng)用程序,用于對Word文檔中的表格進行格式化設(shè)置。用戶可以通過直觀的界面調(diào)整表格的各種格式屬性,包括基本格式、條件格式、邊框和背景等

二:功能描述:

1. 核心功能

(1)文件操作模塊

  • 打開文件:允許用戶選擇并加載.docx文件,自動檢測文件中的第一個表格
  • 保存文件:將修改后的文檔保存為新文件(在原文件名后添加"-整理"后綴)
  • 文件狀態(tài)顯示:在界面頂部顯示當(dāng)前打開的文件名

(2)基本格式設(shè)置

  1. 行高設(shè)置:
  • 默認(rèn)行高:設(shè)置表格數(shù)據(jù)行的默認(rèn)高度(單位:磅)
  • 表頭行數(shù):指定表格中表頭的行數(shù)(表頭行高固定為1cm)
  1. 對齊方式:
  • 水平對齊:居中/左對齊/右對齊
  • 垂直對齊:居中/頂部/底部
  1. 字體設(shè)置:
  • 字體名稱:下拉選擇常見中英文字體(包括系統(tǒng)默認(rèn)字體)
  • 字體大?。?-72磅可調(diào)
  • 字體樣式:加粗/斜體復(fù)選框
  • 字體顏色:通過顏色選擇器設(shè)置

(3)條件格式設(shè)置

  1. 條件1設(shè)置:
  • 應(yīng)用列:指定要應(yīng)用條件的列號
  • 操作符:>=, >, =, <=, <, <>
  • 比較值:數(shù)值比較
  • 背景色:滿足條件時單元格的背景顏色
  1. 條件2設(shè)置:
  • 應(yīng)用列:指定要應(yīng)用條件的列號
  • 操作符:>=, >, =, <=, <, <>
  • 比較值:支持?jǐn)?shù)值和文本比較
  • 背景色:滿足條件時單元格的背景顏色

(4)邊框和背景設(shè)置

  1. 邊框設(shè)置:
  • 邊框樣式:單線/虛線/點線/雙線/無線條
  • 邊框?qū)挾龋?-24磅可調(diào)
  • 邊框顏色:通過顏色選擇器設(shè)置
  • 應(yīng)用邊框:可單獨選擇應(yīng)用左邊框、上邊框、右邊框或下邊框
  1. 背景設(shè)置:
  • 背景顏色:通過顏色選擇器設(shè)置
  • 應(yīng)用范圍:所有單元格/表頭/數(shù)據(jù)行/特定列
  • 列選擇:當(dāng)選擇 “特定列” 時指定列號

2. 功能實現(xiàn)細(xì)節(jié)

(1)表格格式化核心類 - DocxTableEditor

  • set_cell_border:使用python-docx的底層XML操作設(shè)置單元格邊框樣式
  • set_background_color:通過XML操作設(shè)置單元格背景顏色
  • set_cell_font:設(shè)置單元格內(nèi)文本的字體屬性(名稱、大小、加粗、斜體、顏色)

(2)條件格式實現(xiàn)

  • 支持?jǐn)?shù)值比較(條件1)和文本比較(條件2)
  • 只有當(dāng)用戶選擇了背景顏色時才應(yīng)用條件格式
  • 自動跳過表頭行(根據(jù)表頭行數(shù)設(shè)置)

(3)用戶界面特性

  • 使用選項卡組織不同功能模塊
  • 顏色選擇后實時預(yù)覽(標(biāo)簽顯示顏色并設(shè)置背景色)
  • 智能字體選擇(包含常見中英文字體并嘗試檢測系統(tǒng)默認(rèn)字體)
  • 詳細(xì)的錯誤處理和用戶反饋(通過QMessageBox

3. 使用流程

(1)打開文檔:

點擊"打開文件"按鈕選擇包含表格的Word文檔

(2)設(shè)置格式

  • 在"基本格式"選項卡中設(shè)置表格的基礎(chǔ)樣式
  • 在"條件格式"選項卡中設(shè)置基于單元格值的條件格式
  • 在"邊框和背景"選項卡中設(shè)置邊框樣式和單元格背景

(3)保存文檔

點擊"保存文件"按鈕將修改保存為新文檔

4. 技術(shù)特點

  1. 跨平臺性:基于PyQt5開發(fā),可在Windows、macOSLinux上運行
  2. 非破壞性編輯:保留原始文檔內(nèi)容,只修改指定格式屬性
  3. 直觀的用戶界面:通過圖形化控件簡化復(fù)雜的表格格式設(shè)置

5. 適用場景

  1. 批量處理報表文檔的格式
  2. 標(biāo)準(zhǔn)化不同來源的Word表格樣式
  3. 通過條件格式可突出顯示特定數(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("設(shè)置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("行高設(shè)置")
        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("默認(rèn)行高:", 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("字體設(shè)置")
        font_layout = QFormLayout()
        self.font_name_combo = QComboBox()
        common_fonts = [
            "默認(rèn)字體",  
            "宋體", "黑體", "楷體", "仿宋", "微軟雅黑", "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("應(yīng)用基本格式")
        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("條件格式設(shè)置")
        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)  # 默認(rèn)第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("應(yīng)用條件格式")
        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("邊框設(shè)置")
        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("應(yīng)用邊框:", side_layout)
        border_group.setLayout(border_form)
        bg_group = QGroupBox("背景設(shè)置")
        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("應(yīng)用范圍:"))
        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("應(yīng)用邊框和背景")
        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() != "默認(rèn)字體" 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, "成功", "基本格式應(yīng)用成功!")
        except Exception as e:
            QMessageBox.critical(self, "錯誤", f"應(yīng)用基本格式時出錯:\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, "成功", "條件格式應(yīng)用成功!")
        except Exception as e:
            QMessageBox.critical(self, "錯誤", f"應(yīng)用條件格式時出錯:\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, "成功", "邊框和背景應(yīng)用成功!")
        except Exception as e:
            QMessageBox.critical(self, "錯誤", f"應(yīng)用邊框和背景時出錯:\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):
        """設(shè)置單元格邊框樣式
        
        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)

                # 設(shè)置邊框?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):
        """設(shè)置單元格背景色
        
        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元素并設(shè)置填充色
        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):
        """設(shè)置單元格內(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):
    """主應(yīng)用程序窗口"""
    
    def __init__(self):
        super().__init__()
        self.setWindowTitle("設(shè)置Word文檔表格格式")
        self.setGeometry(100, 100, 800, 600)
        self.doc = None  # 當(dāng)前打開的Document對象
        self.table = None  # 當(dāng)前操作的表格對象
        self.file_path = ""  # 當(dāng)前文件路徑
        
        # 初始化顏色標(biāo)簽(用于顯示當(dāng)前選擇的顏色)
        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):
    """應(yīng)用基本格式設(shè)置到表格"""
    if not self.table:
        QMessageBox.warning(self, "警告", "請先打開文件!")
        return

    try:
        # 獲取對齊方式設(shè)置
        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()]
        
        # 獲取字體設(shè)置
        font_name = self.font_name_combo.currentText() if self.font_name_combo.currentText() != "默認(rèn)字體" 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()

        # 遍歷表格應(yīng)用設(shè)置
        for i, row in enumerate(self.table.rows):
            # 設(shè)置行高(表頭行固定1cm,其他行使用指定磅值)
            if i < header_rows:
                row.height = Cm(1)
            else:
                row.height = Pt(default_row_height)

            # 設(shè)置單元格格式
            for cell in row.cells:
                # 設(shè)置段落對齊
                for paragraph in cell.paragraphs:
                    paragraph.alignment = align
                
                # 設(shè)置垂直對齊
                cell.vertical_alignment = valign
                
                # 設(shè)置字體
                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, "成功", "基本格式應(yīng)用成功!")
    except Exception as e:
        QMessageBox.critical(self, "錯誤", f"應(yīng)用基本格式時出錯:\n{str(e)}")

def apply_condition_formatting(self):
    """應(yīng)用條件格式到表格"""
    if not self.table:
        QMessageBox.warning(self, "警告", "請先打開文件!")
        return

    try:
        # 獲取條件1設(shè)置
        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設(shè)置
        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, "成功", "條件格式應(yīng)用成功!")
    except Exception as e:
        QMessageBox.critical(self, "錯誤", f"應(yīng)用條件格式時出錯:\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):
    """應(yīng)用邊框和背景設(shè)置"""
    if not self.table:
        QMessageBox.warning(self, "警告", "請先打開文件!")
        return

    try:
        # 獲取邊框設(shè)置
        border_style = self.border_style_combo.currentText()
        border_width = self.border_width_spin.value()
        border_color = getattr(self, 'border_color', None)
        
        # 獲取要設(shè)置邊框的邊
        sides = []
        for idx, check in enumerate(self.border_sides_check):
            if check.isChecked():
                side_map = ['start', 'top', 'end', 'bottom']
                sides.append(side_map[idx])

        # 獲取背景設(shè)置
        bg_range = self.bg_range_combo.currentText()
        bg_col = self.bg_col_spin.value() - 1
        header_rows = self.header_row_spin.value()

        # 遍歷表格應(yīng)用設(shè)置
        for i, row in enumerate(self.table.rows):
            for j, cell in enumerate(row.cells):
                # 應(yīng)用邊框
                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)

                # 應(yīng)用背景色
                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, "成功", "邊框和背景應(yīng)用成功!")
    except Exception as e:
        QMessageBox.critical(self, "錯誤", f"應(yīng)用邊框和背景時出錯:\n{str(e)}")

以上就是使用Python設(shè)置Word文檔中表格的格式的方法的詳細(xì)內(nèi)容,更多關(guān)于Python Word表格格式設(shè)置的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論

昆山市| 蕲春县| 揭东县| 翁牛特旗| 安吉县| 渝北区| 亚东县| 南靖县| 洛宁县| 广汉市| 阿尔山市| 仲巴县| 香河县| 南宫市| 通榆县| 太湖县| 嘉荫县| 富锦市| 桓仁| 农安县| 大关县| 宜春市| 黎城县| 兴业县| 通山县| 甘南县| 高阳县| 江北区| 塔城市| 金堂县| 灵武市| 静乐县| 富蕴县| 彰武县| 南雄市| 台东县| 溧水县| 东港市| 漯河市| 长海县| 泸西县|