Propertysheets embedded in Dialogs | CodeGuru

Propertysheets embedded in Dialogs

Environment: MSVC++ 5.00, win95 Many have had a problem with propertysheets embedded in dialog-boxes. The problem is that the system hangs after the sheet loses the focus and the window is activated. Below is some sourcecode for propertysheets and pages: (this is a part of a big project with dialogeditor, reporteditor) everything is created on […]

Written By
CodeGuru Staff
CodeGuru Staff
Dec 12, 1998
1 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Environment: MSVC++ 5.00, win95

Many have had a problem with propertysheets embedded in dialog-boxes. The
problem is that the system hangs after the sheet loses the focus and the
window is activated.

Below is some sourcecode for propertysheets and pages:
(this is a part of a big project with dialogeditor, reporteditor)
everything is created on the fly: In my example I have deactivated
the OK and CANCEL (ENTER and ESC-key) for my propertypage-dialogs
(override OnOk and OnCancel).

To use the code all you have to do is the following:

  1. Create a dialog-project
  2. Add the two files (CMyPropertySheet.cpp + *.h) to your project
  3. Create a dialog class (in my example you will find PropPage1 and
    PropPage2)
  4. Add the following lines to you OnInitDialog:
        // Create the CMyPropertysheet
        m_propertySheet.m_Rect.left = 100;    // set the position on the screen
        m_propertySheet.m_Rect.top = 100;
        m_propertySheet.m_Rect.right = 500;
        m_propertySheet.m_Rect.bottom = 300;
        m_propertySheet.m_nPages = -1;        // init this membervariable
        m_propertySheet.m_nActPage = 0;       // init this membervariable
        m_propertySheet.m_nCtrlID = 2000;     // control-id in the dialog
    
        // and create it on the screen
        m_propertySheet.Create (WS_VISIBLE | WS_CHILD | WS_TABSTOP,
            m_propertySheet.m_Rect, this, m_propertySheet.m_nCtrlID);
    
        // Now add the dialogs page per page
        TC_ITEM Item;
        Item.mask = TCIF_TEXT;
        CMyPropertyPage *pPropPage;
    
        int nN;
        int nPages = 2;    // in my example I have two pages
        for (nN = 0; nN < nPages; nN++) {
    
            pPropPage = new (CMyPropertyPage);    // new it
    
            // Create the tab and the dialog
            switch (nN) {
            case 0:    // page number 1 - a small example
                Item.pszText = "Page 1";
                pPropPage->m_strTitle = "&Page1";    // or get the title of the dialog                    
                                                     // whatwever you want
                pPropPage->m_pDialogPage = (CMyPropDialog *) &m_propPage1;
                pPropPage->m_pDialogPage->Create (IDD_PROPPAGE1, &m_propertySheet);
                break;
    
            case 1:    // page number 2 - a small example
                Item.pszText = "Page 2";
                pPropPage->m_strTitle = "&Page2";    // or get the title of the dialog         
                        // whatwever you want
                pPropPage->m_pDialogPage = (CMyPropDialog *) &m_propPage2;
                pPropPage->m_pDialogPage->Create (IDD_PROPPAGE2, &m_propertySheet);
                break;
            }
    
            m_propertySheet.InsertItem (nN, &Item);    // this is for CTabWnd
            pPropPage->m_hLocal = NULL;                // nothing is created on the fly
                                                       // important information on delete!
    
            // add it to the array
            m_propertySheet.m_Dialogs.Add (pPropPage);
            m_propertySheet.m_nPages++;    // one more page
    
    
            // the size of CTabWnd is m_rect
            // the size of the dialog is smaller
            pPropPage->m_Rect.top = 30;     // above there must be enough place for the
                                            // tab-control
            pPropPage->m_Rect.left = 10;    // border of 10 units is good
            pPropPage->m_Rect.bottom = m_propertySheet.m_Rect.bottom -
                        m_propertySheet.m_Rect.top - 10;
            pPropPage->m_Rect.right = m_propertySheet.m_Rect.right -
                        m_propertySheet.m_Rect.left - 10;
    
            // Only the 1. page should be active at startup
            if (nN > 0) {
                pPropPage->m_pDialogPage->SetWindowPos(NULL, pPropPage->m_Rect.left,
                                pPropPage->m_Rect.top, 0, 0,
                                SWP_HIDEWINDOW | SWP_NOSIZE);
            }
            else {
                pPropPage->m_pDialogPage->SetWindowPos(NULL, pPropPage->m_Rect.left,
                                pPropPage->m_Rect.top, 0, 0,
                                SWP_SHOWWINDOW | SWP_NOSIZE);
            }
            // the class will handle the change of the tab-control
            // and synchronize activate-deactivate the dialogpages
        }
    

The source code is as follows.

*************** CMyProperty.h ***************


#define    ID_NEXT_FIELD        1
#define    ID_PREV_FIELD    2

////////////////////////////////////////////////////////////////////////////

// Class to handle the pages
class CMyPropertyPage : public CObject {
public:
    DLGTEMPLATE    m_dlgTemplate;    // Templatestructure
    DLGTEMPLATE    *m_pResource;    // I create my dialogs on the fly
                    // so I need a pointer to the memory
    HLOCAL    m_hLocal;        // Memory-Handle
    CString        m_strTitle;
    CMyPropDialog    *m_pDialogPage;    // pointer to the dialog structur
    CRect        m_Rect;        // size of the dialog on the screen

};

////////////////////////////////////////////////////////////////////////////

// Class to handle the TabCtrl
class CMyPropertySheet : public CTabCtrl
{
// Construction
public:
        CMyPropertySheet();

    CRect   m_Rect;             // Rectangle coordinates
    UINT    m_nCtrlID;          // CTrlID in the dialog
    int             m_nPages;   // number of pages
    int             m_nActPage; // Actual page
    // Array of dialogs
    CObArray    m_Dialogs;

// Attributes
public:

// Operations
public:
    int        SetActivePage (int nPage);
    int        SetActivePage (CMyPropDialog* pPage);
    CMyPropDialog    *GetPage (int nPage);
    CMyPropDialog    *GetActivePage (void);
    int        GetPageCount (void);
    BOOL    DispPage (int    nCommand);        // handling pgup and pgdn


        //{{AFX_VIRTUAL(CMyPropertySheet)
    public:
    virtual BOOL PreTranslateMessage(MSG* pMsg);
    protected:
    virtual void PostNcDestroy();
    //}}AFX_VIRTUAL

// Implementation
public:
        virtual ~CMyPropertySheet();

protected:
        //{{AFX_MSG(CMyPropertySheet)
        afx_msg void OnSelchange(NMHDR* pNMHDR, LRESULT* pResult);
        //}}AFX_MSG

        DECLARE_MESSAGE_MAP()
};

////////////////////////////////////////////////////////////////////////////

// CMyPropDialog the dialog

class CMyPropDialog : public CDialog
{
// Konstruction
public:
    CMyPropDialog(CWnd* pParent = NULL);   // Standardconstruction

// Dialogfields
    //{{AFX_DATA(CMyPropDialog)
    // enum { IDD = _UNKNOWN_RESOURCE_ID_ }; I create my  dialogs on the fly

    //}}AFX_DATA


    //{{AFX_VIRTUAL(CMyPropDialog)
    public:
    virtual BOOL PreTranslateMessage(MSG* pMsg);
    virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra,
                AFX_CMDHANDLERINFO* pHandlerInfo);
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);
    virtual void PostNcDestroy();
    //}}AFX_VIRTUAL

// Implementation
protected:

    //{{AFX_MSG(CMyPropDialog)
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};


**************** CMyProperty.cpp *******************

////////////////////////////////////////////////////////////////////////////

// CMyPropertySheet

CMyPropertySheet::CMyPropertySheet()
{
}

CMyPropertySheet::~CMyPropertySheet()
{
}


BEGIN_MESSAGE_MAP(CMyPropertySheet, CTabCtrl)
        //{{AFX_MSG_MAP(CMyPropertySheet)
        ON_NOTIFY_REFLECT(TCN_SELCHANGE, OnSelchange)
        //}}AFX_MSG_MAP
END_MESSAGE_MAP()

// Change the tab on the top
void CMyPropertySheet::OnSelchange(NMHDR* pNMHDR, LRESULT* pResult)
{
    SetActivePage (GetCurSel ());
    *pResult = 0;
}


////////////////////////////////////////////////////////////////////////////

// This page will be the active page
int CMyPropertySheet::SetActivePage (int nPage) {
    CMyPropertyPage*    pPropPage;

    if (nPage < 0 || nPage > m_nPages) nPage = 0;

    // get the actual page
    pPropPage = (CMyPropertyPage *) m_Dialogs.GetAt (m_nActPage);
    // deactevate it
    nGLTemp = pPropPage->m_pDialogPage->SetWindowPos (NULL,
        pPropPage->m_Rect.left, pPropPage->m_Rect.top, 0, 0, SWP_HIDEWINDOW |
        SWP_NOSIZE);

    // get the new page
    pPropPage = (CMyPropertyPage *) m_Dialogs.GetAt (nPage);
    nGLTemp = pPropPage->m_pDialogPage->SetWindowPos (NULL,
        pPropPage->m_Rect.left, pPropPage->m_Rect.top, 0, 0, SWP_SHOWWINDOW |
        SWP_NOSIZE);

    m_nActPage = nPage;

    // set the CTabCtrl-element
    SetCurSel(m_nActPage);

    return TRUE;
}

////////////////////////////////////////////////////////////////////////////

// Set this page as the active page
int CMyPropertySheet::SetActivePage (CMyPropDialog* pPage){
    CMyPropertyPage*    pPropPage;
    int    nPage, nPageFound=0;
    for (nPage = 0; nPage <= m_nPages; nPage++) {
        pPropPage = (CMyPropertyPage *) m_Dialogs.GetAt (nPage);
        if (pPropPage->m_pDialogPage == pPage) {
            nPageFound = nPage;
            break;
        }
    }

    SetActivePage (nPageFound);

    return TRUE;
}
////////////////////////////////////////////////////////////////////////////

// Show the next or previous page
int CMyPropertySheet::DispPage (int nCommand){
    int    nPage;
    nPage = m_nActPage;

    if (nCommand == ID_NEXT_FIELD)
        nPage++;
    else
        nPage--;

    // are there correct page numbers?
    if (nPage < 0) nPage = m_nPages;
    if (nPage > m_nPages) nPage = 0;

    SetActivePage (nPage);
    return TRUE;
}
////////////////////////////////////////////////////////////////////////////

// Get page number X
CMyPropDialog* CMyPropertySheet::GetPage (int nPage){
    CMyPropertyPage*    pPropPage;

    if (nPage < 0 || nPage > m_nPages) nPage = 0;

    pPropPage = (CMyPropertyPage *) m_Dialogs.GetAt (nPage);
    return pPropPage->m_pDialogPage;
}

////////////////////////////////////////////////////////////////////////////

// Get the active = current page
CMyPropDialog* CMyPropertySheet::GetActivePage (void){
    CMyPropertyPage*    pPropPage;

    pPropPage = (CMyPropertyPage *) m_Dialogs.GetAt (m_nActPage);
    return pPropPage->m_pDialogPage;

}

////////////////////////////////////////////////////////////////////////////

// Get the number of possible pages
int CMyPropertySheet::GetPageCount (void) {
    return    m_nPages;
}


////////////////////////////////////////////////////////////////////////////

// CMyPropDialog 
CMyPropDialog::CMyPropDialog(CWnd* pParent /*=NULL*)
    : CDialog()
//    : CDialog(CMyPropDialog::IDD, pParent)
{
    //{{AFX_DATA_INIT(CMyPropDialog)
        // 
    //}}AFX_DATA_INIT
}


void CMyPropDialog::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CMyPropDialog)
        // 
    //}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CMyPropDialog, CDialog)
    //{{AFX_MSG_MAP(CMyPropDialog)
    ON_WM_CTLCOLOR()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

////////////////////////////////////////////////////////////////////////////

// Messages for CMyPropDialog 

////////////////////////////////////////////////////////////////////////////

// handle CTRL-PGUP & PGDN
BOOL CMyPropDialog::PreTranslateMessage(MSG* pMsg)
{
    // TODO:
    CWnd    *pWnd;

    /*First Property Sheet tab key translation
    Ctrl+PageUp, and Ctrl+PageDown *

    if (pMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_CONTROL) < 0 &&
        pMsg->wParam == VK_PRIOR) {
        ((CMyPropertySheet *) GetParent ())->DispPage (ID_PREV_FIELD);
        return TRUE;
    }
    if (pMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_CONTROL) < 0 &&
        pMsg->wParam == VK_NEXT) {
        ((CMyPropertySheet *) GetParent ())->DispPage (ID_NEXT_FIELD);
        return TRUE;
    }


    return CDialog::PreTranslateMessage(pMsg);
}

////////////////////////////////////////////////////////////////////////////

// 
BOOL CMyPropDialog::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
    // TODO: do nothing here
    return CDialog::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}


////////////////////////////////////////////////////////////////////////////

// CTabCtrl-Handling
BOOL CMyPropertySheet::PreTranslateMessage(MSG* pMsg)
{
    // TODO:

    /*First Property Sheet tab key translation
    Ctrl+PageUp, and Ctrl+PageDown *

    if (pMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_CONTROL) < 0 &&
        pMsg->wParam == VK_PRIOR) {
        DispPage (ID_PREV_FIELD);
        return TRUE;
    }
    if (pMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_CONTROL) < 0 &&
        pMsg->wParam == VK_NEXT) {
        DispPage (ID_NEXT_FIELD);
        return TRUE;
    }

    return CTabCtrl::PreTranslateMessage(pMsg);
}

void CMyPropertySheet::PostNcDestroy()
{
    // TODO: Free and unlock

    UINT    nN;
    CMyPropertyPage*    pPropPage;

    // pPropPages deleten
    for (nN = 0; nN <= m_nPages; nN++) {
        //  get page per page
        pPropPage = (CMyPropertyPage *) m_Dialogs.GetAt (0);
        LocalUnlock (pPropPage->m_hLocal);    //pBuffer =
                            // (BYTE*)LocalLock(pPropPage->m_hLocal);
        LocalFree (pPropPage->m_hLocal);    // LocalAlloc(LHND, nBufferSize);
        m_Dialogs.RemoveAt (0);
        delete (pPropPage);
    }
    m_Font.DeleteObject ();
    CTabCtrl::PostNcDestroy();
    delete (this);        // free Resources
}

void CMyPropDialog::PostNcDestroy()
{
    // TODO: 

    CDialog::PostNcDestroy();
    delete (this);        // free it
}


////////////////////////////////////////////////////////////////////////////

// Change colors if you want
HBRUSH CMyPropDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

    // TODO: Return a different brush if the default is not desired
    return hbr;
}

CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.