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

 
在用 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));
    下面就是使用上面这段代码的对话框改变大小前后的效果图:
 
  
     对两张截图的比较我们可以很容易的理解上面那段代码。
    
我还提供了一个函数:
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);

    
//   记录对话框 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;
}
 
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值