Reputation: 11
Does someone know solution ( Qt methods / external applications / etc ) to test Qml / Quick UI for different DPI scaling and screen resolution on the Windows?
I am writing android qml application with custom ui elements, but when on my own android phone it looks normally, on the other android phones with other DPI it become very different.
I think to use Android emulators or even some virtual displays (like pyvirtualdisplay) but all this solutions are slow and hard to use. I am writing android app with also C++ code so its not only Qml files for rendering.
So maybe someone already decided this issue when dev on Qt for android before?
Ideally it will be some Qt method for QWidget (QQuickView) to render widget content with specific scaling (to simulate DPI).
Upvotes: 1
Views: 1954
Reputation: 4233
I have had "good enough" success by writing some helper code based on the ratio math described in Calculating Scaling Ratio (in the Qt docs).
The main drawback is that this requires you to form a habit around wrapping any raw literal sizing numbers in a helper function.
The starting point is code like the following, which only needs to execute once at the start of the application:
#include <QGuiApplication>
#include <QScreen>
#include <QDebug>
...
auto screen = QGuiApplication::primaryScreen();
const QRect currScreen = screen->geometry();
const qreal dpi = screen->logicalDotsPerInch();
const double refDpi = 96;
const double refHeight = 2160;
const double refWidth = 3840;
// These computations are taken nearly verbatim from:
// https://doc.qt.io/qt-5/scalability.html#calculating-scaling-ratio
// (archival) http://web.archive.org/web/20210511233243/https://doc.qt.io/qt-5/scalability.html#calculating-scaling-ratio
m_extentsRatio = qMin( currScreen.height() / refHeight, currScreen.width() / refWidth );
m_fontsRatio = qMin( currScreen.height() * refDpi / ( dpi * refHeight ), currScreen.width() * refDpi / ( dpi * refWidth ) );
qDebug() << "m_extentsRatio" << m_extentsRatio;
qDebug() << "m_fontsRatio" << m_fontsRatio;
To possibly state the obvious, these variables capture information about the host you are testing on (such as your laptop):
auto screen = QGuiApplication::primaryScreen();
const QRect currScreen = screen->geometry();
const qreal dpi = screen->logicalDotsPerInch();
In contrast:
refDpi
, refHeight
, and refWidth
represent the {DPI,height,width} of the screen you wish to "emulate" (such as some exotic cell phone model).
If you wanted to make this whole approach more readily "pluggable", you could pass in the refDpi
, refHeight
, and refWidth
as command-line arguments to your application, so that you could relaunch to emulate various target models without having to recompile.
The remaining pieces of the solution are to: (1) write a Q_INVOKABLE
helper function that your QML code can use, and (2) consistently prefer to wrap raw literal integer sizes in that helper function.
Concretely:
Q_INVOKABLE double asIfOnSomePhone( double input, bool isFontSize )
{
if( isFontSize )
{
return input * m_fontsRatio;
}
else
{
return input * m_extentsRatio;
}
}
And in the QML:
Layout.minimumHeight: localScreen.asIfOnSomePhone(157,
false /*isFontSize*/)
Layout.maximumHeight: Layout.minimumHeight
Layout.minimumWidth: localScreen.asIfOnSomePhone(625,
false /*isFontSize*/)
Layout.maximumWidth: Layout.minimumWidth
...
property font basicFont
basicFont.bold: false
basicFont.underline: false
basicFont.pointSize: localScreen.asIfOnSomePhone(14, true /*isFontSize*/)
basicFont.family: "Bitstream Vera Sans"
This has allowed me to comfortably iterate on a GUI design that is intended to ultimately run on a display with a much different resolution than the one I use in my day-to-day work. Once I began applying this tactic, I was able to transfer my design to the final platform with minimal surprises.
Another habit that I have developed that eases some of the struggles of writing a responsive UI in QML is to express many measurements as proportions of the total display height and/or width. I use helper functions named percentOfAppHeightCappedMinAndMax and percentOfAppWidthCappedMinAndMax. You can find a full working sample on GitHub.
Upvotes: 2