一、整体概述
这段 Python 代码使用 Tkinter
库创建了一个图形用户界面(GUI)应用程序,用于根据给定的 Word 模板文件生成特定格式的文书文档。其核心功能是让用户选择 Word 模板文件(.docx
格式),输入相关被告信息以及段落插入序号等内容,然后将被告信息按照设定的规则替换模板中的占位符,并插入到指定段落位置后,最终保存生成新的文档。
使用方法和完整代码在最后
二、代码结构与功能模块解释
- 导入模块部分
import tkinter as tk
from tkinter import font as tkFont
from tkinter import ttk, messagebox, filedialog
from docx import Document
from docx.shared import Pt, Cm
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.oxml.ns import qn
import re
import os
这里导入了多个必要的模块,tkinter
是 Python 内置的 GUI 库,用于创建可视化界面及相关组件;font
用于设置字体样式;ttk
提供了一些更高级的界面组件;messagebox
用于弹出提示框;filedialog
用于弹出文件选择对话框;Document
等来自 docx
模块,用于操作 Word 文档(读取、修改、保存等);re
模块用于正则表达式操作,此处用于匹配文档中的占位符;os
模块用于处理文件路径相关操作。
2.PictureViewer
类定义部分
class PictureViewer:
def __init__(self, parent):
# 类的初始化方法,接收父窗口对象
self.parent = parent
self.frame = tk.Frame(parent)
self.content_frame = None
self.template_paths = []
self.name_entries = []
self.gender_entries = []
self.birth_date_entries = []
self.nationality_entries = []
self.native_place_entries = []
self.address_entries = []
self.id_number_entries = []
self.contact_phone_entries = []
self.placeholder_entries = {}
self.defendant_list = []
# 创建并布局主标题标签
self.label = tk.Label(self.frame, text="文书生成1", font=("黑体", 18))
self.label.grid(row=0, column=0, padx=10, pady=10, sticky=tk.W)
# 功能代码部分(后续详细介绍各功能函数)
这是整个应用程序的核心类,在 __init__
方法中初始化了类的各种属性,包括界面框架、各种输入框对应的列表、模板文件路径列表、被告信息列表等,并且创建了一个显示在界面上的主标题标签。
3.extract_placeholders
静态方法
@staticmethod
def extract_placeholders(file_path):
doc = Document(file_path)
placeholder_list = []
seen_placeholders = set()
pattern = re.compile(r'\{\{(.*?)\}\}', re.DOTALL)
for paragraph in doc.paragraphs:
text = paragraph.text
matches = pattern.finditer(text)
for match in matches:
placeholder = match.group(1).strip()
if placeholder not in seen_placeholders:
seen_placeholders.add(placeholder)
placeholder_list.append(placeholder)
return placeholder_list
这个静态方法用于从给定的 Word 文件(file_path
参数指定)中提取占位符信息。它使用正则表达式 r'\{\{(.*?)\}\}'
来匹配文档中类似 {
{xxx}}
格式的占位符,将其中的 xxx
部分提取出来,去除重复的占位符后返回一个包含所有占位符的列表。
4.choose_word_templates
方法
def choose_word_templates(self):
file_paths = filedialog.askopenfilenames(filetypes=[("Word files", "*.docx")])
if file_paths:
self.template_paths = file_paths
self.create_input_window()
该方法通过 filedialog
弹出文件选择对话框,让用户选择 .docx
格式的 Word 模板文件,用户可以选择多个文件。如果用户选择了文件,所选文件的路径列表会被存储在 self.template_paths
属性中,然后调用 create_input_window
方法来创建后续用于输入其他信息的窗口。
5.create_input_window
方法
def create_input_window(self):
if self.content_frame:
self.content_frame.destroy()
self.content_frame = tk.Frame(self.frame, bg="#F0F0F0")
self.content_frame.grid(row=2, column=0, columnspan=2, padx=10, pady=10, sticky=tk.NSEW)
self.create_ui()
这个方法用于创建一个内容框架(如果之前存在则先销毁),作为后续放置各种输入组件的容器。创建好框架后,调用 create_ui
方法在这个框架内构建具体的用户界面组件。
6.create_ui
方法
def create_ui(self):
tk.Label(self.content_frame, text="被告人数:", font=("Arial", 14), bg="#F0F0F0").grid(row=0, column=0,
padx=10, pady=10,
sticky=tk.W)
self.defendant_count_entry = tk.Entry(self.content_frame, font=("Arial", 12))
self.defendant_count_entry.grid(row=0, column=1, padx=10, pady=10, sticky=tk.W + tk.E)
submit_button = tk.Button(self.content_frame, text="确定", command=self.on_submit, font=("Arial", 12),
bg="#4CAF50", fg="white")
submit_button.grid(row=0, column=2, padx=10, pady=10, sticky=tk.E)
self.defendant_count_entry.bind("<KeyRelease>", self.update_entries)
在此方法中,构建了基本的用户输入界面的一部分,包括一个显示 “被告人数” 的标签、一个用于输入被告人数的文本输入框(Entry
组件)以及一个 “确定” 按钮(点击按钮会触发 on_submit
方法)。同时,为被告人数输入框绑定了 <KeyRelease>
事件,当用户松开按键时,会调用 update_entries
方法来实时更新相关的输入框显示等操作。
7.update_entries
方法
def update_entries(self, *args):
defendant_count_text = self.defendant_count_entry.get()
if defendant_count_text:
try:
defendant_count = int(defendant_count_text)
self.create_entries_for_defendants(defendant_count)
except ValueError:
messagebox.showwarning("警告", "请输入有效的整数作为被告人数!")
这个方法获取用户在被告人数输入框中输入的文本内容,尝试将其转换为整数(代表被告人数)。如果转换成功,则调用 create_entries_for_defendants
方法根据被告人数动态创建相应的被告信息输入框;如果转换失败(输入的不是有效的整数),则弹出一个警告提示框告知用户。
8.create_entries_for_defendants
方法
def create_entries_for_defendants(self, defendant_count):
# 清除旧的输入框
for entries in [self.name_entries, self.gender_entries, self.birth_date_entries,
self.nationality_entries, self.native_place_entries, self.address_entries,
self.id_number_entries, self.contact_phone_entries]:
for entry in entries:
entry.destroy()
entries.clear()
# 提取占位符
self.placeholders = list(set([placeholder for template_path in self.template_paths for placeholder in
self.extract_placeholders(template_path)]))
row_num = 1
col_num = 0
# 处理被告信息输入部分
for i in range(defendant_count):
# 第一部分被告信息
first_part_info = [
(f"姓名(被告 {i + 1}):", self.name_entries),
(f"性别(被告 {i + 1}):", self.gender_entries),
(f"出生日期(被告 {i + 1}):", self.birth_date_entries),
(f"民族(被告 {i + 1}):", self.nationality_entries),
]
# 第二部分被告信息
second_part_info = [
(f"籍贯(被告 {i + 1}):", self.native_place_entries),
(f"地址(被告 {i + 1}):", self.address_entries),
(f"身份证号(被告 {i + 1}):", self.id_number_entries),
(f"联系电话(被告 {i + 1}):", self.contact_phone_entries)
]
# 处理第一部分被告信息
for j, (text, entry_list) in enumerate(first_part_info):
label = tk.Label(self.content_frame, text=text, font=("Arial", 12), bg="#F0F0F0")
label.grid(row=row_num, column=j * 2, padx=10, pady=5, sticky=tk.W)
entry = tk.Entry(self.content_frame, font=("Arial", 12))
entry.grid(