在 OnSize 中實現自動縮放,根據視圖類型選擇兩種模式之一:
void CMyDialog::OnSize(UINT nType, int cx, int cy) {
CDialogEx::OnSize(nType, cx, cy);
if (nType == SIZE_MINIMIZED) return;
// 記錄初始尺寸(OnInitDialog 中初始化)
if (m_origWidth == 0) { m_origWidth = cx; m_origHeight = cy; return; }
double ratioX = (double)cx / m_origWidth;
double ratioY = (double)cy / m_origHeight;
// 重定位每個控件
RepositionCtrl(IDC_EDIT1, ratioX, ratioY, ANCHOR_LEFT | ANCHOR_RIGHT | ANCHOR_TOP);
RepositionCtrl(IDC_LIST1, ratioX, ratioY, ANCHOR_ALL);
RepositionCtrl(IDC_BUTTON_OK, ratioX, ratioY, ANCHOR_RIGHT | ANCHOR_BOTTOM);
}
void CMyDialog::RepositionCtrl(int nID, double rX, double rY, DWORD anchor) {
CWnd* pWnd = GetDlgItem(nID);
if (!pWnd) return;
CRect rect;
pWnd->GetWindowRect(&rect);
ScreenToClient(&rect);
// 根據錨點計算新位置
if (anchor & ANCHOR_LEFT) rect.left = (int)(rect.left * rX);
if (anchor & ANCHOR_RIGHT) rect.right = (int)(rect.right * rX);
if (anchor & ANCHOR_TOP) rect.top = (int)(rect.top * rY);
if (anchor & ANCHOR_BOTTOM) rect.bottom = (int)(rect.bottom * rY);
// 水平/垂直居中錨點邏輯可擴展
pWnd->MoveWindow(&rect);
}
void CMyView::OnSize(UINT nType, int cx, int cy) {
CView::OnSize(nType, cx, cy);
Invalidate(TRUE); // 觸發重繪
}
void CMyView::OnDraw(CDC* pDC) {
CRect rect;
GetClientRect(&rect);
// 方法 A:映射模式(推薦)
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(1000, 1000); // 邏輯座標系基準
pDC->SetViewportExt(rect.Width(), rect.Height());
pDC->SetViewportOrg(0, 0);
// 繪製代碼使用 0-1000 邏輯座標
DrawMyGraphics(pDC);
// 方法 B:手動縮放
// double sx = rect.Width() / 1000.0;
// double sy = rect.Height() / 1000.0;
// pDC->Ellipse((int)(100*sx), (int)(100*sy), (int)(300*sx), (int)(300*sy));
}
| 場景 | OnSize 中操作 | 核心 API |
|---|---|---|
| 對話框控件佈局 | 計算比例 → MoveWindow 控件 | GetWindowRect, ScreenToClient, MoveWindow |
| 視圖繪圖縮放 | Invalidate 觸發重繪 | SetMapMode, SetWindowExt, SetViewportExt |
Invalidate() 導致繪圖視圖縮放後不重繪。OnDraw 中調用 MoveWindow 觸發無限重繪循環。cx/cy=0 導致除零錯誤,需 if (cx==0||cy==0) return;。SetProcessDpiAwareness 獲取正確物理像素尺寸。掌握「佈局用 MoveWindow,繪圖用映射模式」這一核心原則,即可在 OnSize 中正確實現各類自動縮放需求。