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

时间:2017-03-22 20:16:20

标签: python tkinter dpi

我希望我的应用程序能够检测它是否在HiDPI屏幕上运行,如果是,请自行调整以便可用。如this question所述,我知道我需要设置一个比例因子,这个因素应该是我的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返回的DPI为196,因此它没有从X服务器获取DPI。

有没有人知道一种跨平台的方式来获取我的屏幕DPI,或者让TkInter能够正确地获取它?或者更重要的是:如何让TkInter在HiDPI屏幕上运行良好,并且在正常情况下也可以正常工作?谢谢!

3 个答案:

答案 0 :(得分:3)

此答案来自此link,并在上面留有评论,但经过数小时的搜索才能找到。我还没有任何问题,但是如果它在您的系统上不起作用,请告诉我!

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厘米(as found here)上的像素数。 因此,要获得dpi,我们要求函数提供1英寸屏幕(“ 1i”)中的像素数。

答案 1 :(得分:0)

我使用的是TclTk,而不是TkInter,而我知道如何执行此操作的唯一方法是从字体指标中得出答案...

%字体指标Tk_DefaultFont -上升30-下降8-行距38-固定0

行距大约是DPI的0.2倍(此处当前设置为192)

答案 2 :(得分:0)

我知道我要晚回答这个问题,但是我想扩展@Andrew Pye的想法。没错,只要您使用“宽度”或“高度”或“ pady”或以像素为单位的任何值,带有tkinter的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()