Fit QML file to screen - qt

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

Related

QT - How to know if the widget changed screens? Is there a signal?

I'm still a beginner at Qt (5.15.2) and I'm trying to implement a way to setMaximumWidth of the application MainWindow based on the current screen it's on.
For example: if the application is on screen 1 (1366x768) it should have maximumWidth of 1366, if it goes to screen 2 (1920x1080), then it should have maximumWidth of 1920, and the same logic applies to a N number of screens. Is there a signal that can help me with this? If there is not, is there a good way to simulate a screen change signal?
What I tried:
I've searched for a QScreen::screenChanged signal but I couldn't find one, so I assume it doesn't exist.
I've tried using QGuiApplication::primaryScreenChanged(), but it didn't work because it only works with primary screens, so when I merely change screens the signal doesn't get activated, only if I go to windows and change the primary screen to the one I'm currently on (which is not desirable).
I've also thought of using timeout signal that would activate a function that checks the current screen and sets the maximum width, it probably would work, but it doesn't seem like a good solution performance wise.
Edit: as for what would cause the screen change, it would be the user, either by dragging the window to another screen or using shortcut keys.

Pixelated gif in QT

I'm trying to show a gif file in QT app, using the approach provided in the link: https://code.qt.io/cgit/qt/qtbase.git/tree/examples/widgets/widgets/movie?h=5.15
Approach makes use of QMovie object set in a QLabel.
The example works well and fine.
But if I enable High DPI scaling for the app, the gif becomes all pixelated. Please see the screenshots below.
This is the line that I add to enable High DPI scaling.
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
Any ideas to get this fixed ?
I have tried the following fixes already:
setScaledSize for the QMovie object
setScaledContents(true) for the QLabel
QT version I'm using is 5.15.2 and platform is Windows.
A GIF picture cannot have more than 256 unique colours. When you load such an image into Qt, it is internally represented in that exact format with the palette (of 256 colours) from the GIF representation, even if your hardware might be able to display many more colours.
This also means that when you scale such an image, Qt is not allowed to extend the colour space to render in-between colours - This means that scaled GIF pictures generally have to look much worse than scaled high-colour images.
The solution to this is either to transform the QImage you created from a GIF picture into a format with a larger colour space before scaling it (with QImage::convertToFormat) or, better still, don't use GIF images at all. After all, GIF is a format developed 30 years ago and has never really been updated to adapt to modern hardware, and using it, you artificially limit your programs to the capabilities of that format.
It seems at this moment there is no way to render sharp gifs when scaled using QMovie and QLabel. I have filed a bug for the same in QT bug tracker.
Meanwhile I have found a workaround that works fine. It is done making use of QML in the QWidget system, using QQuickWidget.
Let me add the full steps here, so that it is helpful to anyone else who run into this problem:
First we need to add support for Qml and QuickWidgets. I use CMake and Visual Studio. Hence I add the below lines in the CMakeLists.txt file. Equivalent changes needs to be made in the .pro file, if QT Creator is used instead.
# I'm only adding the relevant lines for brevity
find_package(Qt5 COMPONENTS Qml QuickWidgets)
target_link_libraries(${APP_TARGET_NAME}
Qt5::Qml
Qt5::QuickWidgets)
# Note the --qmldir switch
add_custom_command (TARGET ${APP_TARGET_NAME} POST_BUILD
COMMAND ${QTDIR}/bin/windeployqt
--qmldir ${CMAKE_CURRENT_SOURCE_DIR}/qml
${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/${APP_TARGET_NAME}.exe)
Then create a spinner.qml file inside a folder named qml:
import QtQuick 2.15
Rectangle {
width: 12
height: 12
AnimatedImage {
y: 5
width: 12
height: 12
id: spinner
source: "img/spinner.gif"
speed: 1.0
}
}
And then load the qml file using QQuickWidget and add the QQuickWidget instance to the QWidget layout.
QHBoxLayout *main_layout = new QHBoxLayout();
auto *spinner_gif = new QQuickWidget(QUrl::fromLocalFile(":/spinner.qml"));
main_layout->addWidget(spinner_gif);
this->setLayout(main_layout);
The gif that shows up won't be pixelated even when scaled and we can see the GPU in use, in the Task Manager, as expected for a QQuickWidget.

How to avoid adding excess 1 pixel spacing by Qt Designer

I'm working on application for embedded and we have 256x64 grayscale screen. Qt 5.3 perfectly renders on that screen with -platform linuxfb option. Obviously, we save every pixel of space, so I faced with trouble: Qt Designer adds excess 1 pixel spacing for every layout element deeper in hierarchy. So they accumulate for the most deep widgets. More precisely, for some reason child element of layout components gets coordinates (1,1) relative to parent. So, it's true for every widget except for root widget. Picture below demonstrates accumulated spacings (thin and thick red lines), and (1,1) coordinates of the very first child widget.
I believe it's Qt behavior itself, not just Qt Designer issue (not tested yet). But I can't work further even if it's shown in Designer only: I need to have pixel-exact view while designing.
Of course, every spacing and margin of every component in form set to 0.
Manual coordinates assigning (from code) eliminates the problem of course, but I need to generate code by uic.
So, my question is: how to avoid such spacings? Fixing Qt core sources can be (hard) option too, since anyway we recompile Qt for the project.
Mirror post on Qt forums
Thanks.
Ilia.
If you select Form > View Code, you can see that the geometry is not actually used for widgets which are inside a layout. So the numbers you see in the Property Editor are purely informational and have no relevance to the eventual code that is generated from the ui file (which is why they are greyed out).
The one pixel offset is there because Qt Designer needs space to draw the red boxes around layouts. They have to be be represented somehow, so I don't see how this can be avoided given the way Qt Designer currently works. If you want a more accurate reprentation of the final results, I suppose you will have to show a preview.
There is a facility in Settings > Preferences > Embedded Design that allows you to specify device profiles (which determine things like style, font, and screen resolution). This will add a new entry to the Preview In menu, which should allow you to refine the accuracy of the previews even further.

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.

qt: after moving window off-screen, how to move it back to default position, including default positioning behaviour?

[qt 4.8]
To get correct window dimensions including its frame, I do the following (as described e.g. here, see comment from Daniel Hedberg).
mainWindow.move(-50000, -50000);
mainWindow.show();
// do something with the window dimensions
mainWindow.move(0, 0);
mainWindow.show()
This works fine, however, I have a problem with the move(0,0) call: It makes the window always appear at position (0,0), while I would like to have the default behaviour, this is, the application only suggests to the window manager that (0,0) is a good place to position the window, and the WM might decide to shift it if necessary to avoid overlapping. In other words, I would like to switch back to Qt's default behaviour as if there weren't a call to move at all.
How can I do that?
One solution is to store Windows original position and use that. For extra safety (in case screen resolution changes), check that entire window still fits on screen and move and even resize if it does not.
A hacky alternative would be to create and open empty, possibly transparent dummy window of the same size and see where it gets positioned. Then move the original there and close the dummy one. Reading your question carefully, I think this would do what you are after.
I don't know of a Qt way to ask Window Manager to reposition the window, so if you really need that, specify the OS etc details.
Looking into the source code of Qt, I can now partially answer my own question: To convert a call to move into a suggestion for positioning instead of a request, do this:
mainWindow.move(100, 100);
mainWindow.setAttribute(Qt::WA_Moved, false);
mainWindow.show();
I've tested the code under X11 using Qt 4.8.4, and hopefully it works with on other platforms too.
Unfortunately, this doesn't solve the very problem I have, namely to use show to get the (decorated) dimensions of an off-screen window which then gets moved to the screen, calling show again. It seems that the first call to show directly sets platform-specific window manager flags which aren't completely reset and reevaluated in the second call. Actually, I'm going to think that this is a bug in Qt, so I'll report it accordingly.

Resources