[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