【问题标题】:Detect DPI/scaling factor in Python TkInter application在 Python TkInter 应用程序中检测 DPI/缩放因子
【发布时间】:2017-08-15 04:00:39
【问题描述】:

我希望我的应用程序能够检测它是否在 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 计算宽度(以 mm 为单位),错误地检测为 96,但我不确定它从哪里得到这个;我目前在 Linux 上,xrdb -query 返回的 DPI 为 196,所以它没有从 X 服务器获取 DPI。

有没有人知道一种跨平台的方式来获取我的屏幕 DPI,或者让 TkInter 能够正确获取它?或者,更重要的是:我怎样才能让 TkInter 在 HiDPI 屏幕上玩得很好,并且在普通屏幕上也能正常工作?谢谢!

【问题讨论】:

标签: python tkinter dpi


【解决方案1】:

这个答案来自这个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”)。

【讨论】:

    【解决方案2】:

    我知道我回答这个问题很晚,但我想扩展 @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()
    

    【讨论】:

      【解决方案3】:

      我使用的是 TclTk,而不是 TkInter,我知道如何做到这一点的唯一方法是从字体指标中计算出来......

      % 字体规格 Tk_DefaultFont -ascent 30 -descent 8 -linespace 38 -fixed 0

      行空间大约是 DPI 的 0.2 倍(目前这里设置为 192)

      【讨论】:

      • (糟糕,这个答案的格式是我的命令“font metrics Tk_DefaultFont”的输出,与命令本身在同一行,很抱歉造成混淆)
      猜你喜欢
      • 2016-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-25
      • 2021-01-18
      • 1970-01-01
      • 2020-10-11
      • 2014-08-13
      相关资源
      最近更新 更多