VC获取屏幕dpi,win32绘图适配高dpi模式
默认MFC支持高dpi模式
mfc程序和控件都是支持高dpi的自适应的,不需要特殊处理,本篇幅可以用在winapi绘制图形高dpi糊掉。
通过winapi提供接口获取屏幕dpi
win8以上通过函数GetDpiForWindow获取
例:
int iDpi = GetDpiForWindow(m_hWnd);
通用推荐使用函数GetDeviceCaps获取
例:
int iDpi = GetDeviceCaps(pDC->m_hDC, LOGPIXELSX);
使用StretchBlt代替BitBlt进行图像绘制
注意MulDiv函数
MulDiv函数执行示例
int resWidth = MulDiv(rect.Width(), 96, iDpi);
使用MuDiv 就相当于
int resWidth = rect.Width() * 96 / iDpi;
其中iDpi就是上面获取到的dpi值,96为设备绘制为100%大小时dpi。
通过这个函数算出实际需要绘制的图形大小。
推测
根据推测高dpi模式图像会糊掉应该是windows在图形绘制到dc之后又进行了一次放大。
所以想要不被糊掉一个途径就是在绘制时进行缩放,在实际的高dpi生效时就会把图像放大,具实际操作发现此时缩放绘制的图像在高dpi模式下并不会失真,估计是系统底层又进行了一次操作。
StrechBlt替换
此过程在OnDraw函数中,&dcMem是原生成内存dc,已在上绘制完,接下来就往窗口dc上进行绘制
原来的绘制流程是直接使用BitBlt进行,此过程中rect是通过 GetClientRect 获取到的窗口区域。
dcMem是对整个窗口区域绘制的内存dc,大小是正常的96dpi的大小。
CRect rect;
GetClientRect(rect);
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &dcMem, 0, 0, SRCCOPY);
现在需要把绘制流程改为StretchBlt,将dcMem中的数据缩小绘制到窗口dc中,再由系统高dpi进行放大
int iDpi = GetDeviceCaps(pDC->m_hDC, LOGPIXELSX);
pDC->StretchBlt(0, 0, MulDiv(rect.Width(), 96, iDpi), MulDiv(rect.Height(), 96, iDpi), &dcMem, 0, 0, rect.Width(), rect.Height(), SRCCOPY);