feat: add Production ID input widget and UI configuration

- Add ProductionIdInput widget with placeholder and multi-line support
- Add UIConfig class for font family, font size, and input width settings
- Refactor data extraction tab to use horizontal PanedWindow layout
  - Left panel: Production ID text input (draggable width)
  - Right panel: control panel and log output
- Share Production IDs between data extraction and material validation tabs
- Add UI settings group in settings page (font selection, size, input width)
- For User users: automatically use shared Production IDs, simplified UI
- Apply font settings to input and log widgets
- Use sashpos() to set initial pane width correctly

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Misaka
2026-02-11 21:47:17 +08:00
parent 62f323d420
commit 6f8df2f2e6
8 changed files with 561 additions and 96 deletions

View File

@@ -6,5 +6,6 @@ GUI 自定义组件模块
from .file_selector import FileSelector
from .log_text import LogText
from .production_id_input import ProductionIdInput
__all__ = ['FileSelector', 'LogText']
__all__ = ['FileSelector', 'LogText', 'ProductionIdInput']

View File

@@ -178,3 +178,9 @@ class LogText(tk.Frame):
def grid(self, **kwargs):
"""Grid 布局"""
super().grid(**kwargs)
def apply_font(self, font_family: str, font_size: int):
"""应用字体设置"""
from tkinter import font as tk_font
font_spec = tk_font.Font(family=font_family, size=font_size)
self.text.configure(font=font_spec)

View File

@@ -0,0 +1,92 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Production ID 输入控件
多行文本输入框,用于输入 Production ID 列表。
"""
import tkinter as tk
from tkinter import ttk, font
class ProductionIdInput(ttk.Frame):
"""Production ID 输入控件"""
def __init__(self, parent, placeholder="每行输入一个 Production ID", **kwargs):
super().__init__(parent, **kwargs)
self.placeholder = placeholder
# 创建文本框和滚动条
self.text_widget = tk.Text(self, wrap=tk.WORD, padx=5, pady=5)
self.scrollbar = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self.text_widget.yview)
self.text_widget.configure(yscrollcommand=self.scrollbar.set)
# 布局
self.text_widget.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# 绑定事件
self.text_widget.bind("<FocusIn>", self._on_focus_in)
self.text_widget.bind("<FocusOut>", self._on_focus_out)
# 显示占位符
self._show_placeholder()
def _on_focus_in(self, event):
"""获得焦点时隐藏占位符"""
if self.text_widget.get("1.0", "end-1c") == self.placeholder:
self.text_widget.delete("1.0", tk.END)
def _on_focus_out(self, event):
"""失去焦点时显示占位符"""
content = self.text_widget.get("1.0", "end-1c")
if not content:
self._show_placeholder()
def _show_placeholder(self):
"""显示占位符"""
self.text_widget.delete("1.0", tk.END)
self.text_widget.insert("1.0", self.placeholder)
self.text_widget.configure(foreground="gray")
def _hide_placeholder(self):
"""隐藏占位符"""
if self.text_widget.get("1.0", "end-1c") == self.placeholder:
self.text_widget.delete("1.0", tk.END)
self.text_widget.configure(foreground="black")
def get(self) -> list[str]:
"""获取 Production ID 列表"""
self._hide_placeholder()
content = self.text_widget.get("1.0", "end-1c").strip()
return [line.strip() for line in content.split("\n") if line.strip()]
def set(self, production_ids: list[str]):
"""设置 Production ID 列表"""
self.text_widget.delete("1.0", tk.END)
if production_ids:
self.text_widget.insert("1.0", "\n".join(production_ids))
self.text_widget.configure(foreground="black")
else:
self._show_placeholder()
def clear(self):
"""清空内容"""
self.text_widget.delete("1.0", tk.END)
self._show_placeholder()
def append(self, production_ids: list[str]):
"""追加 Production ID 列表"""
self._hide_placeholder()
if production_ids:
current_content = self.text_widget.get("1.0", "end-1c")
if current_content.strip():
self.text_widget.insert(tk.END, "\n" + "\n".join(production_ids))
else:
self.text_widget.insert("1.0", "\n".join(production_ids))
def apply_font(self, font_family: str, font_size: int):
"""应用字体设置"""
font_spec = font.Font(family=font_family, size=font_size)
self.text_widget.configure(font=font_spec)