寒星轩

There are innumerable stars in the sky, the smallest is me!

用户操作
[即时聊天] [发私信] [加为好友]
李星ID:starlee
207593次访问,排名341好友65人,关注者107
欢迎大家访问我的Blog。
主要是C++,设计模式,面向对象设计方面的技术文章。
starlee的文章
原创 98 篇
翻译 0 篇
转载 45 篇
评论 331 篇
李星的公告
郑重声明

        本BLOG所发表的 原创文章,作者保留一切权利。必须经过作者本人同意后方可转载,并注名作者(StarLee)和出处(CSDN Blog)。
作者Email:
coolstarlee(at)sohu.com
最近评论
陈诚:好象不一样,我这个共两个类,实现类和接口类
深夜才走在路上:实际上使用CLR封送C++类让人很受伤,在mc中有很多C++的特性不能使用,甚至STL都不可用
hfg :错了错了,当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。

不管基类的析构函数是不是virtual ,派生类的析构函数还是会被调用的,区别只是在于基类的析构函数有没有被调用
Forrest Yu:Star Lee:

如果有两个以上的类需要包装,那又应该怎样做呢?
Forrest Yu:CLR 还是很强大的,
一些老的MFC项目可以先手动添加
#include <afx.h>,
其他的可能要加
#include <windows.h>,
然后再用这种方法.
文章分类
收藏
相册
友情链接
houdy的专栏
lijgame的专栏
lyrebing的专栏
禾青谷
存档
订阅我的博客
XML聚合  FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
订阅到BlogLines
订阅到Yahoo
订阅到GouGou
订阅到飞鸽
订阅到Rojo
订阅到newsgator
订阅到netvibes

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

新一篇: 我看过的IMDB Top250中的电影 | 旧一篇: 电影《鬼子来了》观后感

    在用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(00, m_bitmap.bmWidth, m_bitmap.bmHeight), this0);
    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;
}

发表于 @ 2006年04月17日 09:21:00|评论(loading...)|编辑

新一篇: 我看过的IMDB Top250中的电影 | 旧一篇: 电影《鬼子来了》观后感

评论

#ObjectARX 发表于2006-05-18 11:11:00  IP: 210.22.79.*
哥们是搞AutoCAD二次开发的吧?

AutoCAD的ObjectARX类库里面有一个CAdUiDialog也有 SetControlProperty()函数,跟你这里写的用法一摸一样!看来你是把自己把它给实现出来了,还加上了表示可改变大小的图标。

你这种精神值得鼓励!看到别人的好东西,自己想办法给它实现出来,拿来给大家分享,不错不错!
#我爱CS 发表于2006-05-18 21:28:00  IP: 218.79.16.*
确实不错,用起来很方便!
#jahnkey 发表于2006-11-05 00:01:00  IP: 121.10.76.*
thanks for ur so great codes .
兄弟乃真牛人也,小弟衷心佩服!
#hackyeat 发表于2007-01-10 17:52:15  IP: 218.14.35.*
前阵子尝试做你上面的例子,一时间搞不出效果,原来是忘记把:
BEGIN_MESSAGE_MAP(CSizingDlgDlg, CDialog)
//{{AFX_MSG_MAP(CSizingDlgDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
改为:
BEGIN_MESSAGE_MAP(CSizingDlgDlg, ClxDialog)//改动行
//{{AFX_MSG_MAP(CSizingDlgDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#starlee 发表于2007-01-11 11:17:36  IP: 220.248.120.*
To 所有看这篇文章的Developer:
可能是当时写这篇文章时考虑欠周,造成很多人没能正确的使用我提供的这个类。也有不少人给我发EMail询问和索要源代码,我在EMail中都给予了回复,并把源代码也作为附件发了出去。
据我分析,不能正确使用该对话框类的主要原因就是类似hackyeat在评论中提到的。现在我详细说明一下怎样正确的使用这个对话框类。
比如你有一个CMyDlg的类想实现自动改变控件大小和位置的功能。由于VC自动生成的对话框默认是从CDialog继承来的,要想CMyDlg从ClxDialog继承,请用下列步骤:
首先,在MyDlg.h中加上#include "lxDialog.h"
然后,把MyDlg.h和MyDlg.cpp中所有的CDialog都替换为ClxDialog。
#VC_Fresher 发表于2007-01-11 17:09:45  IP:
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)
{}
不好意思,我是新人,所以对于上段代码没有看明白,好像不太符合语法规则呀,请指教。我把这两个类导入一个新的工程中,编译不能通过。
#VC_Fresher 发表于2007-01-11 17:35:21  IP: 222.131.201.*
unknown character '0xa1'
#VC_Fresher 发表于2007-01-11 17:38:05  IP: 222.131.201.*
听别人说了,那是初始化列表,在构造函数之前执行,见笑了
#VC_Fresher 发表于2007-01-11 18:44:57  IP: 222.131.201.*
呵呵,是因为空格和;是用全角打的,换掉就可以了,谢谢
#lilysam_chen 发表于2008-03-26 13:38:21  IP: 58.252.113.*
请发一份源码给我好吗,谢谢
2008-03-26 16:22:44作者回复
你连个信箱都不留,我怎么发源码给你呀?再说了,你把文章中的代码copy下来不就能用了么。
#xieqidong 发表于2008-04-09 08:11:40  IP: 121.8.39.*
不错,谢谢!
发表评论  


登录
Csdn Blog version 3.1a
Copyright © 李星