In Xamarin.Forms what unit of measurement is intrinsically associated with the number 100 like in this example:
<Button WidthRequest="100" />
Pixels
Points
Inches
None, the size depends on the the runtime platform
I already saw this question:
Xamarin.Forms WidthRequest value meaning
But while the answer explains HOW things work, it doesn't give an exact answer to my question.
For example, I am not sure if the correct answer is "Points" or "Size depends on the runtime platform". To me both are related because, the units you specify in Xamarin Forms are device independent units (can we call it points?) and they are translated to pixels by the platform.
In the same, if you think how device independent pixels work on iOS and Android, they are actually associated with the inch:
1 iOS point ~= 1/163 inch
1 Android dp/dip (density-independent pixel) ~= 1/160 inch
So while I understand how things work, I still don't know the correct answer to the question
Related
According to MDN, the "px" unit can mean 2 completely different things depending on whether it's on a "low-dpi" device or a "high-dpi" device.
For low-dpi devices, the unit px represents the physical reference pixel; other units are defined relative to it.
or
For high-dpi devices, inches (in), centimeters (cm), and millimeters (mm) are the same as their physical counterparts. Therefore, the px unit is defined relative to them (1/96 of 1 inch).
But how exactly does it differentiate one from another? What is the cut off for "high dpi"? How can I tell which one of these 2 cases is being used on a particular device?
Found the answer on the w3 page:
In the past, CSS required that implementations display absolute units correctly even on computer screens. But as the number of incorrect implementations outnumbered correct ones and the situation didn't seem to improve, CSS abandoned that requirement in 2011. Currently, absolute units must work correctly only on printed output and on high-resolution devices.
CSS doesn't define what “high resolution” means. But as low-end printers nowadays start at 300 dpi and high-end screens are at 200 dpi, the cut-off is probably somewhere in between.
https://www.w3.org/Style/Examples/007/units.en.html
Hi, there! I was reading the W3C spec about Units of measurement (https://www.w3.org/TR/css-values-3/#reference-pixel) and the fact is that I didn't understand what is a reference pixel. Can you guys explain it to me, or point me to another reference or explanation that's easier to understand. Also I'm not sure if I really understand the other things about Units and Measurements ha ha. Really, that seems too hard.
Thank you!
The reference pixel is an attempt to standardize what "pixel" means in web development. The reason that this matters is because the physical measurement of a pixel can vary greatly depending on the pixel depth of the display.
For example, old CRT monitors had 72 pixels per inch, whereas an iPhone 7+ has 401 pixels per inch. So a literal measurement of 100px would be 1.39 inches on the CRT monitor and 0.25 inches on the iPhone.
This article also has a pretty good explanation that helped me understand it better.
A List Apart, "A Pixel Identity Crisis" by Scott Kellum. January 17, 2012
"The w3c currently defines the reference pixel as the standard for all
pixel-based measurements. Now, instead of every pixel-based
measurement being based on a hardware pixel it is based on an optical
reference unit that might be twice the size of a hardware pixel. This
new pixel should look exactly the same in all viewing situations..."
"When using a phone that you held close, a reference pixel will be
smaller on the screen than a projection you view from a distance. If
the viewer holds their phone up so it is side-by-side with the
projection, the pixel sizes should look identical no matter the
resolution or pixel density the devices have. When implemented
properly, this new standard will provide unprecedented stability
across all designs on all platforms no matter the pixel density or
viewing distance."
I read the Qt Documentations, I checked out a couple examples provided with the SDK, I build Qt Creator from source to see how the Qt devs do it...still no luck.
I am developing a cross platform application for Windows and Mac. On the Mac side I can try basically any of my solutions all of them work perfectly (I guess that is a thanks to the MacOS). On the other hand on Windows I always find some kind of bug or sketchy behavior.
Before I go into more details the root of my problems is supporting multiple monitor environments with monitors, which have different resolutions.
My two main solutions in a nutshell:
Since I am writing my application mainly in QML I use ApplicationWindow for my main window. I save the state of my ApplicationWindow in Settings. My code takes into consideration if the previously saved position is still valid (for example if the application was closed while it was on a monitor, which is no longer available)...the only reason why I have to do this because Windows would just open my app's window in "outer space" (Mac handles this automatically). My application (on Windows) gets into a really weird state if I close my application on one of the monitors and then I change the other monitors scaling factor and then I reopen my application. It opens up on the right monitor but it gets way over scaled and the UI elements are just weirdly floating. If I resize the window everything gets back to normal.
I exposed my QML ApplicationWindow to C++ put into a QWidget container, which then I attached to a QMainWindow by setting it as a setCentralWidget. With this method I have access to saveGeometry and restoreGeometry, which automatically takes care of multiple monitor positioning, but the scaling anomaly what I described in 1. still persist.
Did anybody solved this? Thanks in advance for any help and hin
#retif asked for me to provide a writeup when I commented I knew about these types of issues months ago.
TLDR
When dealing with an absolute positioning issue with a Qt Windows on the Windows OS - especially on Windows 10, it's best to be using system-DPI awareness. Some interpolation is required when going from Windows coordinate spaces (at different DPI awareness levels) to Qt coordinate spaces when you are trying to have the best scaling.
Here's what I did on my team's application.
The Problem:
It is really hard to do absolute positioning of a Qt Window when there are multiple monitors and multiple DPI resolutions to contend with.
Our application window "pops up" from a Windows task tray icon (or menu bar icon on Mac).
The original code would take the Windows screen coordinate position of the tray icon and use that as a reference to compute the positioning of the window.
At app startup, before Qt was initialized, we'd set the environment variable, QT_SCALE_FACTOR to be a floating point value of the (systemDPI/96.0). Sample code:
HDC hdc = GetDC(nullptr);
unsigned int dpi = ::GetDeviceCaps(hdc, LOGPIXELSX);
stringstream dpiScaleFactor;
dpiScaleFactor << (dpi / 96.0);
qputenv("QT_SCALE_FACTOR", QByteArray::fromStdString(dpiScaleFactor.str()));
The code above takes the primary monitors "DPI scale" and tells Qt to match it. It has the pleasant effect of letting Qt compute all scaling natively instead of a bitmap stretch like Windows would do in a non-DPI aware application.
Because we initialize Qt using the QT_SCALE_FACTOR environment variable (based on primary monitor DPI), we were using that value to scale the Windows coordinates when converting to Qt's QScreen coordinate space for this initial window placement.
Everything worked fine on single monitor scenarios. It even worked fine on multi-monitor scenarios as long as the DPI on both monitors was the same. But on configurations of multiple monitors with different DPIs, things got off. If the window had to pop-up on the non-primary monitor as a result of a screen change or a projector getting plugged in (or unplugged), weird stuff would happen. The Qt windows would appear in the wrong position. Or in some cases, the content inside the window would scale incorrectly. And when it did work, there would be a "too big" or "too small" problem of the windows scaled to one DPI when positioned on a similar sized monitor running at a different DPI.
My initial investigation revealed that Qt's coordinate space for the different QScreens geometries looked off. The coordinates of each QScreen rect was scaled based on the QT_SCALE_FACTOR, but the adjacent axis of the individual QScreen rects were not aligned. e.g. One QScreen rect might be {0,0,2559,1439}, but the monitor to the right would be at {3840,0,4920,1080}. What happened to the region where 2560 <= x < 3840 ? Because our code that scaled x and y based on QT_SCALE_FACTOR or DPI was relying on primary monitor being at (0,0) and all monitors to have adjacent coordinate spaces. If our code scaled the assumed position coordinate to something on the other monitor, it might get positioned in an odd place.
It took a while to realize this wasn't a Qt bug per se. It's just that Qt is just normalizing the Windows coordinate space that has these weird coordinate space gaps to begin with.
The fix:
The better fix is to tell Qt to scale to the primary monitor's DPI setting and run the process in system-aware DPI mode instead of per-monitor-aware DPI mode. This has the benefit of letting Qt scale the window correctly and without blurriness or pixelation on the primary monitor and to let Windows scale it on monitor changes.
A bit of background. Read everything in this section of High DPI programming on MSDN. A good read.
Here's what we did.
Kept the initialization of the QT_SCALE_FACTOR as described above.
Then we switched the initialization of our process and Qt from per-monitor DPI awareness to system-aware DPI. Th benefit of system-dpi is that it lets Windows auto-scale the application windows to the expected size as the monitors change out from underneath it. (All Windows APIs act as if all monitors have the same DPI). As discussed above, Windows is doing a bitmap stretch under the hood when the DPI is different from primary monitor. So there's a "blurriness issue" to contend with on monitor switching. But it's sure better than what it was doing before!
By default Qt will try to initialize the process to a per-monitor aware app. To force it to run in system-dpi awareness, call SetProcessDpiAwareness with a value of PROCESS_SYSTEM_DPI_AWARE very early in application startup before Qt initializes. Qt won't be able to change it after that.
Just switching to System-aware dpi fixed a bunch of other issues.
Final bug fix:
Because we position our window at an absolute position (directly above the systray icon in the task tray), we rely on the Windows API,Shell_NotifyIconGetRect to give us the coordinate of the systray. And once we know the offset of the systray, we calculate a top/left position to position for our window be on the screen. Let's call this position X1,Y1
However, the coordinates returned from Shell_NotifyIconGetRect on Windows 10 will always be the "per-monitor aware" native coordinates and not scaled to the System DPI. Use PhysicalToLogicalPointForPerMonitorDPI to convert. This API doesn't exist on Windows 7, but it's not needed. Use LoadLibrary and GetProcAddress for this API if you are supporting Windows 7. If the API doesn't exist, just skip this step. Use PhysicalToLogicalPointForPerMonitorDPI to convert X1,Y1 to a system-aware DPI coordinate wel'll call X2,Y2.
Ideally, X2,Y2 is passed to Qt methods like QQuickView::setPosition But....
Because we were using the QT_SCALE_FACTOR environment variable to get the application to scale the primary monitor DPI, all the QScreen geometries would have normalized coordinates that were different from what Windows used as the screen coordinate system. So the final windows position coordinate of X2,Y2 computed above would not map to the expected position in Qt coordinates if the QT_SCALE_FACTOR environment var was anything but 1.0
Final fix to get the final top/left position of the Qt window calculated.
Call EnumDisplayMonitors and enumerate the monitors list. Find the monitor in which X2,Y2 discussed above is positioned on. Save off the MONITORINFOEX.szDevice as well as the MONITORINFOEX.rcMonitor geometry in a variable called rect
Call QGuiApplication::screens() and enumerate these objects to find the QScreen instance whose name() property matches the MONITORINFOEX.szDevice in the previous step. And then save off the QRect returned by the geometry() method of this QScreen into a variable called qRect. Save the QScreen into a pointer variable called pScreen
Final step of converting X2,Y2 to XFinal,YFinal is this algorithm:
XFinal = (X2 - rect.left) * qRect.width
------------------------------- + qRect.left
rect.width
YFinal = (Y2 - rect.top) * qRect.height
------------------------------- + qRect.top
rect.height
This is just basic interpolation between screen coordinate mappings.
Then the final window positioning is to set both the QScreen and XFinal,YFinal positions on the view object of Qt.
QPoint position(XFinal, YFinal);
pView->setScreen(pScreen);
pView->setPosition(position);
Other solutions considered:
There is the Qt mode called Qt::AA_EnableHighDpiScaling that can be set on the QGuiApplication object. It does much of the above for you, except it forces all scaling to be an integral scale factor (1x, 2x, 3x, etc... never 1.5 or 1.75). That didn't work for us because a 2x scaling of the window on a DPI setting of 150% looked too big.
Confusingly the Window type in Qt Quick doesn't have a fps (frames per second) property, but Canvas3D does. So I'm measuring my app's fps by having a dummy Canvas3D and displaying its fps property. Is this a valid approach? I think so, because the Canvas3D is probably redrawn exactly at the same moments as the window.
I'd like your answers to provide either proof or a reference for what they claim, so I can be sure I'm getting the right performance measurements.
Is there any evidence of a particular sizing unit taking longer to process? For instance, if you were to use rem to size your entire site would it take longer to calculate/paint the page than if everything were given a specific px value?
Is there any benefit to max-width: 16rem over max-width: 250px?
I'm under the impression that rem takes longer since it has to revert back to the root and calculate while em is like a steady stream of processing, and px would be the fastest because there's nothing to calculate.
Please let me know if anyone has any evidence of which method is faster
Edit: I started off pretty much dismissing this discussion as, well,
polishing the roof of a truck, but I had not considered css-animations
which are quite heavy pocessor users and with CSS not being a
graphically optimized process (-very inefficient) then I think
there is a slightly higher warrent for such a question, if a website
has a large number of css-animations.
Quote from question:
I'm under the impression that rem takes longer since it has to revert back to the root and calculate while em is like a steady stream of processing, and px would be the fastest because there's nothing to calculate.
No. Rem simply takes a factor of the root em value, rather than the parent em value. (As the root doesn't change I would hope that the structure processing of CSS doesn't need to keep calling it and can instead simply regain it from memory).
rem Is the way we should be writing CSS in 2016. It beats lights out of em beyond having one or two parent elements effecting the em value, for instance [from the pont of view of working out as a developer what 1.2em of 1.4 em of 1.2 em of 14px is, why not just have 1.2 of 14px as 1.2rem].
As for px, that is not a straight-to-screen result either as with many modern display devices, the pixel is not a pixel, this may be an interesting topic for you to read.
If you care about the speed of processing rem against px then I personally feel you're in effect trying to get better fuel efficiency from your truck by polishing the roof so that air resistence is reduced, your work may have a tiny impact but there are other far larger consumers of GPU,CPU ram and operating power, and many more of them.
You may also like to read this: How a CSS pixel size is calculated?
And because I want to entertain you, you may like to know that you can now generate full 3D computer game levels developed entirely through CSS. This was made in 2013! I still find it increadible!!
In this game the developer used px throughout. You could perhaps take his code and apply em and/or rem and the heaviness of the page will display if it is indeed notably faster.