Propertysheets embedded in Dialogs
Posted
by Franz Maerzinger
on December 12th, 1998
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:
- Create a dialog-project
- Add the two files (CMyPropertySheet.cpp + *.h) to your project
- Create a dialog class (in my example you will find PropPage1 and PropPage2)
- 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:23amHow to create Pagemaker like stylesheets.
Posted by Legacy on 02/10/2003 12:00amOriginally 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.
ReplyWorks pretty good
Posted by Legacy on 11/07/2002 12:00amOriginally 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!
ReplyA simple solution for the problem above
Posted by Legacy on 09/25/2002 12:00amOriginally 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);
ReplyNew e-mail-address
Posted by Legacy on 10/29/2001 12:00amOriginally posted by: Franz M�rzinger
I have changed my e-mail-address.
The new e-mail-adress is:
fmsoft@nusurf.at
ReplyInserting propety sheets in a toolbar
Posted by Legacy on 01/22/2001 12:00amOriginally posted by: raphael mor
i need either to do this, or to dock a dialog so please if someone could help me...
Replyraphael Mor
Tab font
Posted by Legacy on 08/14/2000 12:00amOriginally 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
ReplyHow do I manipulate strings on the property page
Posted by Legacy on 02/06/2000 12:00amOriginally 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?
ReplyAdd control on propertysheet, how to use the control?
Posted by Legacy on 07/20/1999 12:00amOriginally 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?
ReplyLocalUnlock (pPropPage->m_hLocal); //pBuffer =
// (BYTE*)LocalLock(pPropPage->m_hLocal);
LocalFree (pPropPage->m_hLocal); // LocalAlloc(LHND, nBufferSize);
}
m_Dialogs.RemoveAt (0);
delete (pPropPage);
.....
}
RE: demo and source not found !
Posted by Legacy on 04/30/1999 12:00amOriginally 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