Python 编程:Word 操作

Python 生态中有多个用于操作 Word 文档的库,每个库都有其特点和适用场景。

1. docx2python

特点

  • 专注于从 Word 文档中提取内容

  • 保留文档结构信息

  • 支持表格、文本、图片等元素的提取

安装

pip install docx2python

2. pywin32 (仅Windows)

特点

  • 通过 COM 接口直接操作 Microsoft Word

  • 功能最全面,可以调用 Word 的所有功能

  • 仅适用于 Windows 系统

  • 需要安装 Microsoft Word

安装

pip install pywin32

3. docx-mailmerge

特点

  • 专注于邮件合并功能

  • 简化了模板填充操作

  • 基于 python-docx 构建

安装

pip install docx-mailmerge

4. python-docx-template

特点

  • 支持类似Jinja2的模板语法

  • 可以处理条件语句、循环等复杂逻辑

  • 支持图片、表格等复杂元素的替换

安装

pip install docxtpl

5. mammoth (转换工具)

特点

  • 专注于 Word 到 HTML 的转换

  • 保留基本格式和结构

  • 支持自定义样式映射

安装

pip install mammoth

6. aspose-words

特点

  • 商业库,功能强大

  • 支持多种文档格式互转

  • 跨平台支持

安装

pip install aspose-words

库对比总结

库名称主要功能平台要求许可证适合场景
python-docx创建/修改docx跨平台MIT基本Word操作
docx2python内容提取跨平台MIT数据提取
pywin32全功能Word操作WindowsMIT高级自动化
docx-mailmerge邮件合并跨平台MIT模板填充
docxtpl模板渲染跨平台MIT复杂模板
mammothWord转HTML跨平台BSD内容发布
aspose-words全功能文档处理跨平台商业企业级应用

选择建议

  1. 基本文档生成python-docx 是最佳选择

  2. 内容提取:使用 docx2python

  3. Windows环境高级操作pywin32 提供最全面的功能

  4. 模板填充docx-mailmerge 或 python-docx-template

  5. 文档转换mammoth 或 aspose-words

  6. 企业级应用:考虑商业库 aspose-words

高级技巧:结合使用多个库

from docx import Document
from docx2python import docx2python
from docxtpl import DocxTemplate

# 1. 使用docx2python提取模板结构
doc_content = docx2python('template.docx')
print("模板包含以下段落:", doc_content.text)

# 2. 使用python-docx创建新文档
doc = Document()
doc.add_heading('合并后的文档', level=1)

# 3. 使用docxtpl渲染复杂部分
tpl = DocxTemplate('complex_part.docx')
context = {'data': [...]}
tpl.render(context)
tpl.save('temp.docx')

# 4. 将渲染结果合并到主文档
temp_doc = Document('temp.docx')
for para in temp_doc.paragraphs:
    doc.add_paragraph(para.text)

# 保存最终文档
doc.save('final_output.docx')

Python-docx 库

python-docx 是一个用于创建和修改 Microsoft Word (.docx) 文件的 Python 库。下面是该库的全面介绍和使用指南。

1. 安装与基本使用

安装

pip install python-docx

创建新文档

from docx import Document

# 创建新文档
doc = Document()
doc.add_paragraph('Hello, Word!')
doc.save('hello.docx')

2. 文档结构操作

2.1 段落操作

# 添加段落
paragraph = doc.add_paragraph('这是一个段落')

# 添加带样式的段落
paragraph = doc.add_paragraph('这是一个标题', style='Heading 1')

# 分段添加文本
paragraph.add_run('加粗文本').bold = True
paragraph.add_run('普通文本')
paragraph.add_run('斜体文本').italic = True

# 获取所有段落
for para in doc.paragraphs:
    print(para.text)

2.2 标题设置

# 添加各级标题
doc.add_heading('一级标题', level=1)
doc.add_heading('二级标题', level=2)
doc.add_heading('三级标题', level=3)

3. 文本格式设置

3.1 字体格式

from docx.shared import Pt, RGBColor
from docx.oxml.ns import qn

# 设置中文字体
paragraph = doc.add_paragraph()
run = paragraph.add_run('中文字体测试')
run.font.name = '微软雅黑'
run._element.rPr.rFonts.set(qn('w:eastAsia'), '微软雅黑')

# 设置字体大小
run.font.size = Pt(14)

# 设置字体颜色
run.font.color.rgb = RGBColor(255, 0, 0)  # 红色

# 其他格式
run.bold = True       # 加粗
run.italic = True     # 斜体
run.underline = True  # 下划线

3.2 段落格式

from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.shared import Inches

paragraph = doc.add_paragraph('对齐和缩进示例')

# 对齐方式
paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 居中
# 其他选项: LEFT, RIGHT, JUSTIFY, DISTRIBUTE

# 缩进
paragraph.paragraph_format.left_indent = Inches(0.5)  # 左缩进0.5英寸
paragraph.paragraph_format.right_indent = Inches(0.5) # 右缩进
paragraph.paragraph_format.first_line_indent = Inches(0.5)  # 首行缩进

# 行距
paragraph.paragraph_format.line_spacing = 1.5  # 1.5倍行距
paragraph.paragraph_format.space_after = Pt(12)  # 段后间距12磅
paragraph.paragraph_format.space_before = Pt(12) # 段前间距

4. 表格操作

4.1 创建表格

# 添加3行4列的表格
table = doc.add_table(rows=3, cols=4)

# 填充表格数据
for i in range(3):
    for j in range(4):
        table.cell(i, j).text = f'行{i+1}列{j+1}'

# 另一种添加表格的方式(推荐)
data = [
    ['姓名', '年龄', '性别'],
    ['张三', '25', '男'],
    ['李四', '30', '女']
]

table = doc.add_table(rows=1, cols=3)
hdr_cells = table.rows[0].cells
for i in range(3):
    hdr_cells[i].text = data[0][i]

for row_data in data[1:]:
    row_cells = table.add_row().cells
    for i in range(3):
        row_cells[i].text = row_data[i]

4.2 表格样式

from docx.enum.table import WD_TABLE_ALIGNMENT, WD_CELL_VERTICAL_ALIGNMENT
from docx.enum.table import WD_ROW_HEIGHT_RULE

# 表格对齐
table.alignment = WD_TABLE_ALIGNMENT.CENTER

# 设置行高
table.rows[0].height_rule = WD_ROW_HEIGHT_RULE.EXACTLY
table.rows[0].height = Pt(30)

# 单元格垂直对齐
for row in table.rows:
    for cell in row.cells:
        cell.vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER

# 应用表格样式
table.style = 'Light Shading Accent 1'
# 其他内置样式: 'Table Grid', 'Light List', 'Medium Shading 1' 等

5. 图片与形状

5.1 插入图片

from docx.shared import Cm

doc.add_picture('image.png', width=Cm(10))  # 宽度10厘米
# 也可以使用 Inches(4) 表示4英寸

# 设置图片居中对齐
last_paragraph = doc.paragraphs[-1]
last_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER

5.2 插入形状

from docx.enum.shape import MSO_SHAPE

# 添加一个矩形
shape = doc.add_shape(MSO_SHAPE.RECTANGLE, left=Cm(5), top=Cm(5), 
                     width=Cm(5), height=Cm(3))
shape.text = '这是一个矩形'

# 添加线条
doc.add_shape(MSO_SHAPE.LINE_INVERSE, 
              left=Cm(2), top=Cm(2), 
              width=Cm(10), height=Cm(0))

6. 页眉页脚与分节

6.1 页眉页脚

# 添加页眉
header = doc.sections[0].header
header_para = header.paragraphs[0]
header_para.text = "这是页眉 - 左对齐"
header_para.add_run("右对齐部分").alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT

# 添加页脚
footer = doc.sections[0].footer
footer_para = footer.paragraphs[0]
footer_para.text = "页码: "
footer_para.add_run("1").bold = True

6.2 分节与页面设置

from docx.enum.section import WD_SECTION

# 添加新节
doc.add_section(WD_SECTION.NEW_PAGE)  # 新页分节
# 其他选项: NEW_PAGE, CONTINUOUS, EVEN_PAGE, ODD_PAGE

# 页面设置
section = doc.sections[0]
section.page_height = Cm(29.7)  # A4高度
section.page_width = Cm(21)     # A4宽度
section.left_margin = Cm(2.54)  # 左边距
section.right_margin = Cm(2.54) # 右边距
section.top_margin = Cm(2.54)   # 上边距
section.bottom_margin = Cm(2.54) # 下边距
section.header_distance = Cm(1.25)  # 页眉距离
section.footer_distance = Cm(1.25)  # 页脚距离

7. 高级功能

7.1 样式管理

from docx.enum.style import WD_STYLE_TYPE

# 创建新样式
styles = doc.styles
new_style = styles.add_style('MyStyle', WD_STYLE_TYPE.PARAGRAPH)
new_style.font.name = '微软雅黑'
new_style.font.size = Pt(12)
new_style.font.color.rgb = RGBColor(0x42, 0x24, 0xE9)
new_style.paragraph_format.line_spacing = 1.5

# 应用样式
doc.add_paragraph('自定义样式文本', style='MyStyle')

7.2 目录生成

# 添加目录(需要Word在打开文档后更新字段)
doc.add_paragraph().add_run().add_field('TOC \\o "1-3" \\h \\z \\u')

# 添加分页符
doc.add_page_break()

7.3 超链接

from docx.oxml.shared import OxmlElement
from docx.oxml.ns import qn

def add_hyperlink(paragraph, text, url):
    """添加超链接"""
    part = paragraph.part
    r_id = part.relate_to(
        url, 
        docx.opc.constants.RELATIONSHIP_TYPE.HYPERLINK, 
        is_external=True
    )

    hyperlink = OxmlElement('w:hyperlink')
    hyperlink.set(qn('r:id'), r_id)

    new_run = OxmlElement('w:r')
    rPr = OxmlElement('w:rPr')
    new_run.append(rPr)
    new_run.text = text
    hyperlink.append(new_run)

    paragraph._p.append(hyperlink)
    return hyperlink

# 使用示例
para = doc.add_paragraph()
add_hyperlink(para, "百度", "https://www.baidu.com")

8. 读取现有文档

doc = Document('existing.docx')

# 读取段落
for para in doc.paragraphs:
    print(para.text)

# 读取表格
for table in doc.tables:
    for row in table.rows:
        for cell in row.cells:
            print(cell.text)

# 读取页眉页脚
for section in doc.sections:
    print("页眉:", section.header.paragraphs[0].text)
    print("页脚:", section.footer.paragraphs[0].text)

9. 实际应用示例

9.1 生成报告

def generate_report(data):
    doc = Document()
    
    # 标题
    doc.add_heading('销售报告', level=1)
    
    # 基本信息
    doc.add_paragraph(f'生成日期: {datetime.now().strftime("%Y-%m-%d")}')
    doc.add_paragraph(f'报告周期: {data["start_date"]} 至 {data["end_date"]}')
    
    # 摘要
    doc.add_heading('执行摘要', level=2)
    doc.add_paragraph(data['summary'])
    
    # 销售数据表格
    doc.add_heading('销售数据', level=2)
    table = doc.add_table(rows=1, cols=4)
    table.style = 'Light Shading Accent 1'
    
    # 表头
    hdr_cells = table.rows[0].cells
    hdr_cells[0].text = '产品'
    hdr_cells[1].text = '数量'
    hdr_cells[2].text = '单价'
    hdr_cells[3].text = '总额'
    
    # 表格数据
    for item in data['sales']:
        row_cells = table.add_row().cells
        row_cells[0].text = item['product']
        row_cells[1].text = str(item['quantity'])
        row_cells[2].text = f"¥{item['price']:.2f}"
        row_cells[3].text = f"¥{item['quantity'] * item['price']:.2f}"
    
    # 图表
    doc.add_heading('销售趋势图', level=2)
    doc.add_paragraph('下图显示了销售趋势:')
    doc.add_picture('sales_chart.png', width=Cm(12))
    
    # 结论
    doc.add_heading('结论与建议', level=2)
    doc.add_paragraph(data['conclusion'])
    
    # 保存
    doc.save('sales_report.docx')

9.2 批量生成合同

def generate_contracts(template_path, clients):
    for client in clients:
        doc = Document(template_path)
        
        # 替换占位符
        replacements = {
            '{{client_name}}': client['name'],
            '{{date}}': datetime.now().strftime('%Y年%m月%d日'),
            '{{amount}}': f"¥{client['amount']:,.2f}",
            '{{service}}': client['service']
        }
        
        for para in doc.paragraphs:
            for key, value in replacements.items():
                if key in para.text:
                    para.text = para.text.replace(key, value)
        
        for table in doc.tables:
            for row in table.rows:
                for cell in row.cells:
                    for key, value in replacements.items():
                        if key in cell.text:
                            cell.text = cell.text.replace(key, value)
        
        # 保存
        doc.save(f"contract_{client['id']}.docx")

注意事项

  1. 兼容性:python-docx 只支持 .docx 格式(Word 2007及以后版本),不支持旧的 .doc 格式

  2. 样式限制:某些复杂的Word功能可能无法完全支持

  3. 文档打开:生成的文档需要在Word中打开后才能正确显示某些元素(如目录、页码等)

  4. 性能问题:处理大型文档时可能会有性能问题,建议分批处理

  5. 字体问题:中文字体需要特殊处理,确保同时设置西文和中文字体

通过 python-docx,您可以实现绝大多数常见的Word文档操作需求,从简单的文档生成到复杂的报告自动化都能胜任。

Word文档编辑器实现

下面介绍如何使用Python创建Word文档编辑器,主要使用python-docx库来处理Word文档,并结合PyQt5构建图形用户界面。

1. 环境准备

首先安装必要的库:

pip install python-docx PyQt5

2. 基本Word编辑器实现

import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, QTextEdit, 
                             QFileDialog, QVBoxLayout, QWidget, 
                             QPushButton, QMessageBox, QFontComboBox,
                             QSpinBox, QHBoxLayout, QAction, QToolBar)
from PyQt5.QtGui import QTextCursor, QIcon
from PyQt5.QtCore import Qt
from docx import Document
from docx.shared import Pt
import os

class WordEditor(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Word编辑器")
        self.setGeometry(100, 100, 800, 600)
        
        self.current_file = None
        self.initUI()
        
    def initUI(self):
        # 主窗口部件
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        
        # 主布局
        self.main_layout = QVBoxLayout()
        
        # 创建工具栏
        self.create_toolbar()
        
        # 格式工具栏
        self.format_toolbar = QToolBar("格式工具栏")
        self.addToolBar(Qt.TopToolBarArea, self.format_toolbar)
        
        # 字体选择
        self.font_combo = QFontComboBox()
        self.font_combo.currentFontChanged.connect(self.change_font)
        self.format_toolbar.addWidget(self.font_combo)
        
        # 字号选择
        self.font_size = QSpinBox()
        self.font_size.setRange(8, 72)
        self.font_size.setValue(12)
        self.font_size.valueChanged.connect(self.change_font_size)
        self.format_toolbar.addWidget(self.font_size)
        
        # 加粗按钮
        self.bold_action = QAction(QIcon.fromTheme('format-text-bold'), "加粗", self)
        self.bold_action.setCheckable(True)
        self.bold_action.triggered.connect(self.toggle_bold)
        self.format_toolbar.addAction(self.bold_action)
        
        # 斜体按钮
        self.italic_action = QAction(QIcon.fromTheme('format-text-italic'), "斜体", self)
        self.italic_action.setCheckable(True)
        self.italic_action.triggered.connect(self.toggle_italic)
        self.format_toolbar.addAction(self.italic_action)
        
        # 下划线按钮
        self.underline_action = QAction(QIcon.fromTheme('format-text-underline'), "下划线", self)
        self.underline_action.setCheckable(True)
        self.underline_action.triggered.connect(self.toggle_underline)
        self.format_toolbar.addAction(self.underline_action)
        
        # 文本编辑区
        self.text_edit = QTextEdit()
        self.text_edit.cursorPositionChanged.connect(self.update_format_buttons)
        
        # 添加到布局
        self.main_layout.addWidget(self.text_edit)
        self.central_widget.setLayout(self.main_layout)
        
        # 状态栏
        self.statusBar().showMessage("就绪")
        
        # 创建菜单
        self.create_menus()
    
    def create_toolbar(self):
        toolbar = QToolBar("主工具栏")
        self.addToolBar(Qt.TopToolBarArea, toolbar)
        
        # 新建
        new_action = QAction(QIcon.fromTheme('document-new'), "新建", self)
        new_action.setShortcut("Ctrl+N")
        new_action.triggered.connect(self.new_file)
        toolbar.addAction(new_action)
        
        # 打开
        open_action = QAction(QIcon.fromTheme('document-open'), "打开", self)
        open_action.setShortcut("Ctrl+O")
        open_action.triggered.connect(self.open_file)
        toolbar.addAction(open_action)
        
        # 保存
        self.save_action = QAction(QIcon.fromTheme('document-save'), "保存", self)
        self.save_action.setShortcut("Ctrl+S")
        self.save_action.triggered.connect(self.save_file)
        self.save_action.setEnabled(False)
        toolbar.addAction(self.save_action)
        
        # 另存为
        save_as_action = QAction(QIcon.fromTheme('document-save-as'), "另存为", self)
        save_as_action.triggered.connect(self.save_file_as)
        toolbar.addAction(save_as_action)
        
        toolbar.addSeparator()
        
        # 打印
        print_action = QAction(QIcon.fromTheme('document-print'), "打印", self)
        print_action.setShortcut("Ctrl+P")
        print_action.triggered.connect(self.print_document)
        toolbar.addAction(print_action)
    
    def create_menus(self):
        menubar = self.menuBar()
        
        # 文件菜单
        file_menu = menubar.addMenu("文件")
        
        new_action = QAction("新建", self)
        new_action.setShortcut("Ctrl+N")
        new_action.triggered.connect(self.new_file)
        file_menu.addAction(new_action)
        
        open_action = QAction("打开...", self)
        open_action.setShortcut("Ctrl+O")
        open_action.triggered.connect(self.open_file)
        file_menu.addAction(open_action)
        
        file_menu.addSeparator()
        
        save_action = QAction("保存", self)
        save_action.setShortcut("Ctrl+S")
        save_action.triggered.connect(self.save_file)
        file_menu.addAction(save_action)
        
        save_as_action = QAction("另存为...", self)
        save_as_action.triggered.connect(self.save_file_as)
        file_menu.addAction(save_as_action)
        
        file_menu.addSeparator()
        
        print_action = QAction("打印...", self)
        print_action.setShortcut("Ctrl+P")
        print_action.triggered.connect(self.print_document)
        file_menu.addAction(print_action)
        
        file_menu.addSeparator()
        
        exit_action = QAction("退出", self)
        exit_action.setShortcut("Ctrl+Q")
        exit_action.triggered.connect(self.close)
        file_menu.addAction(exit_action)
        
        # 编辑菜单
        edit_menu = menubar.addMenu("编辑")
        
        undo_action = QAction("撤销", self)
        undo_action.setShortcut("Ctrl+Z")
        undo_action.triggered.connect(self.text_edit.undo)
        edit_menu.addAction(undo_action)
        
        redo_action = QAction("重做", self)
        redo_action.setShortcut("Ctrl+Y")
        redo_action.triggered.connect(self.text_edit.redo)
        edit_menu.addAction(redo_action)
        
        edit_menu.addSeparator()
        
        cut_action = QAction("剪切", self)
        cut_action.setShortcut("Ctrl+X")
        cut_action.triggered.connect(self.text_edit.cut)
        edit_menu.addAction(cut_action)
        
        copy_action = QAction("复制", self)
        copy_action.setShortcut("Ctrl+C")
        copy_action.triggered.connect(self.text_edit.copy)
        edit_menu.addAction(copy_action)
        
        paste_action = QAction("粘贴", self)
        paste_action.setShortcut("Ctrl+V")
        paste_action.triggered.connect(self.text_edit.paste)
        edit_menu.addAction(paste_action)
        
        # 格式菜单
        format_menu = menubar.addMenu("格式")
        
        bold_action = QAction("加粗", self)
        bold_action.setShortcut("Ctrl+B")
        bold_action.setCheckable(True)
        bold_action.triggered.connect(self.toggle_bold)
        format_menu.addAction(bold_action)
        
        italic_action = QAction("斜体", self)
        italic_action.setShortcut("Ctrl+I")
        italic_action.setCheckable(True)
        italic_action.triggered.connect(self.toggle_italic)
        format_menu.addAction(italic_action)
        
        underline_action = QAction("下划线", self)
        underline_action.setShortcut("Ctrl+U")
        underline_action.setCheckable(True)
        underline_action.triggered.connect(self.toggle_underline)
        format_menu.addAction(underline_action)
    
    def new_file(self):
        self.text_edit.clear()
        self.current_file = None
        self.save_action.setEnabled(False)
        self.statusBar().showMessage("新建文档", 2000)
    
    def open_file(self):
        file_path, _ = QFileDialog.getOpenFileName(
            self, "打开Word文档", "", 
            "Word文档 (*.docx);;所有文件 (*)"
        )
        
        if file_path:
            try:
                doc = Document(file_path)
                self.text_edit.clear()
                
                full_text = []
                for para in doc.paragraphs:
                    full_text.append(para.text)
                
                self.text_edit.setPlainText("\n".join(full_text))
                self.current_file = file_path
                self.save_action.setEnabled(True)
                
                self.statusBar().showMessage(f"已打开: {file_path}", 3000)
                
            except Exception as e:
                QMessageBox.critical(self, "错误", f"无法打开文件:\n{str(e)}")
                self.statusBar().showMessage(f"打开文件失败: {str(e)}", 5000)
    
    def save_file(self):
        if not self.current_file:
            self.save_file_as()
            return
            
        try:
            doc = Document()
            text = self.text_edit.toPlainText()
            
            # 保存为段落
            for line in text.split('\n'):
                doc.add_paragraph(line)
            
            doc.save(self.current_file)
            self.statusBar().showMessage(f"文件已保存: {self.current_file}", 3000)
            
        except Exception as e:
            QMessageBox.critical(self, "错误", f"保存失败:\n{str(e)}")
            self.statusBar().showMessage(f"保存失败: {str(e)}", 5000)
    
    def save_file_as(self):
        file_path, _ = QFileDialog.getSaveFileName(
            self, "另存为Word文档", "", 
            "Word文档 (*.docx);;所有文件 (*)"
        )
        
        if file_path:
            # 确保扩展名是.docx
            if not file_path.endswith('.docx'):
                file_path += '.docx'
                
            self.current_file = file_path
            self.save_file()
            self.save_action.setEnabled(True)
    
    def print_document(self):
        # 简单打印功能
        printer = QPrinter()
        print_dialog = QPrintDialog(printer, self)
        
        if print_dialog.exec_() == QPrintDialog.Accepted:
            self.text_edit.print_(printer)
    
    def change_font(self, font):
        cursor = self.text_edit.textCursor()
        if not cursor.hasSelection():
            cursor.select(QTextCursor.WordUnderCursor)
        
        format = cursor.charFormat()
        format.setFontFamily(font.family())
        cursor.mergeCharFormat(format)
    
    def change_font_size(self, size):
        cursor = self.text_edit.textCursor()
        if not cursor.hasSelection():
            cursor.select(QTextCursor.WordUnderCursor)
        
        format = cursor.charFormat()
        format.setFontPointSize(size)
        cursor.mergeCharFormat(format)
    
    def toggle_bold(self):
        cursor = self.text_edit.textCursor()
        if not cursor.hasSelection():
            cursor.select(QTextCursor.WordUnderCursor)
        
        format = cursor.charFormat()
        format.setFontWeight(QFont.Bold if self.bold_action.isChecked() else QFont.Normal)
        cursor.mergeCharFormat(format)
    
    def toggle_italic(self):
        cursor = self.text_edit.textCursor()
        if not cursor.hasSelection():
            cursor.select(QTextCursor.WordUnderCursor)
        
        format = cursor.charFormat()
        format.setFontItalic(self.italic_action.isChecked())
        cursor.mergeCharFormat(format)
    
    def toggle_underline(self):
        cursor = self.text_edit.textCursor()
        if not cursor.hasSelection():
            cursor.select(QTextCursor.WordUnderCursor)
        
        format = cursor.charFormat()
        format.setFontUnderline(self.underline_action.isChecked())
        cursor.mergeCharFormat(format)
    
    def update_format_buttons(self):
        cursor = self.text_edit.textCursor()
        format = cursor.charFormat()
        
        # 更新字体组合框
        self.font_combo.setCurrentFont(QFont(format.fontFamily()))
        
        # 更新字号
        self.font_size.setValue(format.fontPointSize())
        
        # 更新加粗、斜体、下划线按钮状态
        self.bold_action.setChecked(format.fontWeight() == QFont.Bold)
        self.italic_action.setChecked(format.fontItalic())
        self.underline_action.setChecked(format.fontUnderline())

if __name__ == "__main__":
    app = QApplication(sys.argv)
    editor = WordEditor()
    editor.show()
    sys.exit(app.exec_())

3. 功能扩展实现

3.1 添加图片支持

def insert_image(self):
    file_path, _ = QFileDialog.getOpenFileName(
        self, "插入图片", "", 
        "图片文件 (*.png *.jpg *.jpeg *.bmp *.gif)"
    )
    
    if file_path:
        cursor = self.text_edit.textCursor()
        cursor.insertHtml(f'<img src="{file_path}" />')

3.2 添加表格支持

def insert_table(self):
    rows, ok1 = QInputDialog.getInt(self, "插入表格", "行数:", 3, 1, 20)
    cols, ok2 = QInputDialog.getInt(self, "插入表格", "列数:", 3, 1, 20)
    
    if ok1 and ok2:
        cursor = self.text_edit.textCursor()
        table_html = "<table border='1'>"
        for _ in range(rows):
            table_html += "<tr>"
            for _ in range(cols):
                table_html += "<td> </td>"
            table_html += "</tr>"
        table_html += "</table>"
        cursor.insertHtml(table_html)

3.3 添加页眉页脚支持

def add_header_footer(self):
    doc = Document()
    
    # 添加页眉
    header = doc.sections[0].header
    header_para = header.paragraphs[0]
    header_para.text = "这是页眉"
    
    # 添加正文
    doc.add_paragraph(self.text_edit.toPlainText())
    
    # 添加页脚
    footer = doc.sections[0].footer
    footer_para = footer.paragraphs[0]
    footer_para.text = "这是页脚"
    
    # 保存临时文件并打开
    temp_file = "temp_with_header_footer.docx"
    doc.save(temp_file)
    os.startfile(temp_file)  # Windows
    # 在macOS上使用: os.system(f"open {temp_file}")
    # 在Linux上使用: os.system(f"xdg-open {temp_file}")

4. 高级功能实现

4.1 文档格式转换

def convert_to_pdf(self):
    if not self.current_file:
        QMessageBox.warning(self, "警告", "请先保存Word文档")
        return
    
    try:
        from docx2pdf import convert
        pdf_path = os.path.splitext(self.current_file)[0] + ".pdf"
        convert(self.current_file, pdf_path)
        QMessageBox.information(self, "成功", f"已转换为PDF: {pdf_path}")
    except ImportError:
        QMessageBox.critical(self, "错误", "请先安装docx2pdf库: pip install docx2pdf")
    except Exception as e:
        QMessageBox.critical(self, "错误", f"转换失败:\n{str(e)}")

4.2 文档合并

def merge_documents(self):
    files, _ = QFileDialog.getOpenFileNames(
        self, "选择要合并的Word文档", "", 
        "Word文档 (*.docx)"
    )
    
    if len(files) < 2:
        QMessageBox.warning(self, "警告", "请至少选择两个文档进行合并")
        return
    
    try:
        merged = Document()
        for file in files:
            doc = Document(file)
            for element in doc.element.body:
                merged.element.body.append(element)
        
        save_path, _ = QFileDialog.getSaveFileName(
            self, "保存合并后的文档", "", 
            "Word文档 (*.docx)"
        )
        
        if save_path:
            if not save_path.endswith('.docx'):
                save_path += '.docx'
            merged.save(save_path)
            QMessageBox.information(self, "成功", f"文档已合并保存到: {save_path}")
    
    except Exception as e:
        QMessageBox.critical(self, "错误", f"合并失败:\n{str(e)}")

5. 部署为独立应用

可以使用PyInstaller将应用打包为独立可执行文件:

pip install pyinstaller
pyinstaller --onefile --windowed word_editor.py

这将在dist目录下生成可执行文件,可以在没有Python环境的电脑上运行。

6. 总结

这个Word编辑器实现了以下功能:

  • 基本的文档创建、打开、保存和另存为

  • 文本格式设置(字体、字号、加粗、斜体、下划线)

  • 图片和表格插入

  • 页眉页脚支持

  • 文档格式转换(如转PDF)

  • 文档合并功能

进一步扩展功能,例如:

  1. 添加更多格式选项(文本颜色、背景色、对齐方式等)

  2. 实现目录生成功能

  3. 添加批注和修订功能

  4. 实现邮件合并功能

  5. 添加文档加密/解密功能

  6. 集成拼写检查功能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值