#1 - 2022-9-22 11:14
冈崎羽未鹰原汐 (二阶堂芽爱 小河坂青空)
解决方案:
==================== 坑点 =============================
设备名称一定要用 GetMonitorInfo 获取。用 EnumDisplayDevices 得到的设备名称是错的(或者说,index对应的不是正在使用的物理显示器)!
==================== 以下原帖 =============================
我正在写一个选区截图模块,目标之一是能适配多屏幕。
我的思路是获取整块虚拟屏幕(所有屏幕拼起来的画面)的完整截图。然后创造一个置顶的无边框窗口,窗口的左上角设为虚拟屏幕的左上角,窗口的宽高设为虚拟屏幕的宽高,然后在窗口上显示完整截图。这样,截图的位置就能与每个显示器的位置相对应。最后,监听鼠标拖拽来获取截图选区。
目前,我的代码在单块屏幕或多块同缩放比例的屏幕上工作良好。(缩放比例即为windows的更改文本、应用等项目的大小)。但是,当其中一块屏幕的缩放比例与其他不同时,我的程序会出现显示错位的情况;原因是 EnumDisplayMonitors() 只能获取每块屏幕的逻辑分辨率(缩放后)。也许需要获取物理分辨率或缩放系数来配合调整。
用这一段代码可以获得主屏幕的物理分辨率,但是似乎没办法获取其他屏幕。将 EnumDisplayMonitors 得到的第二屏幕的句柄填入 GetDC 或 GetDeviceCaps 似乎也不起作用。
所以求个助,有什么办法可以获取多屏幕的物理分辨率 or 缩放系数呢?或者说我截图模块的设计思路不对,有更好的思路呢?
from win32 import win32api, win32gui, win32print
import win32con # 为了得到两个常量,可以不导入
# 获取所有逻辑屏幕的信息,得到虚拟分辨率和逻辑监视器句柄 hMonitor
# 逻辑监视器信息(tuple): (hMonitor句柄, hdcMonitor没卵用, PyRECT包围盒)
scInfos = win32api.EnumDisplayMonitors()
for index, sc in enumerate(scInfos):
# 获取设备信息字典,得到设备名称 Device
# 物理设备信息(dict) = GetMonitorInfo(hMonitor)
info = win32api.GetMonitorInfo(sc[0])
# 为显示设备创建设备上下文,得到物理设备句柄 hDC
# 设备句柄(int) = CreateDC (设备名称, 设备名称 , None )
hDC = win32gui.CreateDC(info['Device'], info['Device'], None)
w = win32print.GetDeviceCaps(hDC, win32con.DESKTOPHORZRES)
h = win32print.GetDeviceCaps(hDC, win32con.DESKTOPVERTRES)
print(f'第{index}号屏幕:')
print(f'设备名称:{info["Device"]}')
print(f'物理分辨率 w: {w} h: {h}')
print(f'逻辑分辨率 w: {sc[2][2]-sc[2][0]} h: {sc[2][3]-sc[2][1]}')
print(f'逻辑坐标系 x: {sc[2][0]} y: {sc[2][1]}')
print()
==================== 坑点 =============================
设备名称一定要用 GetMonitorInfo 获取。用 EnumDisplayDevices 得到的设备名称是错的(或者说,index对应的不是正在使用的物理显示器)!
# 获取第二块屏幕的名称
index = 1 # 第二块屏幕
device = win32api.EnumDisplayDevices(DevNum=index) # 错!!
print(f'设备名称:{device.DeviceName}') # 这个DeviceName是不能被CreateDC识别的!
info = win32api.GetMonitorInfo( win32api.EnumDisplayMonitors()[index][0] ) # 对!
print(f'设备名称:{info["Device"]}') # 这个Device才能被CreateDC识别!
==================== 以下原帖 =============================
我正在写一个选区截图模块,目标之一是能适配多屏幕。
我的思路是获取整块虚拟屏幕(所有屏幕拼起来的画面)的完整截图。然后创造一个置顶的无边框窗口,窗口的左上角设为虚拟屏幕的左上角,窗口的宽高设为虚拟屏幕的宽高,然后在窗口上显示完整截图。这样,截图的位置就能与每个显示器的位置相对应。最后,监听鼠标拖拽来获取截图选区。
目前,我的代码在单块屏幕或多块同缩放比例的屏幕上工作良好。(缩放比例即为windows的更改文本、应用等项目的大小)。但是,当其中一块屏幕的缩放比例与其他不同时,我的程序会出现显示错位的情况;原因是 EnumDisplayMonitors() 只能获取每块屏幕的逻辑分辨率(缩放后)。也许需要获取物理分辨率或缩放系数来配合调整。
用这一段代码可以获得主屏幕的物理分辨率,但是似乎没办法获取其他屏幕。将 EnumDisplayMonitors 得到的第二屏幕的句柄填入 GetDC 或 GetDeviceCaps 似乎也不起作用。
hDC = win32gui.GetDC(0)
w = win32print.GetDeviceCaps(hDC, win32con.DESKTOPHORZRES)
h = win32print.GetDeviceCaps(hDC, win32con.DESKTOPVERTRES)
所以求个助,有什么办法可以获取多屏幕的物理分辨率 or 缩放系数呢?或者说我截图模块的设计思路不对,有更好的思路呢?
第0号屏幕:453059800
设备名称:\\.\DISPLAY1
物理分辨率 w: 1920 h: 1080
逻辑分辨率 w: 1920 h: 1080
逻辑坐标系 x: 0 y: 0
第1号屏幕:-654236552
设备名称:\\.\DISPLAY2
物理分辨率 w: 1080 h: 1920
逻辑分辨率 w: 1080 h: 1920
逻辑坐标系 x: -1080 y: -527
只要两块屏幕的缩放比例相同(比如你这都是100%),我的截屏都能完美匹配。头疼的是不同缩放比的屏幕组合