如何获取系统显示缩放比例,实现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
相关产品推荐
相关产品推荐

