From 6caa6deaa36d6684af47cfeceb1858f82284a06e Mon Sep 17 00:00:00 2001 From: SkyLi Date: Fri, 15 May 2026 16:25:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=A7=E5=93=81/=E5=AE=A2=E6=88=B7=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E6=94=B9=E4=B8=BA=E8=BE=93=E5=85=A5=E6=A1=86=E4=B8=8B?= =?UTF-8?q?=E6=96=B9=E4=B8=8B=E6=8B=89=E5=88=97=E8=A1=A8=EF=BC=8C=E9=80=89?= =?UTF-8?q?=E4=B8=AD=E5=90=8E=E9=98=BB=E6=AD=A2trace=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 58 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/main.py b/main.py index 58e7ef3..b571198 100644 --- a/main.py +++ b/main.py @@ -217,9 +217,11 @@ class App: r0 = Frame(fixed_frame) r0.pack(fill=X, pady=2) Label(r0, text="产品:", width=10, anchor="e").pack(side="left") - Entry(r0, textvariable=self.fv_product, width=20).pack(side="left", padx=5) + self.fv_product_entry = Entry(r0, textvariable=self.fv_product, width=20) + self.fv_product_entry.pack(side="left", padx=5) Label(r0, text="客户:", width=10, anchor="e").pack(side="left", padx=(30, 0)) - Entry(r0, textvariable=self.fv_customer, width=20).pack(side="left", padx=5) + self.fv_customer_entry = Entry(r0, textvariable=self.fv_customer, width=20) + self.fv_customer_entry.pack(side="left", padx=5) # Row 1: 寄达地 | 无影响 r1 = Frame(fixed_frame) @@ -443,7 +445,7 @@ class App: return names = [c.get("productName", "") for c in candidates] self._show_search_dropdown( - "选择产品", names, + self.fv_product_entry, names, lambda idx: self._on_product_selected(candidates[idx]), ) except Exception as e: @@ -461,26 +463,28 @@ class App: for c in candidates ] self._show_search_dropdown( - "选择客户", names, + self.fv_customer_entry, names, lambda idx: self._on_customer_selected(candidates[idx]), ) except Exception as e: self._log(f"[error] 客户搜索失败: {e}") - def _show_search_dropdown(self, title: str, options: list[str], on_select): - """在屏幕中央弹出下拉选择窗口。""" + def _show_search_dropdown(self, entry: Entry, options: list[str], on_select): + """在输入框正下方弹出下拉候选列表。""" popup = Toplevel(self.root) - popup.title(title) - popup.geometry("360x260") - popup.transient(self.root) - popup.grab_set() + popup.overrideredirect(True) popup.attributes("-topmost", True) - Label(popup, text=title, font=("", 10, "bold"), pady=6).pack() + # 定位在输入框正下方 + x = entry.winfo_rootx() + y = entry.winfo_rooty() + entry.winfo_height() + w = entry.winfo_width() + popup.geometry(f"{w}x180+{x}+{y}") - frame = Frame(popup) - frame.pack(fill="both", expand=True, padx=10, pady=5) - listbox = Listbox(frame, font=("", 10)) + frame = Frame(popup, bd=1, relief="solid") + frame.pack(fill="both", expand=True) + + listbox = Listbox(frame, font=("", 10), selectmode="browse", activestyle="none") scroll = Scrollbar(frame, orient=VERTICAL, command=listbox.yview) listbox.configure(yscrollcommand=scroll.set) scroll.pack(side=RIGHT, fill=Y) @@ -488,37 +492,35 @@ class App: for opt in options: listbox.insert(END, opt) - chosen = [False] - - def select(): + def select(e=None): sel = listbox.curselection() if sel: - chosen[0] = True popup.destroy() on_select(sel[0]) - def cancel(): + def cancel(e=None): popup.destroy() - listbox.bind("", lambda e: select()) - listbox.bind("", lambda e: select()) - listbox.bind("", lambda e: cancel()) + listbox.bind("", select) + listbox.bind("", select) + listbox.bind("", cancel) listbox.focus_set() if listbox.size() > 0: listbox.selection_set(0) - btn_f = Frame(popup) - btn_f.pack(pady=8) - Button(btn_f, text="选择", command=select, bg="#4CAF50", fg="white", width=8).pack(side=LEFT, padx=5) - Button(btn_f, text="取消", command=cancel, width=8).pack(side=LEFT, padx=5) + # 点击外部关闭 + def on_focus_out(e): + popup.after(150, lambda: popup.destroy() if not popup.focus_get() else None) + popup.bind("", on_focus_out) - popup.protocol("WM_DELETE_WINDOW", cancel) popup.wait_window() def _on_product_selected(self, choice: dict): """产品选中:缓存选择并获取详情。""" self._product_cached_choice = choice + self._loading_config = True # 阻止 trace 再次触发搜索 self.fv_product.set(choice.get("productName", "")) + self._loading_config = False # 获取产品详情 try: biz_id = choice.get("productId", "") @@ -532,7 +534,9 @@ class App: def _on_customer_selected(self, choice: dict): """客户选中:缓存选择并获取详情和寄件人实名。""" self._customer_cached_choice = choice + self._loading_config = True # 阻止 trace 再次触发搜索 self.fv_customer.set(choice.get("customerFullName", choice.get("customerName", ""))) + self._loading_config = False # 获取客户详情 try: cust_id = choice.get("customerId", "")