Tentativa de resolver o texto tkinter embaçado + redimensionar em telas de alto DPI do Windows 10, mas preocupada, minha abordagem não é Pythonic ou é insegura
Após horas de ajustes, decidi-me por este código que me permite contornar o problema familiar de texto embaçado / difuso no Windows 10 em telas de alto DPI ao usar interfaces Tkinter no Python 3.
Eu não queria ter que definir o sinalizador de compatibilidade ou esperar que outros o fizessem e descobri que, sinalizando a conscientização de DPI 'on' por meio de uma chamada DLL e, em seguida, recuperando a configuração de DPI, eu poderia aumentar a janela da GUI e os quadros dentro .
Antes de passar isso para outras pessoas, no entanto, eu queria verificar se minha abordagem de passar 'GUI' (uma instância tkinter.Tk ()) para a função MakeTkDPIAware no corpo principal e fazer com que essa função adicione propriedades personalizadas a ele são saudáveis. escolha ou corre o risco de causar problemas para a instância tkinter. As propriedades adicionadas estão disponíveis para uso no corpo principal, mas é seguro supor que isso sempre aconteça?
Consegui descobrir se essa prática é conhecida - e se é mal vista ou uma má escolha de design. (Muitas vezes, em Python, posso estar tão empolgado com o trabalho que esqueço de verificar esse tipo de pergunta na época), então espero que alguém possa aconselhá-lo. Parecia a maneira mais organizada de 'lembrar' os dados de escala, em vez de criar uma nova variável global.
Eu ficaria muito interessado em saber se outra solução seria mais pitônica.
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))