YOU CAN CODE!

 

With The Case Of UCanCode.net  Release The Power OF  Visual C++ !   HomeProducts | PurchaseSupport | Downloads  
Download Evaluation
Pricing & Purchase?
E-XD++Visual C++/ MFC Products
Overview
Features Tour 
Electronic Form Solution
Visualization & HMI Solution
Power system HMI Solution
CAD Drawing and Printing Solution

Bar code labeling Solution
Workflow Solution

Coal industry HMI Solution
Instrumentation Gauge Solution

Report Printing Solution
Graphical modeling Solution
GIS mapping solution

Visio graphics solution
Industrial control SCADA &HMI Solution
BPM business process Solution

Industrial monitoring Solution
Flowchart and diagramming Solution
Organization Diagram Solution

Graphic editor Source Code
UML drawing editor Source Code
Map Diagramming Solution

Architectural Graphic Drawing Solution
Request Evaluation
Purchase
ActiveX COM Products
Overview
Download
Purchase
Technical Support
  General Q & A
Discussion Board
Contact Us

Links

Get Ready to Unleash the Power of UCanCode .NET


UCanCode Software focuses on general application software development. We provide complete solution for developers. No matter you want to develop a simple database workflow application, or an large flow/diagram based system, our product will provide a complete solution for you. Our product had been used by hundreds of top companies around the world!

"100% source code provided! Free you from not daring to use components because of unable to master the key technology of components!"


Visual C++ and MFC Appwizard: CMDIChildWnd with CenterWindow AfxGetMainWnd

 
 
 

Sample Image - CenterMDIWnd1.jpg

Introduction

Have you ever wondered how to get the MDI Child Frame windows in your MDI application to appear centered in the client area of the main frame window? Have you tried using CenterWindow(), but found that the window still isn't centered properly? This article shows you how, and we also talk about the ways of keeping child windows centered, even if the user moves or resizes the main window, or shows or hides the toolbar(s) and status bar.

For the code below, I will assume you are familiar with MFC Doc/View architecture and are using the said architecture in your app. The starter project for the sample application included with this article was created using Visual C++ 6 and the MFC AppWizard. The code in this article has been tested on Windows 98 all editions and Windows NT, 2000, and XP both Home and Professional.

If you have any questions, please feel free to post a message below or email me (see the sample program for the email address). Now, on to centering windows!

The Proper Way to Call CenterWindow()

In this article, we will look more carefully at CenterWindow() and ensure it's called properly. Many thanks go out to the posters to this article's message board (below) for the update. The key to using CenterWindow() is to ensure that the CWnd* pointer you're passing in is the correct pointer, and that the CenterWindow() function is called for the proper window (view, frame, MDI child window etc.) that you mean to center.

Assuming you're using MFC's doc/view architecture, you override CView::OnInitialUpdate and put in the code shown below in bold:

Listing 1: Override of CView::OnInitialUpdate

Collapse Copy Code
void CCenterMDIWndView::OnInitialUpdate() 
{
    // Call base class first
    CView::OnInitialUpdate();

    GetParentFrame()->CenterWindow(AfxGetMainWnd());
}

Remember, this code should go in the view enclosed in the frame you want to center. So we see that we call CMDIChildWnd::CenterWindow (which is inherited from CWnd) and pass a pointer to the main frame window of the application, as returned by AfxGetMainWnd(). Thanks go out to Ravi Bhavnani and Michael Zhao for pointing out this simple solution.

Keeping Your Windows Centered

But what about when you want to keep your newly-centered child window centered, say, if the user re-sizes the main frame window or moves the child window outside the client area? Or if the main frame window is minimized and maximized? We need to handle the so-called 'MFC private message', WM_SIZEPARENT. WM_SIZEPARENT is a so-called 'user message,' and it's defined in <afxpriv.h>. The framework sends this message to child windows of the main frame window in response to the main frame window being resized (and hence receiving a WM_SIZE message from Windows).

So I came up with the following algorithm to handle the case of the main frame window being moved or sized by the user (the WM_SIZE message is sent by Windows in both cases):

Figure 2: Algorithm to re-center child windows when user resizes or moves the main frame window of the application.

Let's work from the end of the flowchart up to the handling of the WM_SIZE message. Working this way, my first step is to add a handler to my CChildFrame (derived from CMDIChildWnd) class for the WM_SIZEPARENT message. The code for this message is declared in <afxpriv.h>, so the best policy is to add a #include line for it to STDAFX.H:

Listing 2: Including the Header for WM_SIZEPARENT

Collapse Copy Code
#include <afxpriv.h>          // MFC private messages

Next, we have to add a line in the DECLARE_MESSAGE_MAP section of the CHILDFRM.H file (where my CChildFrame class is declared):

Listing 3: The Message Map Declaration in CHILDFRM.H

Collapse Copy Code
// Generated message map functions
protected:
    //{{AFX_MSG(CChildFrame)
        // NOTE - the ClassWizard will add and remove member functions here.
        //    DO NOT EDIT what you see in these blocks of generated code!
    //}}AFX_MSG
    afx_msg LRESULT OnSizeParent(WPARAM wParam, LPARAM lParam);
    DECLARE_MESSAGE_MAP()

Next we'll go to the CHILDFRM.CPP file and add a message map entry and handler for the WM_SIZEPARENT message. Notice that the code you type is in bold, and we have to add the entire handler implementation from scratch:

Listing 4: Adding a Message Map Entry and Handler Implementation

Collapse Copy Code
BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWnd)
    //{{AFX_MSG_MAP(CChildFrame)
        // NOTE - the ClassWizard will add and remove mapping macros here.
        //    DO NOT EDIT what you see in these blocks of generated code !
    //}}AFX_MSG_MAP
    ON_MESSAGE(WM_SIZEPARENT, OnSizeParent)
END_MESSAGE_MAP()
Collapse Copy Code
LRESULT CChildFrame::OnSizeParent(WPARAM, LPARAM)
{
    CenterWindow(AfxGetMainWnd());
    return 0;
}

The WM_SIZEPARENT message gets sent by the handler we'll be adding to CMainFrame for the WM_SIZE message. But first, a preliminary. Notice how I mentioned above that the centering of a given MDI child window can be thrown off if, say, the user hides or shows the toolbar(s) or status bar? Let's also account for this. First, an aside on the structure of the main window.

Window Handles and the MDIClient

Window handles exist to denote windows, and they are useful to pass to various Windows API functions when we want to do something to the corresponding window. It turns out that the client area of the main window of a typical MFC application is filled by a window called the MDIClient. It is actually the MDIClient which is the parent of all the MDI child windows currently open in the main window. The window handle of the MDIClient is stored in the CMDIFrameWnd::m_hWndMDIClient member variable.

In order to get the WM_SIZEPARENT message sent out to all the MDI child windows (since we never know a priori just which MDI child windows are open at any given time), we are going to ucancode.net the MDIClient to worry about delivering the said message to all its children. We employ CWnd::FromHandle, which is a static function, to get a CWnd pointer to the MDIClient, and then use CWnd::SendMessageToDescendants to send the WM_SIZEPARENT message to the MDI child windows. As may be guessed from its name, CWnd::SendMessageToDescendants simply sends the specified messages to the given CWnd's child windows, whichever windows those are.

Override CFrameWnd::RecalcLayout() to Send WM_SIZEPARENT

When the user hides or shows the toolbar(s) and the status bar, the framework calls CFrameWnd::RecalcLayout to handle the repositioning of child windows and other elements of the main window. RecalcLayout is a virtual function, which we may override. Since, resizing the main window also amounts to modifying its 'layout'. So let's make our override of RecalcLayout be in charge of sending the WM_SIZEPARENT messages to the MDI child windows currently in the main window.

Open up ClassWizard, and select the CMainFrame class, and override RecalcLayout. We are going to employ the approach mentioned above. Fill in the code shown below in bold:

Listing 5: Overriding CMDIFrameWnd::RecalcLayout

Collapse Copy Code
void CMainFrame::RecalcLayout(BOOL bNotify) 
{
    // Call base class first
    CMDIFrameWnd::RecalcLayout(bNotify);

    if (::IsWindow(m_hWndMDIClient)) {
        CWnd* pClientWnd = CWnd::FromHandle(m_hWndMDIClient);

        // Hopefully this should notify CMDIChildWnds that their
        // client area is changing size -- better re-center themselves!
        pClientWnd->SendMessageToDescendants(WM_SIZEPARENT,
            0, 0, FALSE, FALSE);
    }
}

Note how we call IsWindow to check that the m_hWndMDIClient handle is valid, before proceeding. This is critical if your application automatically creates, e.g., a new document initially on startup. The first time RecalcLayout is called by the framework is before the MDIClient is created, so at this point, CWnd::FromHandle will cause an exception if you try to get a CWnd* pointer from the (now invalid) m_hWndMDIClient handle.

Handle the WM_SIZE Message in CMainFrame

OK, so now if the user hides or shows the toolbar(s) or status bar, we are covered. What about if they move, resize, minimize, maximize, or restore the main window? Odds are nothing will happen. To update the centering of the MDI child window(s) open in the main window, we need to handle the WM_SIZE message. In the message handler, we'll call our RecalcLayout override to do the dirty work. Here's the code (you add the code shown in bold after using ClassWizard to create the handler):

Listing 6: Handling WM_SIZE

Collapse Copy Code
void CMainFrame::OnSize(UINT nType, int cx, int cy) 
{
    CMDIFrameWnd::OnSize(nType, cx, cy);

    RecalcLayout();
}

That's it, we're done. The program should now center its MDI child window(s) upon creation. And resizing/moving etc. the window, or hiding or showing the toolbar(s) or status bar should leave the open MDI child window(s) unscathed.

 

 

 

Copyright ?1998-2022 UCanCode.Net Software , all rights reserved.
Other product and company names herein may be the trademarks of their respective owners.

Please direct your questions or comments to webmaster@ucancode.net