看板 HCHS_BioClub 關於我們 聯絡資訊
http://blog.163.com/linzhigui1988@126/blog/static/1018865812011499827354/ MFC改变对话框的大小,以及子控件的动态改变 2011-05-09 21:20:19| 分类: C/C++/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 ); //编辑控件的大小和位置 都改变 以上方法也适用于各种窗口。 -- 只用 SetWindowPos 似乎就可以了? -- ▍▍▍▍▍▍▍▍▍▍▍▍▍ ▍▍▍▍▍▍▍▍▍▍▍▍▍ ││││││││││││││││││ 我不是鋼琴 能不能黑白分明 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 111.251.179.22
gts2590:這篇太多了拉= =...明明有更簡單的= = 11/28 11:14