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
|
2025-09-22 21:10:29 +08:00
|
|
|
from gui_style_manager import create_style_tab
|
2025-09-21 19:01:40 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
2025-09-22 21:10:29 +08:00
|
|
|
# 文章样式选项卡
|
|
|
|
|
style_frame = create_style_tab(notebook)
|
|
|
|
|
notebook.add(style_frame, text='文章样式')
|
2025-09-21 20:40:36 +08:00
|
|
|
|
|
|
|
|
# 底部按钮
|
|
|
|
|
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)
|
|
|
|
|
|
2025-10-15 17:10:50 +08:00
|
|
|
# 图片插入策略(新增)
|
|
|
|
|
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)
|
|
|
|
|
|
2025-09-21 20:40:36 +08:00
|
|
|
# 图片不足时策略
|
|
|
|
|
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:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2025-10-15 17:10:50 +08:00
|
|
|
def _update_image_interval(value):
|
|
|
|
|
"""更新图片插入间隔"""
|
|
|
|
|
try:
|
|
|
|
|
config.image_insert_interval = int(value)
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2025-09-21 20:40:36 +08:00
|
|
|
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()
|