Trying to resolve blurry text tkinter + scaling on Windows 10 with high DPIs, but my approach is not Pythonic or unsafe

After hours of customization, I decided to use this code, which allows me to get around the familiar blurry / fuzzy text issue in Windows 10 on high DPI displays when using the Tkinter interfaces in Python 3.

I did not want to set the compatibility flag or expect others to do this, and I found that by noting the DPI awareness of 'on' through a DLL call and then extracting the DPI parameter, I could enlarge the GUI window and the borders inside.

However, before passing it on to others, I wanted to check if my approach of passing the "GUI" (an instance of tkinter.Tk ()) to the MakeTkDPIAware function in the main part of the body is suitable and gets this function to add custom properties to it is a healthy choice or may cause problems with the tkinter instance. The added properties are then available for use in the main body, but can it be assumed that this will always happen?

I was able to find out if this practice is known - and if it frowned or a poor design choice. (So โ€‹โ€‹often in Python, I may be so glad to get something working that I forgot to check this question at the time), so I hope someone can advise. It seemed that the most accurate way to โ€œrememberโ€ the scaling data, rather than create a new global variable.

I would be very interested to hear if another solution would be more Pythonic.

import re


def Get_HWND_DPI(window_handle):
    #To detect high DPI displays and avoid need to set Windows compatibility flags
    import os
    if os.name == "nt":
        from ctypes import windll, pointer, wintypes
        try:
            windll.shcore.SetProcessDpiAwareness(1)
        except Exception:
            pass  # this will fail on Windows Server and maybe early Windows
        DPI100pc = 96  # DPI 96 is 100% scaling
        DPI_type = 0  # MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2
        winH = wintypes.HWND(window_handle)
        monitorhandle = windll.user32.MonitorFromWindow(winH, wintypes.DWORD(2))  # MONITOR_DEFAULTTONEAREST = 2
        X = wintypes.UINT()
        Y = wintypes.UINT()
        try:
            windll.shcore.GetDpiForMonitor(monitorhandle, DPI_type, pointer(X), pointer(Y))
            return X.value, Y.value, (X.value + Y.value) / (2 * DPI100pc)
        except Exception:
            return 96, 96, 1  # Assume standard Windows DPI & scaling
    else:
        return None, None, 1  # What to do for other OSs?


def TkGeometryScale(s, cvtfunc):
    patt = r"(?P<W>\d+)x(?P<H>\d+)\+(?P<X>\d+)\+(?P<Y>\d+)"  # format "WxH+X+Y"
    R = re.compile(patt).search(s)
    G = str(cvtfunc(R.group("W"))) + "x"
    G += str(cvtfunc(R.group("H"))) + "+"
    G += str(cvtfunc(R.group("X"))) + "+"
    G += str(cvtfunc(R.group("Y")))
    return G


def MakeTkDPIAware(TKGUI):
    TKGUI.DPI_X, TKGUI.DPI_Y, TKGUI.DPI_scaling = Get_HWND_DPI(TKGUI.winfo_id())
    TKGUI.TkScale = lambda v: int(float(v) * TKGUI.DPI_scaling)
    TKGUI.TkGeometryScale = lambda s: TkGeometryScale(s, TKGUI.TkScale)


#Example use:
import tkinter


GUI = tkinter.Tk()
MakeTkDPIAware(GUI)  # Sets the windows flag + gets adds .DPI_scaling property
GUI.geometry(GUI.TkGeometryScale("600x200+200+100"))
gray = "#cccccc"
DemoFrame = tkinter.Frame(GUI, width=GUI.TkScale(580), height=GUI.TkScale(180), background=gray)
DemoFrame.place(x=GUI.TkScale(10), y=GUI.TkScale(10))
DemoFrame.pack_propagate(False)
LabelText = "Scale = " + str(GUI.DPI_scaling)
DemoLabel = tkinter.Label(DemoFrame, text=LabelText, width=10, height=1)
DemoLabel.pack(pady=GUI.TkScale(70))
+4
source share
1 answer

Just using windll.shcore.SetProcessDpiAwareness(1)and allowing font size adjustment, my problems arose in Windows 10.

I donโ€™t know why no one commented and helped. Blurred fonts are a pain, I would expect this thread to discuss and become the best solution for this Tkinter trouble ..

+5
source

Source: https://habr.com/ru/post/1664789/


All Articles