# -*- coding: utf-8 -*- """重做电脑端界面(保留浅色 + 简洁的设计理念,提升观感)+ 两个新入口。 改动: * 顶栏:主色竖条 + 粗体标题 + 圆角风格的状态徽标(有底色,不是干巴巴一行字) * 配对卡片:更大留白、更清晰的层次、副标题 * 底栏:接收目录 / 连不上? / 设置 / 退出 * 新增 open_selfcheck():一键拉起网络自检的控制台窗口 * 新增 open_settings():投图窗口标题、TTS 音色与语速、本机音乐目录 """ from __future__ import annotations import sys from pathlib import Path UI = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\windows" r"\lanremote\ui.py") OLD_BUILD_START = ''' def _build(self) -> None: pad = {"padx": 14} head = tk.Frame(self.root, bg=BG) head.pack(fill="x", pady=(12, 4), **pad) tk.Label(head, text=APP_NAME, bg=BG, fg=FG, font=FONT_TITLE).pack(side="left") self.lbl_state = tk.Label(head, text="启动中", bg=BG, fg=DIM, font=FONT_SMALL) self.lbl_state.pack(side="right") card = tk.Frame(self.root, bg=CARD, highlightthickness=1, highlightbackground=BORDER) card.pack(fill="x", pady=6, **pad) tk.Label(card, text="在手表上输入这串数字", bg=CARD, fg=DIM, font=FONT_SMALL).pack(pady=(10, 0)) self.lbl_code = tk.Label(card, text="------", bg=CARD, fg=ACCENT, font=FONT_BIG) self.lbl_code.pack(pady=(0, 2)) self.lbl_code.bind("", lambda _e: self.copy_code()) row = tk.Frame(card, bg=CARD) row.pack(pady=(0, 10)) self._btn(row, "换一组", self.new_code, width=8) self._btn(row, "复制", self.copy_code, width=6) ''' NEW_BUILD_START = ''' def _build(self) -> None: pad = {"padx": 14} # ---- 顶栏:主色竖条 + 标题 + 状态徽标 ---- head = tk.Frame(self.root, bg=BG) head.pack(fill="x", pady=(12, 8), **pad) tk.Frame(head, bg=ACCENT, width=4, height=18).pack(side="left", padx=(0, 8)) tk.Label(head, text=APP_NAME, bg=BG, fg=FG, font=("Microsoft YaHei UI", 12, "bold")).pack(side="left") self.state_badge = tk.Frame(head, bg="#eef1f4") self.state_badge.pack(side="right") self.lbl_state = tk.Label(self.state_badge, text="● 启动中", bg="#eef1f4", fg=DIM, font=("Microsoft YaHei UI", 9, "bold"), padx=10, pady=3) self.lbl_state.pack() # ---- 配对码卡片 ---- card = tk.Frame(self.root, bg=CARD, highlightthickness=1, highlightbackground=BORDER) card.pack(fill="x", pady=(0, 8), **pad) tk.Label(card, text="在手表上输入这串数字", bg=CARD, fg=DIM, font=FONT_SMALL).pack(pady=(14, 0)) self.lbl_code = tk.Label(card, text="------", bg=CARD, fg=ACCENT, font=FONT_BIG) self.lbl_code.pack(pady=(2, 0)) self.lbl_code.bind("", lambda _e: self.copy_code()) tk.Label(card, text="双击数字也能复制", bg=CARD, fg="#9aa4af", font=("Microsoft YaHei UI", 8)).pack() row = tk.Frame(card, bg=CARD) row.pack(pady=(12, 16)) self._btn(row, "换一组", self.new_code, width=9) self._btn(row, "复制", self.copy_code, width=7, last=True) ''' OLD_FOOT = ''' foot = tk.Frame(self.root, bg=BG) foot.pack(fill="x", side="bottom", pady=(0, 6), **pad) self._btn(foot, "打开接收目录", self.open_received, width=12) self._btn(foot, "退出", self.quit_app, width=7, danger=True) tk.Label(self.root, text="关掉窗口后仍在后台运行\\n再次双击图标可找回本窗口", bg=BG, fg=DIM, font=("Microsoft YaHei UI", 8), anchor="w", justify="left").pack(fill="x", side="bottom", padx=14, pady=(0, 8)) ''' NEW_FOOT = ''' foot = tk.Frame(self.root, bg=BG) foot.pack(fill="x", side="bottom", pady=(0, 6), **pad) self._btn(foot, "接收目录", self.open_received, width=9) self._btn(foot, "连不上?", self.open_selfcheck, width=9) self._btn(foot, "设置", self.open_settings, width=6) self._btn(foot, "退出", self.quit_app, width=5, danger=True, last=True) tk.Label(self.root, text="关掉窗口后仍在后台运行,再次双击可找回", bg=BG, fg=DIM, font=("Microsoft YaHei UI", 8), anchor="w", justify="left").pack(fill="x", side="bottom", padx=14, pady=(0, 8)) ''' OLD_BTN = ''' def _btn(self, parent, text, command, width=10, danger=False): bg = "#ffeef0" if danger else "#eaeef2" hover = "#ffdce0" if danger else "#dfe4ea" btn = tk.Button(parent, text=text, command=command, width=width, bg=bg, fg=(DANGER if danger else FG), activebackground=hover, activeforeground=(DANGER if danger else FG), highlightthickness=1, highlightbackground=BORDER, bd=0, relief="flat", font=FONT_UI, cursor="hand2", padx=4, pady=4) btn.pack(side="left", padx=(0, 8)) ''' NEW_BTN = ''' def _btn(self, parent, text, command, width=10, danger=False, last=False): bg = "#ffeef0" if danger else "#eaeef2" hover = "#ffdce0" if danger else "#dfe4ea" btn = tk.Button(parent, text=text, command=command, width=width, bg=bg, fg=(DANGER if danger else FG), activebackground=hover, activeforeground=(DANGER if danger else FG), highlightthickness=1, highlightbackground=BORDER, bd=0, relief="flat", font=FONT_UI, cursor="hand2", padx=4, pady=5) btn.pack(side="left", padx=(0, 0 if last else 8)) ''' OLD_REFRESH_STATE = ''' if sharing: self.lbl_state.configure(text="屏幕共享中", fg=DANGER) elif connected: self.lbl_state.configure(text="已连接", fg=OK) else: self.lbl_state.configure(text="运行中", fg=OK) ''' NEW_REFRESH_STATE = ''' if sharing: self.set_badge("● 屏幕共享中", DANGER, "#ffeef0") elif connected: self.set_badge("● 已连接", OK, "#e6f4ea") else: self.set_badge("● 待连接", DIM, "#eef1f4") ''' NEW_METHODS = ''' # ---- 状态徽标 ---- def set_badge(self, text: str, color: str, soft: str) -> None: try: self.state_badge.configure(bg=soft) self.lbl_state.configure(text=text, bg=soft, fg=color) except tk.TclError: pass # ---- 连不上?直接拉起网络自检 ---- def open_selfcheck(self) -> None: """连不上时一键启动网络自检(开一个控制台窗口显示实时结果)。""" import subprocess from .config import app_dir bat = app_dir() / "网络自检.bat" if not bat.is_file(): self.show_message("没找到 网络自检.bat") return try: flags = getattr(subprocess, "CREATE_NEW_CONSOLE", 0) subprocess.Popen(["cmd", "/c", str(bat)], creationflags=flags) except Exception as exc: # noqa: BLE001 self.show_message(f"启动自检失败:{exc}") return self.show_message("已打开网络自检窗口") # ---- 设置 ---- def open_settings(self) -> None: """设置对话框:投图窗口标题 / TTS 音色与语速 / 本机音乐目录。""" from .actions import Actions win = tk.Toplevel(self.root) win.title("设置") win.configure(bg=BG) win.resizable(False, False) def row_label(text, hint=""): box = tk.Frame(win, bg=BG) box.pack(fill="x", padx=16, pady=(10, 2)) tk.Label(box, text=text, bg=BG, fg=FG, font=FONT_UI, anchor="w").pack(side="left") if hint: tk.Label(box, text=hint, bg=BG, fg=DIM, font=("Microsoft YaHei UI", 8)).pack(side="left", padx=(6, 0)) def entry(initial, width=34): box = tk.Frame(win, bg=BG) box.pack(fill="x", padx=16) ent = tk.Entry(box, width=width, bg=CARD, fg=FG, relief="flat", font=FONT_UI, highlightthickness=1, highlightbackground=BORDER, highlightcolor=ACCENT) ent.pack(fill="x", ipady=5) ent.insert(0, initial) return ent # 投图窗口标题 row_label("投图窗口标题", "支持 {name}") ent_title = entry(str(self.store.get("image_window_title") or "")) # TTS 音色 row_label("语音播报音色") voice_box = tk.Frame(win, bg=BG) voice_box.pack(fill="x", padx=16) voices = [] try: voices = Actions(self, self.store).list_voices() except Exception: # noqa: BLE001 voices = [] current = str(self.store.get("tts_voice") or "") options = ["系统默认"] + voices var_voice = tk.StringVar(value=current if current in voices else "系统默认") opt = tk.OptionMenu(voice_box, var_voice, *options) opt.configure(bg=CARD, fg=FG, activebackground="#eaeef2", activeforeground=FG, relief="flat", highlightthickness=1, highlightbackground=BORDER, font=FONT_SMALL, width=26, anchor="w", cursor="hand2", padx=4) try: opt["menu"].configure(bg=CARD, fg=FG, font=FONT_SMALL, activebackground="#eaeef2", bd=0) except tk.TclError: pass opt.pack(side="left") # 语速 row_label("语速", "-10 慢 … 10 快") ent_rate = entry(str(self.store.get("tts_rate", 0)), width=8) # 本机音乐目录 row_label("本机音乐目录", "留空=自动找 音乐 / Music / Downloads") ent_mp3 = entry(str(self.store.get("mp3_dir") or "")) def save(): self.store.set("image_window_title", ent_title.get().strip()) chosen = var_voice.get() self.store.set("tts_voice", "" if chosen == "系统默认" else chosen) raw = ent_rate.get().strip() try: rate = max(-10, min(10, int(raw))) except ValueError: rate = 0 self.store.set("tts_rate", rate) self.store.set("mp3_dir", ent_mp3.get().strip()) self.log(f"设置已保存(音色={chosen},语速={rate})") win.destroy() self.show_message("设置已保存") buttons = tk.Frame(win, bg=BG) buttons.pack(fill="x", padx=16, pady=(16, 16)) self._btn(buttons, "保存", save, width=8) self._btn(buttons, "取消", win.destroy, width=6, last=True) self.center_window(win) def _build(self) -> None: ''' def main() -> int: text = UI.read_text(encoding="utf-8") ok = True for old, new, tag in ((OLD_BUILD_START, NEW_BUILD_START, "顶栏+卡片"), (OLD_FOOT, NEW_FOOT, "底栏"), (OLD_BTN, NEW_BTN, "按钮 last"), (OLD_REFRESH_STATE, NEW_REFRESH_STATE, "状态徽标")): if old not in text: print(f" [失败] {tag} 锚点未匹配") ok = False else: text = text.replace(old, new, 1) print(f" {tag}: OK") if not ok: return 1 # 插入新方法(放在 _build 之前) text = text.replace(" def _build(self) -> None:", NEW_METHODS, 1) UI.write_text(text, encoding="utf-8") print(" 新方法: OK") print("\n语法检查:") import ast try: ast.parse(UI.read_text(encoding="utf-8")) print(" ui.py: OK") except SyntaxError as exc: print(f" ui.py: 语法错误 {exc}") return 1 return 0 if __name__ == "__main__": sys.exit(main())