I designed and implemented an application in Qt ... I wanted to fix the window size so I made the mistake of hard coding the places of the widgets on the window in all the different screens.
Now the application is done and it works perfectly on my screen (or any screen with 1920*1080) resolution... but when I tried on a 4k screen the window looks tiny.. lower resolutions makes it look big as well.
so the question is.. How can I rescale the whole application.. the window with all the buttons and widgets on it depending on the physical screen pixel density without redesigning all the screens?
maybe calculating a scaling factor depending on the screen resolution like:
qreal refDpi = 216.;
qreal refHeight = 1776.;
qreal refWidth = 1080.;
QRect rect = QGuiApplication::primaryScreen()->geometry();
qreal height = qMax(rect.width(), rect.height());
qreal width = qMin(rect.width(), rect.height());
qreal dpi = QGuiApplication::primaryScreen()->logicalDotsPerInch();
m_ratio = qMin(height/refHeight, width/refWidth);
m_ratioFont = qMin(height*refDpi/(dpi*refHeight), width*refDpi/(dpi*refWidth));
and the using setViewport as mentioned here
painter.setViewport(x, y, width*ScaleFactor, height* ScaleFactor);
but where to use that?
All my screens inherits QWidget.. so maybe I can make a new class MyQWidget and overload the render function to implement the rescale?
Related
I'm developing a desktop app in Qtcreator that needs to be resized according to the screen size. I already know how to obtain the screen size. However, I'm not developing it fullscreen yet, because I want to set an optimum intermediate size and resizes it later.
I've set fixed sizes to the parent window (i.e, 1370px,768px) and to all the children widgets using the "setfixedsize()" function and the app looks great. But now I'm setting another fixed size to parent window (i.e, 1920px,1080px) and the children widgets isnt expanding proportionally. I want them to expand and reduce according to the size of parent window.
Am I doing right in setting fixed sizes to all children widgets? Or Is that the problem? What's the correct way to develop an app in Qt with this resize ability?
Thanks guys.
Ps: Sorry about the english.
You should set a fixed size only for the main widget. The size of the child widgets should be determined using layouts.
QWidget* mainWidget = new QWidget;
QVBoxLayout* vBoxLayout = new QVBoxLayout(mainWidget);
QWidget* firstChildWidget = new QLabel("first widget");
QWidget* secondChildWidget = new QLabel("second widget");
QWidget* thirdChildWidget = new QLabel("third widget");
vBoxLayout->addWidget(firstChildWidget);
vBoxLayout->addWidget(secondChildWidget);
vBoxLayout->addWidget(thirdChildWidget);
mainWidget->setFixedSize(400, 400);
mainWidget->show();
I am now trying to resize a qgraphicsview to a preffered size:
I am using layouts:
this->layout()->addWidget(&qtview);
I have layouts everywhere, so thet the size of my main widow is adjusted depending on its contents.
If I use:
qtview.setMinimumWidth(500);
qtviewSetMinimumHeight(500);
Then my view is scaled to the given size, but I am not able to shrink the main window. (which makes sense as I set a minimum soze)
I would like to tell qt my preferred (not minimum or maximum) size for the view, letting the view use scrollbars when needed (i.e. if the preferred size does not fit in my screen), or letting qt have a smaller view than my preferred size if the scene is smaller than my view, (or enlarge the scene to fit the view in this case)
I am searching for something looking like an hypothetical method setPreferredWidth().
What can I do to get this behaviour?
It sounds like you're looking for the QGraphicsView function setSizePolicy: -
setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
So I have a <canvas> element in which I am drawing things. Vectory things, not pixel-pushing. I would like this to display in the highest quality with the least resources under the largest range of viewing conditions. Specifically, I want to ensure that there is a 1:1 mapping between canvas pixels and device pixels, to eliminate blurry, time-consuming pixel scaling operations.
There are a
few things
I've seen about "Retina" displays (conclusion: devicePixelRatio is your friend), but they all assume viewing at 100% zoom. Equally I've seen things about detecting zoom level, but it seems messy and hacky and imprecise
(not to mention prone to breakage). In particular, imprecision is a problem as the entire point is to get a ratio of precisely 1:1. (Plus I don't actually care about the zoom level itself, only about addressing native pixels.)
So my questions, from pragmatic to philosophical:
What is the preferred way of getting a 1:1 canvas in modern (== released in the past 6 months) browsers? Do I really have to detect the device pixel ratio and the zoom (including checking for zoom changes) and calculate things from there?
If I don't care about resource consumption, is a 2:1 canvas (native res on "Retina" displays, upto 200% zoom elsewhere) worth considering? I'm assuming downscaling is less bad than upscaling.
What are browser vendors' take on this? Are there better solutions being worked on? Or is zoom a detail they think web developers should have no need to worry about? [Answered partially here: many consider it important. There seems some indecision on whether devicePixelRatio should change with zoom level or whether a new property that allows user-specified zoom detection as well as device-specific DPI detection is the way forward.]
How many people regularly browse the web at !100% zoom? How many of them are using high DPI displays? Are there stats? [Answered here: about 10% of gmail users.]
What i found (for Chrome and Internet Explorer) is the very tricky, subtle, differences between
canvas.width, and
canvas.style.width
They are not interchangeable. If you want to manipulate them you must do so very carefully to achieve what you want. Some values are measured in physical pixels. Others are measured in logical pixels (the pixels if the screen was still zoomed to 96 dpi).
In my case i want the Canvas to take up the entire window.
First get the size of the window in logical pixels (which i call "CSS pixels"):
//get size in CSS pixels (i.e. 96 dpi)
var styleWidth = window.innerWidth; //e.g. 420. Not document.body.clientWidth
var styleHeight = window.innerHeight; //e.g. 224. Not document.body.clientHeight
These values are in "logical pixels". When my browser is zoomed in, the amount of "logical pixels" decreases:
Zoom window.innerWidth x windows.innerHeight
==== ======================================
100% 1680 x 859
200% 840 x 448
400% 420 x 224
75% 2240 x 1193
What you then have to do is figure out the "real" size of the window; applying a zoom correction factor. For the moment we'll abstract the function that can figure out the current zoom level (using the TypeScript syntax):
function GetZoomLevel(): number
{
}
With the GetZoomLevel() function, we can calculate the real size of the window, in "physical pixels". When we need to set the width and height of the canvas to the size of the window in physical pixels:
//set canvas resolution to that of real pixels
var newZoomLevel = GetZoomLevel();
myCanvas.width = styleWidth * newZoomLevel; //e.g. 1680. Not myCanvas.clientWidth
myCanvas.height = styleHeight * newZoomLevel; //e.g. 859. Not myCanvas.clientHeight
The critical trick is that internally the canvas will render to a surface that is width by height pixels in size. After that rendering is complete, CSS can come along and shrink or stretch your canvas:
blurring it if CSS makes it larger
throwing away pixel data if CSS makes it smaller.
The final piece is to resize the canvas so that it takes up the entire client area window, using CSS length String:
myCanvas.style.width = styleWidth + "px"; //e.g. "420px"
myCanvas.style.height = styleHeight + "px"; //e.g. "224px"
So the canvas will be positioned and sized correctly in your browser window, yet internally is using full "real" pixel resolution.
GetZoomLevel()
Yes, you need the missing piece, GetZoomLevel. Unfortunately only IE supplies the information. Again, using TypeScript notation:
function GetZoomLevel(): number {
/*
Windows 7, running at 131 dpi (136% zoom = 131 / 96)
Internet Explorer's "default" zoom (pressing Ctrl+0) is 136%; matching the system DPI
screen.deviceYDPI: 130
screen.systemYDPI: 131
screen.logicalYDPI: 96
Set IE Zoom to 150%
screen.deviceYDPI: 144
screen.systemYDPI: 131
screen.logicalYDPI: 96
So a user running their system at 131 dpi, with IE at "normal" zoom,
and a user running their system at 96 dpi, with IE at 136% zoom,
both need to see the same thing; everything zoomed in from our default, assumed, 96dpi.
http://msdn.microsoft.com/en-us/library/cc849094(v=vs.85).aspx
Also note that the onresize event is triggered upon change of zoom factor, therefore you should make sure
that any code that takes into account DPI is executed when the onresize event is triggered, as well.
http://htmldoodads.appspot.com/dimensions.html
*/
var zoomLevel: number;
//If the browser supports the corrent API, then use that
if (screen && screen.deviceXDPI && screen.logicalXDPI)
{
//IE6 and above
zoomLevel = (screen.deviceYDPI / screen.logicalYDPI);
else
{
//Chrome (see http://htmldoodads.appspot.com/dimensions.html)
zoomLevel = window.outerWidth / window.innerWidth; //e.g. 1680 / 420
}
return zoomLevel;
}
Unfortunately no browsers besides IE support telling you:
device dpi
logical dpi
My full TS code is:
function OnWindowResize() {
if (drawingTool == null)
return;
//Zoom changes trigger window resize event
//get size in CSS pixels (i.e. 96 dpi)
var styleWidth = window.innerWidth; //myCanvas.clientWidth;
var styleHeight = window.innerHeight; //myCanvas.clientHeight;
var newZoomLevel = GetZoomLevel();
// myCanvas.width = document.body.clientWidth;
// myCanvas.height = document.body.clientHeight;
//set canvas resolution to that of real pixels
myCanvas.width = styleWidth * newZoomLevel;
myCanvas.height = styleHeight * newZoomLevel;
//myCanvas.clientWidth = styleWidth;
//myCanvas.clientHeight = styleHeight;
myCanvas.style.width = styleWidth + "px"; //styleWidth.toString() + "px";
myCanvas.style.height = styleHeight + "px"; //styleHeight.toString() + "px";
drawingTool.Width = myCanvas.width;
drawingTool.Height = myCanvas.height;
// Only take action if zoom factor has changed (won't be triggered by actual resize of window)
if (newZoomLevel != lastZoomLevel) {
lastZoomLevel = newZoomLevel;
drawingTool.CurrentScaleFactor = newZoomLevel;
}
}
It's also important to tell your drawing code the user's current zoom level, in case you try to hard-code any lengths. E.g. attempting to draw
a 32px box at (50,50)
is wrong. You need to draw a
128 px box at (200,200)
when the zoom factor is 4.
Note: Any code is released into the public domain. No attribution required.
You basically cannot detect zoom level on modern browser versions of Firefox and Chrome:
On Firefox 18+ Mozilla changes the devicePixelRatio value on manual zoom (cmd/ctrl +/-), making it impossible to know whether the browser is in zoom mode or is it a retina device, ignoring what the word DEVICE represents.
On Chrome 27 (Meaning WebKit and Blink) webkitTextSizeAdjust was deprecated on desktops versions of the browser. This was the only bullet proof way to detect zoom in desktop chrome that I am aware of.
There are couple of other ways, but they don't cover all the bases - one uses SVG but is not working in iFrames, the other uses window.inner/outerWidth and is not working when there is a sidebar or the DevTools are open on the side.
Source
I have a QWidget which have an horizontal layout which holds a QScrollArea.
When I add a widget to the QScrollArea, I change the maximum size for the container QWidget with:
this->setMaximumSize(newWidget->maximumWidth(), newWidget->maximumHeight());
The maximum size is well changed but the maximize button doesn't work anymore. I can change the size of the widget with the mouse, but not with the maximize button.
If I set the maximum size with a higher value, for example:
this->setMaximumSize(newWidget->maximumWidth() * 2, newWidget->maximumHeight() * 2);
The maximize button works well.
Thanks in advance.
You have set the maximum size to be less than that of your desktop size. So when you try to maximise the widget, you are asking the widget to go beyond the maximum size you set it - so it ignores you.
Presumably newWidget->maximumWidth() * 2 works because that figure is larger than your desktop size.
I have a flex video capturing mobile application that attaches its camera to a UIComponent as follows:
var camera:Camera = Camera.getCamera();
camera.setQuality(0,100);
video = new Video(width, height);
video.attachCamera(camera);
var uiVideo:UIComponent = new UIComponent();
uiVideo.width = video.width;
uiVideo.height = video.height;
uiVideo.addChild(video);
videoGroup.addElement(uiVideo);
*width and height are the mobile's screen size.
The problem with the above code is the video/camera the user sees when recording is zoomed-in when compared with the recorded video. That happens probably because, a camera with dimensions 20x30 is streched to a screen size of 60x90, thus resulting in a zoom of 3x.
How can I avoid that?
Is there a way to strech a camera to fill the mobile screen without zooming-in (distortion is okay, when the screen's ratio is different from the camera's ratio)?
Have you tried Camera.setMode()? You can pass in width, height, frames per second, and a 4th parameter. If the camera does not support that resolution you specify, it will try to use a supported resolution that is similar.