348 lines
16 KiB
Python
348 lines
16 KiB
Python
"""
|
||
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() |