diff --git a/src/tchmaterial_parser/ui/download_panel.py b/src/tchmaterial_parser/ui/download_panel.py index 2d46035..b1fdbb3 100644 --- a/src/tchmaterial_parser/ui/download_panel.py +++ b/src/tchmaterial_parser/ui/download_panel.py @@ -36,12 +36,20 @@ def parse_and_copy() -> None: # 解析并复制链接 messagebox.showwarning("警告", "以下 “行” 无法解析:\n" + "\n".join(failed_urls)) if resource_urls: - url_text.clipboard_clear() - url_text.clipboard_append("\n".join(resource_urls)) # 将链接复制到剪贴板 - messagebox.showinfo( - "提示", - f'资源链接已复制到剪贴板。\n注意:链接可能无法直接下载,需要加上以下 HTTP 标头才能下载{"(以下标头含有隐私信息,请勿分享给别人)" if config.access_token else ""}:\n\nAuthorization: Bearer {config.access_token or "0"}\nX-ND-AUTH: MAC id="{config.access_token or "0"}",nonce="0",mac="0"' - ) + try: + resource_urls_str = "\n".join(resource_urls) + url_text.clipboard_clear() + url_text.clipboard_append(resource_urls_str) # 将链接复制到剪贴板 + if url_text.clipboard_get() == resource_urls_str: # 检查剪贴板内容是否正确 + messagebox.showinfo( + "提示", + f'资源链接已复制到剪贴板。\n注意:链接可能无法直接下载,需要加上以下 HTTP 标头才能下载{"(以下标头含有隐私信息,请勿分享给别人)" if config.access_token else ""}:\n\nAuthorization: Bearer {config.access_token or "0"}\nX-ND-AUTH: MAC id="{config.access_token or "0"}",nonce="0",mac="0"' + ) + else: + messagebox.showerror("错误", "无法将链接复制到剪贴板,请手动复制。") + except Exception as e: + print_error(e) + messagebox.showerror("错误", "无法将链接复制到剪贴板,请手动复制。") def download() -> None: # 下载资源文件 global download_states diff --git a/src/tchmaterial_parser/ui/widgets.py b/src/tchmaterial_parser/ui/widgets.py index b7d04f1..059390f 100644 --- a/src/tchmaterial_parser/ui/widgets.py +++ b/src/tchmaterial_parser/ui/widgets.py @@ -9,9 +9,12 @@ from . import runtime from .theme import register_themed_widget from ..platform_utils import os_name +root_handlers_bound: dict[tk.Menu, bool] = {} # 用于记录每个右键菜单是否已绑定根窗口事件,避免重复绑定 + def bind_context_menu(parent: tk.Widget, type: Literal["normal", "noundo", "readonly"] = "normal") -> None: # 创建右键菜单 context_menu = tk.Menu(parent, tearoff=False, font="AppBodyFont") register_themed_widget(context_menu) + root_handlers_bound[context_menu] = False # 初始化为未绑定根窗口事件 if type == "normal": context_menu.add_command(label="撤销 (U)", underline=4, accelerator="Ctrl+Z", command=lambda: parent.event_generate("<>")) context_menu.add_separator() @@ -23,17 +26,37 @@ def bind_context_menu(parent: tk.Widget, type: Literal["normal", "noundo", "read context_menu.add_separator() context_menu.add_command(label="全选 (A)", underline=4, accelerator="Ctrl+A", command=lambda: parent.event_generate("<>")) - def show_context_menu(event: tk.Event) -> None: - context_menu.post(event.x_root, event.y_root) + def show_context_menu(event: tk.Event, keyboard: bool = False) -> None: + if not keyboard and event.x_root >= 0 and event.y_root >= 0: + context_menu.post(event.x_root, event.y_root) + else: # 通过键盘打开菜单或 x_root 与 y_root 无效时 + try: # 优先尝试在插入点(文本控件)位置显示菜单 + bbox = parent.bbox("insert") # 此处可能抛异常或返回 None + if bbox: + bx, by, bw, bh = bbox + x_root = parent.winfo_rootx() + bx + y_root = parent.winfo_rooty() + by + bh + else: + raise Exception("无法获取插入点位置") + except Exception: # 再尝试使用鼠标指针位置(如果有) + px, py = parent.winfo_pointerx(), parent.winfo_pointery() + if px >= 0 and py >= 0: + x_root, y_root = px, py + else: # 最后回退到控件中心 + x_root = round(parent.winfo_rootx() + parent.winfo_width() // 2) + y_root = round(parent.winfo_rooty() + parent.winfo_height() // 2) + context_menu.post(x_root, y_root) context_menu.bind("", lambda e: context_menu.unpost()) # 绑定失焦事件,失焦时自动关闭菜单 context_menu.bind("", lambda e: context_menu.unpost(), add="+") # 绑定 Esc 键,按下时关闭菜单 - runtime.root.bind("", lambda e: context_menu.unpost(), add="+") # 绑定 Esc 键,按下时关闭菜单 - runtime.root.bind("", lambda e: context_menu.unpost(), add="+") # 绑定左键点击事件,点击其他地方也关闭菜单 + if not root_handlers_bound.get(context_menu): + root_handlers_bound[context_menu] = True + runtime.root.bind("", lambda e: context_menu.unpost(), add="+") # 绑定 Esc 键,按下时关闭菜单 + runtime.root.bind("", lambda e: context_menu.unpost(), add="+") # 绑定左键点击事件,点击其他地方也关闭菜单 # 绑定右键菜单到文本框 parent.bind("", show_context_menu) # 鼠标右键 - parent.bind("", show_context_menu) # BUG: 按下菜单键不起作用 - parent.bind("", show_context_menu) + parent.bind("", lambda e: show_context_menu(e, True)) # BUG: 按下菜单键不起作用 + parent.bind("", lambda e: show_context_menu(e, True)) if os_name == "Darwin": parent.bind("", show_context_menu) # Command + 鼠标左键 parent.bind("", show_context_menu) # 鼠标中键