在Python TkInter应用程序中检测DPI/缩放因子

8

我希望我的应用程序能够检测是否在HiDPI屏幕上运行,如果是,则缩放自身以便可用。如此问题中所述,我知道需要设置缩放因子,而该因子应为我的DPI除以72;我的困难在于获取我的DPI。以下是我的内容:

def get_dpi(window):
    MM_TO_IN = 1/25.4
    pxw = window.master.winfo_screenwidth()
    inw = window.master.winfo_screenmmwidth() * MM_TO_IN
    return pxw/inw

root = Tk()
root.tk.call('tk', 'scaling', get_dpi(root)/72)

当前代码无法正常工作(在我的4k笔记本上测试)。进一步检查后,我发现get_dpi()返回96.0,并且winfo_screenmmwidth()返回1016!(幸运的是,我的笔记本没有超过一米宽)。

我猜测TkInter从某个内部检测到的DPI中计算出毫米宽度,将其错误地检测为96,但我不确定它从哪里获取这个值;我目前在Linux上,xrdb -query返回196 DPI,因此它没有从X服务器获取DPI。

是否有人知道跨平台获取屏幕DPI的方法,或者让TkInter能够正确获取它的方法?或者更重要的是:如何使TkInter在HiDPI屏幕上正常工作并在普通屏幕上表现良好?谢谢!


1
请点击以下链接查看有关编程的内容:https://mail.python.org/pipermail/tkinter-discuss/2009-March/001863.html。 - Oblivion
你找到解决方法了吗?我也遇到了同样的问题,如果您可以发布如何使其正常工作的方法,那将对我很有帮助。 - Aman Grover
3个回答

9

以下答案来自于这个链接,并作为以上的一条评论留下。但是要花费几个小时才能找到它。我还没有遇到任何问题,但如果在您的系统上没有起作用,请告诉我!

import tkinter
root = tkinter.Tk()
dpi = root.winfo_fpixels('1i')

这里的文档说明如下:
winfo_fpixels(number)
# Return the number of pixels for the given distance NUMBER (e.g. "3c") as float

一个距离数是一个数字后面跟着一个单位,因此3c表示3厘米,该函数给出在屏幕上3厘米的像素数(在这里找到)。 要获取dpi,我们向函数询问屏幕上1英寸中的像素数(“1i”)。

5

我知道我回答这个问题有些晚,但我想扩展一下@Andrew Pye的想法。你是对的,使用tkinter创建GUI时,每当你使用“width”、“height”、“pady”或任何以像素为单位测量的内容,GUI在不同DPI的不同显示器上看起来都会有所不同。我在台式机上创建了一个GUI,但后来在我的4K笔记本电脑上运行相同的GUI时发现(窗口和微件出现得要小得多)。这是我解决它的方法,对我有效。

from tkinter import *

ORIGINAL_DPI = 240.23645320197045   # This is the DPI of the computer you're making/testing the script on.

def get_dpi():
    screen = Tk()
    current_dpi = screen.winfo_fpixels('1i')
    screen.destroy()
    return current_dpi

SCALE = get_dpi()/ORIGINAL_DPI    # Now this is the appropriate scale factor you were mentioning.

# Now every time you use a dimension in pixels, replace it with scaled(*pixel dimension*)
def scaled(original_width):
    return round(original_width * SCALE)

if __name__ == '__main__':
    root = Tk()
    root.geometry(f'{scaled(500)}x{scaled(500)}')    # This window now has the same size across all monitors. Notice that the scaled factor is one if the script is being run on a the same computer with ORIGINAL_DPI. 
    root.mainloop()

我怎样才能获取原始DPI值? - TurboC
1
在感兴趣的计算机上运行 get_dpi() 函数并打印其值。 - Gabe Morris

1
我正在使用TclTk而不是TkInter,我知道的唯一方法是从字体度量中计算出来...
% 字体度量 Tk_DefaultFont -上升 30 -下降 8 -行间距 38 -固定 0
行间距大约是DPI的0.2倍(当前设置为192)

抱歉,这个答案的格式混乱了,我在同一行中使用了“font metrics Tk_DefaultFont”命令的输出结果。对于造成的困惑,我表示抱歉。 - Jasper Taylor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接