我有一个适用于 Windows 的 Python 小型 OpenGL 应用程序。应用程序窗口是无边框窗口;它不是全屏的。当使用 SetWindowPos() 将应用程序窗口移动到第二个显示器时,我需要单击第一个显示器以使应用程序处理鼠标输入;即,当我单击第一个监视器时,应用程序仅捕获鼠标单击。单击应用程序窗口会将其转到后台,就像单击桌面一样。看起来 Windows (11) 对应用程序窗口的位置有错误的认识。
两台显示器均在 Windows 中正确配置。
我不知道为什么会发生这种情况。我的意思是,当我使用 ctypes.windll.user32.SetWindowPos() 移动窗口时,Windows 应该跟踪它,不是吗?
打电话
windll.user32.SetCapture(globals.displayHandler.windowHandle)
或
pygame.event.set_grab(True)
没有帮助。
我该如何解决这个问题?
最小可重现示例(Python 3.11.4,因为它带有预构建的 pyopengl 和 pyopengl-accelerate):
import pygame
from screeninfo import get_monitors
from ctypes import windll, Structure, c_long, byref
class WindowRect(Structure):
_fields_ = [
('left', c_long),
('top', c_long),
('right', c_long),
('bottom', c_long),
]
def width(self): return self.right - self.left
def height(self): return self.bottom - self.top
class DisplayHandler:
def __init__ (self):
monitorInfo = get_monitors()
numDisplays = len(monitorInfo)
if numDisplays == 1:
self.appDisplay = 0
self.xOffset = 0
else:
self.appDisplay = 1
self.xOffset = monitorInfo[self.appDisplay].width
self.maxWidth = monitorInfo[self.appDisplay].width
self.maxHeight = monitorInfo[self.appDisplay].height
self.screenType = pygame.DOUBLEBUF | pygame.OPENGL | pygame.NOFRAME
try:
pygame.display.set_mode (size = (self.maxWidth, self.maxHeight), flags = self.screenType, vsync = 1)
except pygame.error:
print ("Couldn't set display mode ({0})".format (pygame.get_error()))
exit()
self.windowHandle = pygame.display.get_wm_info()['window']
self.FixWindowPos()
def FixWindowPos(self):
if self.appDisplay > 0:
rc = WindowRect()
windll.user32.GetWindowRect(self.windowHandle, byref(rc))
if (rc.left != self.xOffset):
print ("fixing window position")
windll.user32.SetWindowLongPtrW(self.windowHandle, -20, windll.user32.GetWindowLongPtrW(self.windowHandle, -20) | 0x08000000)
windll.user32.SetForegroundWindow (self.windowHandle)
windll.user32.SetActiveWindow (self.windowHandle)
windll.user32.SetFocus (self.windowHandle)
windll.user32.SetWindowPos(self.windowHandle, -1, self.xOffset, 0, 0, 0, 0x0215)
class Application:
def __init__(self):
self.displayHandler = DisplayHandler ()
def HandleEvents (self) -> bool:
for event in pygame.event.get():
if (event.type == pygame.QUIT):
return False
elif (event.type == pygame.KEYDOWN):
if (event.key == pygame.K_ESCAPE):
return False
return True
def Run(self):
print ("press ESC to quit ...")
while self.HandleEvents():
self.displayHandler.FixWindowPos()
app = Application()
app.Run()
我自己设法找到了解决方案,但我把这个问题和我的解决方案一起提出来,供将来可能遇到这个问题的人使用。
通过在 pygame.display.set_mode 的调用中添加参数“display = self.appDisplay”,可以轻松解决该问题:
try:
pygame.display.set_mode (size = (self.maxWidth, self.maxHeight), flags = self.screenType, vsync = 1, display = self.appDisplay)
except pygame.error:
print ("Couldn't set display mode ({0})".format (pygame.get_error()))
exit()