I have a Qt application and I need to adapt the application (zoom-in/zoom-out) as the scaling changes from the OS in Display Settings.
I have read from Internet that:
The standard DPI settings are 100% (96 DPI), 125% (120 DPI), and 150%
(144 DPI)
But, I am getting below DPI values when logged from the Qt application:
Scale - Physical DPI X - Physical DPI Y
100% - 158, 159
125% - 158, 159
150% - 79, 79
175% - 79, 79
So, as per the above values, the application text size has no difference for the 100% and 125% scale. Same behavior applies for 150% and 175%.
Below is the Qt code that I used:
#include <QWidget>
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QWidget widget;
qInfo() << "Hello Qt";
int dpiX = widget.physicalDpiX();
int dpiY = widget.physicalDpiY();
qInfo() << dpiX;
qInfo() << dpiY;
Can anyone please guide? What I am trying to achieve is that the Qt application behaves (changes application size/ font size) depending on scaling set in Display Settings of the OS.
I initially suggested using QWindow::devicePixelRatio() in this answer. However, as of Qt 5.12, this does not actually work correctly yet. Qt will avoid fractional scaling ratios due to a bug in Qt's UI scaling implementation. So for 125%, it will still return a 1.0 scaling factor. At 175%, it will return 2.0 instead of 1.75.
So for now, you should fall back to querying the DPI. However, query the logical DPI, not the physical DPI as you are doing now. Replace calls to physicalDpi() functions with calls to logicalDpi() ones. This should give you the standard 96/120/144 DPI reported by Microsoft Windows.
The previous part of the answer below can be used once Qt fixes the bug.
Previous answer, applicable once Qt fixes their scaling bug
Query the scaling ratio directly, don't try to infer it from the DPI. You use QWindow::devicePixelRatio() for this. At 100% scaling, this will return 1.0. At 125% scaling, it will return 1.25. And so on. Since this is a scaling factor, you use it as a multiplier for your sizes.
You should call devicePixelRatio() on the window your widget is currently in. This is because different windows can be on different displays on multi-monitor setups.
The window the widget is in can be obtained with QWidget::windowHandle(). This can return null if the widget is not a window. So you should probably write a small helper function that returns the correct DPR (Device Pixel Ratio) for a widget. It should take a QWidget as argument, and if windowHandle() returns null for the widget, walk up the parent tree, calling windowHandle() on each parent until it finds the first one that doesn't return null. Then return windowHandle()->devicePixelRatio(). This will be the correct DPR to use in that widget.
Related
I was under the impression that if you do this in your application
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication* app = new QApplication(temp, NULL);
then Fonts gets automatically scaled up on high resolution display. Same if you explicitly increase font scaling in Windows 10 (Settings-->System->Custom Scaling).
However, when running the following code with 100% and then 200% scaling in Windows 10, it does not return doubled size.
QFont font = QFont("arial", 10);
QFontMetrics fm(font);
int width = fm.width("abcdefgABCDEFG");
Strangely there is only 1 pixel difference.
100% --> width = 108 pixels
200% --> width = 109 pixels
Why is that? Can I get QFontMetrics to account for Windows scaling? Or do I need to use Logical / Physical DPI to deduce that font size must be increased by a factor 2?
Thanks
For the proper scaling of custom-drawn items use QScreen::physicalDotPerInch property to realize the scaling coefficient to apply to actual drawings:
qreal myScale = pScreen->physicalDotPerInch() / constStandardPerInch;
P.S. The question still needs to be revised.
How to get the current mouse cursor size measured in pixels? I tried mywidget.cursor().pixmap().size() but it returns (0,0) for the standard arrow cursor.
(I need this to show a special tool tip label which would appear just below the cursor and would follow the cursor and I cannot use the standard QToolTip for certain reasons - delays etc. I already have a nice, working solution but if I display the label exactly at the cursor position, the cursor is painted over it hiding some text on the label. Of course I could move it down using some 'magic' number like 32 pixels, but this would cause me bad stomach feelings.)
You can't do this with the standard cursors. The QCursor methods only work with custom bitmaps or pixmaps. So you will either have to use your own cursors, or estimate the size.
A quick web-search suggests that the standard cursors can vary in size and there is no fixed maximum (although that probably depends on the platform). For example, on X11, the size range usually includes 16, 24, 32, 48, and 64, but other sizes may be possible (even as large as 512). The default is normally 32.
If you need accuracy, it would seem that using custom cursors is the only way to solve this problem.
You could use the code that is used in QTipLabel::placeTip, which offsets tooltips based on cursor size:
const int screenIndex = /*figure out what screen you are on*/;
const QScreen *screen = QGuiApplication::screens().value(screenIndex, QGuiApplication::primaryScreen());
if (const QPlatformScreen *platformScreen = screen ? screen->handle() : nullptr) {
QPlatformCursor *cursor = platformScreen->cursor();
const QSize nativeSize = cursor ? cursor->size() : QSize(16, 16);
const QSize cursorSize = QHighDpi::fromNativePixels(nativeSize, platformScreen);
}
To do this you do need at least one private header:
#include <qpa/qplatformscreen.h>
#include <qpa/qplatformcursor.h>
#include <QtGui/private/qhighdpiscaling_p.h>
If it doesn't have to be portable you can look at the size implementation of the QPlatformCursor implementation for the platform you're targeting (e.g. QWindowsCursor::size()) and use that code.
I use Qt 4.8 in embedded linux. I want to change mouse cursor(QCursor) size, it's too small, but in QCursor class there is no function can change the size.
in Qt document: http://qt-project.org/doc/qt-4.8/qcursor.html#QCursor-3
it says here that:
Valid cursor sizes depend on the display hardware (or the underlying window system). We recommend using 32 x 32 cursors, because this size is supported on all platforms. Some platforms also support 16 x 16, 48 x 48, and 64 x 64 cursors.
so my question is: how to change the default cursor(QCursor) size in embedded linux ? I'm searching for answers on the Internet, almost no one mentioned this problem !?
(I know it can use QPixmap or QBitmap to change the cursor icon, but this is not the fundamental way.)
thanks.
I need to draw 2 centimeters long line on screen on an Adobe Air application. I don't know how to do it!
Explanation:
I am getting parameters from another application say x centimeters, and that parameter is in centimeters.
I need to draw a circle exactly x centimeters from the top of the screen.
best regards
If I remember correctly, you won't be able to do it on desktop since AIR always returns 72DPI for the screen (I may be incorrect on that point, however). It is fairly easy to do on mobile, though, assuming AIR returns the proper DPI (retina iPads did not return the correct DPIs prior to AIR 3.3, I believe).
Basically, you convert inches to pixels simply by multiplying by the DPI.
var dpi:Number = Capabilities.screenDPI; //unnecessary to save local version, just easier to reference
var heightCM:Number = 5;
var widthCM:Number = 5;
var widthPixels:Number, heightPixels:Number;
var heightIn:Number = cmToInches( heightCM );
var widthIn:Number = cmToInches( widthCM );
widthPixels = widthIn * dpi;
heightPixels = heightIn * dpi;
function cmToInches( value:Number ):Number {
return value * .393701;
}
That will take a size (I built it for height and width, but you can adapt it to your needs) in centimeters, convert it to inches, and then convert it to pixels. You'd obviously want to turn that into a neat static Util method, but it would do the trick.
If you want, I created a Flex application last year to try and understand how AIR handles DPI differences. It just draws a red rectangle to a specific size on screen using on-screen sliders to determine the size (in inches). I don't have it here at work, but I could post the code when I get home.
Again, I do not believe this will work in desktop applications due to AIR always reporting 72 DPI. I hope I am wrong, but I do not believe I am.
I am writing Qt (4.8.1 on Ubuntu 12.04) application that stores it's main window geometry between sessions. I noticed that if widget is maximized, qt is not storing it's non-maximized geometry. Obviously I would like my application to return to it's non-maximized size just the same if it was closed/started since last maximization. In
Main window is not maximized and has geometry X;
maximize main window;
save window geometry (using QWidget::saveGeometry) to config file;
close my application;
start it again;
load geometry from config file
Restore (un-maximize? ;)
After step 6 window gets maximized (as expected), but after step 7 it returns to some internal default size (i. e. one set while designing form in QtCreator), not to last non-maximized geometry X.
Is this desired behavior? Or is it impossible/difficult to implement inside qt?
Is it because when maximized, the non maximized size is remembered by window manager and not qt (at least on linux)?
You do not need to save the geometry when the window is maximized to begin-with.
To get your required functionality just modify your steps as follows:
Main window is not maximized and has geometry X;
Save Geometry X also left-top position of window as QPoint Y
maximize main window;
Do NOT save geometry (You can figure if window state is maximized using QWidget::isMaximized() before saving to config file). Save a new isMaximised state value to config file instead.
close my application;
start it again;
Before you call window->show() apply a window->resize(lastQSizeSavedinSettingsofNonMaximisedState) and a window->move(lastQPointSavedinSettingsofNonMaximisedState)
Now check the isMaximised state value from config and if true, just call QWidget::showMaximized() else just QWidget::show()
Now when you restore window size, you should have your desired functionality :)
Something to keep in mind when working with window size/states.
Always provide a fallback geometry and position in-case the last saved positions are out of bounds when the application is started and values you try to restore are not within the screen bounds anymore. (This helps catering for cases where someone changes resolution / monitor count / monitor position / virtual desktops)
4. Do NOT save geometry (You can figure if window state is maximized using QWidget::isMaximized() before saving to config file). Save a new isMaximised state value to config file instead.
Another problem here is: A window will not just be maximized/minimized based on its position on the screen but based on where the greater part of the window is. If 80% of the window is on screen1 but the upper left corner is on screen 2, the maximized window will be on screen1.
Still, your idea is the best one. After over an hour of google (using QT5), I now use:
writeSettings:
settings.setValue("pos", pos());
if(!isMaximized())
settings.setValue("size", size());
settings.setValue("maximized", isMaximized());
readSettings:
if(settings.contains("pos"))
move(settings.value("pos").toPoint());
if(settings.contains("size"))
resize(settings.value("size").toSize());
if(settings.value("maximized").toBool())
setWindowState(windowState() | Qt::WindowMaximized);
I think the issue you're having is coming from a number of geometries and sizes being readable and set-able for a QWidget. Specifically, you might want to look at the differences between normalGeometry, height, width, maximumHeight, maximumWidth, minimumHeight, minimumWidth etc.