高DPI顯示器愈來愈普及,軟件天然也要適應這個變化,最近實習的時候也遇到了一個關於DPI縮放的問題。由於內部框架的一個控件有BUG,會致使內容的顯示出問題,後來實在沒辦法改爲了用Windows Native API來本身定義字體,可是這一寫就出問題了,原本在內部開發機100%放縮下好好的,一跑到我本身的WIN10,在2K屏放上縮放125%就字體就顯示不正常了(字體變得過大)。windows
Window Vista之後的系統能夠直接來個SetProcessDpiAwareness來控制程序的DPI問題,可是這個函數不是很好用,仍是沒有辦法精確控制縮放,並且這個函數只有在Windows 8.1以上的系統才能用(SetProcessDPIAware也行,不過也必須是Windows Vista以上的系統),萬一咱們的程序須要在XP上運行呢?這就須要用另一個辦法了。框架
其實這個辦法也很簡單,就是用GetDeviceCaps來獲取當前環境句柄的DPI就能夠了,而後和默認的DPI(96)作運算,得到咱們真正想要的DPI函數
case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd,&ps); auto curDPIX = GetDeviceCaps(hdc, LOGPIXELSX); auto curDPIY = GetDeviceCaps(hdc, LOGPIXELSY); std::wstring str(L"Hello World"); LOGFONT lf; HGDIOBJ hObject; ZeroMemory(&lf, sizeof(LOGFONT)); f.lfCharSet = GB2312_CHARSET; lf.lfWidth = MulDiv(20, 96, curDPIX); lf.lfHeight = MulDiv(55, 96, curDPIY); lf.lfPitchAndFamily = VARIABLE_PITCH; swprintf_s(lf.lfFaceName, _countof(lf.lfFaceName), L"微軟雅黑"); hObject = SelectObject(hdc, CreateFontIndirect(&lf)); TextOut(hdc, 21, 100, str.data(), str.length()); DeleteObject(SelectObject(hdc, hObject)); lf.lfWidth = 20; lf.lfHeight = 55; hObject = SelectObject(hdc, CreateFontIndirect(&lf)); TextOut(hdc, 21, 200, str.data(), str.length()); DeleteObject(SelectObject(hdc, hObject)); EndPaint(hwnd, &ps); return 0; }
這裏演示的是在屏幕上輸出Hello Wolrd,如今假設咱們的字體被放大了,可是假設咱們其餘控件沒有被放大,那麼字在控件裏面就會顯示不正常,這個時候就要縮小字的尺寸,要想和100%的時候相似,就須要MulDiv(尺寸, 96, curDPI);一下,字體被縮小了同理字體
這下咱們能夠看到,第二行是在120%放大下被放大的高度爲55,寬度爲22的字體,字體偏大,咱們經過上面的方法,把字體縮小回正常的尺寸spa