我正在使用4k显示器(3840x2160)。
from tkinter import *
root = Tk()
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
print (width, height)
mainloop()
当我运行此代码时,输出为1536 x 864
有人可以解释为什么会这样,以及我如何解决它,谢谢。
答案 0 :(得分:2)
看着问题,这似乎是ms-windows中的缺陷,tk
没有使用已知的解决方法。
查看tk
的源代码,在文件win/tkWinX.c
中,函数TkWinDisplayChanged
使用Windows API调用GetDeviceCaps
来获取带有参数的屏幕宽度和高度HORZRES
和VERTRES
。
不幸的是,this page声明(强调我):
注意
GetDeviceCaps
报告显示驱动程序提供的信息。 如果显示驱动程序拒绝报告任何信息,则GetDeviceCaps
将基于固定的计算来计算该信息。。如果显示驱动程序报告了无效的信息,则GetDeviceCaps将返回无效的信息。另外,如果显示驱动程序拒绝报告信息,则GetDeviceCaps可能会计算不正确的信息,因为它假定使用固定的DPI(96 DPI)或固定的大小(取决于显示驱动程序提供和未提供的信息)。 不幸的是,已实施到Windows Display Driver Model(WDDM)(Windows Vista中引入)的显示驱动程序导致GDI无法获取信息,因此GetDeviceCaps必须始终计算信息。
我将其表述如下: “在Windows Vista之后,将不信任来自GetDeviceCaps
的显示信息。”
有this page about high-dpi displays。
此页面使用其他GetDeviceCaps
和LOGPIXELSX
和LOGPIXELSY
值(x和y中每“逻辑英寸”的像素数)来计算 real 窗口尺寸。
GetDeviceCaps
似乎使用的“默认” DPI是96。
看一下tk
中的win/tkWinX.c
代码片段,您可以看到tk
使用LOGPIXELSX
和LOGPIXELSY
来计算屏幕尺寸,单位为mm。
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)
答案 1 :(得分:1)
这应该是DPI感知的问题,请在MSDN official document中阅读。
在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()
Requirements of SetProcessDpiAwareness
在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))
(以及那些需要传递position参数的函数)时,可能会得到错误的大小。
答案 2 :(得分:0)
我在Raspberry pi上运行了代码,并为我的显示器(不是4K显示器)获得了正确的值。
我没有解决方案,但我发现您的预期/观察到的答案之间的比例是
3840 / 1536 = 2.5
2160 / 864 = 2.5
4K显示器的屏幕驱动程序可能会影响实际物理像素(3840x2160)和某些概念("逻辑像素")。目的是避免某些软件显示,例如,具有8个真实物理像素的8点文本,因为这是不可读的。
我无法测试这个(我没有硬件),这只是一个假设。我也可能没有确切的术语。
(顺便说一句,在iOS上有点与像素的概念 - 你可以搜索这些术语。即使它没有解答你的问题,也可能是一个类似的问题)。