为何调整窗口大小时DC的Window Extent与Viewport Extent保持不变?
问题原因及解决方案
核心原因
你观察到的现象源于GDI映射模式的默认行为:
- 固定映射模式(MM_TEXT、MM_HIENGLISH、MM_LOENGLISH、MM_HIMETRIC、MM_LOMETRIC、MM_TWIPS):这些模式的
WindowExtent和ViewportExtent是系统预定义的常量值,不会随窗口尺寸变化。比如MM_TEXT默认WindowExt=(1,1)、ViewportExt=(1,1);MM_HIENGLISH默认WindowExt=(1000,1000)、ViewportExt=(1,-1),窗口调整大小不会改变这些固定值。 - 可调整映射模式(MM_ISOTROPIC、MM_ANISOTROPIC):你仅调用
SetMapMode切换到这些模式,但未通过SetWindowExtEx或SetViewportExtEx设置自定义范围,系统会保留初始默认值,因此也不会随窗口大小变化。
另外你的WM_SIZE分支末尾缺少break语句,会导致代码执行完WM_SIZE后直接进入WM_PAINT分支,虽不影响当前核心功能,但属于逻辑不严谨,建议补上。
解决办法
如果需要让ViewportExtent随窗口大小动态变化,需在WM_PAINT(或WM_SIZE)中针对目标映射模式手动设置窗口/视口范围。示例修改如下:
case WM_PAINT: { int height = 50; TCHAR buff[256] = { 0 }; HDC hdc = BeginPaint(hwnd, &ps); // 获取当前客户区尺寸 RECT clientRect; GetClientRect(hwnd, &clientRect); int cxClient = clientRect.right - clientRect.left; int cyClient = clientRect.bottom - clientRect.top; // MM_TEXT模式:设置ViewportExt为客户区大小 SetMapMode(hdc, MM_TEXT); SetViewportExtEx(hdc, cxClient, cyClient, NULL); // 新增设置视口范围 SIZE size1; GetWindowExtEx(hdc, &size1); SIZE size2; GetViewportExtEx(hdc, &size2); _stprintf_s(buff, TEXT("TEXT MODE:WindowExtent=[%d, %d], ViewportExtent=[%d,%d]"),size1.cx,size1.cy, size2.cx,size2.cy); TextOut(hdc,0, height * 0,buff, _tcslen(buff)); // MM_HIENGLISH模式:匹配其0.001英寸单位与Y轴向上的特性 SetMapMode(hdc, MM_HIENGLISH); SetViewportExtEx(hdc, cxClient * 1000, -cyClient * 1000, NULL); GetWindowExtEx(hdc, &size1); GetViewportExtEx(hdc, &size2); memset(buff, 0, 256); _stprintf_s(buff, TEXT("HIENGLISH MODE:WindowExtent=[%d, %d], ViewportExtent=[%d,%d]"), size1.cx, size1.cy, size2.cx, size2.cy); TextOut(hdc, 0, -height * 1, buff, _tcslen(buff)); // 其余模式按对应单位、坐标方向调整ViewportExt即可... EndPaint(hwnd, &ps); break; }
注意:不同映射模式的单位和坐标方向存在差异,设置ViewportExt时需匹配模式特性(比如MM_HIENGLISH的Y轴正向向上,因此cy需设为负值)。
内容的提问来源于stack exchange,提问作者SZYoo
相关产品推荐
相关产品推荐

