MFC控件和背景图片自适应窗口最大化和拉伸缩放的实现

在编程时碰到了窗口大小改变时控件位置的调整问题。这里在单文档和对话框中分别介绍一下这种方法的实现。第一部分针对 MFC 单文档程序中改变窗口的大小时,视图中的控件位置能够以相应的比例进行调整。第二部分针对对话框应用程序。

一、MFC SDI控件和背景自适应窗口最大化和拉伸缩放的实现

1.控件

示意图1和示意图2展示了窗口自由缩放,界面中的控件相对位置不变的效果。

 

示意图1

 

示意图2 

示意图中的数字12标识的是该段线段的长度,同一幅图中数值相同表示距离相等。

实现效果即:无论界面如何变化控件的相对位置保持不变。 

前面的博文中介绍了如何在单文档程序中添加Button的方法,这里就不再重复。创建Button对象之后,当界面大小改变时,位置需要调整,这就需要捕获当前界面大小的信息,需要用到一个函数Onsize,先讲一下在代码中的实现,再扩展。

代码实现:

void CTerisView::OnSize(UINT nType, int cx, int cy)
{
//cx
//指定工作区的新的宽度
//cy
//指定工作区的新的高度
m_btnStart.MoveWindow(40,10,60,30); 
m_btnEnd.MoveWindow(40,10,60,30); 
//计算控件的位置
m_btnPause.MoveWindow((cx-20)/3,10,60,30); 
m_btnResume.MoveWindow((cx-20)/3,10,60,30); 
m_btnSetting.MoveWindow((cx*2-160)/3,10,60,30); 
m_btnAbout.MoveWindow(cx-100,10,60,30); 
CView::OnSize(nType, cx, cy);  
}

这个函数会在窗口大小改变结束后被调用,通常会在这个函数里重新摆放各个控件的位置及大小红色加粗部分是通过数学计算得到的表达式,数值2标识的长度相等,通过数学关系或得控件起始坐标的表达式。控件大小在此处是通过后两个参数设置的。

 

这里再扩展一下,MFC窗口变化消息还有两个OnSizing()OnGetMinMaxInfo()

三个消息分别是:WM_SIZEWM_SIZINGWM_GETMINMAXINFO;分别对应相应的处理函数:OnSizeOnSizingOnGetMinMaxInfo

void CXXXView::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)   
{  
    	lpMMI->ptMinTrackSize.x = 500;   //x宽度  
	lpMMI->ptMinTrackSize.y = 100;   //y高度  
	CView::OnGetMinMaxInfo(lpMMI);    
}  

说明:对于单文档应用程序同样适用,这里的Dialog需要对应View,下同。

OnGetMinMaxInfo

这个函数在窗口初始化的时候会被调用一次,当窗口大小发生改变的时候也会被调用。利用这个函数,可以比较方便的实现窗口最大最小尺寸的控制。

参数lpMMI是一个结构体指针,其中包含了有关窗口的最大化大小和位置以及最小、最大跟踪大小的信息。

使用这个函数控制窗口最小尺寸的示例的代码如下:

void CXXXView::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)   
{  
    lpMMI->ptMinTrackSize.x = 500;   //x宽度  
    lpMMI->ptMinTrackSize.y = 100;   //y高度    
    CView::OnGetMinMaxInfo(lpMMI);  
}   

以上代码可以使得窗口大小变化时,最小宽度为500px,最小高度为100px

OnSizing

这个函数在窗口大小发生变化时被调用。在这个函数里,也可以控制窗口的最大最小尺寸,但是没有OnGetMinMaxInfo方便。

void CXXXView::OnSizing(UINT fwSide, LPRECT pRect)   
{  
    if ((pRect->right - pRect->left) < 500)  
    {  
        //return ;  //直接return是无效的,窗口大小还是会改变  
        pRect->right = pRect->left + 500;  
    }    
    CView::OnSizing(fwSide, pRect);  
}   

用上面的方法,如果是从右边改变大小,可以达到想要的效果,但是从左边改变大小,虽然大小可以控制在最小500,但是当达到最小宽度后,再缩小,会发现整个窗口往右移动了,原因是代码中的pRect->right = pRect->left + 500;这句是针对left来改变right的,所以left移动了,right也移动了,看上去就像是这个窗口右移了。所以针对这种情况又要另外做相应的处理。

2.背景

这里的背景指的是View类中绘制的背景区域。如示意图中的绿色的区域。

实现方法,在View类的OnDraw函数中添加如下的代码:

//获取主窗口的大小
CRect rect;
GetWindowRect(&rect);
 
//游戏区域绘制 背景及其他
CPen pen_gamearea; 
CPen*myoldpen_gamearea;
//创建蓝色的画笔
pen_gamearea.CreatePen(PS_SOLID,3,RGB(0,0,255)); 
myoldpen_gamearea=pDC->SelectObject(&pen_gamearea);
pDC->MoveTo(0,rect.Height()-20);//到左下顶点 左侧边线和左边框重合 不绘制边线
pDC->LineTo(rect.Width()*2/3,rect.Height()-20); //底部边线
pDC->LineTo(rect.Width()*2/3,51); //右部边线
//方块游戏区域  
CRect rect_gamearea(0,50,rect.Width()*2/3,rect.Height()-20);
CBrush mybrush_gamearea; 
//创建画刷 绿色
mybrush_gamearea.CreateSolidBrush(RGB(0,222,0));
//绘制背景
pDC->FillRect(rect_gamearea,&mybrush_gamearea);
pDC->SelectObject(myoldpen_gamearea);  

说明:关键还是红色加粗部分,即获取客户区的size,这个值随窗口大小的改变而改变。

注:由于OnDraw和创建控件的时机不同,以及MFC消息响应机制的关系,这个值不能够应用于控件位置的动态调整。

上面的处理是在单文档中进行,下面在扩展一下在MFC基于对话框应用程序实现类似的效果。 

二、MFC对话框控件和背景图片自适应窗口最大化和拉伸缩放的实现

假设创建的对话框的类名是CMyDlg,具体过程如下: 

步骤一:把easysize.h拷贝到CMyDlg项目文件夹中,同时在CMyDlg.h文件和.cpp文件中加入#include"easysize.h"

or#include EasySize.h to your stdafx.h (or put it in your include directory and #include <EasySize.h> , which I recommend)

步骤二:在CMyDlg类的h文件中,加入DECLARE_EASYSIZE,注意结尾处不要加 

class CMyDlg : public CDialog

{

       DECLARE_EASYSIZE

// Construction

}

步骤三:在CMyDlg类的OnInitDialog()函数的结尾处加入INIT_EASYSIZE, 注意此处结尾处要加

BOOL CMyDlg::OnInitDialog()

{     …

// TODO: Add extra initialization here

       INIT_EASYSIZE;

       return TRUE; // return TRUE unless you set the focus to a control

步骤四:增加WM_SIZE消息响应函数OnSize(),在函数中加入UPDATE_EASYSIZE,注意此处结尾处要加

void CMyDlg::OnSize(UINT nType, int cx, int cy)

{

       CDialog::OnSize(nType, cx, cy);

       // TODO: Add your message handler code here

       UPDATE_EASYSIZE;

步骤五:在CMyDlgcpp文件中添加EASYSIZE 的宏映射 

BEGIN_EASYSIZE_MAP(CMyDlg)

EASYSIZE(control,left,top,right,bottom,options)

END_EASYSIZE_MAP 

注意:如果没有添加EASYSIZE 的宏映射就开始编译的话,会出现链接错误! 

这里需要解释的是宏EASYSIZE()的用法,其原型如下:

EASYSIZE(control,left,top,right,bottom,options)

该宏表示对ID值为control的控件实施缩放效果,缩放后的上下左右位置由control,left,top,right,bottom来确定,大小由option确定。

其中:control为对话框中的控件ID值,left,top,right,bottom四个参数为控件位置的坐标,其值可以选择ES_BOARD,ES_KEEPSIZE, 控件ID值三者之一。Options可以为ES_HCENTER, ES_VCENTER的结合,options可置0 

ES_BOARD表示控件与对话框边界(以下简称边界)的距离;

ES_KEEPSIZE表示控件水平/垂直方向上尺寸保持不变;

控件ID值表示当前控件与指定控件之间的距离;

ES_HCENTER表示缩放后控件在指定位置内水平居中;

ES_VCENTER表示缩放后控件在指定位置内垂直居中;

 

例如:

EASYSIZE(IDOK,ES_BORDER,ES_BORDER,ES_BORDER,ES_BORDER,0)

表示缩放后,值为IDOK的控件,距离边界上下左右位置保持不变,水平和垂直方向尺寸拉伸; 


EASYSIZE(IDOK,ES_BORDER,ES_BORDER,ES_BORDER,ES_BORDER,ES_HCENTER)

表示缩放后,值为IDOK的控件,距离边界上下位置保持不变,垂直方向尺寸拉伸,水平居中; 


EASYSIZE(IDOK,ES_BORDER,ES_BORDER,ES_BORDER,ES_BORDER,ES_HCENTER| ES_HCENTER)

表示缩放后,值为IDOK的控件,在对话框内垂直居中,水平居中;

 

EASYSIZE(IDOK,ES_BORDER,ES_KEEPSIZE,ES_KEEPSIZE,ES_BORDER,0)

表示缩放后,值为IDOK的控件,距离边界左、下方位置保持不变,同时保持控件尺寸;

 

EASYSIZE(IDOK,ES_BORDER,ES_KEEPSIZE, ES_BORDER,ES_BORDER,0)

表示缩放后,值为IDOK的控件,距离边界左、右、下方位置保持不变,水平方向尺寸拉伸,垂直方向尺寸不变;

 

EASYSIZE(IDOK,ES_BORDER,ES_BORDER,IDCANCEL,ES_BORDER,0)

表示缩放后,值为IDOK的控件,距离边界上下左位置保持不变,距离ID值为IDCANCEL的右方位置距离保持不变,水平和垂直方向尺寸拉伸;(当使用指定控件作为定位参数时候,确保指定控件的EASYSIZE在该宏前面)  

(注)第二部分内容为转载  

  • 3
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

法哥2012

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值