diff --git a/gui/widgets/production_id_input.py b/gui/widgets/production_id_input.py index 9fc6200..1687dca 100644 --- a/gui/widgets/production_id_input.py +++ b/gui/widgets/production_id_input.py @@ -4,6 +4,7 @@ Production ID 输入控件 多行文本输入框,用于输入 Production ID 列表。 +支持内容溢出时自动显示滚动条。 """ import tkinter as tk @@ -16,23 +17,44 @@ class ProductionIdInput(ttk.Frame): def __init__(self, parent, placeholder="每行输入一个 Production ID", **kwargs): super().__init__(parent, **kwargs) self.placeholder = placeholder + self._scrollbar_visible = False + self._check_pending = False - # 创建文本框和滚动条 + # 创建文本框 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.scrollbar = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self.text_widget.yview) + self.text_widget.configure(yscrollcommand=self._on_scroll) + + # 布局 - 使用 grid 以便动态显示/隐藏滚动条 + self.text_widget.grid(row=0, column=0, sticky="nsew") + self.scrollbar.grid(row=0, column=1, sticky="ns") + + # 配置行列权重 + self.grid_rowconfigure(0, weight=1) + self.grid_columnconfigure(0, weight=1) # 绑定事件 self.text_widget.bind("", self._on_focus_in) self.text_widget.bind("", self._on_focus_out) + # 监听内容变化事件 + self.text_widget.bind("", self._schedule_check) + self.text_widget.bind("", self._schedule_check) + self.text_widget.bind("", self._schedule_check) + self.text_widget.bind("", self._schedule_check) + # 绑定粘贴事件 + self.text_widget.bind("<>", self._schedule_check) + + # 初始隐藏滚动条 + self.scrollbar.grid_remove() # 显示占位符 self._show_placeholder() + # 延迟检查初始状态 + self.after(100, self._check_scrollbar_needed) + def _on_focus_in(self, event): """获得焦点时隐藏占位符""" if self.text_widget.get("1.0", "end-1c") == self.placeholder: @@ -70,11 +92,13 @@ class ProductionIdInput(ttk.Frame): self.text_widget.configure(foreground="black") else: self._show_placeholder() + self._schedule_check() def clear(self): """清空内容""" self.text_widget.delete("1.0", tk.END) self._show_placeholder() + self._schedule_check() def append(self, production_ids: list[str]): """追加 Production ID 列表""" @@ -85,8 +109,39 @@ class ProductionIdInput(ttk.Frame): self.text_widget.insert(tk.END, "\n" + "\n".join(production_ids)) else: self.text_widget.insert("1.0", "\n".join(production_ids)) + self._schedule_check() 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) + + def _on_scroll(self, first, last): + """滚动回调,更新滚动条位置""" + self.scrollbar.set(first, last) + + def _schedule_check(self, event=None): + """调度滚动条检查(防抖)""" + if not self._check_pending: + self._check_pending = True + self.after(50, self._check_scrollbar_needed) + + def _check_scrollbar_needed(self): + """检查是否需要显示滚动条""" + self._check_pending = False + + # 更新界面以确保获取准确的尺寸 + self.text_widget.update_idletasks() + + # 使用 yview() 返回值判断 + first, last = self.text_widget.yview() + # last < 1.0 表示内容超出了可见区域(需要滚动条) + needs_scrollbar = last < 1.0 + + if needs_scrollbar != self._scrollbar_visible: + if needs_scrollbar: + self.scrollbar.grid() + self._scrollbar_visible = True + else: + self.scrollbar.grid_remove() + self._scrollbar_visible = False