怎样在程序中修改对话框、对话框中的控件的大小?怎样设置一个CDialogBar可以用鼠标拖动改变大小,并且里面的对话框也动态改变大小呢?

解决方案 »

  1.   

    繼承一個CDialogBar類,如CMyDialogBar,重載OnSize,在OnSize中根據DialogBar 之RECT用MoveWindow控件修改大小
      

  2.   

    參閱Advanced MFC Programming
      

  3.   

    1.9. Resizable Dialog Bar
    Because dialog bar can contain more powerful controls than tool bar, we could use it to implement control bars with more flexibility. To make user-friendly interface, sometimes we may really want to dynamically change a dialog bar’s size.
    Class CControlBar has two member functions dealing with control bar layout: CControlBar:: CalcFixedLayout(…) and CControlBar::CalcDynamicLayout(…). The first function returns the fixed size of a control bar, which is determined from the resource of a control bar. The second function is designed for implementing dynamic layout, however in class CControlBar, this function does noting but calling CControlBar::CalcFixedLayout(…). So actually CControlBar does not have dynamic layout feature.
    Class CToolBar overrides function CControlBar::CalcDynamicLayout(…), which adjusts the size of control bar according to its current docking state and the size of buttons. Whenever its docking state is changed, this function will be called to obtain the information of a tool bar before its layout is changed accordingly. With this implementation, a tool bar can always have a balanced appearance.
    Unlike CToolBar, CDialogBar does not override this function, so when the docking state of a dialog bar is changed, the default CControlBar::CalcDynamicLayout(…) is called, which of course, will not perform any dynamic layout for the dialog bar. If we want to add any dynamic layout feature, we must override this member function.
    Sample 1.9\Bar demonstrates how to build a dialog bar that can be resized dynamically. The application is a standard SDI application generated from Application Wizard, with four classes named CBarApp, CMainFrame, CBarDoc, and CBarView. In the sample, a dialog bar with an edit control is added to the application. This dialog bar will support dynamic layout feature: when we float or dock it to different borders of the mainframe window, the size of the dialog bar will change accordingly.
      

  4.   

    *Deriving New Class from CDialogBar
    To implement dialog bar, first we need to add a dialog-template resource. In the sample, the ID of the new resource is IDD_DIALOGBAR, which contains an edit box. The ID of this edit box is IDC_EDIT, it supports multiple-line editing. To enable this style, first we can open “Edit Properties” property sheet of the edit control (To invoke this property sheet, when editing the dialog template, we can double click on the edit control or right click on it and move to “Properties” menu item), then we need to click “Styles” tab and check “Multiline” check box.
    To override the default function, first we need to derive a new class from CDialogBar. The following code fragment shows the derived class MCDialogBar, which resides in file “MDlgBar.h”:class MCDialogBar : public CDialogBar
    {
    public:
    MCDialogBar();
    //{{AFX_DATA(MCDialogBar)
    //}}AFX_DATA
    virtual CSize CalcDynamicLayout(int, DWORD);
    //{{AFX_VIRTUAL(MCDialogBar)
    //}}AFX_VIRTUALprotected:
    //{{AFX_MSG(MCDialogBar)
    afx_msg void OnSize(UINT nType, int cx, int cy);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    };Besides constructor, the only things included in this class are two functions. As we already know, MCDialogBar::CalcDynamicLayout(…) will be used to support dynamic layout. Another afx_msg type function MCDialogBar::OnSize(…) is a message handler, which will be used to resize the edit control contained in the dialog bar. By doing this, we can see that whenever the size of the dialog bar is adjusted, the size of the edit box will also change accordingly. This will let the edit box fit well within the dialog bar.
    The new class can be added by opening new files (“.h” and “.cpp” files) and typing in the new class and function implementations. Then we can execute Project | Add To Project | Files… command to add the newly created files to the project. However, if we do so, we can not use Class Wizard to add member variables and functions to the class. In this case, we need to implement message mapping manually. If this is our choice, we must make sure that DECLARE_MESSAGE_MAP() macro is included in the class, and BEGIN_MESSAGE_MAP, END_MESSAGE_MAP macros are included in the implementation file (“.cpp” file) so that the class will support message mapping.
      

  5.   

    We can also use Class Wizard to add new class. In order to do this, after invoking the Class Wizard, we can click button labeled “Add Class…” then select “New…” from the popup menu. This will invoke a dialog box that lets us add a new class to the project. We can type in the new class name, select the header and implementation file names, and designate base class name. Unfortunately, CDialogBar is not in the list of base classes. A workaround is that we can select CDialog as the base class, after the class is generated, delete the unnecessary functions, and change all CDialog keywords to CDialogBar in both header and implementation files.
    Resizing Edit Control
    The edit control should be resized whenever the size of its parent window changes. In order to do this, we can trap WM_SIZE message, which is sent to a window when its size is about to change. We need to declare an afx_msg type member function as the message handler, and implement the message mapping using ON_WM_SIZE macro. The message handler of WM_SIZE should have the following format:afx_msg void OnSize(UINT nType, int cx, int cy);Here nType indicates how the window’s size will be changed (is it maximized, minimized…), cx and cy indicate the new window size.
    It is not very difficult to add message mapping macro, we can either add it manually, or ask Class Wizard to do it for us:BEGIN_MESSAGE_MAP(MCDialogBar, CDialogBar)
    //{{AFX_MSG_MAP(MCDialogBar)
    ON_WM_SIZE()
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()Please note that we do not need to specify function name when using macro ON_WM_SIZE. Instead, we must use OnSize to name the message handler of WM_SIZE.
    To change a window’s size, we can call function CWnd::MoveWindow(…):void CWnd::MoveWindow(int x, int y, int nWidth, int nHeight, BOOL bRepaint=TRUE);We need to provide new position and size in order to call this function. Because the function is a member of CWnd, we need to first obtain a pointer to the edit window then use it to call this function.
    For controls contained in a dialog box, their window pointers can be obtained by calling function CWnd::GetDlgItem(…). This function requires a valid control ID:CWnd *CWnd::GetDlgItem(int nID);The function returns a CWnd type pointer. With this pointer, we can call any member functions of CWnd to retrieve its information or change the properties of the control.
    Because we want to set the edit control’s size according to the parent window’s size (dialog bar), we need to find a way of retrieving a window’s dimension. This can be implemented by calling another member function of CWnd:void CWnd::GetClientRect(LPRECT lpRect);It is very easy to use this function. We can just declare a CRect type variable, and pass its pointer to the above function when calling it. After this, the position and size of the window will be stored in the variable.
    The following shows how message WM_SIZE is handled in the sample:void MCDialogBar::OnSize(UINT nType, int cx, int cy) 
    {
    CWnd *ptrWnd;
    CRect rectWnd; CDialogBar::OnSize(nType, cx, cy); GetClientRect(rectWnd);
    ptrWnd=GetDlgItem(IDC_EDIT);
    if(ptrWnd != NULL)
    {
    ptrWnd->MoveWindow
    (
    rectWnd.left+15,
    rectWnd.top+15,
    rectWnd.Width()-30,
    rectWnd.Height()-30
    );
    }
    }We can not use parameter cx and cy to resize the edit control directly because after the dialog bar gets this information, its layout may change again. The ultimate dimension of the dialog bar depends on both cx, cy and the layout algorithm. So before adjusting the size of edit control, we have to call CDialogBar::OnSize(…) first to let the dialog bar adjust its own size, then call CWnd::GetClientRect(…) to retrieve the final dimension of the dialog bar.
    The rest part of this function can be easily understood: we first obtain a window pointer to the edit control and store it in pointer ptrWnd, then use it to call function CWnd::MoveWindow(…) to resize the edit control.
      

  6.   

    重载OnSize()函数
    在msdn上参考SetWindowPos()函数
      

  7.   

    Dynamic Layout
    Now we need to implement function MCDialogBar::CalcDynamicLayout(…). Like what we did in section 1.7, here we need to return a custom layout size when the function is called for retrieving either horizontal or vertical docking size. The following is our layout algorithm: when the bar is docked horizontally, we set its width to the horizontal size of the mainframe window’s client area, and set its height to the dialog bar’s floating vertical size; when it is docked vertically, we set its height to the vertical size of the mainframe window’s client area, and set its width to the dialog bar’s floating horizontal size.
    Parameter dwMode of this function is used to tell what types of dimension is be inquired. If either LM_VERTDOCK or LM_HORZDOCK bit is set, we need to return a custom docking size. In this case, we can use another bit LM_HORZ to check if the dialog bar is docked horizontally or vertically. If this bit is set, the horizontal docking size is being inquired, otherwise the vertically docking size is being inquired.
    The floating size can be obtained from a public variable: CDialogBar::m_sizeDefault. By default, this variable is initialized to the dialog template size, and is updated when the user changes the size of the dialog bar when it is floating. So this variable always represents the floating size of the dialog bar.
    The following is the implementation of this function:CSize MCDialogBar::CalcDynamicLayout(int nLength, DWORD dwMode)
    {
    CSize size;
    CMainFrame *ptrWnd;
    CRect rect; ptrWnd=(CMainFrame *)(AfxGetApp()->m_pMainWnd);
    ptrWnd->GetClientRect(rect);
    if((dwMode & LM_VERTDOCK) || (dwMode & LM_HORZDOCK))
    {
    size.cx=(dwMode & LM_HORZ) ? rect.Width():m_sizeDefault.cx;
    size.cy=(dwMode & LM_HORZ) ? m_sizeDefault.cy:rect.Height(); return size;
    }
    return CDialogBar::CalcDynamicLayout(nLength, dwMode);
    }First, we obtain the dimension of mainframe window’s client area. For this purpose, first a window pointer to the mainframe window is obtained, then function CMainFrame::GetClientRect(…) is called to retrieve its dimension. Here the pointer to the mainframe window is obtained from a public member variable of class CWinApp. In MFC, every application has a CWinApp derived class, which contains a pointer m_pMainWnd pointing to the mainframe window. For any application, the pointer to the CWinApp object can be obtained anywhere in the program by calling function AfxGetApp(). Using this method, we can easily find the mainframe window of any MFC application.
    Because the application supports status bar and tool bar, part of its client area may be covered by the control bar. So we need to deduct the covered area when calculating the dimension of the client area. For this purpose, in CMainFrame, function CWnd::GetClientRect(…) is overridden. Within the overridden function, the client area is adjusted if either the status bar or the tool bar is present:void CMainFrame::GetClientRect(LPRECT lpRect)
    {
    CRect rect; CFrameWnd::GetClientRect(lpRect);
    if(m_wndToolBar.IsWindowVisible())
    {
    m_wndToolBar.GetClientRect(rect);
    lpRect->bottom-=rect.Height();
    }
    if(m_wndStatusBar.IsWindowVisible())
    {
    m_wndStatusBar.GetClientRect(rect);
    lpRect->bottom-=rect.Height();
    }
    }Now back to MCDialogBar::CalcDynamicLayout(…) implementation. After obtaining the size of mainframe window’s client area, we examine LM_VERTDOCK and LM_HORZDOCK bits of dwMode parameter to see if the docking size is being inquired. If so, we further examine LM_HORZ bit to see if we should return horizontally docked size or vertically docked size. We return different sizes for different cases. For all other conditions, we just return the default implementation of the base class.
      

  8.   

    在控件的父窗体重载OnSize(),然后使用MoveWindow()
      

  9.   

    干脆用AdjustWindowRect()这个函数试一下。
      

  10.   

    在Onsize()中修改对话框的大小,然后根据对话框的改变情况,再对各个控件进行计算,用MoveWindow()修改控件和对话框的大小