用C#写Windows程序的时候,我们可以注意到里面有个很有意思并且很有用的东东“Anchor”。它可以被指定为“Top, Bottom, Left, Right”的组合。这个东西可以简化我们的界面上的很多工作,很多时候都可以不用对布局写代码。以下是我在VC6里给出的模拟解决方案: #pragma warning(disable: 4786) #include <map> typedef enum anchor{ AR_NONE = 0, AR_LEFT = 1, AR_TOP = 2, AR_RIGHT = 4, AR_BOTTOM = 8, AR_FILL = AR_LEFT | AR_TOP | AR_RIGHT | AR_BOTTOM, AR_LEFTTOP = AR_LEFT | AR_TOP, AR_RIGHTTOP = AR_RIGHT | AR_TOP, AR_LEFTBOTTOM = AR_LEFT | AR_BOTTOM, AR_RIGHTBOTTOM = AR_RIGHT | AR_BOTTOM }anchor; typedef std::map<CWnd*, UINT> anchorMap; typedef std::map<UINT, UINT> anchorMapById;
。。。。。。
void baseDlg::registerAnchor(CWnd* child, UINT anchor /* = AR_NONE */) { anchors[child] = anchor; } void baseDlg::unRegisterAnchor(CWnd* child) { anchorMap::iterator iter = anchors.find(child); if (iter != anchors.end()) anchors.erase(iter); }
void baseDlg::registerAnchorById(UINT itemId, UINT anchor /* = AR_NONE */) { anchorsById[itemId] = anchor; }
void baseDlg::unRegisterAnchorById(UINT itemId) { anchorMapById::iterator iter = anchorsById.find(itemId); if (iter != anchorsById.end()) anchorsById.erase(iter); }
void baseDlg::OnSize(UINT nType, int cx, int cy) { CDialog::OnSize(nType, cx, cy);
if (!IsWindowVisible()) return;
CRect rtClientNew; GetClientRect(&rtClientNew); int dx = rtClientNew.right - oldClient.right; int dy = rtClientNew.bottom - oldClient.bottom;
if (rtClientNew.Width() < 2 || rtClientNew.Height() < 2) return;
for (anchorMap::iterator iter = anchors.begin(); iter != anchors.end(); ++iter) { CWnd* child = iter->first; if (child == NULL || !IsWindow(child->m_hWnd)) continue;
UINT anchor = iter->second; static CRect rtOrign; child->GetWindowRect(&rtOrign); ScreenToClient(&rtOrign);
static CRect rtNew; rtNew = rtOrign; if (anchor & AR_LEFT) { rtNew.left = rtOrign.left; } else { rtNew.left += dx / 2; }
if (anchor & AR_TOP) { rtNew.top = rtOrign.top; } else { rtNew.top += dy / 2; }
if (anchor & AR_RIGHT) { rtNew.right += dx; if (!(anchor & AR_LEFT)) rtNew.left = rtOrign.left + dx; } else { rtNew.right += dx / 2; if (anchor & AR_LEFT) rtNew.right = rtNew.left + rtOrign.Width(); }
if (anchor & AR_BOTTOM) { rtNew.bottom += (dy); if (!(anchor & AR_TOP)) rtNew.top = rtOrign.top + dy; } else { rtNew.bottom += dy / 2; if (anchor & AR_TOP) rtNew.bottom = rtNew.top + rtOrign.Height(); }
child->MoveWindow(&rtNew); }
for (anchorMapById::iterator iterById = anchorsById.begin(); iterById != anchorsById.end(); ++iterById) { CWnd* child = GetDlgItem(iterById->first); if (child == NULL || !IsWindow(child->m_hWnd)) continue;
UINT anchor = iterById->second; static CRect rtOrign; child->GetWindowRect(&rtOrign); ScreenToClient(&rtOrign);
static CRect rtNew; rtNew = rtOrign; if (anchor & AR_LEFT) { rtNew.left = rtOrign.left; } else { rtNew.left += dx / 2; }
if (anchor & AR_TOP) { rtNew.top = rtOrign.top; } else { rtNew.top += dy / 2; }
if (anchor & AR_RIGHT) { rtNew.right += dx; if (!(anchor & AR_LEFT)) rtNew.left = rtOrign.left + dx; } else { rtNew.right += dx / 2; if (anchor & AR_LEFT) rtNew.right = rtNew.left + rtOrign.Width(); }
if (anchor & AR_BOTTOM) { rtNew.bottom += (dy); if (!(anchor & AR_TOP)) rtNew.top = rtOrign.top + dy; } else { rtNew.bottom += dy / 2; if (anchor & AR_TOP) rtNew.bottom = rtNew.top + rtOrign.Height(); }
child->MoveWindow(&rtNew); }
oldClient = rtClientNew;
Invalidate(); } 
|