如何用Python创建Windows顶层穿透透明GUI以绘制游戏悬浮图形?
在Windows中实现视觉透明、点击穿透的Python顶层绘图窗口
可行方案:使用Windows分层窗口API
通过Windows的**分层窗口(Layered Window)**机制,结合win32api和win32gui模块,可以实现仅显示绘制图形、背景完全透明且鼠标点击穿透的顶层窗口,同时避免卡顿和闪烁问题。
核心原理
- 分层窗口(WS_EX_LAYERED):允许窗口设置透明度或指定透明色,仅保留绘制的图形内容,背景完全透明。
- 点击穿透(WS_EX_TRANSPARENT):让窗口忽略所有鼠标和键盘输入,直接传递给底层窗口(如游戏)。
- 顶层窗口(WS_EX_TOPMOST):确保窗口始终显示在所有程序之上。
解决之前方案的问题
- Tkinter方案缺陷:
-alpha是全局透明度,无法单独让窗口背景透明;未设置点击穿透的扩展样式,导致窗口阻挡输入。 - win32gui直接绘点缺陷:直接操作屏幕DC会被系统刷新覆盖,频繁调用
SetPixel效率极低,引发卡顿和闪烁。
完整实现代码
import win32gui import win32api import win32con class OverlayWindow: def __init__(self): # 窗口类名和标题 self.class_name = "PythonOverlayClass" self.window_name = "GameOverlay" # 注册窗口类 wc = win32gui.WNDCLASS() wc.style = win32con.CS_HREDRAW | win32con.CS_VREDRAW wc.lpfnWndProc = self.wnd_proc wc.hInstance = win32api.GetModuleHandle(None) wc.hCursor = win32gui.LoadCursor(0, win32con.IDC_ARROW) wc.lpszClassName = self.class_name win32gui.RegisterClass(wc) # 获取屏幕尺寸 self.screen_width = win32api.GetSystemMetrics(win32con.SM_CXSCREEN) self.screen_height = win32api.GetSystemMetrics(win32con.SM_CYSCREEN) # 创建窗口:设置扩展样式为分层、点击穿透、顶层 self.hwnd = win32gui.CreateWindowEx( win32con.WS_EX_LAYERED | win32con.WS_EX_TRANSPARENT | win32con.WS_EX_TOPMOST, self.class_name, self.window_name, win32con.WS_POPUP, # 无边框窗口 0, 0, self.screen_width, self.screen_height, None, None, wc.hInstance, None ) # 设置分层窗口属性:指定白色为透明色(后续绘制时背景用白色,会被透明化) win32gui.SetLayeredWindowAttributes(self.hwnd, win32api.RGB(255,255,255), 0, win32con.LWA_COLORKEY) # 显示窗口 win32gui.ShowWindow(self.hwnd, win32con.SW_SHOW) def wnd_proc(self, hwnd, msg, wparam, lparam): # 处理窗口消息,这里只处理重绘和退出 if msg == win32con.WM_PAINT: self.on_paint() return 0 elif msg == win32con.WM_DESTROY: win32api.PostQuitMessage(0) return 0 return win32gui.DefWindowProc(hwnd, msg, wparam, lparam) def on_paint(self): # 获取窗口DC hdc = win32gui.GetDC(self.hwnd) try: # 设置背景为透明色(白色) white_brush = win32gui.GetStockObject(win32con.WHITE_BRUSH) win32gui.SelectObject(hdc, white_brush) win32gui.Rectangle(hdc, 0, 0, self.screen_width, self.screen_height) # 绘制图形:屏幕中心红色矩形 center_x = self.screen_width // 2 center_y = self.screen_height // 2 size = 10 # 创建红色画笔 red_pen = win32gui.CreatePen(win32con.PS_SOLID, 2, win32api.RGB(255,0,0)) win32gui.SelectObject(hdc, red_pen) # 绘制矩形 win32gui.Rectangle(hdc, center_x - size, center_y - size, center_x + size, center_y + size) # 清理画笔 win32gui.DeleteObject(red_pen) # 示例:绘制十字光标线 cross_size = 50 win32gui.MoveToEx(hdc, center_x - cross_size, center_y, None) win32gui.LineTo(hdc, center_x + cross_size, center_y) win32gui.MoveToEx(hdc, center_x, center_y - cross_size, None) win32gui.LineTo(hdc, center_x, center_y + cross_size) finally: # 释放DC win32gui.ReleaseDC(self.hwnd, hdc) def run(self): # 消息循环,保持窗口运行 msg = win32gui.GetMessage(None, 0, 0) while msg[0] != win32con.WM_QUIT: win32gui.TranslateMessage(msg) win32gui.DispatchMessage(msg) msg = win32gui.GetMessage(None, 0, 0) if __name__ == "__main__": overlay = OverlayWindow() overlay.run()
关键说明
- 透明色设置:代码中指定白色为透明色,绘制时窗口背景填充白色,会被系统自动透明化,仅保留绘制的彩色图形。
- 点击穿透:
WS_EX_TRANSPARENT扩展样式让窗口完全忽略鼠标输入,不会干扰游戏或其他程序的操作。 - 性能优化:通过窗口消息触发重绘(
WM_PAINT),而非循环强制绘制,避免卡顿和闪烁;若需要动态更新图形,可调用win32gui.InvalidateRect触发重绘。 - 反作弊注意:分层窗口是Windows原生机制,大部分游戏不会检测,但使用时需遵守游戏的用户协议,避免违规操作。
内容的提问来源于stack exchange,提问作者NONAME




