# -*- coding: utf-8 -*- """投图窗口按「外框」在「工作区」里居中。 原来的写法: x = (winfo_screenwidth() - width) // 2 y = (winfo_screenheight() - height) // 2 win.geometry(f"{width}x{height}+{x}+{y}") 两个问题: 1. winfo_reqwidth/height 是**客户区**尺寸,真正的窗口还带标题栏和边框, 所以外框会往下多出一截,看起来不是居中。 2. 用的是整屏高度,没扣任务栏 —— 任务栏常显时窗口会被挤下去。 改成:先量出真实外框,再在工作区(扣掉任务栏)里居中。 """ from __future__ import annotations import sys from pathlib import Path ACTIONS = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\windows" r"\lanremote\actions.py") OLD = ''' # 摆到屏幕正中间 —— 普通窗口,有标题栏和关闭按钮 win.update_idletasks() width = win.winfo_reqwidth() height = win.winfo_reqheight() x = max(0, (win.winfo_screenwidth() - width) // 2) y = max(0, (win.winfo_screenheight() - height) // 2) win.geometry(f"{width}x{height}+{x}+{y}") win.lift() win.focus_force()''' NEW = ''' # 摆到屏幕正中间 —— 普通窗口,有标题栏和关闭按钮 _place_centered(win, win.winfo_reqwidth(), win.winfo_reqheight())''' HELPER_ANCHOR = "class Actions:" HELPER = '''def work_area() -> tuple: """屏幕工作区 (left, top, width, height) —— 已经扣掉任务栏。 直接读 SPI_GETWORKAREA,比自己猜任务栏多高靠谱。 """ try: import ctypes.wintypes rect = ctypes.wintypes.RECT() ok = ctypes.windll.user32.SystemParametersInfoW( 0x0030, 0, ctypes.byref(rect), 0) # SPI_GETWORKAREA if ok and rect.right > rect.left and rect.bottom > rect.top: return (rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top) except Exception: # noqa: BLE001 pass try: import tkinter as tk root = tk._default_root # noqa: SLF001 if root is not None: return (0, 0, root.winfo_screenwidth(), root.winfo_screenheight()) except Exception: # noqa: BLE001 pass return (0, 0, 1920, 1080) def _outer_size(win) -> tuple: """窗口的真实外框尺寸(含标题栏和边框)。 客户区尺寸不等于窗口占的地方 —— 不按外框算,看起来就不居中。 """ try: import ctypes import ctypes.wintypes hwnd = int(win.frame(), 0) # '0x00012345' rect = ctypes.wintypes.RECT() if ctypes.windll.user32.GetWindowRect(hwnd, ctypes.byref(rect)): return (rect.right - rect.left, rect.bottom - rect.top, rect.left, rect.top) except Exception: # noqa: BLE001 pass return (win.winfo_width(), win.winfo_height(), 0, 0) def _place_centered(win, client_w: int, client_h: int) -> None: """在工作区正中间摆好这个窗口(按外框算)。""" client_w = max(1, int(client_w)) client_h = max(1, int(client_h)) # 先放到 0,0,好量出真实外框 win.geometry(f"{client_w}x{client_h}+0+0") win.update_idletasks() outer_w, outer_h, outer_x, outer_y = _outer_size(win) # 外框相对客户区多出来的部分(左边框 / 标题栏+上边框) chrome_w = max(0, outer_w - client_w) chrome_h = max(0, outer_h - client_h) area_x, area_y, area_w, area_h = work_area() x = area_x + max(0, (area_w - outer_w) // 2) + chrome_w // 2 y = area_y + max(0, (area_h - outer_h) // 2) + chrome_h - chrome_h // 2 win.geometry(f"{client_w}x{client_h}+{x}+{y}") win.update_idletasks() win.lift() win.focus_force() ''' + HELPER_ANCHOR def main() -> int: text = ACTIONS.read_text(encoding="utf-8") if "_place_centered" in text: print(" 已经改过") return 0 if OLD not in text: print(" [失败] 定位锚点没找到") return 1 text = text.replace(OLD, NEW, 1) if HELPER_ANCHOR not in text: print(" [失败] 找不到 class Actions") return 1 text = text.replace(HELPER_ANCHOR, HELPER, 1) ACTIONS.write_text(text, encoding="utf-8") print(" 已改成按外框在工作区居中") import ast try: ast.parse(ACTIONS.read_text(encoding="utf-8")) print(" actions.py: 语法 OK") except SyntaxError as exc: print(f" actions.py: 语法错误 {exc}") return 1 return 0 if __name__ == "__main__": sys.exit(main())