您好,登錄后才能下訂單哦!
DPI , dot per inch ,即每英寸包含的點(diǎn)數(shù)。還有一個(gè)概念是 PPI ,即每英寸包含的像素?cái)?shù)。一般我們用 DPI 就夠了,對于專業(yè)人士處理超高 DPI 的場景,使用 PPI 可能更精確一些。在 Qt 中,只有 DPI ,所以我們單說它吧。
這個(gè)值越大,像素密度越大,小尺寸的屏幕就可以有大分辨率。比如有的 Android 手機(jī), 3.7 吋屏幕就能提供 960x540 的分辨率,而有的手機(jī), 5 吋屏幕卻提供 800x480 的分辨率。這兩種不同屏幕的尺寸和分辨率的手機(jī),5 吋屏看起來會有顆粒感,而 3.7 吋看起來則非常細(xì)膩。這就是像素密度帶來的差別。
有的屏幕,橫向的 DPI 和縱向的 DPI 不一樣,即像素點(diǎn)不是正方形,這就更復(fù)雜了……
我們在寫應(yīng)用時(shí),理想的情況是:應(yīng)當(dāng)根據(jù) DPI + 屏幕分辨率來設(shè)置界面元素的大小。
Mac OS 10.8(10.7是非正式的?)添加了對高DPI的Retina顯示的支持。Qt 4免費(fèi)獲得這一支持,因?yàn)樗褂玫氖荂oreGraphics繪制引擎。
Qt 5使用的是光柵繪制引擎并且Qt通過縮放繪圖器變換(transform)實(shí)現(xiàn)了高DPI矢量的繪制。HITheme同時(shí)為Qt 4和5提供了高DPI的Mac風(fēng)格。在Qt 5的Fusion風(fēng)格中,對于高DPI模式的支持也已經(jīng)修改好了。
OpenGL是一種基于設(shè)備像素的API并且對于高DPI模式也仍然如此。在NSView中有一個(gè)flag可以用來開啟或者禁用2x縮放——Qt在所有情況下都可以設(shè)置它。Shaders運(yùn)行在設(shè)備像素中。
Qt Quick 1是構(gòu)建于QGraphicsView之上的,它是一個(gè)QWidget并且通過QPainter獲得對于高DPI的支持。
Qt Quick 2是基于Scene Graph(和OpenGL),已經(jīng)更新了高DPI的支持。Qt Quick控件(也就是以前的Desktop Component)也已經(jīng)更新了在高DPI模式下的渲染,其中包括距離場(distance field)文本渲染。(譯者注:關(guān)于距離場,可以參考Yoann Lopes – Text Rendering in the QML Scene Graph以及iKDE上的譯文。)
這里的賣點(diǎn)是應(yīng)用程序開發(fā)人員不需要關(guān)心這些,您只需要在設(shè)備無關(guān)像素的空間里舒適地開發(fā),Qt和/或OS會為您處理那些復(fù)雜的事情。但有一個(gè)例外,光柵內(nèi)容(raster content)——需要提供高DPI光柵內(nèi)容,并且應(yīng)用程序代碼需要正確處理這些內(nèi)容。
QPainter代碼絕大多數(shù)情況下都和原來一樣。我們來看看繪制漸變(gradient)的代碼:
在高DPI顯示器上,這個(gè)漸變在屏幕上的大小還是一樣的,但是被填充了更多的(設(shè)備)像素。
繪制一個(gè)像素映射(pixmap)也是類似的:
QRect destinationRect = ...QPixmap pixmap = ...painter.drawPixmap(destinationRect, pixmap);
為了避免在高DPI顯示器上出現(xiàn)縮放失真,像素映射必須包含足夠的像素:兩倍于destinationRect的寬和高。應(yīng)用程序可以直接提供它們,也可以使用QIcon來管理不同的解析度:
QRect destinationRect = ...QIcon icon = ...painter.drawPixmap(destinationRect, icon.pixmap(destinationRect.size()));
QIcon::pixmap()已經(jīng)被修改了,可以在高DPI系統(tǒng)中返回一個(gè)更大的像素映射。這種行為的改變會破壞現(xiàn)有的代碼,所以它是由AA_UseHighDpiPixmaps這個(gè)應(yīng)用程序?qū)傩詠砜刂频模?/p>
qApp->setAttribute(Qt::AA_UseHighDpiPixmaps);
在Qt 5.1中這個(gè)屬性默認(rèn)值是關(guān)閉的,但在未來的Qt發(fā)布中它很有可能默認(rèn)為打開。
Qt的窗口部件有一些極端情況。在理想情況下,它一直使用QIcon,并且在繪制的時(shí)候會使用正確的像素映射,但是實(shí)際情況是Qt API經(jīng)常直接生成和使用像素映射。當(dāng)像素映射的大小被用來計(jì)算布局的幾何信息時(shí),會發(fā)生錯誤——如果一個(gè)像素映射已經(jīng)是高分辨率的,那么在屏幕上它就不應(yīng)該再占用更多的空間。
通過使用QPixmap::devicePixelRatio(),就能讓200x200的像素映射實(shí)際占據(jù)100x100的設(shè)備無關(guān)像素。由QIcon::pixmap()返回的像素映射中devicePixelRatio已經(jīng)設(shè)置好了。
例如QLabel就是一個(gè)“像素映射消費(fèi)者”:
QPixmap pixmap2x = ...pixmap2x.setDevicePixelRatio(2.0); QLabel *label = ...label->setPixmap(pixmap2x);
然后QLabel會除以devicePixelRatio來獲得布局的大?。?/p>
QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio();
與此類似的幾種情況在Qt中都已經(jīng)修復(fù),并且應(yīng)用程序代碼在啟用AA_UseHighDpiPixmaps之前也需要做類似處理。
下面幾個(gè)Qt類中都提供了devicePixelRatio()的讀寫函數(shù):
類 | 注釋 |
---|---|
QWindow::devicePixelRatio() | 推薦使用的讀寫函數(shù) |
QScreen::devicePixelRatio() | |
QGuiApplication::devicePixelRatio() | 如果沒有QWindow指針,請使用這個(gè) |
QImage::[set]devicePixelRatio() | |
QPixmap::[set]devicePixelRatio() |
字體大小還可以和原來一樣,會在高DPI顯示中產(chǎn)生類似的大小(但會有一點(diǎn)小問題)。字體的像素大小是設(shè)備無關(guān)的像素大小。您在高DPI顯示中永遠(yuǎn)不會得到太小的文本。
OpenGL是在設(shè)備像素空間中工作的。例如,傳遞給glViewport的寬和高應(yīng)該是設(shè)備像素。QGLWidget::resizeGL()中的寬和高也是設(shè)備像素的。
不管怎樣,QGLWidget::width()實(shí)際上就是QWidget::width(),它返回的是設(shè)備無關(guān)像素的值。如果需要,用它來乘以widget->windowHandle()->devicePixelRatio()可以解決很多問題。
Qt Quick 2和Qt Quick控件可以直接使用。因?yàn)榇翱诓考淖鴺?biāo)是設(shè)備無關(guān)像素的。Qt Quick也有幾個(gè)和光柵相關(guān)的極端情況,因?yàn)镼ML的Image元素是通過URL來指定圖像源的,這樣就避免了像素映射的傳遞。
Qt Quick控件
還有一個(gè)例外是OpenGL著色器(shader),它運(yùn)行在設(shè)備像素空間中并且可以看到全分辨率。在通常情況下這沒有什么問題,我們應(yīng)該知道的一件重要的事情是,鼠標(biāo)坐標(biāo)是設(shè)備無關(guān)像素的,也許需要被轉(zhuǎn)換成設(shè)備像素。
運(yùn)行中的著色器效果實(shí)例
正如我們所看到的,在縮放的情況下,光柵內(nèi)容看起來會不夠好,所以必須提供高解析度的內(nèi)容。作為應(yīng)用程序開發(fā)人員,您有兩個(gè)選項(xiàng):(請忽略“什么都不做”選項(xiàng))
使用高解析度版本替換現(xiàn)有光柵內(nèi)容
另外提供一份高解析度內(nèi)容
第一個(gè)選項(xiàng)很簡單,因?yàn)槊總€(gè)資源只有一個(gè)版本??墒悄苍S會發(fā)現(xiàn)(或者您的設(shè)計(jì)師會告訴您)像圖標(biāo)這樣的資源只有在它被創(chuàng)建的那個(gè)特定解析度下看起來才最好。為了解決這個(gè)問題,Qt沿用了“@2x”這種圖像文件名的方案:
foo.pngfoo@2x.png
這樣高解析度的內(nèi)容和原來的一一對應(yīng)。在需要的時(shí)候,“@2x”的版本會被QML的Image元素以及QIcon自動加載。
Image { source = “foo.png” } QIcon icon(“foo.png”)
(對于QIcon請記住使用AA_UseHighDpiPixmaps)
QPA允許我們相對容易的完成跨平臺的實(shí)現(xiàn)。Qt現(xiàn)在把這一問題分為三層:
應(yīng)用程序?qū)?應(yīng)用程序代碼和使用QPA類的Qt代碼)
QPA層(QWindow、QScreen、QBackingStore)
平臺插件層(QPlatform*子類)
簡化一下,應(yīng)用程序?qū)邮窃谠O(shè)備無關(guān)像素空間中工作的,并不知道設(shè)備像素。平臺插件是在設(shè)備像素空間中工作的,并不知道設(shè)備無關(guān)像素。QPA層在兩者之間,基于一個(gè)由環(huán)境變量QT_HIGHDPI_SCALE_FACTOR指定的縮放因子進(jìn)行轉(zhuǎn)換。
實(shí)際上,這個(gè)情況還會更復(fù)雜一些,各層之間會有泄露的事情發(fā)生,并且在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.
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。