mrwad99
asked on
Property sheet: selecting pages programatically - problems
Ah hello.
I have a CPropertySheet. On this sheet I have two pages. When the first page gets hit, I want to activate the second immediately. Consider this:
BOOL CFirstPage::OnSetActive()
{
((CMyPropertySheet*)GetPar ent())->Se tActivePag e ( 1 );
return CPropertyPage::OnSetActive ();
}
This fails; it results in the first page being displayed. However, this works:
BOOL CFirstPage::OnSetActive()
{
GetParent()->PostMessage(P SM_SETCURS EL, 1);
return CPropertyPage::OnSetActive ();
}
Now, I stepped into the code for SetActivePage, and found the following:
BOOL CPropertySheet::SetActiveP age(int nPage)
{
if (m_hWnd == NULL)
{
m_psh.nStartPage = nPage;
return TRUE;
}
return (BOOL)SendMessage(PSM_SETC URSEL, nPage);
}
So the only difference between what works and what doesn't is the use of PostMessage over SendMessage.
I have uploaded a simple project to http://mrwad99.fortunecity.com/ demonstrating this.
Can someone explain what is going on to me please ?
TIA
I have a CPropertySheet. On this sheet I have two pages. When the first page gets hit, I want to activate the second immediately. Consider this:
BOOL CFirstPage::OnSetActive()
{
((CMyPropertySheet*)GetPar
return CPropertyPage::OnSetActive
}
This fails; it results in the first page being displayed. However, this works:
BOOL CFirstPage::OnSetActive()
{
GetParent()->PostMessage(P
return CPropertyPage::OnSetActive
}
Now, I stepped into the code for SetActivePage, and found the following:
BOOL CPropertySheet::SetActiveP
{
if (m_hWnd == NULL)
{
m_psh.nStartPage = nPage;
return TRUE;
}
return (BOOL)SendMessage(PSM_SETC
}
So the only difference between what works and what doesn't is the use of PostMessage over SendMessage.
I have uploaded a simple project to http://mrwad99.fortunecity.com/ demonstrating this.
Can someone explain what is going on to me please ?
TIA
Further to the ps - it also works here one first page (just tried it on a standard (non-customised) CPropertyPage/CPropertyShe et)
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Hi Andy
>> PostMessage - message appended to queue
>> SendMessage - queue is bypassed and message handler called directly.
Yeah I am aware of the differences between the two.
>> ps. your code that falis works here (when used on another tab - not the first one)
I don't get that. I add four pages, and on OnSetActive within page 2, I add the line
((CMyPropertySheet*)GetPar ent())->Se tActivePag e ( 3 );
Nothing happens; the third page (which of course has index 2) is still displayed.
If I change it to
GetParent()->PostMessage(P SM_SETCURS EL, 3);
it works.
>> Also do you want to disable the first tab or do you want the prop sheet to start with the second tab as the default page being displayed?
Not at all; I have a bigger app that uses some logic to determine the page to be displayed. For example, say the user has to make a choice on page 2, if they have specified this choice via the command line, we can skip page 2 and goto page 3.
Thanks.
>> PostMessage - message appended to queue
>> SendMessage - queue is bypassed and message handler called directly.
Yeah I am aware of the differences between the two.
>> ps. your code that falis works here (when used on another tab - not the first one)
I don't get that. I add four pages, and on OnSetActive within page 2, I add the line
((CMyPropertySheet*)GetPar
Nothing happens; the third page (which of course has index 2) is still displayed.
If I change it to
GetParent()->PostMessage(P
it works.
>> Also do you want to disable the first tab or do you want the prop sheet to start with the second tab as the default page being displayed?
Not at all; I have a bigger app that uses some logic to determine the page to be displayed. For example, say the user has to make a choice on page 2, if they have specified this choice via the command line, we can skip page 2 and goto page 3.
Thanks.
ASKER
- Sorry AlexFM, I did not receive notification of your post - reading your comment now -
ASKER
The second page's OnSetActive code contains the code to programatically select the *fourth* page. This is why I start the callstacks with the second page becoming active.
Here is the callstack when I programatically select the fourth page with SetActivePage(), i.e.
BOOL CSecondPage::OnSetActive()
{
((CMyPropertySheet*)GetPar ent())->Se tActivePag e ( 3 );
return CPropertyPage::OnSetActive ();
}
When activating the second of four pages, the callstack is as follows:
CPropertyPage::OnNotify - PSN_SETACTIVE message. 'this' is a CSecondPage object
CSecondPage::OnSetActive() - contains code ((CMyPropertySheet*)GetPar ent())->Se tActivePag e ( 3 );
CPropertyPage::OnNotify - PSN_SETACTIVE message. 'this' is a CFourthPage object, which is what I would expect
CPropertyPage::OnSetActive () - (I did not override this for CFourthPage). Ends up returning TRUE
I end up with the second page still being shown.
Here is the callstack when I programatically select the fourth page with PostMessage, i.e.
BOOL CSecondPage::OnSetActive()
{
GetParent()->PostMessage(P SM_SETCURS EL, 3);
return CPropertyPage::OnSetActive ();
}
CPropertyPage::OnNotify - PSN_SETACTIVE message. 'this' is a CSecondPage object
CSecondPage::OnSetActive() - contains code GetParent()->PostMessage(P SM_SETCURS EL, 3);
CPropertyPage::OnSetActive () - 'this' is a CSecondPage object. Ends up returning TRUE. This is reached as a consequence of immediately dropping through the PostMessage() call in CSecondPage::OnSetActive() .
CPropertyPage::OnNotify - PSN_SETACTIVE message. 'this' is a CFourthPage object, which is what I would expect.
CPropertyPage::OnSetActive () - I did not override OnSetActive() for CFourthPage, hence this base class version got called. 'this' is a CFourthPage object.
Now, I have spent time tracing through, but am missing the crucial point between these. Can someone explain the differences and the resultant behaviour please ?
Here is the callstack when I programatically select the fourth page with SetActivePage(), i.e.
BOOL CSecondPage::OnSetActive()
{
((CMyPropertySheet*)GetPar
return CPropertyPage::OnSetActive
}
When activating the second of four pages, the callstack is as follows:
CPropertyPage::OnNotify - PSN_SETACTIVE message. 'this' is a CSecondPage object
CSecondPage::OnSetActive()
CPropertyPage::OnNotify - PSN_SETACTIVE message. 'this' is a CFourthPage object, which is what I would expect
CPropertyPage::OnSetActive
I end up with the second page still being shown.
Here is the callstack when I programatically select the fourth page with PostMessage, i.e.
BOOL CSecondPage::OnSetActive()
{
GetParent()->PostMessage(P
return CPropertyPage::OnSetActive
}
CPropertyPage::OnNotify - PSN_SETACTIVE message. 'this' is a CSecondPage object
CSecondPage::OnSetActive()
CPropertyPage::OnSetActive
CPropertyPage::OnNotify - PSN_SETACTIVE message. 'this' is a CFourthPage object, which is what I would expect.
CPropertyPage::OnSetActive
Now, I have spent time tracing through, but am missing the crucial point between these. Can someone explain the differences and the resultant behaviour please ?
<Yeah I am aware of the differences between the two. >
That is a major difference between the order in which actions are performed. Often a reason why one works and the other occasionally fails. <So the only difference between what works and what doesn't is the use of PostMessage over SendMessage>
The code snippet.
BOOL CFirstPage::OnSetActive()
{
((CMyPropertySheet*)GetPar ent())->Se tActivePag e ( 1 );
return CPropertyPage::OnSetActive ();
}
This fails; it results in the first page being displayed.
Erm - here it works fine using a CPropertySheet/CPropertyPa ge without any customisation (well any that I *think* should interfere)
<For example, say the user has to make a choice on page 2, if they have specified this choice via the command line, we can skip page 2 and goto page 3>
Sounds like a wizard - have you looked at the virtual OnWizardNext function?
That is a major difference between the order in which actions are performed. Often a reason why one works and the other occasionally fails. <So the only difference between what works and what doesn't is the use of PostMessage over SendMessage>
The code snippet.
BOOL CFirstPage::OnSetActive()
{
((CMyPropertySheet*)GetPar
return CPropertyPage::OnSetActive
}
This fails; it results in the first page being displayed.
Erm - here it works fine using a CPropertySheet/CPropertyPa
<For example, say the user has to make a choice on page 2, if they have specified this choice via the command line, we can skip page 2 and goto page 3>
Sounds like a wizard - have you looked at the virtual OnWizardNext function?
ASKER
>> Sounds like a wizard - have you looked at the virtual OnWizardNext function?
Yes, it is a wizard. I could look at that function, but that would not answer the question I have posted.
Did you download and try the code Andy ?
Yes, it is a wizard. I could look at that function, but that would not answer the question I have posted.
Did you download and try the code Andy ?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks. I ended up using OnWizardNext/OnWizardBack to do what I required.
SendMessage - queue is bypassed and message handler called directly.
ps. your code that falis works here (when used on another tab - not the first one)
Also do you want to disable the first tab or do you want the prop sheet to start with the second tab as the default page being displayed?