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 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;
}



Comments

  • VeryGOog

    Posted by objectarx on 01/22/2011 04:23am

    VeryGood

    Reply
  • How to create Pagemaker like stylesheets.

    Posted by Legacy on 02/10/2003 12:00am

    Originally posted by: Kalyan

    Hai ,
    I have a problem Creating a Interface.The requirement for me is that in a window i want to have control bars / property pages /child windows which are Dockable and all the windows to be activated at same time.I have a created the control bars and and all the windows are getting activated at the same time.But i need those controlbars to be docked with in another.All controlbars i created are derived from mfc class ccontrolbar. Above effect can be visualized in pagemaker products. Those were named as show colors, show styles etc.Colors and styles are controlbars those can be docked within one another.I tried a lot my work doesnt get any fruit.
    I hope this post will help a lot in developing that type of effectable windows/controlbars.

    Kalyan.

    Reply
  • Works pretty good

    Posted by Legacy on 11/07/2002 12:00am

    Originally posted by: Thorsten Beck

    I had the job to show some PropertyPages on a page which is one of the pages of a CTabCrtl. No idea how to do that. So I made (inspired from this example code) a dialog on my tabpage and put this special PropertySheet with some PropertyPages on that dialog. Works perfect.

    Thanx a lot and may the force be with you!

    Reply
  • A simple solution for the problem above

    Posted by Legacy on 09/25/2002 12:00am

    Originally posted by: Ralf M�ting

    Take a look on this site:

    http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q149501&

    Add the following line in CPropertySheet::OnInitDialog:

    ModifyStyleEx(0,WS_EX_CONTROLPARENT);

    Reply
  • New e-mail-address

    Posted by Legacy on 10/29/2001 12:00am

    Originally posted by: Franz M�rzinger

    I have changed my e-mail-address.
    The new e-mail-adress is:

    fmsoft@nusurf.at

    Reply
  • Inserting propety sheets in a toolbar

    Posted by Legacy on 01/22/2001 12:00am

    Originally posted by: raphael mor

    i need either to do this, or to dock a dialog so please if someone could help me...
    raphael Mor

    Reply
  • Tab font

    Posted by Legacy on 08/14/2000 12:00am

    Originally posted by: Philip Hebert

    How do you change the tab text font?

    I want to change it to a smaller font.

    I tried calling SetFont on the property sheet before
    any of the tabs were created, but all that did was shrink
    the tab headers while leaving the text size the same.

    Any suggestions?

    Philip

    Reply
  • How do I manipulate strings on the property page

    Posted by Legacy on 02/06/2000 12:00am

    Originally posted by: Mikael Johansson

    How do I manipulate e.g edit boxes on a property page?
    I wish to do this from the main dialog.

    Reading the edit boxes is done by using

    m_propPage1.UpdateData();

    Changing a CString is done by
    m_propPage1.m_strEditText = "test";

    How do I update the porperty page dialog?


    Reply
  • Add control on propertysheet, how to use the control?

    Posted by Legacy on 07/20/1999 12:00am

    Originally posted by: X.Guang Shi

    It is a very good code, I am using it. One thing I have not solved is how to use the control which I put on the propertysheet.
    I have put three pages of propertysheets within a dialog.
    on each page, I gave some controls, like edit, combo, and list. But I can not manipulate the controls.
    I need more instruction. Could you help me?
    is it related the the following code:

    BOOL CExampleDlg::OnInitDialog()
    {
    ...
    m_propertySheet.InsertItem (nN, &Item); // this is fot CTabWnd
    pPropPage->m_hLocal = NULL; // nothing is created on fly // important information on delete!
    ....
    }

    void CMyPropertySheet::PostNcDestroy()
    {
    ........

    if (pPropPage->m_hLocal) { // you created the dialog on the fly?
    LocalUnlock (pPropPage->m_hLocal); //pBuffer =
    // (BYTE*)LocalLock(pPropPage->m_hLocal);
    LocalFree (pPropPage->m_hLocal); // LocalAlloc(LHND, nBufferSize);
    }
    m_Dialogs.RemoveAt (0);
    delete (pPropPage);
    .....
    }

    Reply
  • RE: demo and source not found !

    Posted by Legacy on 04/30/1999 12:00am

    Originally posted by: Michael Robinson

    Copy the shortcuts to your URL edit box and append .zip to them, that will point you to the files. Whoever did the HTML just forgot to do that in the HREF :)

    Reply
  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

Most Popular Programming Stories

More for Developers

RSS Feeds