C++/VB - CPropertyPage::OnSetActive recursion or how can I extend CTabCtrl?

Asked By tenpoundnot
29-Jan-08 07:19 PM
I have an MFC application that uses PropertyPages and a PropertySheet
within a dialog as part of a GUI.  In addition there are other dialogs on the
screen which contain information that is specific to what is displayed on
each property page.  I've overriden the OnSetActive handler of the five
property pages I have so that I can update the other dialogs and make some
adjustments to what is displayed on the property page.  OnSetActive makes
some MFC calls including Wnd::RedrawWindow on a dialog within the property
page, and CWnd::ShowWindow on the dialogs outside the property page.  I only
call SetActivePage once in the entire application: on initialization.  I am
completely sure that SetActivePage is not called within OnSetActive.

I am using Visual C++ 2003 (version 7.1.6030).

My problem is that if I subject the property pages to some moderate stress
testing (i.e., lots of clicking) then sometimes the MFC calls within
OnSetActive will cause OnSetActive to be called again (recursively) by the
same thread, which is the main thread.  Realizing this I created a flag that
causes OnSetActive to bail out if recursion is detected.  I've observed that
this recursion always happens a multiple of 5 times, which is interesting
because I have 5 property pages / tabs.  It does not necessarily happen on
each tab, and it sometimes happens on tabs that weren't clicked, and
sometimes on tabs that were.  The strangest thing about this behaviour is
that the call stack does not show the recursion because it terminates in
Windows's OS dlls.  For this reason I don't know what part of MFC is causing
these effects.

Has anyone ever heard of or seen something like this?

I think that the problem may be related to some kind of latency between
the moment the CTabCtrl object within the property sheet is clicked and the
moment

OnSetActive is invoked.  If The user manages to click another tab in between
these two points in time, Windows's message queue will pick up the second
CTabCtrl click when it is handling my MFC ShowWindow and RedrawWindow calls
and then somehow get confused and cause 5 OnSetActive handlers to be invoked.

The easiest solution would be to somehow trap the CTabCtrl click, display
a WaitCursor and stop the user from clicking anything else until the
OnSetActive method has finished.  I don't know how to do this.  I've tried
overriding some of the property sheets methods but none get invoked.  I've
tried overriding the property page's OnKillActive, but the result was
unhelpful.  What I would really like is some way of extending the CTabCtrl
class and then overriding some of its event handlers, but it's unclear to me
how the CTabCtrl class is instantiated and what I would need to do.

Does anyone know of a way of overriding the CTabCtrl class that is used
together with a property page?  Does anyone know of any other way of trapping
when the CTabCtrl object is clicked?

Any insight would be appreciated.
OnSetActivehandler
(1)
SetActivePage
(1)
CPropertyPage
(1)
OnKillActive
(1)
OnSetActive
(1)
CTabCtrl
(1)
PropertySheet
(1)
PropertyPages
(1)
  David Lowndes replied...
30-Jan-08 02:54 AM
I'd try removing aspects of the code you have in the OnSetActive
handler to see which (if any) is allowing the recursion to occur. I'm
guessing that something you call is allowing another message loop to
run and that's then processing the mouse clicks and giving rise to the
issue.

Dave
help
how can i get a CPropertySheet pointer in its CPropertyPage? Thanks~ C++ / VB I have a class extends CPropertyPage, I want to add a button in this page, for jumping to another CPropertyPage. But how can I get a pointer of CPropertySheet? Then I can use the SetActivePage(). or there is other way to realize this fuction? Thanks a lot. VC MFC Discussions CToolMainFrame (1) GetPropertySheet (1) GetActiveWindow (1) CPropertySheet (1) SetActivePage (1) CPropertyPage (1) CRuntimeClass (1) CToolSheet (1) On 7 = D4 = C215 = C8 = D5, = CF = C2 = CE = E71 now i try to use this CToolSheet* pSheet = 3D (CToolSheet*) ((CToolMainFrame*)AfxGetApp()-> m_pMainWnd)-> GetActiveWindow(); pSheet-> SetActivePage(m_PageID); it seems workable, but I am really not sure if there is a problem sheet. now i try to use this CToolSheet* pSheet = (CToolSheet*) ((CToolMainFrame*)AfxGetApp()-> m_pMainWnd)-> GetActiveWindow(); pSheet-> SetActivePage(m_PageID); it seems workable, but I am really not sure if there is a problem
VC MFC Discussions CppXXXXUeR (1) CppXXXXStR (1) CpshXXXX (1) CppXXXX (1) SendMessageToDescendants (1) CPropertySheet (1) CPropertyPage (1) OnOK (1) Hi SaranG, nomally I use for multiple dialoges the classes CPropertySheet / CPropertyPage. I don't know if you do so. But I will explain you the way to close the pages on the following sample. CPropertySheet = parent +-> CPropertyPage -> CPropertySheet = parent +-> CPropertyPage . . +-> CPropertyPage . . +-> CPropertyPage . . +-> CPropertyPage . . / * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = OnOK ( CPropertyPage ) = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * / void CppXXXX::OnOK() { CPropertyPage::OnOK(); / / On button OK send a close message to the parent
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 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 VC MFC Discussions Dlg2.SetWindowPos (1) Dlg1.SetWindowPos (1) Dlg1 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 m_pMainTabs-> GetTabControl()-> SetWindowPos( NULL, rcSheet.left, rcSheet.top, rcSheet.Width(), rcSheet.Height(), SWP_NOZORDER | SWP_NOACTIVATE ); m_pMainTabs-> SetActivePage(m_pMyPage1); - -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -; The OnSize method of the propertysheet class would be a good place to resize 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
message of child window C++ / VB Hello, I've created a MFC window inheriting of CPropertyPage. In it, I've created some CCcombobox window. I looking for a way to catch do it without creating new class. Regards, William VC MFC Discussions OnSelEndOK (1) GetDlgCtrlId (1) CPropertyPage (1) OnSelChange (1) CMyWindow (1) CComboBox (1) SendMessage (1) MyComboBox (1) What's a previous CBN_SELCHANGE message. All you have to do is set a ON_CBN_SELCHANGE(. . .) message handler in the CPropertyPage derived class that is the parent of the combobox. Go to your CPropertyPage dialog template right click on the combobox and select add event handler, select CBN_SELCHANGE and Let me try to answer a question I think you are asking class CMyWindow : public CPropertyPage { }; then in the class CMyWindow you can create a CBN_SELCHANGE handler by "Add Event Handler com / mvp_tips.htm an example to be a little bit more clear. class CMyWindow : public CPropertyPage { private: CComboBox myComboBox; }; And I want to catch in CMyWindow class the "myComboBox" message (especially to do this. I don't know if it's possible. - - William class CMyWindow : public CPropertyPage { protected: afx_msg void OnCbnSelChangeComboBox(); DECLARE_MESSAGE_MAP(); private: CComboBox myComboBox; }; BEGIN_MESSAGE_MAP(CMyWindow, CPropertyPage) ON_CBN_SELCHANGE(IDC_COMBOBOXID, OnCbnSelChangeComboBox) END_MESSAGE_MAP() void CMyWindow::OnCbnSelChangeComboBox() { / / this method gets called when the user changes
How to handle tab notifications in CTabCtrl subclass? C++ / VB Tab pages are inherited from CPropertyPage and control that is holding them is inherited from CTabCtrl. I would like to use OnSetActive but this is never called since I'm not using CPropertySheet to hold my pages MFC Discussions Pages.GetAt (1) PNMHDR (1) CMyTabCtrl (1) CPropertySheet (1) OnTcnSelchange (1) OnChildNotify (1) CPropertyPage (1) OnSetActive (1) Catch the TCN_SELCHANGE message in your CTabCtrl class using message reflection. And then call the select pages OnSetActive. BEGIN_MESSAGE_MAP(CMyTabCtrl, CTabCtrl) ON_NOTIFY_REFLECT(TCN_SELCHANGE, OnTcnSelchange) END_MESSAGE_MAP() void CMyTabCtrl::OnTcnSelchange(NMHDR *pNMHDR, LRESULT *pResult) { if GetCurSel() ! = -1) { m_Pages.GetAt(GetCurSel())-> OnSetActive(); } *pResult = 0; } AliR. But this way the first tab (the one that is already shown) never gets OnSetActive called. Not until I change selection to some other tab and then to first one keywords: How, to, handle, tab, notifications, in, CTabCtrl, subclass? description: Tab pages are inherited from CPropertyPage and control that is holding them is inherited from CTabCtrl. I would like to use