Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Change Property Sheet Size?

1,343 views
Skip to first unread message

rockdale

unread,
Jan 14, 2009, 9:20:51 AM1/14/09
to
Hi, all:

My MFC application is Dialog based and I need to adjust the dialog
size based on user's screen resolution. (which works fine). I have a
property sheet with 2 property pages on my dialog. I tried to adjust
the property sheet size when the dialog size adjusted, basically just
expand the property sheet to occupy the whole dialog, but I could not
have it done. Following is my code:

/*
CMyPage1, CMyPage2 are classes derived from CPropertyPage
*/

CPropertySheet* m_pMainTabs;
CPropertyPage* m_pMyPage1;
CPropertyPage* m_pMyPage2;


BOOL CMyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
//resize window to maximum screen size
CSize screenSize;
screenSize.cx = ::GetSystemMetrics(SM_CXSCREEN);
screenSize.cy = ::GetSystemMetrics(SM_CYSCREEN);
MoveWindow(0,0, screenSize.cx, screenSize.cy);

//create property sheet and pages
m_pMyPage1 = new CMyPage1();
m_pMyPage2 = new CMyPage2();

m_pMainTabs = new CPropertySheet;

//Resize PropertySheet before add pages
CRect rcDlg, rcSheet;
GetWindowRect(&rcDlg);
ScreenToClient( &rcDlg );

m_pMainTabs->SetWindowPos( NULL, rcDlg.left, rcDlg.top, rcDlg.Width()
+100, rcDlg.Height()+100,
SWP_NOZORDER | SWP_NOACTIVATE );

m_pMainTabs->AddPage(m_pMyPage1);
m_pMainTabs->AddPage(m_pMyPage2);

m_pMainTabs->Create(this, WS_CHILD | WS_VISIBLE);
m_pMainTabs->ModifyStyleEx (0, WS_EX_CONTROLPARENT);
m_pMainTabs->ModifyStyle( 0, WS_TABSTOP );

m_pMainTabs->SetActivePage(m_pMyPage1);
}


thanks in advance
-rockdale

Victor

unread,
Jan 14, 2009, 10:55:01 AM1/14/09
to
You may not (and must not) call m_pMainTabs->SetWindowPos(...) before your
m_pMainTabs sheet has not been created (before m_pMainTabs->Create(...) call).

Victor

Joseph M. Newcomer

unread,
Jan 14, 2009, 10:59:54 AM1/14/09
to
Note that the property sheet has to go through and change the size of all its child
dialogs. There's a discussion about dynamically-sizing property sheets in
www.codeproject.com.
joe

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

AliR (VC++ MVP)

unread,
Jan 14, 2009, 11:00:07 AM1/14/09
to
You will have to resize the PropretyPages and the tab control, otherwise the
PropertySheet will resize but the tab inside of it will stay the same size.

http://support.microsoft.com/kb/300606

You said that you want to resize the propretysheet to take up the entire
main dialog. Why aren't you using the property sheet as your main dialog?

AliR.

"rockdale" <rockdal...@gmail.com> wrote in message
news:84864941-4fc7-4692...@v15g2000yqn.googlegroups.com...

Ajay Kalra

unread,
Jan 14, 2009, 11:07:33 AM1/14/09
to
> You said that you want to resize the propretysheet to take up the entire
> main dialog.  Why aren't you using the property sheet as your main dialog?

My thoughts as well.

--
Ajay

rockdale

unread,
Jan 14, 2009, 2:35:07 PM1/14/09
to
Thanks for all the reply. It is very informative.

I should not put the property sheet need to occupy the whole dialog.
This is just for simplify my question. My main dialog contains other
controls too. (not only the property sheet).

Victor- you are right. I can not call setwindowpos before I create the
propertysheet. Then here is another question, I create the
PropertySheet first then call the setwindowpos, then whenever I call
m_pMainTabs->GetWindowRect, I got the original size of the
propertysheet. I need the changed size so that I can lay out my
controls in the property page?


ALiR- Yes, I need to call The GetTabControl to get the CTabCtrl and
resize it. Now my problem is where should I resize my PropertyPage? I
read the MS article before but I do not need to make the Dialog
resizable, I just want to adjust the dialog size to the max of user
screen size and lay out the property sheet, property pages and
controls properly.

See my changed code below:

This code successfully resize the PropertySheet and its TabCtrl to the
dialog size,

in onInitDialog of PropertyPage

CRect rcPage;
CRect rcSheet;

GetParent()->GetWindowRect(&rcSheet);
GetWindowRect(&rcPage);

the rcSheet shows the original size of the property sheet.
and the rcPage shows the original size of the property page.

This OnInitDialog of propertyPage get called when I create the
propertysheet, and now I have not resize the property sheet yet, hence
I can not get the right size to layout my controls on the property
page.

I find some examples on CodeGuru and CodeParojects, but none of them
is what I wanted. Maybe somebody can show me links or point out what
should I do?

------------------------------------------------------


CPropertySheet* m_pMainTabs;
CPropertyPage* m_pMyPage1;
CPropertyPage* m_pMyPage2;

BOOL CMyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
//resize window to maximum screen size
CSize screenSize;
screenSize.cx = ::GetSystemMetrics(SM_CXSCREEN);
screenSize.cy = ::GetSystemMetrics(SM_CYSCREEN);
MoveWindow(0,0, screenSize.cx, screenSize.cy);

//Resize PropertySheet before add pages
CRect rcDlg, rcSheet;
GetWindowRect(&rcDlg);

m_pMainTabs->AddPage(m_pMyPage1);
m_pMainTabs->AddPage(m_pMyPage2);


// Now "initialize" the property sheet window.
if(!m_pMainTabs->Create(this, WS_CHILD | WS_VISIBLE)){
delete m_pMainTabs;
m_pMainTabs = NULL;
return;


}
m_pMainTabs->ModifyStyleEx (0, WS_EX_CONTROLPARENT);
m_pMainTabs->ModifyStyle( 0, WS_TABSTOP );

m_pMainTabs->SetWindowPos(NULL, rcDlg.left, rcDlg.top, rcDlg.Width(),
rcDlg.Height(),
SWP_NOZORDER | SWP_NOACTIVATE );

m_pMainTabs->GetWindowRect(&rcSheet);
ScreenToClient(&rcSheet);

m_pMainTabs->GetTabControl()->SetWindowPos( NULL, rcSheet.left,
rcSheet.top, rcSheet.Width(), rcSheet.Height(),
SWP_NOZORDER | SWP_NOACTIVATE );


m_pMainTabs->SetActivePage(m_pMyPage1);


--------------------------------;


AliR (VC++ MVP)

unread,
Jan 14, 2009, 5:17:55 PM1/14/09
to
The OnSize method of the propertysheet class would be a good place to resize
the tab and the pages. The article I posted describes this. The apply it
to a propertysheet that gets resized by the user, your is getting resized by
the programmer, subtract the code that puts the resize ancher on the bottom
of the dialog and the rest is exactly the same.

Here is the answer all spelled out:
//////////////////////////// CMyPropertySheet.h
/////////////////////////////////
#pragma once

// CMyPropertySheet

class CMyPropertySheet : public CPropertySheet
{
DECLARE_DYNAMIC(CMyPropertySheet)

public:
CMyPropertySheet();
CMyPropertySheet(UINT nIDCaption, CWnd* pParentWnd = NULL, UINT
iSelectPage = 0);
CMyPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd = NULL, UINT
iSelectPage = 0);
virtual ~CMyPropertySheet();

protected:
BOOL m_bNeedInit;
CRect m_rCrt;

virtual BOOL OnInitDialog();
afx_msg void OnSize(UINT nType, int cx, int cy);
DECLARE_MESSAGE_MAP()
};

//////////////////////////// CMyPropertySheet.cpp
/////////////////////////////////
// MyPropertySheet.cpp : implementation file
//

#include "stdafx.h"
#include "MyPropertySheet.h"
#include ".\mypropertysheet.h"


// CMyPropertySheet

IMPLEMENT_DYNAMIC(CMyPropertySheet, CPropertySheet)

CMyPropertySheet::CMyPropertySheet()
: m_bNeedInit(TRUE)
{
}

CMyPropertySheet::CMyPropertySheet(UINT nIDCaption, CWnd* pParentWnd, UINT
iSelectPage)
:CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
, m_bNeedInit(TRUE)
{
}

CMyPropertySheet::CMyPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd,
UINT iSelectPage)
: CPropertySheet(pszCaption, pParentWnd, iSelectPage)
, m_bNeedInit(TRUE)
{
}

CMyPropertySheet::~CMyPropertySheet()
{
}


BEGIN_MESSAGE_MAP(CMyPropertySheet, CPropertySheet)
ON_WM_SIZE()
END_MESSAGE_MAP()


// CMyPropertySheet message handlers

BOOL CMyPropertySheet::OnInitDialog()
{
BOOL bResult = CPropertySheet::OnInitDialog();

m_bNeedInit = FALSE;
GetClientRect(&m_rCrt);

return bResult;
}

// Handle WM_SIZE events by resizing the tab control and by
// moving all the buttons on the property sheet.
void CMyPropertySheet::OnSize(UINT nType, int cx, int cy)
{
CRect r1;
CPropertySheet::OnSize(nType, cx, cy);

if (m_bNeedInit)
return;

CTabCtrl *pTab = GetTabControl();
ASSERT(NULL != pTab && IsWindow(pTab->m_hWnd));

int dx = cx - m_rCrt.Width();
int dy = cy - m_rCrt.Height();
GetClientRect(&m_rCrt);

HDWP hDWP = ::BeginDeferWindowPos(5);

pTab->GetClientRect(&r1);
r1.right += dx; r1.bottom += dy;
::DeferWindowPos(hDWP, pTab->m_hWnd, NULL,
0, 0, r1.Width(), r1.Height(),
SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);

// Move all buttons with the lower right sides
for (CWnd *pChild = GetWindow(GW_CHILD);
pChild != NULL;
pChild = pChild->GetWindow(GW_HWNDNEXT))
{
if (pChild->SendMessage(WM_GETDLGCODE) & DLGC_BUTTON)
{
pChild->GetWindowRect(&r1); ScreenToClient(&r1);
r1.top += dy; r1.bottom += dy; r1.left+= dx; r1.right += dx;
::DeferWindowPos(hDWP, pChild->m_hWnd, NULL,
r1.left, r1.top, 0, 0,
SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER);
}
// Resize everything else...
else
{
pChild->GetClientRect(&r1);
r1.right += dx; r1.bottom += dy;
::DeferWindowPos(hDWP, pChild->m_hWnd, NULL, 0, 0, r1.Width(),
r1.Height(),SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
}

}

::EndDeferWindowPos(hDWP);
}

And you can change the layout of the controls on your propertypages in the
OnSize handler of each of your PropertyPage classes.


AliR.
"rockdale" <rockdal...@gmail.com> wrote in message

news:977bf1d6-96a3-4f1c...@v38g2000yqb.googlegroups.com...

Tom Serface

unread,
Jan 14, 2009, 7:01:32 PM1/14/09
to
This article is a little dated (for VC6), but not much has changed in this
area since then so I think it should still work:

http://support.microsoft.com/kb/300606

Tom

"rockdale" <rockdal...@gmail.com> wrote in message

news:84864941-4fc7-4692...@v15g2000yqn.googlegroups.com...

AliR (VC++ MVP)

unread,
Jan 15, 2009, 10:34:18 AM1/15/09
to
That's what I said. It's a nice solution.

AliR.

"Tom Serface" <t...@nospam.camaswood.com> wrote in message
news:C168BF05-72D1-4722...@microsoft.com...

rockdale

unread,
Jan 15, 2009, 11:18:02 AM1/15/09
to
AliR, Thanks, I got your point.

But I do not think I can use the OnSize event.

A little bit background for what I am trying to achieve, (should write
this in the first post, sorry)

On my propertyPage, I need to dynamic create a matrix of buttons and
other controls (CList, More buttons, CEdit..etc), I need to calculate
how many buttons I need to create based on the screen size, and then
layout other controls properly, all these are working already.

So in my ideal world, I should be able to:

1. In InitDialog the main Dialog and Resize the Dialog to screen.
2. In InitDialog of the main Dialog Create the PropertySheet and
resize the sheet to the Dialog size.
3. In InitDialog of the PropertyPage, get the PropertySheet size and
adjust Property Page size, based on the size of peroperty page,
calculate number of buttons I need to create, create buttons and
controls and layout them properly based on the property page size.

And from what I experienced, since I can not Resize the property sheet
before I actually create(instancialize) it, the propertyPage get
created(InitDialog get called) in this process, when I get to where I
need the size of the proprerty page to calculate button bumber and
layout them, I get the ORIGINAL size since I have not resize the
property sheet yet.

Any more suggestion? Or I did it totally wrong?

Thanks again
-Rockdale

AliR (VC++ MVP)

unread,
Jan 15, 2009, 12:14:49 PM1/15/09
to
If I was doing this, then I would not use a PropertySheet. I would simply
put a tab control in my dialog and add the dialogs myself, and then switch
between them. (Basically what a propertysheet does for you).

This way you have full control over when the dialogs get created, and at
what size they get created. That way you won't have to worry about catching
OnSize and changing things there. Although there is no way to specifiy a
size for a dialog when it is being created, you can create the dialog, and
then set its size, and then call a method in it to create its controls.

This is very simply to implement, you would have have this done, in the same
amount of time you have spent looking for the solution to the PropertySheet
problem.

The only trick here is to pass the tab control on your dialog as the parent
of the child dialogs that will be in the tab, and for placement of the
dialog you can use CTabCtrl::AdjustRect method to find the inside area of
the tab for placing your dialogs.

CRect Rect;
m_Tab.GetClientRect(&Rect);
m_Tab.AdjustRect(FALSE,&Rect);
m_Dlg1.SetWindowPos(NULL,Rect.left,Rect.top,Rect.Width(),Rect.Height(),SWP_NOZORDER);
m_Dlg2.SetWindowPos(NULL,Rect.left,Rect.top,Rect.Width(),Rect.Height(),SWP_NOZORDER);
m_Dlg1.CreateControls();
m_Dlg2.CreateControls();

m_Dlg1.ShowWindow(SW_SHOW);

And then catch the TCN_SELCHANGE message from the tab control, and hide the
current dialog (if not the same as newly selected dialog), and show the
newly selected tab's dialog.

AliR.


"rockdale" <rockdal...@gmail.com> wrote in message

news:dd51b434-80b1-4c50...@l33g2000pri.googlegroups.com...

Joseph M. Newcomer

unread,
Jan 15, 2009, 12:42:18 PM1/15/09
to
I agree. The property sheet is just a wrapper for a tab control with a few features
added. I use a modified form of CTabView from www.codeproject.com, and you can find this
in examples on my Web site such as my Locale Explorer.

Note that OnInitDialog is not necessarily the right time to make these decisions, such as
how many buttons will fit. What happens if the window is resized on the fly? I had to do
this, and would do dynamic layout of the buttons based ont he window size, and had to
support scrolling within the dialog/formview because when the window got small, the
buttons stacked vertically, pushing everything else down.
joe

rockdale

unread,
Jan 15, 2009, 3:50:45 PM1/15/09
to
Thanks, AliR and Joe

After reading the last 2 posts. I first tried using CTabCtrl,(never
used CTabCtrl, I have always use PropertySheet for tabs :). Create
myPages and then resize them then create controls, It works, need some
minus tuning thought. Then it occur to me why I must put my create
controls code inside the OnInitDialog? I should put it in a seperate
function and and explicit call this function after I resize the
property sheet and property page. It works beautifully.

Something like this: (added code is between ####)

CPropertySheet* m_pMainTabs;
CPropertyPage* m_pMyPage1;
CPropertyPage* m_pMyPage2;

BOOL CMyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
//resize window to maximum screen size
CSize screenSize;
screenSize.cx = ::GetSystemMetrics(SM_CXSCREEN);
screenSize.cy = ::GetSystemMetrics(SM_CYSCREEN);
MoveWindow(0,0, screenSize.cx, screenSize.cy);

//Resize PropertySheet before add pages
CRect rcDlg, rcSheet;
GetWindowRect(&rcDlg);

m_pMainTabs->AddPage(m_pMyPage1);
m_pMainTabs->AddPage(m_pMyPage2);

// Now "initialize" the property sheet window.
if(!m_pMainTabs->Create(this, WS_CHILD | WS_VISIBLE)){
delete m_pMainTabs;
m_pMainTabs = NULL;
return;
}

m_pMainTabs->ModifyStyleEx (0, WS_EX_CONTROLPARENT);
m_pMainTabs->ModifyStyle( 0, WS_TABSTOP );

m_pMainTabs->SetWindowPos(NULL, rcDlg.left, rcDlg.top,


rcDlg.Width(),
rcDlg.Height(),
SWP_NOZORDER | SWP_NOACTIVATE );

m_pMainTabs->GetWindowRect(&rcSheet);
ScreenToClient(&rcSheet);

m_pMainTabs->GetTabControl()->SetWindowPos( NULL,
rcSheet.left,
rcSheet.top, rcSheet.Width(), rcSheet.Height(),
SWP_NOZORDER | SWP_NOACTIVATE );

###########################
m_pMyPage1->SetWindowPos( NULL, rcSheet.left, rcSheet.top,


rcSheet.Width(), rcSheet.Height(),
SWP_NOZORDER | SWP_NOACTIVATE );

m_pMyPage2->SetWindowPos( NULL, rcSheet.left, rcSheet.top,


rcSheet.Width(), rcSheet.Height(),
SWP_NOZORDER | SWP_NOACTIVATE );

m_pMyPage1->InitControls();
m_pMyPage2->InitControls();
############################

m_pMainTabs->SetActivePage(m_pMyPage1);


Again ,thanks guys.

-rockdale

0 new messages