TxT2Docx/gui_config.py
wsb1224 d3ac3238ed 更新功能:
段落控制功能,可自定义控制每个段落有多少句话
2025-10-15 17:54:51 +08:00

348 lines
16 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
GUI配置窗口模块
提供配置设置的图形界面。
"""
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from config import config
from gui_style_manager import create_style_tab
def show_config_window():
"""显示配置窗口"""
# 创建配置窗口
config_window = tk.Toplevel()
config_window.title('转换设置')
config_window.geometry('600x700')
config_window.transient()
config_window.grab_set()
# 创建笔记本组件
notebook = ttk.Notebook(config_window)
notebook.pack(fill='both', expand=True, padx=10, pady=10)
# 文件处理选项卡
file_frame = ttk.Frame(notebook)
notebook.add(file_frame, text='文件处理')
_create_file_tab(file_frame)
# 文字处理选项卡
text_frame = ttk.Frame(notebook)
notebook.add(text_frame, text='文字处理')
char_vars = _create_text_tab(text_frame)
# 图片处理选项卡
image_frame = ttk.Frame(notebook)
notebook.add(image_frame, text='图片处理')
_create_image_tab(image_frame)
# 文章样式选项卡
style_frame = create_style_tab(notebook)
notebook.add(style_frame, text='文章样式')
# 底部按钮
button_frame = ttk.Frame(config_window)
button_frame.pack(fill='x', padx=10, pady=10)
ttk.Button(button_frame, text='确定', command=lambda: _save_config(config_window, char_vars)).pack(side='left', padx=5)
ttk.Button(button_frame, text='取消', command=config_window.destroy).pack(side='left', padx=5)
ttk.Button(button_frame, text='重置为默认', command=lambda: _reset_to_default(char_vars)).pack(side='left', padx=5)
return char_vars
def _create_file_tab(parent):
"""创建文件处理选项卡"""
# 标题
ttk.Label(parent, text='文件处理设置', font=('', 12, 'bold')).pack(anchor='w', padx=10, pady=(10, 5))
ttk.Separator(parent, orient='horizontal').pack(fill='x', padx=10, pady=5)
# TXT编码
encoding_frame = ttk.Frame(parent)
encoding_frame.pack(fill='x', padx=10, pady=5)
ttk.Label(encoding_frame, text='TXT编码:', width=12).pack(side='left')
encoding_var = tk.StringVar(value=config.txt_encoding)
encoding_combo = ttk.Combobox(encoding_frame, textvariable=encoding_var,
values=['utf-8', 'gbk', 'utf-16'], state='readonly', width=15)
encoding_combo.pack(side='left', padx=(0, 10))
encoding_combo.bind('<<ComboboxSelected>>', lambda e: setattr(config, 'txt_encoding', encoding_var.get()))
# 匹配模式
ttk.Label(parent, text='匹配模式:', font=('', 10, 'bold')).pack(anchor='w', padx=10, pady=(15, 5))
match_var = tk.StringVar(value=config.match_pattern)
ttk.Radiobutton(parent, text='完全匹配(文件名与文件夹名相同)',
variable=match_var, value='exact').pack(anchor='w', padx=20, pady=2)
ttk.Radiobutton(parent, text='前缀匹配',
variable=match_var, value='prefix').pack(anchor='w', padx=20, pady=2)
ttk.Radiobutton(parent, text='包含匹配',
variable=match_var, value='contains').pack(anchor='w', padx=20, pady=2)
match_var.trace('w', lambda *args: setattr(config, 'match_pattern', match_var.get()))
ttk.Separator(parent, orient='horizontal').pack(fill='x', padx=10, pady=15)
# 输出位置
ttk.Label(parent, text='输出位置:', font=('', 10, 'bold')).pack(anchor='w', padx=10, pady=(0, 5))
output_var = tk.StringVar(value=config.output_location)
ttk.Radiobutton(parent, text='输出到TXT文件所在文件夹',
variable=output_var, value='txt_folder').pack(anchor='w', padx=20, pady=2)
ttk.Radiobutton(parent, text='输出到指定文件夹',
variable=output_var, value='custom').pack(anchor='w', padx=20, pady=2)
output_var.trace('w', lambda *args: setattr(config, 'output_location', output_var.get()))
def _create_text_tab(parent):
"""创建文字处理选项卡"""
# 标题
ttk.Label(parent, text='文字处理设置', font=('', 12, 'bold')).pack(anchor='w', padx=10, pady=(10, 5))
ttk.Separator(parent, orient='horizontal').pack(fill='x', padx=10, pady=5)
# 文字处理选项
reverse_var = tk.BooleanVar(value=config.reverse_text_order)
ttk.Checkbutton(parent, text='转换文字顺序', variable=reverse_var).pack(anchor='w', padx=10, pady=5)
reverse_var.trace('w', lambda *args: setattr(config, 'reverse_text_order', reverse_var.get()))
punctuation_var = tk.BooleanVar(value=config.replace_punctuation)
ttk.Checkbutton(parent, text='替换标点符号(句号转逗号,保留结尾句号)',
variable=punctuation_var).pack(anchor='w', padx=10, pady=5)
punctuation_var.trace('w', lambda *args: setattr(config, 'replace_punctuation', punctuation_var.get()))
ttk.Separator(parent, orient='horizontal').pack(fill='x', padx=10, pady=15)
# 错别字处理
ttk.Label(parent, text='错别字处理', font=('', 11, 'bold'), foreground='darkblue').pack(anchor='w', padx=10, pady=(0, 5))
enable_errors_var = tk.BooleanVar(value=config.enable_char_errors)
enable_checkbox = ttk.Checkbutton(parent, text='启用错别字处理',
variable=enable_errors_var)
enable_checkbox.pack(anchor='w', padx=10, pady=5)
# 错误强度
intensity_frame = ttk.Frame(parent)
intensity_frame.pack(fill='x', padx=10, pady=5)
ttk.Label(intensity_frame, text='错误强度:', width=10).pack(side='left')
intensity_var = tk.DoubleVar(value=config.char_error_intensity)
intensity_scale = ttk.Scale(intensity_frame, from_=0.0, to=1.0, variable=intensity_var,
orient='horizontal', length=200)
intensity_scale.pack(side='left', padx=(0, 10))
intensity_label = ttk.Label(intensity_frame, text=f'{config.char_error_intensity:.1f}')
intensity_label.pack(side='left')
def update_intensity_label(*args):
intensity_label.config(text=f'{intensity_var.get():.1f}')
config.char_error_intensity = intensity_var.get()
intensity_var.trace('w', update_intensity_label)
# 错别字库路径
db_frame = ttk.Frame(parent)
db_frame.pack(fill='x', padx=10, pady=5)
ttk.Label(db_frame, text='错别字库路径:', width=12).pack(side='left')
db_var = tk.StringVar(value=config.char_error_db_path)
db_entry = ttk.Entry(db_frame, textvariable=db_var, width=30)
db_entry.pack(side='left', fill='x', expand=True, padx=(0, 5))
def browse_db_file():
filename = filedialog.askopenfilename(title='选择错别字库文件',
filetypes=[('JSON Files', '*.json')])
if filename:
db_var.set(filename)
ttk.Button(db_frame, text='浏览', command=browse_db_file).pack(side='right')
db_var.trace('w', lambda *args: setattr(config, 'char_error_db_path', db_var.get()))
ttk.Separator(parent, orient='horizontal').pack(fill='x', padx=10, pady=15)
# 段落句子数控制
ttk.Label(parent, text='段落控制', font=('', 11, 'bold'), foreground='darkblue').pack(anchor='w', padx=10, pady=(0, 5))
# 每段最大句子数
sentence_frame = ttk.Frame(parent)
sentence_frame.pack(fill='x', padx=10, pady=5)
ttk.Label(sentence_frame, text='每段最大句子数:', width=15).pack(side='left')
sentence_var = tk.IntVar(value=config.max_sentences_per_paragraph)
sentence_spin = ttk.Spinbox(sentence_frame, from_=0, to=100, textvariable=sentence_var, width=10)
sentence_spin.pack(side='left', padx=(0, 10))
ttk.Label(sentence_frame, text='(0表示不限制)').pack(side='left')
def update_sentence_limit(*args):
try:
config.max_sentences_per_paragraph = sentence_var.get()
except (tk.TclError, ValueError):
# 如果输入无效设置为默认值0
config.max_sentences_per_paragraph = 0
sentence_var.set(0)
sentence_var.trace('w', update_sentence_limit)
ttk.Separator(parent, orient='horizontal').pack(fill='x', padx=10, pady=15)
# 免责声明
disclaimer_var = tk.BooleanVar(value=config.add_disclaimer)
ttk.Checkbutton(parent, text='添加免责声明', variable=disclaimer_var).pack(anchor='w', padx=10, pady=5)
disclaimer_var.trace('w', lambda *args: setattr(config, 'add_disclaimer', disclaimer_var.get()))
# 启用/禁用错别字相关控件
def toggle_error_controls(*args):
state = 'normal' if enable_errors_var.get() else 'disabled'
intensity_scale.configure(state=state)
db_entry.configure(state=state)
config.enable_char_errors = enable_errors_var.get()
enable_errors_var.trace('w', toggle_error_controls)
toggle_error_controls() # 初始化状态
return {
'enable_errors': enable_errors_var,
'intensity': intensity_var,
'db_path': db_var,
'reverse_text': reverse_var,
'punctuation': punctuation_var,
'disclaimer': disclaimer_var,
'max_sentences': sentence_var # 添加返回值
}
def _create_image_tab(parent):
"""创建图片处理选项卡"""
# 标题
ttk.Label(parent, text='图片处理设置', font=('', 12, 'bold')).pack(anchor='w', padx=10, pady=(10, 5))
ttk.Separator(parent, orient='horizontal').pack(fill='x', padx=10, pady=5)
# 图片排序方式
ttk.Label(parent, text='图片排序方式:', font=('', 10, 'bold')).pack(anchor='w', padx=10, pady=(0, 5))
sort_var = tk.StringVar(value=config.image_sort_by)
ttk.Radiobutton(parent, text='按名称', variable=sort_var, value='name').pack(anchor='w', padx=20, pady=2)
ttk.Radiobutton(parent, text='按修改时间', variable=sort_var, value='time').pack(anchor='w', padx=20, pady=2)
sort_var.trace('w', lambda *args: setattr(config, 'image_sort_by', sort_var.get()))
ttk.Separator(parent, orient='horizontal').pack(fill='x', padx=10, pady=15)
# 图片尺寸调整
ttk.Label(parent, text='图片尺寸调整:', font=('', 10, 'bold')).pack(anchor='w', padx=10, pady=(0, 5))
resize_var = tk.StringVar(value=config.image_resize)
ttk.Radiobutton(parent, text='不调整', variable=resize_var, value='none').pack(anchor='w', padx=20, pady=2)
width_frame = ttk.Frame(parent)
width_frame.pack(anchor='w', padx=20, pady=2)
width_radio = ttk.Radiobutton(width_frame, text='按宽度:', variable=resize_var, value='width')
width_radio.pack(side='left')
width_var = tk.StringVar(value=str(config.image_width))
width_entry = ttk.Entry(width_frame, textvariable=width_var, width=8)
width_entry.pack(side='left', padx=(5, 5))
ttk.Label(width_frame, text='英寸').pack(side='left')
resize_var.trace('w', lambda *args: setattr(config, 'image_resize', resize_var.get()))
width_var.trace('w', lambda *args: _update_image_width(width_var.get()))
ttk.Separator(parent, orient='horizontal').pack(fill='x', padx=10, pady=15)
# 图片对齐方式
ttk.Label(parent, text='图片对齐方式:', font=('', 10, 'bold')).pack(anchor='w', padx=10, pady=(0, 5))
align_var = tk.StringVar(value=config.image_alignment)
ttk.Radiobutton(parent, text='左对齐', variable=align_var, value='left').pack(anchor='w', padx=20, pady=2)
ttk.Radiobutton(parent, text='居中', variable=align_var, value='center').pack(anchor='w', padx=20, pady=2)
ttk.Radiobutton(parent, text='右对齐', variable=align_var, value='right').pack(anchor='w', padx=20, pady=2)
align_var.trace('w', lambda *args: setattr(config, 'image_alignment', align_var.get()))
ttk.Separator(parent, orient='horizontal').pack(fill='x', padx=10, pady=15)
# 图片插入策略(新增)
ttk.Label(parent, text='图片插入策略:', font=('', 10, 'bold')).pack(anchor='w', padx=10, pady=(0, 5))
# 有标题时的图片插入位置
ttk.Label(parent, text='有标题时:', font=('', 9)).pack(anchor='w', padx=20, pady=(0, 2))
position_var = tk.StringVar(value=getattr(config, 'image_insert_position', 'after_title'))
ttk.Radiobutton(parent, text='标题前插入', variable=position_var, value='before_title').pack(anchor='w', padx=30, pady=1)
ttk.Radiobutton(parent, text='标题后插入', variable=position_var, value='after_title').pack(anchor='w', padx=30, pady=1)
position_var.trace('w', lambda *args: setattr(config, 'image_insert_position', position_var.get()))
# 无标题时的图片插入间隔
interval_frame = ttk.Frame(parent)
interval_frame.pack(anchor='w', padx=20, pady=5)
ttk.Label(interval_frame, text='无标题时每隔', font=('', 9)).pack(side='left')
interval_var = tk.StringVar(value=str(getattr(config, 'image_insert_interval', 5)))
interval_entry = ttk.Entry(interval_frame, textvariable=interval_var, width=5)
interval_entry.pack(side='left', padx=2)
ttk.Label(interval_frame, text='段插入一张图片', font=('', 9)).pack(side='left')
interval_var.trace('w', lambda *args: _update_image_interval(interval_var.get()))
ttk.Separator(parent, orient='horizontal').pack(fill='x', padx=10, pady=15)
# 图片不足时策略
ttk.Label(parent, text='图片不足时策略:', font=('', 10, 'bold')).pack(anchor='w', padx=10, pady=(0, 5))
strategy_var = tk.StringVar(value=config.image_strategy)
ttk.Radiobutton(parent, text='循环使用', variable=strategy_var, value='cycle').pack(anchor='w', padx=20, pady=2)
ttk.Radiobutton(parent, text='忽略多余标题', variable=strategy_var, value='truncate').pack(anchor='w', padx=20, pady=2)
ttk.Radiobutton(parent, text='重复最后一张', variable=strategy_var, value='repeat_last').pack(anchor='w', padx=20, pady=2)
strategy_var.trace('w', lambda *args: setattr(config, 'image_strategy', strategy_var.get()))
def _update_image_width(value):
"""更新图片宽度"""
try:
config.image_width = float(value)
except (ValueError, tk.TclError):
# 如果输入无效,保持当前值不变
pass
def _update_image_interval(value):
"""更新图片插入间隔"""
try:
config.image_insert_interval = int(value)
except (ValueError, tk.TclError):
# 如果输入无效,保持当前值不变
pass
def _reset_to_default(char_vars):
"""重置为默认值"""
from config import Config
default_config = Config()
# 更新所有配置
config.txt_encoding = default_config.txt_encoding
config.match_pattern = default_config.match_pattern
config.output_location = default_config.output_location
config.reverse_text_order = default_config.reverse_text_order
config.replace_punctuation = default_config.replace_punctuation
config.enable_char_errors = default_config.enable_char_errors
config.char_error_intensity = default_config.char_error_intensity
config.char_error_db_path = default_config.char_error_db_path
config.add_disclaimer = default_config.add_disclaimer
config.image_sort_by = default_config.image_sort_by
config.image_resize = default_config.image_resize
config.image_width = default_config.image_width
config.image_alignment = default_config.image_alignment
config.image_strategy = default_config.image_strategy
config.line_spacing = default_config.line_spacing
config.title_levels = default_config.title_levels
config.max_sentences_per_paragraph = default_config.max_sentences_per_paragraph # 添加这行
# 更新界面变量
if char_vars:
char_vars['enable_errors'].set(default_config.enable_char_errors)
char_vars['intensity'].set(default_config.char_error_intensity)
char_vars['db_path'].set(default_config.char_error_db_path)
char_vars['reverse_text'].set(default_config.reverse_text_order)
char_vars['punctuation'].set(default_config.replace_punctuation)
char_vars['disclaimer'].set(default_config.add_disclaimer)
char_vars['max_sentences'].set(default_config.max_sentences_per_paragraph) # 添加这行
messagebox.showinfo('信息', '配置已重置为默认值')
def _save_config(window, char_vars):
"""保存配置"""
from config import CONFIG_FILE_PATH
config.save_to_file(CONFIG_FILE_PATH)
messagebox.showinfo('信息', '配置已保存')
window.destroy()