用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();
}