我正在使用一台4K显示器(3840x2160)。
from tkinter import *
root = Tk()
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
print (width, height)
mainloop()
当我运行这段代码时,输出的大小为1536乘以864。请问为什么会这样,并且我该如何解决呢?谢谢。我正在使用一台4K显示器(3840x2160)。
from tkinter import *
root = Tk()
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
print (width, height)
mainloop()
当我运行这段代码时,输出的大小为1536乘以864。请问为什么会这样,并且我该如何解决呢?谢谢。这应该是DPI感知的问题,请参阅MSDN官方文档。
在Windows 10中:
您需要使用SetProcessDpiAwareness
(或SetThreadDpiAwarenessContext
),尝试使用:
import tkinter as tk
import ctypes
ctypes.windll.shcore.SetProcessDpiAwareness(2) # your windows version should >= 8.1,it will raise exception.
root = tk.Tk()
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
print(width,height)
root.mainloop()
在Windows XP或7中,您需要使用SetProcessDPIAware()
所以所有的代码可能是:
import tkinter as tk
import ctypes
try:
ctypes.windll.shcore.SetProcessDpiAwareness(2) # if your windows version >= 8.1
except:
ctypes.windll.user32.SetProcessDPIAware() # win 8.0 or less
root = tk.Tk()
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
print(width,height)
root.mainloop()
tk.call('tk', 'scaling')
,也可以。但当您使用ImageGrab.grab((xxxx))
(以及需要传递位置参数的其他函数)时,可能会获得错误的大小。tk
没有使用已知的解决方法。tk
的源代码,在文件win/tkWinX.c
中,函数TkWinDisplayChanged
使用windows API调用GetDeviceCaps
获取屏幕宽度和高度,参数为HORZRES
和VERTRES
。GetDeviceCaps
报告显示驱动程序提供的信息。如果显示驱动程序拒绝报告任何信息,则GetDeviceCaps
将根据固定计算计算信息。如果显示驱动程序报告无效信息,则GetDeviceCaps返回无效信息。此外,如果显示驱动程序拒绝报告信息,则GetDeviceCaps可能计算错误的信息,因为它假定固定DPI(96 DPI)或固定大小(取决于显示驱动程序提供和未提供的信息)。不幸的是,实现Windows显示驱动程序模型(WDDM)(在Windows Vista中引入)的显示驱动程序会导致GDI无法获取信息,因此GetDeviceCaps必须始终计算信息。”GetDeviceCaps
的显示信息。”GetDeviceCaps
值,LOGPIXELSX
和LOGPIXELSY
(每英寸x和y逻辑英寸中的像素数)来计算真实的窗口大小。 GetDeviceCaps
似乎使用的“默认”DPI为96。tk
代码中的这个片段,你可以看到tk
使用LOGPIXELSX
和LOGPIXELSY
来计算屏幕大小(以毫米为单位)。void
TkWinDisplayChanged(
Display *display)
{
HDC dc;
Screen *screen;
if (display == NULL || display->screens == NULL) {
return;
}
screen = display->screens;
dc = GetDC(NULL);
screen->width = GetDeviceCaps(dc, HORZRES);
screen->height = GetDeviceCaps(dc, VERTRES);
screen->mwidth = MulDiv(screen->width, 254,
GetDeviceCaps(dc, LOGPIXELSX) * 10);
screen->mheight = MulDiv(screen->height, 254,
GetDeviceCaps(dc, LOGPIXELSY) * 10);
这个值似乎被用于计算 winfo_fpixels()
。因此,我认为如果你使用 root.winfo_fpixels('1i')
,你将得到一个可靠的 DPI 值。
所以,请尝试这样做:
import tkinter as tk
root = tk.Tk()
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
dpi = root.winfo_fpixels('1i')
real_width = int(width * dpi / 96)
real_height = int(height * dpi / 96)
print('real width should be', real_width)
print('real height should be', real_height)
编辑 解决方法是设置tkinter
的缩放因子:
factor = dpi / 72
root.tk.call('tk', 'scaling', factor)
3840 / 1536 = 2.5
2160 / 864 = 2.5