使用 Tkinter 构建一个文本分割工具
在日常的编程工作中,我们有时会遇到需要将大段文本按照一定规则分割成小段的情况。手动完成这项任务既耗时又容易出错,因此编写一个小工具来自动处理这种需求是非常有用的。本博文将介绍如何使用 Python 的 Tkinter
库构建一个图形界面应用程序,它能够帮助用户快速地将长文本分割为指定长度的小段,并提供复制和保存功能。
工具特性
- 输入文本:用户可以在一个大的文本框中输入或粘贴待分割的文本。
- 字符计数:实时显示当前输入文本的总字符数。
- 设置分割长度:用户可以自定义每个小段文本的字符数。
- 分割按钮:点击后将文本按设定长度分割,并展示每个段落。
- 复制按钮:对于每个分割后的段落,都有一个按钮可以将该段落复制到剪贴板。
- 保存单个段落:允许用户单独保存某个段落到文件。
- 保存所有段落:一键保存所有分割后的段落到指定目录下的多个文件中。
- 清空按钮:清除所有输入和分割结果,重新开始。
import tkinter as tk
from tkinter import messagebox, ttk, filedialog
import pyperclip
import os
def onFrameConfigure(canvas):
"""Reset the scroll region to encompass the inner frame"""
canvas.configure(scrollregion=canvas.bbox("all"))
def split_text():
# 清空之前的小文本框和复制按钮
clear_text_boxes()
# 获取输入框中的文本
input_text = input_entry.get("1.0", tk.END).strip()
if not input_text:
messagebox.showwarning("警告", "请输入要分割的文本")
return
# 获取每个段落的字符数
try:
segment_length = int(segment_length_var.get())
if segment_length <= 0:
raise ValueError
except ValueError:
messagebox.showwarning("警告", "请输入有效的正整数作为每个段落的字符数")
return
# 分割文本
segments = [
input_text[i : i + segment_length]
for i in range(0, len(input_text), segment_length)
]
# 创建小文本框和复制按钮
for i, segment in enumerate(segments):
create_text_box(segment, i)
status_label.config(text=f"已分割为 {len(segments)} 段文本")
def create_text_box(text, index):
global canvas_frame
# 创建一个 Frame 来容纳文本框、字符数和复制按钮
frame = tk.Frame(canvas_frame)
frame.pack(padx=10, pady=5, anchor="w")
# 显示序号
index_label = tk.Label(frame, text=f"段落 {index + 1}:")
index_label.pack(side=tk.LEFT)
# 创建小文本框
text_box = tk.Text(frame, height=5, width=50, wrap=tk.WORD)
text_box.insert(tk.END, text)
text_box.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# 显示字符数
character_count = len(text)
count_label = tk.Label(frame, text=f"字符数: {character_count}")
count_label.pack(side=tk.LEFT)
# 创建复制按钮
copy_button = tk.Button(frame, text="复制文本", command=lambda t=text: copy_text(t))
copy_button.pack(side=tk.RIGHT)
# 创建保存单个段落按钮
save_button = tk.Button(
frame, text="保存段落", command=lambda t=text, i=index: save_single_text(t, i)
)
save_button.pack(side=tk.RIGHT)
def copy_text(text):
# 复制文本到剪贴板
pyperclip.copy(text)
status_label.config(text="文本已复制到剪贴板")
def save_single_text(text, index):
# 选择保存文件的位置
file_path = filedialog.asksaveasfilename(
defaultextension=".txt",
filetypes=[("Text files", "*.txt"), ("All files", "*.*")],
initialfile=f"段落{index + 1}.txt",
)
if file_path:
with open(file_path, "w", encoding="utf-8") as file:
file.write(text)
status_label.config(text=f"段落 {index + 1} 已保存到 {file_path}")
def save_all_text():
global canvas_frame
# 获取所有分割后的文本
all_text = []
for widget in canvas_frame.winfo_children():
if isinstance(widget, tk.Frame):
text_box = widget.winfo_children()[1] # 小文本框是第二个子控件
all_text.append((text_box, widget))
# 选择保存文件夹的位置
folder_path = filedialog.askdirectory()
if folder_path:
for i, (text_box, frame) in enumerate(all_text):
text = text_box.get("1.0", tk.END).strip()
file_path = os.path.join(folder_path, f"段落{i + 1}.txt")
with open(file_path, "w", encoding="utf-8") as file:
file.write(text)
status_label.config(text=f"所有文本已保存到 {folder_path}")
def clear_text_boxes():
global canvas_frame
# 清空之前的小文本框和复制按钮
for widget in canvas_frame.winfo_children():
if isinstance(widget, tk.Frame):
widget.destroy()
def clear_all():
# 清空输入框和生成的小文本框
input_entry.delete("1.0", tk.END)
clear_text_boxes()
status_label.config(text="已清空所有内容")
def count_characters(event):
# 计算输入文本的字符数并显示
input_text = input_entry.get("1.0", tk.END).strip()
character_count = len(input_text)
count_label.config(text=f"总字符数: {character_count}")
# 创建主窗口
root = tk.Tk()
root.title("文本分割程序")
# 设置窗口大小
root.geometry("720x520")
# 创建文本输入框
input_label = tk.Label(root, text="输入文本:")
input_label.grid(row=0, column=0, padx=10, pady=5, sticky="w")
input_entry = tk.Text(root, height=10, width=50, wrap=tk.WORD)
input_entry.grid(row=1, column=0, columnspan=4, padx=10, pady=5, sticky="nsew")
input_entry.bind("<KeyRelease>", count_characters) # 绑定事件,实时更新字符数
# 添加滚动条
input_scrollbar = ttk.Scrollbar(root, orient=tk.VERTICAL, command=input_entry.yview)
input_entry.configure(yscrollcommand=input_scrollbar.set)
input_scrollbar.grid(row=1, column=4, sticky="ns")
# 创建分割长度输入框
segment_length_label = tk.Label(root, text="每个段落的字符数:")
segment_length_label.grid(row=2, column=0, padx=10, pady=5, sticky="w")
segment_length_var = tk.StringVar(value="5900") # 默认值
segment_length_entry = tk.Entry(root, textvariable=segment_length_var, width=10)
segment_length_entry.grid(row=2, column=1, padx=10, pady=5, sticky="w")
# 创建分割按钮
split_button = tk.Button(root, text="分割", command=split_text)
split_button.grid(row=2, column=2, padx=10, pady=5, sticky="e")
# 创建清空按钮
clear_button = tk.Button(root, text="清空", command=clear_all)
clear_button.grid(row=2, column=3, padx=10, pady=5, sticky="e")
# 显示总字符数
count_label = tk.Label(root, text="总字符数: 0")
count_label.grid(row=0, column=2, padx=10, pady=5, sticky="e")
# 创建保存所有文本按钮
save_all_button = tk.Button(root, text="保存所有文本段落", command=save_all_text)
save_all_button.grid(row=2, column=4, padx=10, pady=5, sticky="e")
# 状态栏
status_label = tk.Label(root, text="", bd=1, relief=tk.SUNKEN, anchor=tk.W)
status_label.grid(row=100, column=0, columnspan=5, sticky="ew")
# 创建 Canvas 和 Scrollbar
canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
canvas_frame = tk.Frame(canvas, background="#ffffff")
vsb = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)
vsb.grid(row=3, column=4, sticky="ns")
canvas.grid(row=3, column=0, columnspan=4, sticky="nsew")
canvas.create_window((4, 4), window=canvas_frame, anchor="nw")
canvas_frame.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))
# 使列和行自动扩展
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(3, weight=1)
# 运行主循环
root.mainloop()