若是說之前XP時代咱們還有理由不關注高DPI, 那麼在移動設備時代和大顯示器的高分辨率時代, 咱們就沒有理由不關注高DPI了, 好比Surface Pro的分辨率是1920x1080, 這種狀況下若是系統咱們不設置高DPI, 基本上就無法觸摸和操做了,因此如今普通程序對高DPI的支持已經成爲趨勢了。
什麼DPI? 全稱是dots per inch (DPI), 也就是每英寸的點數,在顯示器上就是每英寸的像素個數,Window上通常默認是96 dpi 做爲100% 的縮放比率, 可是要注意的是該值未必是真正的顯示器物理值, 只是Windows裏咱們的一個參考標準。
下面咱們思考爲何DPI設置高了以後, 咱們看到的字體會變大? 由於系統字體是是以固定大小(宋體10號字,物理尺寸爲(10/72)英寸)設計的, 當咱們DPI設置高了以後 ,說明該字體要佔有更多的像素, 在屏幕分辨率不變的前提下, 看起來也就大了。因此若是咱們設置高DPI,一般也意味着咱們的顯示器是高分辨率, 裏面的字體看起來過小了, 咱們須要提升DPI來把內容放大。
那麼咱們的程序如何才能支持高DPI? 對於高DPI的支持, 不一樣操做系統有不一樣的方案。一般來講若是咱們程序支持高DPI, 意味着咱們要對繪畫的內容進行相應的放大, 好比字體,圖片和控件等。固然, 若是咱們用的是系統字體(好比GetStockObject(DEFAULT_GUI_FONT)), 那麼這種狀況下咱們不用操心, 由於系統會對該字體在高DPI時進行相應的放大; 若是咱們是用CreateFont本身建立的字體, 那就要咱們本身對該字體進行放大了。
下面咱們看XP是如何對高DPI進行支持的?
XP對高DPI的支持比較差勁, 大部分狀況下就是字體的放大, 固然咱們程序也能夠經過GetDeviceCaps(hDC, LOGPIXELSX)獲取DPI後本身對繪畫的內容進行縮放。
下面咱們看Vista/Win7/Win8是如何對高DPI進行支持的?
咱們知道Vista/Win7咱們能夠禁止DWM(Desktop Window Manager), 該模式咱們稱之爲Basic模式, 這種模式下的高DPI效果和XP同樣。
對於DWM沒有禁掉的狀況, Vista/Win7/Win8 對高DPI的支持又分爲2種狀況, 具體看下圖:
一種XP風格的高DPi支持, 這種方式咱們上面討論過了;
還有一種是經過 DWM 虛擬化支持的 高DPI方式, 下面咱們討論下該方式:
該種方式的高DPI支持是經過DWM的縮放實現的, 具體過程是這樣的, 好比咱們當前系統的DPI是200%, 咱們程序運行時,系統會告訴你當前DPI仍然是96(100%), 因此咱們程序會仍然按照100%的方式進行繪畫, 可是可是系統給咱們的座標是根據DPI縮小事後的(也就是咱們對窗口調用GetWindowRect或是經過GetSystemMetrics(SM_CXSCREEN)獲得的大小會比實際大小減半) , 當咱們畫完以後, DWM再對整個窗口進行200% 放大後畫到屏幕上, 這樣看起來咱們的程序就自動支持高DPI了。
這種方式看起來很美妙, 可是它也有缺點, 主要是通過縮放後的內容看起來會變模糊, 好比文字會有明顯的鋸齒。
既然DWM虛擬化用戶效果有時不是那麼好, 那麼咱們不少時候可能會本身支持高DPI, 如何讓咱們的程序禁用該效果?
這裏還有特殊狀況也提一下: 咱們在高DPI下經過窗口句柄取到的座標信息是和目標程序是否支持DWM虛擬化相關聯的, 咱們對其餘支持DWM虛擬化的程序窗口調用GetWindowRect, 取到的座標也是通過DWM縮放後的座標; 對禁用DWM虛擬化程序的窗口調用GetWindowRect, 取到的座標則是沒有通過縮放的原始座標。
typedef enum _Process_DPI_Awareness {
Process_DPI_Unaware = 0,
Process_System_DPI_Aware = 1,
Process_Per_Monitor_DPI_Aware = 2
} Process_DPI_Awareness;
下面咱們依次討論這3種方式:
第一種Unaware, 該種方式是告訴系統, 個人程序不支持DPI aware, 請經過DWM虛擬化幫咱們實現。 該方式和上面Win7/Win8對高DPI的支持的實現基本同樣,主要區別是它經過GetWindowRect取到的座標都是通過DWM縮放後的, 不管對方窗口是否是支持DWM虛擬化。
第二種方式是System DPI aware, 該方式下告訴系統, 個人程序會在啓動的顯示器上本身支持DPI aware, 因此不須要對我進行DWM 虛擬化。 可是當個人程序被拖動到其餘DPI不同的顯示器時, 請對咱們先進行system DWM虛擬化縮放。
第三種方式是Per Monitor DPI aware, 該方式是告訴系統, 請永遠不要對我進行DWM虛擬化,我會本身針對不一樣的Monitor的DPi縮放比率進行縮放。
再介紹下相關API:
最後,簡單總結下, 從上面咱們能夠看到微軟在不一樣操做系統上對高DPI支持的改進線路,不少方面也體現了他們對老程序兼容性上的考慮, DWM虛擬化雖然很簡單, 卻丟失了用戶體驗。
PS, 我在我機器上測試發現,桌面程序基本上只有微軟本身的程序能作到在高DPI下完美支持, 其餘大部分程序(即便如Chrome)也是經過DWM虛擬化實現的高DPI支持。固然如今WPF和Window store App基本上都是內置支持高DPI的。
統計下, 大家的程序支持高DPI嗎?