您好,登錄后才能下訂單哦!
DPI , dot per inch ,即每英寸包含的點數。還有一個概念是 PPI ,即每英寸包含的像素數。一般我們用 DPI 就夠了,對于專業人士處理超高 DPI 的場景,使用 PPI 可能更精確一些。在 Qt 中,只有 DPI ,所以我們單說它吧。
這個值越大,像素密度越大,小尺寸的屏幕就可以有大分辨率。比如有的 Android 手機, 3.7 吋屏幕就能提供 960x540 的分辨率,而有的手機, 5 吋屏幕卻提供 800x480 的分辨率。這兩種不同屏幕的尺寸和分辨率的手機,5 吋屏看起來會有顆粒感,而 3.7 吋看起來則非常細膩。這就是像素密度帶來的差別。
有的屏幕,橫向的 DPI 和縱向的 DPI 不一樣,即像素點不是正方形,這就更復雜了……
我們在寫應用時,理想的情況是:應當根據 DPI + 屏幕分辨率來設置界面元素的大小。
Mac OS 10.8(10.7是非正式的?)添加了對高DPI的Retina顯示的支持。Qt 4免費獲得這一支持,因為它使用的是CoreGraphics繪制引擎。
Qt 5使用的是光柵繪制引擎并且Qt通過縮放繪圖器變換(transform)實現了高DPI矢量的繪制。HITheme同時為Qt 4和5提供了高DPI的Mac風格。在Qt 5的Fusion風格中,對于高DPI模式的支持也已經修改好了。
OpenGL是一種基于設備像素的API并且對于高DPI模式也仍然如此。在NSView中有一個flag可以用來開啟或者禁用2x縮放——Qt在所有情況下都可以設置它。Shaders運行在設備像素中。
Qt Quick 1是構建于QGraphicsView之上的,它是一個QWidget并且通過QPainter獲得對于高DPI的支持。
Qt Quick 2是基于Scene Graph(和OpenGL),已經更新了高DPI的支持。Qt Quick控件(也就是以前的Desktop Component)也已經更新了在高DPI模式下的渲染,其中包括距離場(distance field)文本渲染。(譯者注:關于距離場,可以參考Yoann Lopes – Text Rendering in the QML Scene Graph以及iKDE上的譯文。)
這里的賣點是應用程序開發人員不需要關心這些,您只需要在設備無關像素的空間里舒適地開發,Qt和/或OS會為您處理那些復雜的事情。但有一個例外,光柵內容(raster content)——需要提供高DPI光柵內容,并且應用程序代碼需要正確處理這些內容。
QPainter代碼絕大多數情況下都和原來一樣。我們來看看繪制漸變(gradient)的代碼:
在高DPI顯示器上,這個漸變在屏幕上的大小還是一樣的,但是被填充了更多的(設備)像素。
繪制一個像素映射(pixmap)也是類似的:
QRect destinationRect = ...QPixmap pixmap = ...painter.drawPixmap(destinationRect, pixmap);
為了避免在高DPI顯示器上出現縮放失真,像素映射必須包含足夠的像素:兩倍于destinationRect的寬和高。應用程序可以直接提供它們,也可以使用QIcon來管理不同的解析度:
QRect destinationRect = ...QIcon icon = ...painter.drawPixmap(destinationRect, icon.pixmap(destinationRect.size()));
QIcon::pixmap()已經被修改了,可以在高DPI系統中返回一個更大的像素映射。這種行為的改變會破壞現有的代碼,所以它是由AA_UseHighDpiPixmaps這個應用程序屬性來控制的:
qApp->setAttribute(Qt::AA_UseHighDpiPixmaps);
在Qt 5.1中這個屬性默認值是關閉的,但在未來的Qt發布中它很有可能默認為打開。
Qt的窗口部件有一些極端情況。在理想情況下,它一直使用QIcon,并且在繪制的時候會使用正確的像素映射,但是實際情況是Qt API經常直接生成和使用像素映射。當像素映射的大小被用來計算布局的幾何信息時,會發生錯誤——如果一個像素映射已經是高分辨率的,那么在屏幕上它就不應該再占用更多的空間。
通過使用QPixmap::devicePixelRatio(),就能讓200x200的像素映射實際占據100x100的設備無關像素。由QIcon::pixmap()返回的像素映射中devicePixelRatio已經設置好了。
例如QLabel就是一個“像素映射消費者”:
QPixmap pixmap2x = ...pixmap2x.setDevicePixelRatio(2.0); QLabel *label = ...label->setPixmap(pixmap2x);
然后QLabel會除以devicePixelRatio來獲得布局的大小:
QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio();
與此類似的幾種情況在Qt中都已經修復,并且應用程序代碼在啟用AA_UseHighDpiPixmaps之前也需要做類似處理。
下面幾個Qt類中都提供了devicePixelRatio()的讀寫函數:
類 | 注釋 |
---|---|
QWindow::devicePixelRatio() | 推薦使用的讀寫函數 |
QScreen::devicePixelRatio() | |
QGuiApplication::devicePixelRatio() | 如果沒有QWindow指針,請使用這個 |
QImage::[set]devicePixelRatio() | |
QPixmap::[set]devicePixelRatio() |
字體大小還可以和原來一樣,會在高DPI顯示中產生類似的大小(但會有一點小問題)。字體的像素大小是設備無關的像素大小。您在高DPI顯示中永遠不會得到太小的文本。
OpenGL是在設備像素空間中工作的。例如,傳遞給glViewport的寬和高應該是設備像素。QGLWidget::resizeGL()中的寬和高也是設備像素的。
不管怎樣,QGLWidget::width()實際上就是QWidget::width(),它返回的是設備無關像素的值。如果需要,用它來乘以widget->windowHandle()->devicePixelRatio()可以解決很多問題。
Qt Quick 2和Qt Quick控件可以直接使用。因為窗口部件的坐標是設備無關像素的。Qt Quick也有幾個和光柵相關的極端情況,因為QML的Image元素是通過URL來指定圖像源的,這樣就避免了像素映射的傳遞。
Qt Quick控件
還有一個例外是OpenGL著色器(shader),它運行在設備像素空間中并且可以看到全分辨率。在通常情況下這沒有什么問題,我們應該知道的一件重要的事情是,鼠標坐標是設備無關像素的,也許需要被轉換成設備像素。
運行中的著色器效果實例
正如我們所看到的,在縮放的情況下,光柵內容看起來會不夠好,所以必須提供高解析度的內容。作為應用程序開發人員,您有兩個選項:(請忽略“什么都不做”選項)
使用高解析度版本替換現有光柵內容
另外提供一份高解析度內容
第一個選項很簡單,因為每個資源只有一個版本。可是您也許會發現(或者您的設計師會告訴您)像圖標這樣的資源只有在它被創建的那個特定解析度下看起來才最好。為了解決這個問題,Qt沿用了“@2x”這種圖像文件名的方案:
foo.pngfoo@2x.png
這樣高解析度的內容和原來的一一對應。在需要的時候,“@2x”的版本會被QML的Image元素以及QIcon自動加載。
Image { source = “foo.png” } QIcon icon(“foo.png”)
(對于QIcon請記住使用AA_UseHighDpiPixmaps)
QPA允許我們相對容易的完成跨平臺的實現。Qt現在把這一問題分為三層:
應用程序層(應用程序代碼和使用QPA類的Qt代碼)
QPA層(QWindow、QScreen、QBackingStore)
平臺插件層(QPlatform*子類)
簡化一下,應用程序層是在設備無關像素空間中工作的,并不知道設備像素。平臺插件是在設備像素空間中工作的,并不知道設備無關像素。QPA層在兩者之間,基于一個由環境變量QT_HIGHDPI_SCALE_FACTOR指定的縮放因子進行轉換。
實際上,這個情況還會更復雜一些,各層之間會有泄露的事情發生,并且在Mac和iOS下還會有一些例外情況。
代碼在github上。最后是XCB下的Qt Creator的截屏:
DPI縮放的Qt Creator
QT_HIGDPI_SCALE_FACTOR=2縮放的Qt Creator
High DPI Revisited
A few weeks ago I talked about high DPI in KDE applications
By settings QT_DEVICE_PIXEL_RATIO=2 Qt will scale all painting to draw things twice the size
By default this will just scale all our p_w_picpaths so it slightly defeats the point of buying a fancy new high resolution screen
Qt can try and be clever and draw high resolution icons and other p_w_picpaths
This is liable to break stuff, so requires each and every app to opt-in
On Monday this week I was loaned a high resolution laptop, and set about trying to make sure everything works perfectly within the KDE world.We can now set this environment variable from a configuration file, and a user interface is in review to allow the user to manually set their scaling factor.
I then set about trying to enable high resolution p_w_picpath support in various applications and trying to fix all that is broken.
This task is two-fold. The first is fixing any bugs that result in simply enabling the high resolution icons. Second is making sure applications that provide their own p_w_picpaths, do so in a way that still look spot on when used on a high resolution monitor.
Here is my screenshot just after installing Kubuntu CI on a high resolution laptop (3800x1800).
We can correct some parts by just boosting the font size, but that doesn't solve the problems of small checkboxes, buttons and other hit areas. This isn't just a superficial problem and it becomes a major usability problem especially as these screens become more widespread.
This second screenshot shows the result with the device pixel ratio set and a weeks worth of fixing in a range of apps. (click for full size)
The most obvious thing is that the sizes are bigger, but more importantly this is happening whilst all icons and scrollbars remain crystal clear at the native resolution for that screen.
A zoomed in section looks like this:
Every Qt5 app can double up with no work at all, but to look right requires some effort.
For some applications supporting high DPI has been easy. It is a single one line in KWrite, and suddenly all icons look spot on with no regressions. For applications such as Dolphin which do a lot more graphical tasks, this has not been so trivial. There are a lot of p_w_picpaths involved, and a lot of complicated code around caching these which conflicts with the high resolution support without some further work.
I am tracking progress on a Kanboard page . Naturally I can't do every application, but I hope that by checking a few I can make sure all of our frameworks have full support making it easy for every other developer.
We also have a problem that Qt4 applications do not support device independent pixels. There are still many applications without a frameworks release even in the upcoming 15.04 applications release. Even in the next applications release in 15.08 August we are still unlikely to see a released PIM stack.Is it a good idea to add an option into our UIs that improves some applications at the cost of consistency? It's not an easy answer.
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。