TxT2Docx/gui_config.py

331 lines
15 KiB
Python
Raw Normal View History

2025-09-21 19:01:40 +08:00
"""
GUI配置窗口模块
提供配置设置的图形界面
"""
2025-09-21 20:40:36 +08:00
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
2025-09-21 19:01:40 +08:00
from config import config
def show_config_window():
"""显示配置窗口"""
2025-09-21 20:40:36 +08:00
# 创建配置窗口
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)
# 文档格式选项卅
format_frame = ttk.Frame(notebook)
notebook.add(format_frame, text='文档格式')
_create_format_tab(format_frame)
# 底部按钮
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)
# 免责声明
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
}
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))
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 _create_format_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)
# 行间距
spacing_frame = ttk.Frame(parent)
spacing_frame.pack(fill='x', padx=10, pady=5)
ttk.Label(spacing_frame, text='行间距:', width=12).pack(side='left')
spacing_var = tk.StringVar(value=str(config.line_spacing))
spacing_entry = ttk.Entry(spacing_frame, textvariable=spacing_var, width=8)
spacing_entry.pack(side='left')
spacing_var.trace('w', lambda *args: _update_line_spacing(spacing_var.get()))
# 最大标题层级
title_frame = ttk.Frame(parent)
title_frame.pack(fill='x', padx=10, pady=5)
ttk.Label(title_frame, text='最大标题层级:', width=12).pack(side='left')
title_var = tk.StringVar(value=str(config.title_levels))
title_combo = ttk.Combobox(title_frame, textvariable=title_var, values=['1', '2', '3', '4', '5', '6'],
state='readonly', width=8)
title_combo.pack(side='left')
title_var.trace('w', lambda *args: _update_title_levels(title_var.get()))
def _update_image_width(value):
"""更新图片宽度"""
try:
config.image_width = float(value)
except:
pass
def _update_line_spacing(value):
"""更新行间距"""
try:
config.line_spacing = float(value)
except:
pass
def _update_title_levels(value):
"""更新标题层级"""
try:
config.title_levels = int(value)
except:
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
# 更新界面变量
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)
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()