qt - how to develop application independent of screen resolution? [duplicate] - qt

I'm writing a Qt application that needs to run on high-dpi Windows (192dpi instead of 96dpi).
Unfortunately the Qt framework does not have support for high-dpi yet (at least on Windows), so my application and all its elements looks half the size it should.
Is there any way to force/simulate automatic upscaling of such apps by Windows?

Applications that use fixed coordinates and sizes will look small on high-DPI resolutions. Although even if using layouts there are some issues regarding element and font sizes and margins. Fortunately there is support for high-DPI displays since Qt 5.4 as there has been many high-DPI issue fixes.
An application on Windows can assume one of the following levels of "DPI Awareness" (From the Qt documentation) :
DPI Unaware: This level has been introduced in Windows-Vista. Windows will pretend to the application that it is running on a
standard display of 96 DPI of 1920x1080 and scale the application
accordingly. It is intended to accommodate older applications designed
for low DPI displays. Some artifacts may result from this type of
scaling.
System-DPI Aware: This level has been introduced in Windows-Vista. It differs from Per-Monitor DPI Aware only when multiple monitors are
connected. Windows will calculate a scaling suitable for all connected
monitors.
Per-Monitor DPI Aware: This level has been introduced in Windows 8.1. Windows does not perform any scaling at all.
Also it states that :
Qt applications by default are Per-Monitor DPI Aware on Windows 8.1 or
System-DPI Aware on older versions of Windows. As of Qt 5.4, the level
can be specified by passing a parameter to the platform plugin (see
Using qt.conf):
<application> -platform windows:dpiawareness=0,1,2
You can read more information here.
In general to have a good UI on high-DPI displays, consider the following :
Use the latest version of Qt
Use layouts and avoid fixed sizes (unless you calculate scaling ratios on your own)
Make appropriate DPI-related settings depending on your application needs, for example set Qt::AA_UseHighDpiPixmaps attribute if you work with QPainter and pixmaps, or calculate a scaling ratio for adjusting certain element sizes in special situations.

Qt fully supports high DPI monitors from Qt 5.6 onward, via attribute or environment variable (except on OS X where support is native). For the attribute method, use:
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // DPI support
QApplication app(argc, argv);
return app.exec();
}
or set the system environment variable:
QT_AUTO_SCREEN_SCALE_FACTOR=1
I've tested both methods on windows 10 with a high-DPI surfacebook monitor and the results are scaled properly as expected.

Here is the quickest way to get the issue solved on Windows.
Next to the executable, create a qt.conf file (if not already there) and add the following:
[Platforms]
WindowsArguments = dpiawareness=0
The window will appear blurry when scaled up. The big advantage of this solution is that Windows does the scaling, not Qt. Therefore the occurence of artifacts is minimized. Furthermore, this can apply to an already-distributed app as it does not require a rebuild.
Of course, this is not the most pleasant result but the quickest to get you out of trouble in short term, letting you develop the "real" DPI-aware version without pressure.

I' am using Qt 4.8. First, you should use layouts. My goal was to prevent user to resize dialogs, forms etc. too.
I achieved correct display results on different DPI by put this code in dialog constructor:
adjustSize();
setFixedSize(size());
First line adjustSize() adjust size of dialog to fit its content.
Second line setFixedSize(size()) fixes size of dialog after adjusting its size to content and prevent users to resize it. You haven't to set size policies.

I' am using Qt 4.8.7. This is my code.
static float dpiX = (float)0;
inline int autoDpiSize(int inSize)
{
if (dpiX == (float)0)
{
HDC screen = GetDC(0);
dpiX = static_cast<float >(GetDeviceCaps(screen, LOGPIXELSX)) / 96.0;
ReleaseDC(0, screen);
}
return dpiX * inSize;
}
someWidget->setFixedHeight(autoDpiSize(30));

Related

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...?

Qt5, X11, libxcb. Sliders and other parts of widgets is too small

Some parts of widgets (e.g. button in a QDateEdit) are by far too small so they cannot be properly used with touch screens.
On my system, the sliders, e.g. for the widget's scroll areas, become bigger if I use setGlobalStrut() accordingly. But a slider has buttons with arrows which are very small on our system. The same is true for QDateWidget. The Buttons with the arrows are very, very small in our system and therefore cannot be well used with touchscreen.
We use Pvbrowser (pvbrowser.org) for visualisation of a gas measurement device on an embedded system with touchscreen. It is running an embedded linux yocto/poky "jethroo". By passing a parameter, the application calls QApplication::setGlobalStrut. The effect is, that some elements become bigger, but not sub elements within the widget.
Is there any way to change the appearance of Qt applications on systems like this:
X11 was used instead of egl because the vnc functionality is needed. A display manager is not used and the windows manager is "matchbox". Qt is version 5.5.1.
In the meantime I have found a solution. The screen size was not set in X11 and xrandr reported 0 dpi.
If I set the dpi, e.g. by calling "xrandr --dpi 146" from mconsole, the size of arrow elements etc. within dateTime widgets, scroll bars or other are adjusted accordingly when the application is restarted.
Not only the widgets and its elements are changed but also the font size since it is given in points which depends on dpi.

Limitations of using GLFW and OpenGL for GUIs

I would like to know what kind of limitations can result from using GLFW and OpenGL instead of using a traditional GUI toolkit like Qt or GTK.
Of course, I know that GLFW with OpenGL don't expose the same level of functionality, but if only a few kind of widgets are needed, I think that those could be easily implemented.
The question is, is there some feature that couldn't be implemented on top of GLFW/OpenGL in contrast to Qt or GTK?
For example, I'm worried about drawing menus outside the window region (I guess that an auxiliary non-decorated window could be use in this case).
I know that GLFW with OpenGL don't expose the same level of functionality, but if only a few kind of widgets are needed
When it comes to OpenGL, there isn't any limit per se. You can draw wherever and whatever you want. The area where you can draw is a limiting factor from the operating system's side of things.
Remember that some "simple" functionality like say a textbox, is already complicated. Not only do you have to handle rendering (and scalable text isn't always fun), but you also have to handle keyboard events. Drawing the cursor and text selection, etc.
For example, I'm worried about drawing menus outside the window region (I guess that an auxiliary non-decorated window could be use in this case).
When it comes to drawing outside the window region, this isn't directly OpenGL related. It's more a question depending on the OS.
For instance using the WinAPI, you can draw anywhere on the screen simply by doing:
#include <Windows.h>
int main(int argc, char **argv)
{
HWND desktop = GetDesktopWindow();
HDC dc = GetDC(desktop);
RECT rect = { 20, 20, 200, 200 };
HBRUSH brush = CreateSolidBrush(RGB(0, 0, 255));
FillRect(dc, &rect, brush);
return 0;
}
Note that the rectangle will disappear immediately when the screen redraws that area.
When you already have a window, then you can use SetWindowRgn() to change the area which your application is allowed to draw within. Note that you can't just change this area, and everything will be fine and dandy.
The question is, is there some feature that couldn't be implemented on top of GLFW/OpenGL in contrast to Qt or GTK?
Bottom line is no. There's isn't any feature you can't implement with OpenGL that is in Qt and GTK. The point is that it isn't just OpenGL, and that a lot of it depends on the operating system, thus needing OS specific code.

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?

How to change logical DPI for QML app?

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.

Resources