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

问题描述 投票:0回答:4

我希望我的应用程序能够检测它是否在 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
返回的 DPI 为 196,因此它无法从 X 服务器获取 DPI。

有谁知道一种跨平台的方法来获取我的屏幕 DPI,或者使 TkInter 能够正确获取它?或者,更重要的是:如何使 TkInter 在 HiDPI 屏幕上运行良好,并且在普通屏幕上也能正常工作?谢谢!

python tkinter dpi
4个回答
9
投票

这个答案来自这个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 厘米上的像素数(如此处所示)。 因此,为了获得 dpi,我们向函数询问 1 英寸屏幕(“1i”)中的像素数。


6
投票

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

1
投票

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

% 字体规格 Tk_DefaultFont -上升 30 -下降 8 -行间距 38 -固定 0

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


0
投票

我是 Python 和 Tkinter 的新手,但这个解决方案适用于我的 4K 显示器上的任何类型的窗口大小。我希望它也对你有用:

import tkinter as tk
import customtkinter as ctk
from customtkinter import *

app = CTk()

screen_width = app.winfo_screenwidth()
screen_height = app.winfo_screenheight()
print("screen width = ", screen_width)
print("screen height = ", screen_height)

ratio_width = screen_width/3840
ratio_height = screen_height/2160
print("ratio width = ", ratio_width)
print("ratio height = ", ratio_height)

width_I_want = 1920
height_I_want = 1080

width = int(width_I_want*ratio_width)
height = int(height_I_want*ratio_height)
print("width = ", width)
print("height = ", height)

x = int((screen_width - width) /2/ratio_width)
y = int((screen_height - height) /2/ratio_height)
print("x = ", x)
print("y = ", y)

app.geometry(f"{width}x{height}+{x}+{y}")
set_appearance_mode("dark")

app.mainloop()
© www.soinside.com 2019 - 2024. All rights reserved.