VC中自动改变控件位置和大小的对话框类

在用VC开发应用程序时,经常会要做一些可以改变大小的对话框,而这个时候就要求对话框上的控件会随着对话框大小的改变而改变自己的位置和大小。如果控件比较少,那可以在对话框的OnSize()事件里面添加代码,通过计算来调整各个控件的位置和大小;但是,如果对话框上的控件比较多的话,那这将是一件非常痛苦的事情!要是程序中又有很多可以改变大小的对话框,那一个一个的OnSize()写下来,那会使程序员崩溃的!
为了解决这个问题,我写了一个自动改变控件位置和大小的对话框类ClxDialog。从这个类继承的对话框类,只要在OnInitDialog()里对控件做一些简单的设置,对话框上的控件就会随着对话框大小的改变而改变自己的位置和大小(当然,别忘了把对话框的Border属性改为Resizing)。
为了保存控件信息,我定义了一个结构:

typedefstruct_dlgControlTag
{
intiId;//控件ID
intiFlag;//标志,表示怎样改变控件的位置或者大小
intiPercent;//改变值占对话框改变值的百分比
}DLGCTLINFO,*PDLGCTLINFO;

这里要对结构中的iFlag和iPercent进行一些解释。其中iFlag是下面的枚举值:

enum
{
MOVEX
=0,//控件在X方向(左右)移动
MOVEY,//控件在Y方向(上下)移动
MOVEXY,//控件在X方向和Y方向同时移动
ELASTICX,//控件在X方向(宽度)改变大小
ELASTICY,//控件在Y方向改(高度)改变大小
ELASTICXY//控件在X方向和Y方向同时改变大小
};

iPercent表示改变值占对话框改变值的百分比。例如,一个控件的iPercent值为100,iFlag值为MOVEX,那么当对话框的宽度改变100个单位的时候,这个控件就在X方向移动100个单位;又如,一个控件的iPercent值为100,iFlag值为ELASTICXY,那么当对话框的宽度和高度分别改变100个单位的时候,控件的高度和宽度也相应的改变100个单位。
下面是设置控件信息的函数:

BOOLSetControlProperty(PDLGCTLINFOlp,intnElements);

使用起来非常简单,在对话框的OnInitDialog()函数里面添加类似下面的代码就行了:

//控件信息数组
staticDLGCTLINFOdcMenuGroup[]=
{
{IDOK,MOVEX,
100},
{IDCANCEL,MOVEX,
100},
{IDC_BUTTON1,MOVEX,
50},
{IDC_BUTTON1,MOVEY,
100},
{IDC_EDIT1,ELASTICX,
100},
{IDC_EDIT2,ELASTICX,
50},
{IDC_EDIT3,ELASTICX,
50},
{IDC_EDIT3,MOVEX,
50},
{IDC_EDIT4,ELASTICY,
100},
{IDC_EDIT5,ELASTICX,
100},
{IDC_EDIT5,ELASTICY,
50},
{IDC_EDIT6,ELASTICX,
100},
{IDC_EDIT6,ELASTICY,
50},
{IDC_EDIT6,MOVEY,
50},
};

//设置控件信息
SetControlProperty(dcMenuGroup,sizeof(dcMenuGroup)/sizeof(DLGCTLINFO));

下面就是使用上面这段代码的对话框改变大小前后的效果图:

VC中自动改变控件位置和大小的对话框类

VC中自动改变控件位置和大小的对话框类

对两张截图的比较我们可以很容易的理解上面那段代码。
我还提供了一个函数:

voidShowSizeIcon(BOOLbShow=TRUE);

来设置是否显示对话框右下角表示可以改变大小的图标。这个图标是从系统中读取的,我上面的截图是Windows2000下的,在WindowsXP中就会自动变成XP风格的。
好了,闲话不多说了,下面贴出该对话框类ClxDialog的源代码,里面有详细的注释:
lxDialog.h文件:

//
//自动改变控件位置和大小的对话框类
//文件名:lxDialog.h
//作者:StarLee([email protected])
//

classClxDialog:publicCDialog
{
public:
ClxDialog(UINTnID,CWnd
*pParent=NULL);

typedef
struct_dlgControlTag
{
intiId;
intiFlag;
intiPercent;
}DLGCTLINFO,
*PDLGCTLINFO;

enum
{
MOVEX
=0,
MOVEY,
MOVEXY,
ELASTICX,
ELASTICY,
ELASTICXY
};

//设置控件信息
BOOLSetControlProperty(PDLGCTLINFOlp,intnElements);

//是否在对话框右下角显示表示可改变大小的图标
voidShowSizeIcon(BOOLbShow=TRUE);

protected:
virtualBOOLOnInitDialog();
afx_msg
voidOnSize(UINTnType,intcx,intcy);
afx_msg
voidOnSizing(UINTnSide,LPRECTlpRect);
DECLARE_MESSAGE_MAP()

private:
intm_iClientWidth;//对话框client区域的宽度
intm_iClientHeight;//对话框client区域的高度
intm_iMinWidth;//对话框的最小宽度
intm_iMinHeight;//对话框的最小高度
PDLGCTLINFOm_pControlArray;//控件信息数组指针
intm_iControlNumber;//设置控件信息的控件个数
BOOLm_bShowSizeIcon;//是否显示表示可改变大小的图标
CStaticm_wndSizeIcon;//放图标的静态控件
//保存图标的bitmap
CBitmapm_bmpSizeIcon;
BITMAPm_bitmap;
};

lxDialog.cpp文件:

//
//自动改变控件位置和大小的对话框类
//文件名:lxDialog.cpp
//作者:StarLee([email protected])
//

#include
"stdafx.h"
#include
"lxDialog.h"

//表示可改变大小的图标ID
#ifndefOBM_SIZE
#defineOBM_SIZE32766
#endif

ClxDialog::ClxDialog(UINTnID,CWnd
*pParent/*=NULL*/)
:CDialog(nID,pParent)
,m_iClientWidth(
0)
,m_iClientHeight(
0)
,m_iMinWidth(
0)
,m_iMinHeight(
0)
,m_pControlArray(NULL)
,m_iControlNumber(
0)
,m_bShowSizeIcon(TRUE)
{}

BEGIN_MESSAGE_MAP(ClxDialog,CDialog)
ON_WM_SIZE()
ON_WM_SIZING()
END_MESSAGE_MAP()

BOOLClxDialog::OnInitDialog()
{
CDialog::OnInitDialog();

//设置对话框为可变大小的
ModifyStyle(0,WS_SIZEBOX);

//以对话框的初始大小作为对话框的宽度和高度的最小值
CRectrectDlg;
GetWindowRect(rectDlg);
m_iMinWidth
=rectDlg.Width();
m_iMinHeight
=rectDlg.Height();

//得到对话框client区域的大小
CRectrectClient;
GetClientRect(rectClient);
m_iClientWidth
=rectClient.Width();
m_iClientHeight
=rectClient.Height();

//Load图标
m_bmpSizeIcon.LoadOEMBitmap(OBM_SIZE);
m_bmpSizeIcon.GetBitmap(
&m_bitmap);

//创建显示图标的静态控件并放在对话框右下角
m_wndSizeIcon.Create(NULL,WS_CHILD|WS_VISIBLE|SS_BITMAP,CRect(0,0,m_bitmap.bmWidth,m_bitmap.bmHeight),this,0);
m_wndSizeIcon.SetBitmap(m_bmpSizeIcon);
m_wndSizeIcon.MoveWindow(m_iClientWidth
-m_bitmap.bmWidth,m_iClientHeight-m_bitmap.bmHeight,m_bitmap.bmWidth,m_bitmap.bmHeight);

//显示图标
m_wndSizeIcon.ShowWindow(m_bShowSizeIcon);

returnTRUE;
}

voidClxDialog::OnSize(UINTnType,intcx,intcy)
{
CDialog::OnSize(nType,cx,cy);

//对话框宽度和高度的增量
intiIncrementX=cx-m_iClientWidth;
intiIncrementY=cy-m_iClientHeight;

//最小化时增量为0
if(nType==SIZE_MINIMIZED)
{
iIncrementX
=iIncrementY=0;
}

for(inti=0;i<m_iControlNumber;i++)
{
CWnd
*pWndCtrl=NULL;

intiId=m_pControlArray[i].iId;
intiFlag=m_pControlArray[i].iFlag;
intiPercent=m_pControlArray[i].iPercent;

//无效值
if((iPercent<0)||(iPercent>100))
continue;

//得到控件指针
pWndCtrl=GetDlgItem(iId);
if((NULL!=pWndCtrl)&&IsWindow(pWndCtrl->GetSafeHwnd()))
{
CRectrectCtrl;
pWndCtrl
->GetWindowRect(rectCtrl);

ScreenToClient(rectCtrl);

intiLeft=rectCtrl.left;
intiTop=rectCtrl.top;
intiWidth=rectCtrl.Width();
intiHeight=rectCtrl.Height();

switch(iFlag)
{
caseMOVEX://X方向移动
iLeft+=(iIncrementX*iPercent/100);
break;

caseMOVEY://Y方向移动
iTop+=(iIncrementY*iPercent/100);
break;

caseMOVEXY://X方向和Y方向同时移动
iLeft+=(iIncrementX*iPercent/100);
iTop
+=(iIncrementY*iPercent/100);
break;

caseELASTICX://X方向改变大小
iWidth+=(iIncrementX*iPercent/100);
break;

caseELASTICY://Y方向改变大小
iHeight+=(iIncrementY*iPercent/100);
break;

caseELASTICXY://X方向和Y方向同时改变大小
iWidth+=(iIncrementX*iPercent/100);
iHeight
+=(iIncrementY*iPercent/100);
break;

default:
;
}

//把控件移动到新位置
pWndCtrl->MoveWindow(iLeft,iTop,iWidth,iHeight);
}
}

//把图标移动到对话框右下角
if(IsWindow(m_wndSizeIcon.GetSafeHwnd()))
{
m_wndSizeIcon.MoveWindow(cx
-m_bitmap.bmWidth,cy-m_bitmap.bmHeight,m_bitmap.bmWidth,m_bitmap.bmHeight);

if(nType==SIZE_MAXIMIZED)
m_wndSizeIcon.ShowWindow(FALSE);
else
m_wndSizeIcon.ShowWindow(TRUE);
}

Invalidate();

//记录对话框client区域的大小
if(nType!=SIZE_MINIMIZED)
{
m_iClientWidth
=cx;
m_iClientHeight
=cy;
}
}

voidClxDialog::OnSizing(UINTnSide,LPRECTlpRect)
{
CDialog::OnSizing(nSide,lpRect);

//对话框不能小于初始大小

intiWidth=lpRect->right-lpRect->left;
intiHeight=lpRect->bottom-lpRect->top;

if(iWidth<=m_iMinWidth)
lpRect
->right=lpRect->left+m_iMinWidth;

if(iHeight<=m_iMinHeight)
lpRect
->bottom=lpRect->top+m_iMinHeight;
}

BOOLClxDialog::SetControlProperty(PDLGCTLINFOlp,
intnElements)
{
//设置控件数组信息

if(NULL==lp)
returnFALSE;

if(nElements<=0)
returnFALSE;

m_pControlArray
=lp;
m_iControlNumber
=nElements;

returnTRUE;
}

voidClxDialog::ShowSizeIcon(BOOLbShow/*=TRUE*/)
{
m_bShowSizeIcon
=bShow;
}