Reputation: 918
In these days I realized that there is an issue with my GUI created with Tkinter and the system display settings (scale option).
If you change the display resolution, it's ok, because the pixel are always the same, but if you change the scale, it affects only the widgets that use text inside them. Imagines can talk better than thousand words:
Below the code:
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()
How can I solve this issue? I saw other softwares (not written in Python) with a toolbar, and in all of them, with different kind of system scales, the icons resolution changed always properly. How can I reach the same behaviour with Tkinter?
In my example, I was thinking about to create a custom function to change the resolution of the self.start_logo
in according with the system scale option, but.. How? To do that, I need to get the system scale value or something like that, .. how can I do that? Do you have some advices?
Upvotes: 1
Views: 154
Reputation: 1121
Currently, the user can set the icon’s size manually using this command:
self.start_logo=svg_to_image(dic_tool_bar["start"], fill=self.icon_color, scale=0.035)
To automate the process, we can use the following function to determine the current DPI:
from PyQt5.QtWidgets import QApplication as QApp
def get_dpi():
dpi = 0
with QApp([]) as app:
dpi = app.screens()[0].physicalDotsPerInch()
return dpi
You can read more about QApplication in the docs and here - note that many examples use sys.argv, but a simple empty list (as shown above) works just fine.
Then you can update your call to use the dpi to figure out the scale. Assuming the value from your question, 0.035, corresponds to normal dpi, you could scale this value by the computed dpi as a fraction of the baseline.
Upvotes: 0