Qt之高DPI顯示器(一) - 解決方案整理

原文連接:Qt之高DPI顯示器(一) - 解決方案整理html

最近一直在處理高DPI問題,也花費了很多功夫,前先後後使用了多種解決方案,各類方案也都有利弊,筆者最終採用了自適配方案,雖然複雜一些,可是結果可控。這裏把處理的過程記錄下來,留給有一樣需求的同窗web

DPI發展

隨着顯示器質量的增高,高分屏逐漸增多,不少用戶平時使用的機器都是2k屏甚至是4k屏。正則表達式

顯示器分辨率變大後,一樣的物理尺寸下能夠表示更多的點,也就是咱們平時所說的像素。shell

誤區說明windows

咱們如今平時所說的軟件像素應該是PPI(Pixels Per Inch),中文意思是每英寸像素數,而咱們windows系統中修改的DPI其實就是這個PPI。api

爲何會有這個誤區呢?app

答案:由於這個世界正在盡人類想象所能地使其變得難懂。函數

一、PPI

每英寸像素數,像素表示的是「圖片的原色」,足夠靠近你顯示屏上的圖片你就會看到他們:一排一排的小方塊。換句話說,他們也是一個電子圖片的最小可尋址單元。工具

其中每個電子圖片則是由更小的光學單元組成,這些光學單元就是紅色、綠色和藍色。佈局

PPI的始做俑者

可悲的是,一些生產廠商將這些 sub-pixel 描述爲「dot」,爲何這樣認爲呢?由於他和DPI的墨點工做方式相同,而後就是一頓商業互吹,用DPI來描述PPI就被開始誤用了。

須要注意的是,pixel 是一個固定大小的物理物體,所以,一個屏幕上的 PPI 是固定的。大部顯示器都是 66 - 130ppi。

PPI 和打印的目標

只有要打印出來時,設定 PPI 纔有效。

在打印的過程當中,全部在屏幕上組成圖片的物理pixel都被轉換成不一樣色調的小正方形,這些小正方形是另一種「像素」,下文中都使用pixel-d來表示。

當打印時,若是增長圖片的大小爲300%,圖片是放大了300%,可是圖片的顆粒度更大了!若是想要清晰度不變,而大小發生變化,這個時候咱們就須要修改PPI。

看一個圖片打印的示例

圖片尺寸 PPI 物理春 結果 打印機(DPI) 每英寸點數 總點數 結果
300px * 300px 10 30 * 30英寸 很是大 60 60 * 60 30 * 30 * 每英寸點數 很是虛
300px * 300px 300 1 * 1英寸 很是小 90 90 * 90 1 * 1 * 每英寸點數 細膩
300px * 300px 60 5 * 5英寸 可能合適 120 120 * 120 5 * 5 * 每英寸點數 很是細膩

對於最終的打印輸出而言,將 PPI 輸入認爲是一種調節物理大小的方式,而不是分辨率。

PPI能夠決定打印的大小,想要更加細膩的打印效果則是須要增長更多的pixel-d。

二、DPI

DPI 只是打印機的技術參數,就像是你電腦顯示器的 pixel 分辨率。

好比說,你以 600 dpi 來打印一幅 150ppi 的圖像,那麼每一個「pixel」將會包括16個 dot(600 dot/150 「pixel」 = 4 x 4 / 「pixel」)。

名稱 說明
Inch英寸 物理單位,能夠衡量顯示器的物理大小
PPI每英寸像素數 物理值,由硬件廠商決定。表示每英寸下能夠存儲多少個光學單元
DPI每英寸點數 打印機單位,一個技術參數,表明打印機的好壞。一般來講,dot 矩陣打印機可打印的 dpi 範圍爲 60 - 90,噴墨打印機的 dpi 範圍爲 300 - 600,而激光打印機爲 600 - 1800。
Resolution分辨率 顯示器單位,描述每英寸像素數
windows系統DPI 我的理解:windows本身的一個標準,表示每英寸像素數,也就是PPI(顯示器真正的PPI不支持修改);相似於打印時的DPI。一個技術指標或者參數

綜上:對於咱們軟件開發來講,其實所說的像素大小都是指PPI,這裏要區分不是顯示器的固定PPI,windows系統上修改DPI時其實修改的系統模擬出來的PPI;就相似於咱們打印圖片時輸出的PPI同樣,能夠決定圖片打印的物理尺寸。

1、Win自適應系統

High DPI Desktop Application Development on Windows

總的來講能夠用,可是會模糊。目前win10效果最好,基本清晰,可是還能夠優化;win7系統上基本是糊的,若是您的產品是一個互聯網軟件,那麼系統自適應絕對不是最佳方案。

2、Qt機制

要使用Qt高DPI縮放,首先得禁用系統縮放。

方式1: QApplication構造前設置Qt::AA_EnableHighDpiScaling屬性

方式2: 設置環境變量QT_AUTO_SCREEN_SCALE_FACTOR爲1

一、Windows系統DWM縮放

啓用系統縮放時,因爲使用的都是圖片拉伸的方式則會產品模糊

--- DPI Unaware System DPI Awareness Per-Monitor and Per-Monitor (V2) DPI Awareness
含義 啓用系統縮放 應用程序已在啓動的顯示器上支持高DPI,可是沒有對其餘顯示器支持,也就是說請系統在其餘顯示器上幫我啓用系統縮放 永遠不要對我作虛擬化,由於我本身能搞定

啓用系統DPI虛擬化,能夠調用SetProcessDpiAwareness接口。該接口有一個枚舉的參數類型PROCESS_DPI_AWARENESS,可是這個參數只有在Win8.1以後纔有。

Win10上有一個加強型虛擬化,能夠大大優化DWM效果。

Win7能夠調用SetProcessDpiAware接口

二、 Qt適配高DPI

基於Qt5.7測試結果

--- Qt虛擬化 推薦度 系統虛擬化 推薦度
Win7 只能使用整數倍放大,效果會模糊 * 支持系統下拉框中的浮點縮放,圖片會模糊(有些系統失效) **
Win10 只能使用整數倍放大,字體比較清晰,可是須要適配高DPI圖片 **** 圖片拉伸,啓用了Win加強型DWM,效果還能夠,但字體沒有Qt適配清楚 **

基於Qt5.13測試結果

--- Qt虛擬化 推薦度 系統虛擬化 推薦度
Win7 同Qt5.7,可是顯示有過好於Qt5.7 ** 同Qt5.7 **
Win10 支持系統自定義分辨率,例如125%、175%
在不一樣分辨率下分別啓動軟件後,在相同指定分辨率下顯示大小不同
例如:在分辨率125%下啓動軟件,此時不要關閉程序1並修改分辨率爲150%,而後在啓動一次軟件爲程序2,觀察程序1和程序2的大小,發現不一大。
**** 同Qt5.7 **

咱們的軟件在Win10上會強制啓用加強型虛擬戶,須要對exe右鍵屬性-兼容性-全部用戶設置進行禁用

三、適配DPI結論

一、Qt5.7只支持整數比例縮放

  1. 100%:0-149%
  2. 200%:150%-249%
  3. 300%:250%-349%
  4. ...日後依次類推
  5. 100%DPI下啓動程序,切換DPI時沒法對已啓動軟件大小作出影響;反之若是非100%DPI啓動程序則是正常的。

二、Qt5.13支持系統預約義縮放比例

  1. 100%:100%
  2. 125%:125%
  3. ...日後依次類推,若是自定義了縮放比,默認按250%(測試結果,不必定準,有待測試多個顯示器)顯示。但不一樣分辨率下啓動同一個軟件後(啓動的軟件不關閉切換分辨率),在最後切換的分辨率上觀察程序,大小都不同。

Qt5.7和Qt5.13都有的問題

100%DPI啓動軟件後,再次修改DPI時,軟件大小不會再次發生變化。

到這這裏高DPI測試基本結束,綜合各類狀況,得出以下兩個結論

  1. 高DPI適配使用Qt來作。Qt支持高DPI比windows系統縮放效果要好。
  2. Qt使用5.7。升級Qt到5.13時,須要升級vs至少到2015,而且軟件只能是x64版本的,不然還須要升級工具到更高版本,而且咱們的依賴庫也可能須要從新編譯,成本較高,並且5.13支持高DPI比5.7多的地方咱們暫時能夠不須要(主要是支持系統定義好的浮點縮放),所以不作Qt升級工做。

3、Qt適配

因爲升級到5.13有不少成本,暫且使用Qt5.7進行適配

使用Qt5.7適配高DPI

缺點請看一節第三小節中Qt5.7只支持整數比例縮放

決定使用Qt5.7適配高DPI後,咱們須要幹以下幾件事:

  1. 原生放大比例和web放大比例統一
  2. 系統DPI修改時,禁用刷新
  3. 添加不一樣DPI下圖片

一、統一比例

100% 200%

二、強制刷新

WM_DPICHANGED

接收系統DPI發生變化消息

三、圖片適配

添加不一樣DPI下圖片

Qt適配完以後仍是存在一些問題,比方說只支持系統已有縮放比,不能支持任意比例縮放,並且有時候還存在刷新問題、軟件異常放大等等。

4、本身適配

業務層不須要考慮scale,只須要使用T打頭控件開發便可。

注:因爲篇幅的緣故,T打頭的控件下一篇文章講解

適配項目

  1. 窗口大小
  2. 字體大小
  3. 間距
  4. 圖標

一、窗口大小

重寫頂層窗口設置界面大小函數

setFixedWidth
setFixedHeight
......

動態調整

記錄調用了哪些設置大小的函數,在dpi發生變化時從新設置一遍

if (testflag("setfixedWidth"))
{
    setFixedWidth(width * scale);
}

二、字體大小

從新生成qss文件

讀取原有qss文件,使用正則表達式生成scale版本的新qss文件。

三、間距

佈局的margin

記錄調用了哪些設置大小的函數,在dpi發生變化時從新設置一遍,相似於窗口大小變化時所做調整

if (testflag("margin"))
{
    setContextMargin(...);
}

padding和margin

讀取原有qss文件,使用正則表達式生成scale版本的新qss文件。

四、圖標

工程中須要添加1x 2x 3x等不一樣分辨率的圖標,1x圖標爲正常狀況下使用的圖標,2x和3x圖標分別是高分辨率下的圖標

替換圖標有兩種狀況,一種是使用qss方式貼圖,另外一種是自繪貼圖

qss方式

預先生成高分辨率下的整數倍xxx_2x.qss和xxx_3x.qss文件,實際使用的時候在動態調整,具體方案下一篇文章講解

自繪

若是是自繪文字圖圖片,那就須要本身控制縮放比,和圖片壓縮係數,具體方案下一篇文章講解

5、參考文章

PPI vs. DPI: 有什麼區別?

High DPI Desktop Application Development on Windows

PROCESS_DPI_AWARENESS Enumeration

SetProcessDPIAware function:Win Vista開始支持的接口

SetProcessDpiAwareness function:Win8.1開始支持的接口

關於Windows高DPI的一些簡單總結

如何開發新的Qt 5.7高DPI每監視器DPI感

值得一看的優秀文章:

  1. 財聯社-產品展現
  2. 廣聯達-產品展現
  3. Qt定製控件列表
  4. 牛逼哄哄的Qt庫

若是您以爲文章不錯,不妨給個 打賞,寫做不易,感謝各位的支持。您的支持是我最大的動力,謝謝!!!




很重要--轉載聲明

  1. 本站文章無特別說明,皆爲原創,版權全部,轉載時請用連接的方式,給出原文出處。同時寫上原做者:朝十晚八 or Twowords

  2. 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時經過修改本文達到有利於轉載者的目的。

相關文章
相關標籤/搜索