How to change logical DPI for QML app? - qt

I want to control the pointSize-to-pixel scaling of all Text elements in my Qt 5.2.1 QML/C++ app.
I have a QML singleton component with target display properties like width, height and dot pitch that calculates appropriate pixel sizes for common dimensions such as the recommended size in pixels for a touchscreen button. This works fine for controls I write, but the Text element has a perfectly good font.pointSize that I would like to use if I could just set the logical DPI used for text scaling.
I use this to simulate target devices with very different screen DPI while debugging on my 96 DPI development screen. For example, I would like to run my app that targets a 1280x720 133DPI display and has an element like:
Text { font.pointSize: 72; text: “Xy” }
display 133 pixels tall, not the 96 pixel tall text I get because the OS tells Qt that I have a 96 DPI monitor attached. I want to override the logical DPI scaling for my application.
I can see the logicalDotsPerInchX through the QGuiApplication QScreen list. There is tons of documentation on how to get the logical DPI. But I cannot find any information on how to change it.
How can I change the logical DPI for my Qt app?

I don't think you can simply change the DPI values in the QScreen class (there are only public getter methods).
Maybe there are some "hacks" for that problem if you modify the QScreen class and add a public setter or something yourself and then recompile Qt, but that might be some work and takes a lot of time...
Another solution might be to just add a scale factor to your font sizes? I don't know how many you have but that can be simply done in QML and I use something like that even for production setting to scale the fonts and other sizes properly to the device.
You could use Screen.pixelDensityor just define your custom QML property and multiply that to all font sizes? if you do that you can dynamically change the sizes while the app is running.

Related

Whats the proper way for scaling text?

I am developing a Qt QML based application that runs on both Desktop and Mobile operating systems. I am having problems with proper fonts and components scaling- what does look good on large, desktop monitor is barely visible on a mobile phone, even though the scaling is the same.
I was wondering, what is the proper approach for this problem? I would like to run the same code on all platforms. For example, is there a way for a font to stay the same size (in mm or inches), no matter the screen resolution and size?
In QML I am always setting the font.pointSize property. It is scaled evenly, but because of that, the font are barely visible on mobile devices.
Have you tried font.pixelSize property yet?
I think this will be good for you.
"Sets the font size in pixels.
Using this function makes the font device dependent. Use pointSize to set the size of the font in a device independent manner."
https://doc.qt.io/qt-5/qml-qtquick-text.html#font.pixelSize-prop

Relative UI unit in QT Widgets QSS stylesheets

My current UI doesn't use QT widgets paint and it's mostly done with QSS markup. The current styles are defined in pixels and I could not find anything in the QT documentation that allows the styles to be defined as relative unit as opposed to pixels. I would like to know if it's possible to use something relative then tie that unit to a ROOT font-size. In case I need to adjust for a particular screen size like a battery charger IOT device that has a small screen, while my main UI was designed for very large screens (27 inch monitor). So instead of me styling a button just for the IOT device, I shrink the base unit (technique similar to web responsive like REM) then everything like fonts, padding, buttons shrink proportionally. Is that something that QT supports?
To my knowledge vanilla Qt Widgets don't support free scaling at all. Recently high-DPI display support was added, but it only scales in fixed ratios (e.g. 1:2). There are other options to get scaling in Qt applications:
Use QML (didn't try this yet myself, but it's developed with adaption to different displays in mind)
Use QGraphicsScene with QGraphicsWidget
Use QGraphicsScene with custom graphics objects that implement the behavior you need
Roll your own widgets
I'd love to stand corrected on this answer - maybe in a future Qt version...?

Using high DPI images with QtStyleSheet

I have a Qt Widgets application using Qt styleSheet for the app look and feel. We want to add support for high-DPI displays, as on these, the app looks very small. The first step was thus to call:
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
This does most of the job and the app window is big enough. The only remaining issue is the resolution of the images used in style sheet.
Say that we have:
QCheckBox::indicator::unchecked {
image: url(:/res/checkbox_off.png);
}
MainWindow QFrame {
background-image: url(:/res/background.png);
}
When using high DPI scaling, these images get upscaled accordingly which is a problem. For high DPI, I would prefer to use higher resolution images to make them look as crisp as possible.
As expected, a naive approach of simply providing the images in higher resolution does not work - it makes images and controls twice as large (on both low and high DPI screens).
Qt documentation on QImageReader states that
The high resolution version is marked by the suffix #2x on the base name. The image read will have its device pixel ratio set to a value of 2.
However, I have provided these resources with twice the resolution, added them to qrc file, but the images displayed are still the same on device with pixel_ratio of 3.
Are there any other steps needed to make this automatic image loading work with stylesheets?

QDialogs using layouts but with a fixed size (no size grip)

I have several QDialogs that I have made in Qt Designer that use layouts, so the dialog can size itself correctly depending on the size of its children. The size of its children is run-time dependent (variable text fields, system font size etc).
It does not make sense for my dialog to be user-resizeable, so I want the size grip disabled. As far as I can tell, the size grip is disabled by calling setFixedSize(). However, I cannot put in a pixel size here, so I have implemented resizeEvent() like so:
void cRemoteConnectionDialog::resizeEvent(QResizeEvent *)
{
setFixedSize(minimumSize());
}
This works fine on Windows, but the dialog is far to small on Mac OS X.
How can I achieve a program resizable but not user resizeable QDialog that takes up the minimum space it requires based on run-time state?
Try something like this on your dialog:
this->layout()->setSizeConstraint(QLayout::SetFixedSize);

Fit QML file to screen

I have created an application with a screen resolution of 640 x 360 for the nokia n8. It includes a lot of flickables, labels, etc. I want it to run on the nokia e6 with a resolution of 640 x 480.
Up to now I have simply copied the the QML file and modified it for the new resolution but it's getting a little tiresome to do it for each update. I want to know if there is any simple way I can get it to automatically fit the output to any screen resolution? Or if there is something else I can do to simplify my task. I would prefer not to use anchors because it makes it too complicated to design the QML file.
How about using QApplication::desktop()->availableGeometry() to set the geometry of your application window?
From the docs:
QDesktopWidget::availableGeometry()
Returns the available geometry of the screen with index screen. What is available will be subrect of screenGeometry() based on what the platform decides is available (for example excludes the dock and menu bar on Mac OS X, or the task bar on Windows).
Addressing your comment below:
does it re size the entire screen
The const in QDesktopWidget::availableGeometry() const tells you that you can be pretty sure that the function doesn't alter anything. You'll need to do the resizing yourself.
Edit: The QML docs should give you the information you need to automatically change your application geometry. You could either change the geometry of the QML object from C++ or define your available screen geometry as a Q_PROPERTY and access it from QML. I'd recommend the former, as hooking up to the signal QDesktopWidget::workAreaResized might help you on mobile devices where your available geometery may change.
Actually you should avoid hardcoding the interface pixel by pixel and start using anchors. Ther will be some phones that have yet another screen resolution and then you have to create new QML for each of them. With anchors you can let the content fill all available space

Resources