Qt 5.3 full screen issue - c++

I have a Qt application which runs on Ubuntu 12.04 Server with KDE plasma desktop. If I compile with Qt 4.8 full screen works as expected. With Qt 5.3, the window is getting bigger than the available resolution. If I set the resolution using the following code, it works.
QSize sz(QApplication::desktop()->size());
main_window->setFixedSize(sz.width() + 1, sz.height() + 1);
main_window->showFullScreen();
Is this the proper way to solve this issue?
Thanks in advance.

Qt is quite flexible in application sizing and provides you with a lots of informations (and options).
For what concerns QApplication you can use QDesktopWidget.
QDesktopWidget * screen = QApplication::desktop();
screen->availableGeometry();
As stated in the docs about 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). The default screen is
used if screen is -1.
Read the section "Use of the Primary Screen" in QDesktopWidget docs for details about the "default screen" and the general handling of multiple screens. Using these methods you will have full control over the way your application is laid out, even with multiple screens available.
For what concerns QGuiApplication you can use QScreen:
QScreen * screen = QGuiApplication::primaryScreen();
screen->availableGeometry();
Finally, in QML it is possible (and advisable) to use Screen object which provides Screen.desktopAvailableWidth and Screen.desktopAvailableHeight which ensure proper resizing with different versions of Android/iOS.

Related

Design user interfaces with automatically scaling fontsizes in Qt

Qt 5.7 is claiming to have improved high DPI support. With modern Qt it is possible to create an app starter like:
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
return app.exec();
}
I expect UI to automatically scale when running on high DPI, but the scaling doesn't necessarily work as expected. At least it doesn't scale the UI for me under Linux. What I am seeing is that the layout scales up, but the fonts stay right where they were, at the sizes Qt Creator assigned them in the form layout tool.
If you want a larger size font for some element, and you set it in form Design screen, there seems no way to say "twice as big". Instead it injects a font property with an absolute point size.
It seems to be the same for the QMessageBox static methods too. Display a static QMessageBox, like QMessageBox::info and its text and icon do not get scaled up to compensate for the high dpi.
So exactly what is it you are supposed to do to allow your Qt application, designed in Creator at a standard DPI, to automatically adjust to a high DPI environment, fonts, QMessageBoxes and all.
I've gotten some traction setting the application's style sheet to use larger font for QMessageBox. but it feels ugly, and I'm not sure how to trigger it automatically.
EDIT:
Manually setting the environment variable
declare -x QT_SCALE_FACTOR=2
Does seem to invoke the sort of behavior I am looking for. But how to do it automatically only on High DPI environment, and preferably inside the program itself . ( setenv (3) could work under Linux, I guess )
As of Qt5.11 the following seems to be good enough for my Ubuntu 18.04 laptop with a 4k screen:
Download and install Qt5.11 from official website (not from apt).
Open the ~/.local/share/applications/DigiaQt-qtcreator-community.desktop file.
Change the line Exec=/path/to/Qt/Tools/QtCreator/bin/qtcreator to Exec=env QT_AUTO_SCREEN_SCALE_FACTOR=1 /path/to/Qt/Tools/QtCreator/bin/qtcreator
Restart Qt Creator.

OpenGL in Qt Quick cross platform application

I'm trying to develop a cross platform (or at least desktop + embedded hardware) application. I would like to use Qt Quick to create a touch friendly GUI. I have been implemented a classical application with a QGLWidget displaying data. It is important that only a part of the window is in OpenGL. Because of this there are problems with EGLFS and LinuxFB. Only X11 (or maybe Wayland) can display the application properly (others generates a couple of errors about missing setParent function and the whole screen is black). Now I'm trying to achieve the same thing in QML. I want to use this OpenGL renderer as part of my QML application and some Qt Quick widgets around it. I found a couple of people asking about the same thing and the answer is always to subclass QDeclarativeItem and call the painter's beginNativePainting() (the others says to export it through QDeclarativeItem, but I cannot figure out how to do this). The problem is that on desktop, Qt 5.11 the native painter is not OpenGL. And in QT5 there is no way to force OpenGL graphics system. So when I try to get the OpenGL context (QGLContext::currentContext()) I always get NULL. Another problem: If I export my widget with qmlRegisterType("Test", 1, 0, "Test"); it becomes only visible when I use QDeclarativeView, but then it doesn't sees Qt Quick. If I use QQuickView it says module "Test" is not installed. How can I implement this properly?
QDeclarativeItem is from Qt Quick 1 and Qt4. With Qt 5 and Qt Quick 2 you should use QQuickItem.
There is at least 1 example of this provided with qt docs, which you can find in Qt Creator in the Welcome tab in the Examples section.

Resize size of Main Window depending on Hardware in Qt?

I have developed my Application with most of the Widgets in Qt Creator's Designer module.
I have hard coded the sizes of my widgets depending on how they appeared on my laptop. Yesterday when I ran the application on my Desktop (lower screen resolution than laptop) some of the Main Window widgets were not visible & on startup there was horizontal scrollbar & I had to scroll to see those widgets; which is not the case on my laptop.
I have 2 problems:
Is it possible to resize all of my widgets (even those which are added run time by code) by using some resize factor? Maybe at startup I will get the screen resolution of Hardware in which application is running & then create a ratio of that with resolution of my laptop. Is it possible to multiply this factor to all widgets without adding code for each widget?
How do I get the resolution of the Screen in which my Application is running?
PS: I would like to know the defacto method of solving this problem...
Thank You.
You could try a function like this:
resize(theDesktop->screenGeometry().width()*PERCENTAGE_OF_MONITOR_WIDTH_FOR_SCREEN, theDesktop->screenGeometry().height()*PERCENTAGE_OF_MONITOR_HEIGHT_FOR_SCREEN);
Resize is a member function of the QWidget class and the PERCENTAGE_OF_MONITOR variables would be whatever percentage of the monitor you want your application to take up.
theDesktop is of the type QDesktopWidget.
You should use Layouts to manage the size policy of your widgets.
Qt layouts automatically position and resize widgets when the amount of space
available for them changes, ensuring that they are consistently
arranged and that the user interface as a whole remains usable."
You could also check this question for more information regarding layout machanisms in Qt.
Qt website has got excelent documentation on the subject. You can start here for more information on working with layouts in Qt Designer.

QWidget / QWindow title bar: custom look, native feel (similar to Chrome)

I know how to make a QWidget (in Qt4 or Qt5) / QWindow (since Qt5) borderless, draw a custom title bar and manually implement mouse dragging to move the window on the screen by simply tracking the mouse position with some mouseMoveEvent and updating the window position.
However, this movement behaves different than the native one as implemented by the window manager. For example, moving the window near the screen's border can be interpreted as "fullscreen" or "split screen"; or windows snap to each other's borders, depending on the system / window manager. These things don't work if you implement the window movement like above.
Google Chrome / Chromium is only one example for an application which implements a custom window title bar and border, while still adapting to the native behavior of the window manager. I'm wondering whether Chrome implements these by itself (and detects the window manager and its configuration) or if there is some functionality in most window managers (clearly, this is still highly platform-dependent) for telling "start native window movement" and "stop native window movement" or similar.
Is something like that possible in Qt? If not, maybe using some other libraries like Qxt?
FYI: I'm mainly targeting Windows and Linux, where I see the difficulty that the user can have any window manager installed.
Based on attempting the same with Qt4 recently, I fear the answer is, you need to tune this per-platform / per-window-manager. I expect patches to QWindow to improve the behaviour in this area would be accepted, but I'm not aware of any standard hook to tell the OS/window-manager what you're trying to achieve.
Equally Qt should be not be 'getting in the way' of solving this, it's simply an area where it can't do anything to help you in a generic way.

How to get the width of a window frame, before creating any windows?

EDIT: this app will run on Windows, Mac, and various Linux distros. I'm aware Linux has issues with this, but what about Windows? Mac?
Is there any way to get the width of the frame for a normal window, PRIOR to showing any windows? After showing a window, I know I can subtract the size() from the frameSize(), but that doesn't work until after the window is shown.
I've looked at QApplication::style()->pixelMetric(), and I can get the height of the title bar using
QApplication::style()->pixelMetric(QStyle::PM_TitleBarHeight)
but I don't see any options to get the width of the rest of the border around the window.
The only solution I've found so far is to:
set the window opacity to 0 (so the user doesn't see it),
show the window
then subtract size() from frameSize()
Is there a better way?
I posted a suggested solution in a different question at StackOverflow, but I'll post it here as well. You can move the window to somewhere far outside the screen before showing it and then query it for its geometry, and finally move it to where you want it (if that is what you need the geometry for). For instance to center a main window on the primary screen without flickering I do the following:
MainWindow mainWindow;
QRect primaryScreenGeometry(QApplication::desktop()->screenGeometry());
mainWindow.move(-50000,-50000);
mainWindow.show();
mainWindow.move((primaryScreenGeometry.width() - mainWindow.width()) / 2.0,
(primaryScreenGeometry.height() - mainWindow.height()) / 2.0);
I've only tested this code on Windows XP and Qt 4.8.x. Hopefully it works on other platforms as well.
In case you haven't seen it, the Qt doc page Window and Dialog Widgets contains a lot of information about this.
You don't say what platform you are running on, but it it's X11, the answer seems to be 'No', there isn't a better way:
X11 Peculiarities
On X11, a window does not have a frame until the window manager decorates it. This happens asynchronously at some point in time after calling QWidget::show() and the first paint event the window receives, or it does not happen at all. Bear in mind that X11 is policy-free (others call it flexible). Thus you cannot make any safe assumption about the decoration frame your window will get. Basic rule: There's always one user who uses a window manager that breaks your assumption, and who will complain to you.
(I like your workaround of setting the opacity to 0: neat!)
The python version of the answer by Daniel Hedberg.
One example to show window at screen's right bottom corner:
from PySide2 import QtWidgets, QtGui
app = QtWidgets.QApplication()
allScreensTotalWidth = sum([x.size().width() for x in QtGui.QGuiApplication.screens()])
allScreensTotalHeight = sum([x.size().height() for x in QtGui.QGuiApplication.screens()])
primaryScreenViewportWidth = QtGui.QGuiApplication.primaryScreen().availableSize().width()
primaryScreenViewportHeight = QtGui.QGuiApplication.primaryScreen().availableSize().height()
widget = QtWidgets.QWidget()
widget.resize(200, 200)
widget.move(allScreensTotalWidth, allScreensTotalHeight)
widget.show()
widget.move(
primaryScreenViewportWidth - widget.frameSize().width(),
primaryScreenViewportHeight - widget.frameSize().height())
app.exec_()
Sum of all QtGui.QScreen's size is the position not visible for user.