[Development] Qt 6 high-dpi support
Henry Skoglund
henry at tungware.se
Thu May 14 03:45:45 CEST 2020
On 2020-05-13 23:41, Henry Skoglund wrote:
> On 2020-05-13 16:53, Morten Sørvig wrote:
>> We are indeed planning to addreess high-DPI support for Qt 6. You can
>> test the implementation on
>> Qt 5.14+ today by setting
>>
>> QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
>> QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
>>
>> This should make sure labels and line edits are correctly sized, also
>> for 125% and 150%.
>>
>> Interestingly, Qt will then “lie” about the about the screen size the
>> same way that dpiawareness=0
>> does, although while rendering at the full resolution (so no
>> blurriness).
>>
>> Morten
> Thank you for this!
>
> All of my apps had the blurriness problem, in fact recently one of my
> users on a brand new laptop (with a 150% scale screen) complained and
> said that my program looked like "East Germany" which (if you're old
> enough to realize) is not a compliment :-(
>
> My old code (I wanted a fire-and-forget solution, i.e. no qt.conf
> which is easily forgotten, so C++) was this:
> ...
> #if !defined(DPI_AWARENESS_CONTEXT_UNAWARE)
> // (these lines are copied from a fresh windef.h)
> DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
>
> #define DPI_AWARENESS_CONTEXT_UNAWARE ((DPI_AWARENESS_CONTEXT)-1)
> #define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
> ((DPI_AWARENESS_CONTEXT)-2)
> #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
> ((DPI_AWARENESS_CONTEXT)-3)
> #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
> ((DPI_AWARENESS_CONTEXT)-4)
> #define DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED
> ((DPI_AWARENESS_CONTEXT)-5)
> #endif
> static const int nnBuild1703 = 15063; // can use
> DPI_AWARENESS_CONTEXT_UNAWARE
> static const int nnBuild1809 = 17763; // can use
> DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED
>
> // Windows 10 build 1703 or later?
> if (QOperatingSystemVersion::current() >=
> QOperatingSystemVersion(QOperatingSystemVersion::Windows,10,0,nnBuild1703))
> {
> // dynamically resolve the address to SetProcessDpiAwarenessContext()
> auto f = reinterpret_cast<bool (__stdcall
> *)(DPI_AWARENESS_CONTEXT)>(QLibrary("user32.dll").resolve("SetProcessDpiAwarenessContext"));
> auto value = DPI_AWARENESS_CONTEXT_UNAWARE;
>
> // on build 1809 (or later)? let's try GDISCALED
> if (QOperatingSystemVersion::current() >=
> QOperatingSystemVersion(QOperatingSystemVersion::Windows,10,0,nnBuild1809))
> value = DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED;
>
> bool bOk = f(value);
> if (!bOk)
> qWarning("SetProcessDpiAwarenessContext() failed.");
> }
> ...
> I think very few of my users are on Windows 8.1 so I leapfrogged the
> DpiAware functions in SHCore.dll and went for the new ones in Windows
> 10 (they are in user32.dll) but to no avail, it was East Germany
> anyway, here are 2 screenshots, first from a 100% screen for
> comparison, then from a 125% screen using my code above (I've
> anonymized patient names etc.):
> https://tripleboot.org/Pictures/Scale100Percent.png
> https://tripleboot.org/Pictures/Scale125PercentDpiAwareness0.png
>
> On the 100% screen all is fine and dandy but on the 125% screen ->
> fuzziness galore.
>
> So I tossed the code above and tried your 2 liner from today:
> ...
> QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
> QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
>
> ...
>
> Voila: https://tripleboot.org/Pictures/Scale125PercentPassThrough.png
> Goodbye East Germany!
>
> Thank you again /Henry
>
> P.S. Now this wouldn't be complete without some small complaint, I'm
> thinking of the horizontal lines for separating the different rows of
> patients (they are QFrames, or "Horizontal Line" as they are called in
> Qt Creator's widget designer).
> I insert them manually on top of the QTableWidget, they have a
> lineWidth of 1 and are rendered as such on the 100% or the 200%
> screens. But on 125%, 150% etc. screens they are rendered a bit uneven
> using the new 2 liner/passthrough code, you can see it on my last/3rd
> screenshot. I suspect it's some kind of rounding problem. This is
> *not* a big deal, just me being pedantic.
About that "rounding problem", don't bother with it, I think I fixed it,
or at least understand it:
turns it occurs on 125% and 175% screens every 4 row, and on a 150%
screen every 2nd row.
So I added this tweaking code (which simulates the rounding error) where
I calculcate the QRect for the QFrame:
...
int top = ...... // the top for the QFrame's geometry for the current row
int nDPRatioPercent = qRound(devicePixelRatioF() * 100); // will be 100,
125, 150 etc.
int topNudged = (((top * nDPRatioPercent) / 100) * 100) / nDPRatioPercent;
...
topNudged will differ with 1 pixel (compared to top) for every 4th row
on 125% and 175% screens, and for every 2nd row on 150% screens, so I
just use topNudged instead of top for QFrame's geometry. With that tweak
I think I have a good result, screenshot here:
https://tripleboot.org/Pictures/Scale125PercentWithNudge.png
Rgrds Henry
More information about the Development
mailing list