Click here to Skip to main content
15,885,278 members
Articles / Desktop Programming / MFC
Article

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

Rate me:
Please Sign up or sign in to vote.
4.12/5 (13 votes)
20 Feb 20063 min read 95.3K   2.7K   20   6
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


Written By
Software Developer
United States United States
Although an electrical engineer by major, I slowly transformed into a software developer as I realized I liked working with logical AND and ORs more than the physical ones on chips. I have taught C++ at ITT tech and worked on videoconferencing as a programmer. A summer class at Harvard got me into windows programming and I have enjoyed it ever since.

I like hiking, camping, walking and swimming. Tennis gets me going too as does discussing human psychology.

Comments and Discussions

 
GeneralCode needs updating Pin
ReturnVoid8-Jun-14 18:38
ReturnVoid8-Jun-14 18:38 
GeneralRe: Code needs updating Pin
kacy12330-Nov-16 4:47
kacy12330-Nov-16 4:47 
GeneralMy vote of 5 Pin
up2wing25-Nov-12 16:26
up2wing25-Nov-12 16:26 
GeneralRe: My vote of 5 Pin
Rafique Sheikh25-Nov-12 18:53
Rafique Sheikh25-Nov-12 18:53 
QuestionCreating topmost non-modal dialog box Pin
Tushar Jadhav20-May-07 20:05
Tushar Jadhav20-May-07 20:05 
AnswerRe: Creating topmost non-modal dialog box Pin
Anikan8-Jun-07 4:18
Anikan8-Jun-07 4:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.