MFC改变对话框的大小,以及子控件的动态改变  


无论是单文档还是基于对话框,可能更普遍的方式是接受WM_size消息,使用setWindowPos(),moveWindow()方法。

1、首先写一个示例

// 自动改变控件位置和大小的对话框类
 // 文件名:lxDialog.h
 /
 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
 //
 #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 /*=NULL*/)
 {
     m_bShowSizeIcon = bShow;
 }

《《《《《《《《《《《《《《《《《《《《《《《《《《《《》》》》》》》》》》》》》》》》》》》》》》》》》

2、再写一个示例,还是动态改变对话框的(基于dialog的对话框)

初始化时用来猎取每个控件的位置和大小,写一个函数是在窗口大小改变时,根据原来获得的各控件大小和位置进行等比例放大和缩小即可

一 在头文件 POINT Old;//存放对话框的宽和高。

OnInitDialog //计录宽和高。
  CRect rect;   
  GetClientRect(&rect); //取客户区大小  
  Old.x=rect.right-rect.left;
  Old.y=rect.bottom-rect.top;




二 添加 WM_SIZE消息:

if(nType==SIZE_RESTORED||nType==SIZE_MAXIMIZED)//窗体大小发生变动。处理函数resize
  {
   resize();
  }

 三 添加reseze函数
 void CMy2610Dlg::resize()
 {
  float fsp[2];
  POINT Newp; //获取现在对话框的大小
  CRect recta;   
  GetClientRect(&recta); //取客户区大小  
  Newp.x=recta.right-recta.left;
  Newp.y=recta.bottom-recta.top;
  fsp[0]=(float)Newp.x/Old.x;
  fsp[1]=(float)Newp.y/Old.y;
  CRect Rect;
  int woc;
  CPoint OldTLPoint,TLPoint; //左上角
  CPoint OldBRPoint,BRPoint; //右下角
  HWND hwndChild=::GetWindow(m_hWnd,GW_CHILD); //列出所有控件  
  while(hwndChild)   
  {   
   woc=::GetDlgCtrlID(hwndChild);//取得ID
   GetDlgItem(woc)->GetWindowRect(Rect);  
   ScreenToClient(Rect);  
   OldTLPoint = Rect.TopLeft();  
   TLPoint.x = long(OldTLPoint.x*fsp[0]);  
   TLPoint.y = long(OldTLPoint.y*fsp[1]);  
   OldBRPoint = Rect.BottomRight();  
   BRPoint.x = long(OldBRPoint.x *fsp[0]);  
   BRPoint.y = long(OldBRPoint.y *fsp[1]);  
   Rect.SetRect(TLPoint,BRPoint);  
   GetDlgItem(woc)->MoveWindow(Rect,TRUE);
   hwndChild=::GetWindow(hwndChild, GW_HWNDNEXT);   
  }
  Old=Newp;
 }


注:若只要最大化,不用拖动可以不用设置下面的
需要拖动的需要设置
中文版:右击对话框属性--样式--边框(调整大小)
英文版:Styles--Border--选择Risizing,   

说明:

如果你窗口中有comboBox这种高度只读的控件,改变窗口大小后下拉框会拉不开,这是需要在遍历控件时加判断,如果是comboBox,就不要改变BRPoint.y值,也就是不要改变高度。

 

《《《《《《《《《《《《《《《《《《《《《》》》》》》》》》》》》》》》》》》》》》》》》

3、窗口最大化

vc++ 窗口最大化方法

一般的做法是在 C**App::InitInstance()中,修改成这样:

{
 //...
 m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
 m_pMainWnd->UpdateWindow();
 //...
 }
 或者,还在 CMainFrame::PreCreateWindow(CREATESTRUCT& cs)中,添加:
 {
 //...
 cs.style |= WS_MAXIMIZE;
 //...
 }



这种做法能产生窗口最大化,但效果是显示的时候窗口从普通大小"闪"到最大化。还有的做法,是先将窗口隐藏,然后再最大化。那么怎样使窗口正常一开始出现就最大化?看看下面的流程,从 C**App::InitInstance()中的ProcessShellCommand(...)开始:

{
 //...
 //ProcessShellCommand中第一次显示了窗口
 if (!ProcessShellCommand(cmdInfo))
   return FALSE;
 m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
 m_pMainWnd->UpdateWindow();
 //...
 }


 ->CWinApp::ProcessShellCommand  
 ->AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL)  
 //如果你自己处理了ID_FILE_NEW要调用CWinApp::OnFileNew()
 ->CWinApp::OnFileNew()
 ->CDocManager::OnFileNew()  
 ->CSingleDocTemplate::OpenDocumentFile //当前文档模板初始化
 ->CSingleDocTemplate::CreateNewDocument //创建文档
 //加载资源并创建主窗口(顺便创建视图),但没显示
 ->CSingleDocTemplate::CreateNewFrame  
 ->CFrameWnd::InitialUpdateFrame
 {
 //...
 int nCmdShow = -1; // default
 CWinApp* pApp = AfxGetApp();
 if (pApp != NULL && pApp->m_pMainWnd == this)
 {
   nCmdShow = pApp->m_nCmdShow; // use the parameter from WinMain
   pApp->m_nCmdShow = -1; // set to default after first time
 }
 ActivateFrame(nCmdShow); //在这里第一次显示窗口
 //...
 }
 ->CFrameWnd::ActivateFrame(int nCmdShow)
 // nCmdShow is the normal show mode this frame should be in
 {
 // translate default nCmdShow (-1)
 if (nCmdShow == -1)
 {
   if (!IsWindowVisible())
   nCmdShow = SW_SHOWNORMAL;
   else if (IsIconic())
   nCmdShow = SW_RESTORE;
 }

 // bring to top before showing
 BringToTop(nCmdShow);

 if (nCmdShow != -1)
 {
   // show the window as specified
   ShowWindow(nCmdShow); //第一次显示窗口

   // and finally, bring to top after showing
   BringToTop(nCmdShow);
 }
 }
 ->***



从上面可以看出,CWinApp::ProcessShellCommand函数创建了窗口并显示,这是窗口第一次显示,先于:
m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
m_pMainWnd->UpdateWindow();


怎么解决问题? 让窗口第一次显示就最大化?

CCommandLineInfo cmdInfo;
 ParseCommandLine(cmdInfo);

 // Dispatch commands specified on the command line
 //在ParseCommandLine之后,ProcessShellCommand之前,添加这句!!!
 m_nCmdShow = SW_SHOWMAXIMIZED;  
 if (!ProcessShellCommand(cmdInfo))
   return FALSE;

 // The one and only window has been initialized, so show and update it.
 m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
 m_pMainWnd->UpdateWindow();


《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《》》》》》》》》》》

用CWnd类的函数MoveWindow()或SetWindowPos()可以改变控件的大小和位置。

void MoveWindow(int x,int y,int nWidth,int nHeight);
void MoveWindow(LPCRECT lpRect);
第一种用法需给出控件新的坐标和宽度、高度;
第二种用法给出存放位置的CRect对象;
例:
CWnd *pWnd;
pWnd = GetDlgItem( IDC_EDIT1 );    //获取控件指针,IDC_EDIT1为控件ID号
pWnd->MoveWindow( CRect(0,0,100,100) );    //在窗口左上角显示一个宽100、高100的编辑控件

SetWindowPos()函数使用更灵活,多用于只修改控件位置而大小不变或只修改大小而位置不变的情况:
BOOL SetWindowPos(const CWnd* pWndInsertAfter,int x,int y,int cx,int cy,UINT nFlags);
第一个参数我不会用,一般设为NULL;
x、y控件位置;cx、cy控件宽度和高度;
nFlags常用取值:
SWP_NOZORDER:忽略第一个参数;
SWP_NOMOVE:忽略x、y,维持位置不变;
SWP_NOSIZE:忽略cx、cy,维持大小不变;
例:

CWnd *pWnd;
 pWnd = GetDlgItem( IDC_BUTTON1 );    //获取控件指针,IDC_BUTTON1为控件ID号
 pWnd->SetWindowPos( NULL,50,80,0,0,SWP_NOZORDER | SWP_NOSIZE );    //把按钮移到窗口的(50,80)处
 pWnd = GetDlgItem( IDC_EDIT1 );
 pWnd->SetWindowPos( NULL,0,0,100,80,SWP_NOZORDER | SWP_NOMOVE );    //把编辑控件的大小设为(100,80),位置不变
 pWnd = GetDlgItem( IDC_EDIT1 );
 pWnd->SetWindowPos( NULL,0,0,100,80,SWP_NOZORDER );    //编辑控件的大小和位置都改变


以上方法也适用于各种窗口。

MFC改变对话框的大小,以及子控件的动态改变_ide  

<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

4、MFC教程

http://www.vczx.com/tutorial/mfc/mfc.php