MulDiv skaliert in X-Richtung falsch bei 125% und 175%. 100% und 150% sind okay.
-
Hi!
Wie in meinem anderen Thread (https://www.c-plusplus.net/forum/topic/352434/bunte-kästchen-wie-in-den-defrag-tools) erwähnt, habe ich mir ein Dialogfenster gebaut, welches neben per Designer hinzugefügten Elementen auch einige per Code hinzugefügte PNG Grafiken enthält.
Nun habe ich das Problem, dass die Position der Grafiken nicht mehr stimmt, sobald ich unter Windows die Skalierung des Desktops auf 125% (120dpi) oder 175%(168dpi) stelle. Bei 100% und 150% sind die Positionen der Elemente korrekt.
Mein Layout inkl. der X/Y-Werte habe ich unter 100% Skalierung entworfen. Für die Anpassung der Positionen der PNG-Grafiken im Dialog nutze ich die folgende Funktionen:
int currentDpi = GetDpiForWindow(GetSafeHwnd()); [...] m_offsetX = MulDiv(m_offsetX, currentDpi, 96); m_offsetY = MulDiv(m_offsetY, currentDpi, 96); [...]
Wie gesagt, bei 100% und 150% stimmen die Offsets. Bei 125% und bei 175% sind die per MulDiv ermittelten Werte zu groß, so dass alle Elemente zu weit nach rechts gerückt sind. Dies ist aber nur in X-Richtung der Fall! In Y-Richtung sieht es eigentlich ganz okay aus.
Mein Workaround ist momentan der Folgende:
[...] if (currentDpi >96 && currentDpi <144) { m_offsetX = round(m_offsetX * 1.14); [...] } else { m_offsetX = MulDiv(m_offsetX, currentDpi, 96); [...] }
Das erscheint mir aber irgendwie nicht zielführend und ich weiß auch nicht, ob dass dann nur bei mir stimmt oder auch bei allen anderen.
Mein Dialogfenster ist laut VS2019 Designer bzw. Resource-Datei 495x437 groß. Dargestellt wird es dann bei 100% in 745x742.
Ist:
100% => 745x742 = 1,00 x 1,00
125% => 868 x 913 = 1,165 x 1,230
150% => 1116 x 1084 = 1,499 x 1,461Soll (nach meinem Verständnis):
125% => 931x927 => 1,25 x 1,25
150% => 1117x1113 => 1,50 x 1,50In den Manifest-Einstellungen habe ich "DPI Awareness" auf "High DPI Aware" stehen. Okay, ich kann hier auf "None" stellen, aber dann sieht ab 125% alles ekelhaft matschig aus.
Welchen Trick kenne ich hier noch nicht?
Vielen lieben Dank!
-
Dann teste
MulDiv
doch mal mit Konstanten und überprüf die Ergebnisse. Ich habe jedenfalls keine Auffälligkeiten entdeckt, liegt dein Fehler evtl. woanders?
-
@ikarsian Ich vermute mal deine Resource wird anhand der Font-Grösse skaliert, d.h. u.U. in X und Y Richtung nicht gleichmässig. Siehst du ja auch anhand deiner Zahlen, 495x437 (deutlich unterschiedliche Seiten) und 745x742 (fast quadratisch) haben offensichtlich nicht den selben Aspect Ratio.
-
@hustbaer Ach du Ka.... das ist doch echt nicht wahr! O.O Habe mal versuchsweise eine andere Schrift genommen (Consolas, feste Breite) und damit wird das Fenster bei 125% schon direkt viel größer.
Jetzt muss ich überlegen, wie ich das irgendwie sinnvoll hinbekomme. Macht es Sinn, wenn ich irgendwie die Koordinaten von z.B. meinen verwendeten GroupBoxes auslese und dann hierauf einfach den nötigen Offset draufrechne? Ich hoffe nicht, dass ich jetzt jedes einzelne Control per Sourcecode generieren muss...
-
@DocShoe Das MulDiv scheint tatsächlich nicht das Problem zu sein, sondern die automatische Skalierung der Control-Elemente durch Windows - in Anhängigkeit der verwendeten Schriftart.
Obwohl mir tatsächlich schleierhaft ist, wieso diese bei den 125% und 175% anders skaliert als bei 100% und 150%. Eventuell stelle ich das Fenster morgen einmal auf gerade Werte wie 800x600 und gucke dann noch einmal, was Windows daraus macht.
-
@ikarsian sagte in MulDiv skaliert in X-Richtung falsch bei 125% und 175%. 100% und 150% sind okay.:
@hustbaer Ach du Ka.... das ist doch echt nicht wahr! O.O Habe mal versuchsweise eine andere Schrift genommen (Consolas, feste Breite) und damit wird das Fenster bei 125% schon direkt viel größer.
Naja, das ist soweit ich weiss Standard bei MFC. Also auch ohne "high DPI" Zeugs werden Dialoge mit der Schriftart skaliert. Ich mach schon ewig kein MFC mehr, aber ich meine mich zu erinnern dass man das abschalten kann.
Was dann geht, ist die Controls selbst zu repositionieren bevor das Fenster angezeigt wird. Dazu kannst du einfach in einer Schleife alle Child-Controls des Dialogs durchgehen und anhand des DPI Werts alle Koordinaten skalieren und die Controls repositionieren.
Kann aber auch leicht sein dass es dafür eine viel elegantere Möglichkeit gibt. Wie gesagt, ich mache schon lang nix mehr mit MFC
Macht es Sinn, wenn ich irgendwie die Koordinaten von z.B. meinen verwendeten GroupBoxes auslese und dann hierauf einfach den nötigen Offset draufrechne?
Naja... wenn du damit leben kannst dass die Skalierung dir den Aspect-Ratio ändert, dann kannst du das sicher so machen. Bzw. ich hab dazu oft unsichtbare "static" Controls verwendet. Also wenn ich einen Platzhalter gebraucht hab den ich im Editor schön positionieren kann und der dann mit der Font-Grösse mit skaliert.
Ich hoffe nicht, dass ich jetzt jedes einzelne Control per Sourcecode generieren muss...
Das wird sich ganz sicher vermeiden lassen
-
@hustbaer Meine Lösung ist jetzt tatsächlich, dass ich die skalierten XY-Koordinaten von zwei Controls (GroupBox) als Referenzpunkt nehme und anhand derer alle nötigen Offsets für die Grafiken berechne. Da treten dann zwar Ungenauigkeiten auf, weil ein Offset dann, statt bei (x)12,88/(y)12,31, bei 12/12 liegt. Aber das kann ich verschmerzen. Sieht man nur dann, wenn man wild zwischen 100%, 125%, 150% und 175% wechselt.
Also es ist jetzt so:
|x|P|g|P|g|P|g|P|g|P|g|P|g|P|g|P|x|
x ist eine fester Abstand, links und rechts.
P ist das PNG
g ist der Abstand zwischen den PNG, so dass links und rechts x einigermaßen stimmtAuf die Breite von 8xP ist dann dann maximal eine Differenz von 7 Pixeln zum rechten x hin.