Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Modifying a modal dialog's style and position at run time

0.00/5 (No votes)
20 Feb 2006 1  
This article describes how to modify a modal dialog's styles and position at run-time so it can work both as a child of a CPropertySheet as well as a pop-up window on its own.

dialog modified to pop-up and centered in main window at run-time

Introduction

This article describes how to modify a modal dialog's styles and position at run-time so it can work both as a child of a CPropertySheet as well as a pop-up window on its own.

Background

When a CPropertyPage is added to a CPropertySheet, it has to be a child of that property sheet. Also, the property page has to be disabled and not visible initially. What if the same property page has to be run independent of the property sheet, as a modal dialog? In that case, the styles have to be changed at run-time. When do we change the styles? It turns out that doing so in OnInitDialog() is too late. Besides, the repositioning of the popup dialog requires some specific options which may not be apparent from the MSDN documentation. This article shows how to do both.

Using the code

The DialogStyleModificationExample project is a very simple dialog based MFC app with two buttons. The "Open Dialog With Default Styles" button adds the property page CPropertyPageFirst, without changing its style or position, to a CPropertySheet and opens the property sheet.

The "Open Dialog With Modified Styles" sets the modify flag for the property page and starts it up as a modal dialog on its own. We override PreSubclassWindow to change the property page's styles.

void CPropertyPageFirst::PreSubclassWindow() 
{
    //If the modify flag is set, modify window styles here. Some Styles

    //such as CHILD/POPUP and DISABLED have to be modified before

    //OnInitDialog() otherwise it is too late.

    if (m_bModifyDlgStylesAndPos == true)
    {
        if(m_hWnd != NULL)
        {
            //First get the current Window Styles

            LONG lStyle = GetWindowLong(m_hWnd, GWL_STYLE);
            
            lStyle &= ~WS_CHILD;        //remove the CHILD style

            lStyle &= ~WS_DISABLED;        //remove the DISABLED style


            lStyle |= WS_POPUP;            //Add the POPUP style

            lStyle |= WS_VISIBLE;        //Add the VISIBLE style

            lStyle |= WS_SYSMENU;        //Add the SYSMENU to have a close button

                        
            //Now set the Modified Window Style

            SetWindowLong(m_hWnd, GWL_STYLE, lStyle);  
        }
    }

    //We also have to change the window position but it is too early to do it here

    //has to be done in OnInitDialog()


    CPropertyPage::PreSubclassWindow();
}

We set the dialog's position by overriding OnInitDialog().

BOOL CPropertyPageFirst::OnInitDialog() 
{
    CPropertyPage::OnInitDialog();

    //Let's change the window position if it has been modified. Otherwise it

    //gets drawn relative to the desktop with some transparent areas.

    
    if((m_bModifyDlgStylesAndPos == true) && m_hWnd)
    {
        SetWindowText("Modified Property Page");

        // Put window in center of Main Dialog 

        CRect rectFrame, rectDlg;
        CWnd* pMainWnd = AfxGetMainWnd();
        if(pMainWnd != NULL)
        {
            pMainWnd->GetClientRect(rectFrame);
            pMainWnd->ClientToScreen(rectFrame);
            GetWindowRect(rectDlg);

            int nXPos = rectFrame.left + (rectFrame.Width() / 2) 
                                       - (rectDlg.Width() / 2);
            int nYPos = rectFrame.top + (rectFrame.Height() / 2) 
                                      - (rectDlg.Height() / 2);
            
            //When setting window's position, we make 

            //it the TOP Window. Making it the TOPMOST may

            //not be such a good idea and may annoy some people!!

            //The most important thing to keep in mind here 

            //is to specify SWP_NOCOPYBITS as the 

            //the window sizing and positioning flag, 

            //otherwise all valid contents of the client area

            //of the previous window position are copied 

            //into the client area after the window is 

            //sized or repositioned.


            ::SetWindowPos(m_hWnd, HWND_TOP, nXPos, nYPos, 
              rectDlg.Width(), rectDlg.Height(), SWP_NOCOPYBITS);
            
        }
    }
}

Points of Interest

The main task here was to use the same property page in two different environments:

  1. As a child of a CPropertySheet.
  2. As an independent pop-up dialog.

It was apparent that I would have to modify the dialog's style in case #2. I tried doing this in OnInitDialog() with ModifyStyle(...) but that did not work as it is too late to change a child window to a pop-up in OnInitDialog().

I considered PreCreateWindow(...) thinking I could change the CREATESTRUCT in this function to change both the styles and position in one go. But it turns out that PreCreateWindow(...) doesn't get called at all for modal dialogs.

I could try instantiating the dialog as modeless but there were two problems with this approach:

  1. The PreCreateWindow(...) still didn't get called.
  2. Memory management problems occurred as one instance of the dialog was modal and the other was modeless.

I could get around a) above by calling CreateEx(...) as doing so would call PreCreateWindow(...) but at this point we would be creating the styles for the dialog from scratch instead of modifying them which is not what we intended. So the solution was to modify the styles in PreSubclassWindow(). Now you may be tempted to re-position the dialog here as well but no matter how you try it, the dialog does not move from the left corner of the screen. Additionally, the dialog is drawn with some areas as transparent. So you have to re-position it in OnInitDialog().

There is one more catch though: when using ::SetWindowPos(...), you have to specify SWP_NOCOPYBITS as the window sizing and positioning flag, otherwise all valid contents of the client area of the previous window position are copied into the client area after the window is sized or repositioned, resulting in a strange looking dialog with some unexpected graphics.

That's it! Please go ahead and experiment, suggest other ways to accomplish the same. Enjoy!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here