You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取系统显示缩放比例,实现Tkinter图标自适应缩放?

解决Tkinter GUI适配系统缩放比例的图标问题

近期用Tkinter开发GUI时发现:调整显示器分辨率时组件显示正常,但修改系统缩放比例后,仅文本类组件能自动适配,SVG图标无法正确缩放。

示例代码

import tkinter as tk

import io
import tksvg
from lxml import etree

import ctypes
from sys import platform

# resolution fix:
if platform == "win32":
    try:
        ctypes.windll.shcore.SetProcessDpiAwareness(2) # windows >= 8.1
    except:
        ctypes.windll.user32.SetProcessDPIAware() # windows <= 8.0

# my free svg icon:
dic_tool_bar={"start":'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg>'}

# function to use svg icon in Tkinter:
def svg_to_image(source, fill=None, scale_to_width=None, scale_to_height=None, scale=1):

    # parse xml data
    root = etree.fromstring(source)
    tree = etree.ElementTree(root)

    # set path fill color if provided
    if fill is not None:
        root.attrib["fill"] = fill

    imgdata = io.BytesIO()
    tree.write(imgdata)
    kw = {"data": imgdata.getvalue()}
    if scale_to_width:
        kw["scaletowidth"] = scale_to_width
    if scale_to_height:
        kw["scaletoheight"] = scale_to_height
    if scale != 1:
        kw["scale"] = scale

    return tksvg.SvgImage(**kw)

class MainWindow:
    def __init__(self):

        self.parent=tk.Tk()
        self.parent.title("TEST")
        self.parent.minsize(350, 300)
        self.icon_color="#484848"
        self.default_font=("Segoe UI",9, "bold")
        
        self.obj_tool_bar=ToolBar(self)
        self.obj_tool_bar.pack(fill=tk.BOTH)
        
        self.parent.mainloop()

class ToolBar(tk.Frame):
    def __init__(self, mw):
        super().__init__(mw.parent)

        self["background"]="white"
        self.default_font=mw.default_font
        self.icon_color=mw.icon_color

        self.columnconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)
        
        self.name=tk.Label(self, anchor="w", background="white", text="TEST!!", font=(self.default_font))
        self.border_up=tk.Frame(self, background="#bfbfbf", highlightthickness=0)
        self.border_down=tk.Frame(self, background="#bfbfbf", highlightthickness=0)

        self.start_logo=svg_to_image(dic_tool_bar["start"], fill=self.icon_color, scale=0.035)
        self.start=tk.Button(self, relief="flat", borderwidth=0, background="white", activebackground="white", image=self.start_logo)

        self.border_up.grid(column=0, row=0, sticky="new")
        self.name.grid(column=0, row=1, sticky="nsw", padx=(4,4), pady=(2,2))
        self.start.grid(column=0, row=1, sticky="ens", ipadx=4)
        self.border_down.grid(column=0, row=2, sticky="sew")

# start
app=MainWindow()

解决方案

1. 获取系统缩放比例

Windows平台可通过系统API获取当前DPI值,计算出缩放比例(默认DPI为96,缩放比例=当前DPI/96)。添加以下函数:

def get_system_scale():
    if platform == "win32":
        try:
            # 适配Windows 8.1及以上版本
            dpi = ctypes.windll.shcore.GetDpiForSystem()
            return dpi / 96.0
        except:
            # 适配Windows 8及以下版本
            user32 = ctypes.windll.user32
            user32.SetProcessDPIAware()
            dc = user32.GetDC(0)
            dpi_x = ctypes.windll.gdi32.GetDeviceCaps(dc, 88)  # 获取水平DPI
            user32.ReleaseDC(0, dc)
            return dpi_x / 96.0
    # Linux/macOS平台可补充对应逻辑,默认返回1.0
    return 1.0

2. 动态调整SVG图标大小

在创建图标时,将固定的scale值乘以系统缩放比例,让图标跟随系统缩放:
修改ToolBar类的图标创建代码:

# 获取系统缩放比例
system_scale = get_system_scale()
# 用系统缩放比例调整图标大小
self.start_logo = svg_to_image(dic_tool_bar["start"], fill=self.icon_color, scale=0.035 * system_scale)

3. 可选:支持动态缩放更新(用户中途修改缩放比例)

若需要支持用户在程序运行时修改系统缩放比例后自动更新图标,可在Windows平台监听WM_DPICHANGED消息,或定时检测缩放比例变化,重新生成图标并更新按钮的image属性。示例逻辑:

# 在MainWindow中添加定时检测逻辑
def check_scale_update(self):
    current_scale = get_system_scale()
    if hasattr(self, 'last_scale') and current_scale != self.last_scale:
        # 更新所有图标
        self.obj_tool_bar.update_icons(current_scale)
        self.last_scale = current_scale
    else:
        self.last_scale = current_scale
    self.parent.after(1000, self.check_scale_update)

# 在ToolBar中添加更新图标的方法
def update_icons(self, scale):
    self.start_logo = svg_to_image(dic_tool_bar["start"], fill=self.icon_color, scale=0.035 * scale)
    self.start.config(image=self.start_logo)

然后在MainWindow的__init__中启动定时检测:

self.last_scale = get_system_scale()
self.check_scale_update()

内容的提问来源于stack exchange,提问作者TurboC

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 21:17:23