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

时间:2021-06-20 03:46:44

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

typedef  struct  _dlgControlTag 
{
    
int  iId;   //   控件ID
     int  iFlag;   //   标志,表示怎样改变控件的位置或者大小
     int  iPercent;   //   改变值占对话框改变值的百分比
} 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个单位。
    下面是设置控件信息的函数:

BOOL SetControlProperty(PDLGCTLINFO lp,  int  nElements);

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

//   控件信息数组
static  DLGCTLINFO  dcMenuGroup[]  =  
{
    {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中自动改变控件位置和大小的对话框类  

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

void  ShowSizeIcon(BOOL bShow  =  TRUE);

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

//
//       自动改变控件位置和大小的对话框类
//       文件名:lxDialog.h
//       作者:StarLee(coolstarlee@sohu.com)
//

class  ClxDialog :  public  CDialog
{
public :
    ClxDialog(UINT nID, CWnd
*  pParent  =  NULL);

    typedef 
struct  _dlgControlTag 
    {
        
int  iId;
        
int  iFlag;
        
int  iPercent;
    } DLGCTLINFO, 
* PDLGCTLINFO;

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

    
//   设置控件信息
    BOOL SetControlProperty(PDLGCTLINFO lp,  int  nElements);

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

protected :
    
virtual  BOOL OnInitDialog();
    afx_msg 
void  OnSize(UINT nType,  int  cx,  int  cy);
    afx_msg 
void  OnSizing(UINT nSide, LPRECT lpRect);
    DECLARE_MESSAGE_MAP()

private :
    
int  m_iClientWidth;   //   对话框client区域的宽度
     int  m_iClientHeight;   //   对话框client区域的高度
     int  m_iMinWidth;   //   对话框的最小宽度
     int  m_iMinHeight;   //   对话框的最小高度
    PDLGCTLINFO m_pControlArray;   //   控件信息数组指针
     int  m_iControlNumber;   //   设置控件信息的控件个数
    BOOL m_bShowSizeIcon;   //   是否显示表示可改变大小的图标
    CStatic m_wndSizeIcon;   //   放图标的静态控件
    
//   保存图标的bitmap
    CBitmap m_bmpSizeIcon; 
    BITMAP m_bitmap; 
};

    lxDialog.cpp文件:

//
//       自动改变控件位置和大小的对话框类
//       文件名:lxDialog.cpp
//       作者:StarLee(coolstarlee@sohu.com)
//

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

//   表示可改变大小的图标ID
#ifndef OBM_SIZE
#define  OBM_SIZE 32766
#endif

ClxDialog::ClxDialog(UINT nID, 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()

BOOL ClxDialog::OnInitDialog()
{
    CDialog::OnInitDialog();

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

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

    
//   得到对话框client区域的大小
    CRect rectClient;
    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);

    
return  TRUE;
}

void  ClxDialog::OnSize(UINT nType,  int  cx,  int  cy) 
{
    CDialog::OnSize(nType, cx, cy);
 
    
//   对话框宽度和高度的增量 
     int  iIncrementX  =  cx  -  m_iClientWidth;
    
int  iIncrementY  =  cy  -  m_iClientHeight;

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

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

        
int  iId  =  m_pControlArray[i].iId;
        
int  iFlag  =  m_pControlArray[i].iFlag;
        
int  iPercent  =  m_pControlArray[i].iPercent;

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

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

            ScreenToClient(rectCtrl);

            
int  iLeft  =  rectCtrl.left;
            
int  iTop  =  rectCtrl.top;
            
int  iWidth  =  rectCtrl.Width();
            
int  iHeight  =  rectCtrl.Height();

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

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

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

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

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

            
case  ELASTICXY:   //   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;
    }
}

void  ClxDialog::OnSizing(UINT nSide, LPRECT lpRect)
{
    CDialog::OnSizing(nSide, lpRect);

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

    
int  iWidth  =  lpRect -> right  -  lpRect -> left;
    
int  iHeight  =  lpRect -> bottom  -  lpRect -> top;

    
if  (iWidth  <=  m_iMinWidth)
        lpRect
-> right  =  lpRect -> left  +  m_iMinWidth;
  
    
if (iHeight  <=  m_iMinHeight)
        lpRect
-> bottom  =  lpRect -> top  +  m_iMinHeight;
}

BOOL ClxDialog::SetControlProperty(PDLGCTLINFO lp, 
int  nElements)
{
    
//   设置控件数组信息

    
if  (NULL  ==  lp)
        
return  FALSE;

    
if  (nElements  <=   0 )
        
return  FALSE;

    m_pControlArray 
=  lp;
    m_iControlNumber 
=  nElements;

    
return  TRUE;
}

void  ClxDialog::ShowSizeIcon(BOOL bShow  /* =TRUE */ )
{
    m_bShowSizeIcon 
=  bShow;
}


示例代码下载:http://download.csdn.net/download/starlee/4009546