Fix exe silent start: show activation window instead of hidden Tk parent.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-17 19:32:35 +08:00
parent d25a4c6862
commit accdab9499
3 changed files with 114 additions and 60 deletions
+92 -53
View File
@@ -4,74 +4,113 @@ from __future__ import annotations
import tkinter as tk import tkinter as tk
from tkinter import messagebox, ttk from tkinter import messagebox, ttk
from typing import Optional
import hub_client import hub_client
from device_store import is_activated, load_device, machine_fingerprint, save_device from device_store import load_device, machine_fingerprint
def ensure_activated(root: tk.Tk) -> bool: def _bring_front(win: tk.Misc) -> None:
"""确保对话框在 Windows 上可见(避免挂在 withdraw 根窗后不显示)。"""
try:
win.update_idletasks()
win.deiconify()
win.lift()
win.focus_force()
win.attributes("-topmost", True)
win.after(200, lambda: win.attributes("-topmost", False))
except Exception:
pass
def ensure_activated(parent: Optional[tk.Misc] = None) -> bool:
"""已激活且能 ping 通则通过;否则弹出激活窗。返回是否可继续。""" """已激活且能 ping 通则通过;否则弹出激活窗。返回是否可继续。"""
device = load_device() device = load_device()
if device.get("token") and device.get("server"): owns_root = False
if hub_client.ping(): root: tk.Misc
return True if parent is not None:
# token 失效时允许重新激活 root = parent
if not messagebox.askyesno( else:
"激活校验", root = tk.Tk()
"无法连接中控或令牌失效,是否重新激活?\n选「否」将以离线模式继续(不上报复盘)。", root.title("黄金市价辅助")
parent=root, root.geometry("360x80")
): ttk.Label(root, text="正在启动…").pack(expand=True, padx=16, pady=16)
return True root.update()
owns_root = True
win = tk.Toplevel(root) try:
win.title("激活黄金辅助") if device.get("token") and device.get("server"):
win.geometry("460x280") if hub_client.ping():
win.transient(root) return True
win.grab_set() _bring_front(root)
result = {"ok": False} if not messagebox.askyesno(
"激活校验",
"无法连接中控或令牌失效,是否重新激活?\n选「否」将以离线模式继续(不上报复盘)。",
parent=root,
):
return True
frm = ttk.Frame(win, padding=16) win = tk.Toplevel(root)
frm.pack(fill=tk.BOTH, expand=True) win.title("激活黄金辅助")
win.geometry("480x300")
win.resizable(False, False)
# 不要 transient 到已隐藏的父窗,否则 Windows 上常不显示
result = {"ok": False}
ttk.Label(frm, text="首次使用请输入中控地址与激活码(网页下载中心生成)").pack(anchor="w") frm = ttk.Frame(win, padding=16)
ttk.Label(frm, text="服务器地址(例:http://192.168.1.10:5800)").pack(anchor="w", pady=(12, 4)) frm.pack(fill=tk.BOTH, expand=True)
var_server = tk.StringVar(value=device.get("server") or "http://127.0.0.1:5800")
ttk.Entry(frm, textvariable=var_server, width=48).pack(fill=tk.X)
ttk.Label(frm, text="激活码").pack(anchor="w", pady=(12, 4)) ttk.Label(frm, text="首次使用请输入中控地址与激活码(网页下载中心生成)").pack(anchor="w")
var_code = tk.StringVar() ttk.Label(frm, text="服务器地址(例:http://192.168.1.10:5800)").pack(anchor="w", pady=(12, 4))
ttk.Entry(frm, textvariable=var_code, width=48).pack(fill=tk.X) var_server = tk.StringVar(value=device.get("server") or "http://127.0.0.1:5800")
ttk.Entry(frm, textvariable=var_server, width=48).pack(fill=tk.X)
ttk.Label(frm, text="本机名称(可改)").pack(anchor="w", pady=(12, 4)) ttk.Label(frm, text="激活码").pack(anchor="w", pady=(12, 4))
var_name = tk.StringVar(value=device.get("machine_name") or "") var_code = tk.StringVar()
ttk.Entry(frm, textvariable=var_name, width=48).pack(fill=tk.X) ttk.Entry(frm, textvariable=var_code, width=48).pack(fill=tk.X)
status = ttk.Label(frm, text="", foreground="#888") ttk.Label(frm, text="本机名称(可改)").pack(anchor="w", pady=(12, 4))
status.pack(anchor="w", pady=(10, 0)) var_name = tk.StringVar(value=device.get("machine_name") or "")
ttk.Entry(frm, textvariable=var_name, width=48).pack(fill=tk.X)
def do_skip(): status = ttk.Label(frm, text="", foreground="#888")
result["ok"] = True status.pack(anchor="w", pady=(10, 0))
win.destroy()
def do_ok(): def do_skip():
server = var_server.get().strip()
code = var_code.get().strip()
if not server or not code:
status.configure(text="请填写服务器与激活码", foreground="#f6465d")
return
try:
hub_client.activate(server, code, machine_fingerprint(), var_name.get().strip() or "PC")
result["ok"] = True result["ok"] = True
messagebox.showinfo("激活成功", "已绑定账户与机器,成交将上报复盘中心。", parent=win)
win.destroy() win.destroy()
except hub_client.HubError as exc:
status.configure(text=str(exc), foreground="#f6465d")
btns = ttk.Frame(frm) def do_ok():
btns.pack(fill=tk.X, pady=(16, 0)) server = var_server.get().strip()
ttk.Button(btns, text="离线使用", command=do_skip).pack(side=tk.LEFT) code = var_code.get().strip()
ttk.Button(btns, text="激活", command=do_ok).pack(side=tk.RIGHT) if not server or not code:
status.configure(text="请填写服务器与激活码", foreground="#f6465d")
return
try:
hub_client.activate(
server, code, machine_fingerprint(), var_name.get().strip() or "PC"
)
result["ok"] = True
messagebox.showinfo(
"激活成功", "已绑定账户与机器,成交将上报复盘中心。", parent=win
)
win.destroy()
except hub_client.HubError as exc:
status.configure(text=str(exc), foreground="#f6465d")
win.protocol("WM_DELETE_WINDOW", do_skip) btns = ttk.Frame(frm)
root.wait_window(win) btns.pack(fill=tk.X, pady=(16, 0))
return result["ok"] ttk.Button(btns, text="离线使用", command=do_skip).pack(side=tk.LEFT)
ttk.Button(btns, text="激活", command=do_ok).pack(side=tk.RIGHT)
win.protocol("WM_DELETE_WINDOW", do_skip)
_bring_front(win)
win.grab_set()
root.wait_window(win)
return result["ok"]
finally:
if owns_root:
try:
root.destroy()
except Exception:
pass
+22 -7
View File
@@ -1472,14 +1472,10 @@ class OrderApp(tk.Tk):
def main() -> None: def main() -> None:
enable_dpi_awareness() enable_dpi_awareness()
# 先建隐藏根窗完成激活,再开主界面 # 激活窗自管可见性(勿对隐藏根窗挂 Toplevel,Windows 上会双击无界面)
boot = tk.Tk()
boot.withdraw()
if ensure_activated is not None: if ensure_activated is not None:
if not ensure_activated(boot): if not ensure_activated():
boot.destroy()
return return
boot.destroy()
app = OrderApp() app = OrderApp()
if is_activated(): if is_activated():
@@ -1495,4 +1491,23 @@ def main() -> None:
if __name__ == "__main__": if __name__ == "__main__":
main() try:
main()
except Exception as exc:
try:
import traceback
from pathlib import Path
log = Path.home() / ".gold_monitor" / "crash.log"
log.parent.mkdir(parents=True, exist_ok=True)
log.write_text(traceback.format_exc(), encoding="utf-8")
except Exception:
pass
try:
root = tk.Tk()
root.withdraw()
messagebox.showerror("黄金市价辅助", f"启动失败:{exc}\n详情见 %USERPROFILE%\\.gold_monitor\\crash.log")
root.destroy()
except Exception:
pass
raise
Binary file not shown.