[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2461
  • Last Modified:

Closing a CPropertySheet

I have created a CPropertySheet with some pages, when I press "Cancel", I wan to have a AfxMessageBox("Not all data saved, still cancel ?"), So this is what I've done

BEGIN_MESSAGE_MAP()
ON_WM_CLOSE();
END_MESSAGE_MAP()

void CMyPropertySheet::OnClose() //Overload OnClose
{
 AfxMessageBox("Sure you wanna cancel ?");
}

... Then I implement it in my program
void CMyProgram::ShowSheet()
{
CMyPropertySheet test;
if(test.DoModal() == ID_OK)
{
 Container.SetData(test.GetData());
}

Problem is, I never get the WM_CLOSE in my CPropertySheet ??,,, I don't want to put the OnClose in my CPropertyPages, if I can avoid it.

I can use the OnOk, and OnCancel.. but what do I do with the |X| in the top of the window, I somemone push it, you will leave the sheet, withaout the warning messagebox .. that is the problem
0
win32
Asked:
win32
  • 3
  • 2
1 Solution
 
komarCommented:
Hi,

You do not need to override CPropertySheet::OnClose() to implement the requirement. Instead you should override OnCancel() (and OnOK() if needed) member of each CPropertyPage.

I understand that you don't want to put handlers in each CPropertyPage object that you create, this can be avoided by deriving a class from CPropertyPage (call it CBasePage) to override the OnCancel() member to notify the parent property sheet. Then derive all your property pages from the new class. Also, derive a class from CPropertySheet (call it CNewSheet) to provide required handling.

Below are some code snippets of what i'm talking about:

      // BasePage.h
      
      #define UM_CANCEL_RECEIVED            ((UINT)(WM_USER + 0x0101))
      class CBasePage : public CPropertyPage
      {
            ...
            ...
            virtual void OnOK() { }
            virtual void OnCancel();
            ...
            ...
      };
      
      // BasePage.cpp
      
            ...
            ...
      void CBasePage::OnCancel()
      {
            //Notify the parent about the event
            GetParent()->PostMessage(UM_CANCEL_RECEIVED, 0, 0);
      }
            ...
            ...
      
      //NewSheet.h
      class CNewSheet : public CpropertySheet
      {
            afx_msg LRESULT MyHandler(WPARAM wParam, LPARAM lPARAM);
      };
      
      //NewSheet.cpp
      #include "BasePage.h"
      
      //Put this       line in the message map
      ON_MESSAGE(UM_CANCEL_RECEIVED, MyHandler)

      LRESULT CNewSheet::MyHandler(WPARAM /*wParam*/, LPARAM /*lPARAM*/)
      {
            LRESULT lRet = 0;
      
            if(AfxMessageBox("Sure you wanna cancel ?", MB_YESNO | MB_ICONQUESTION) == IDYES)
            {
                  DestroyWindow();
            }
      
            return lRet;
      }

Thanks,
Khalid Omar
0
 
win32Author Commented:
But that does not solve the problem if the user press the |X| in the upper right corner ??
0
 
komarCommented:
Hi again,

This time I created a test project to test my solution in the first comment. Here is what I did:
  1. Create a class called CNewSheet derived from CPropertySheet.
  2. Create a class called CBasePage derived from CPropertyPage.
  3. I modified the constructor created by class wizard of the CBasePage so that it looks like:
   In the .h file
      CBasePage(UINT uDialogResource = -1);

   In the .cpp file
      CBasePage::CBasePage(UINT uDialogResource) : CPropertyPage(uDialogResource)
      {
            //{{AFX_DATA_INIT(CBasePage)
                  // NOTE: the ClassWizard will add member initialization here
            //}}AFX_DATA_INIT
      }

  4. In class view, right click the CBasePage class and select "Add Virtual function". In the window that pops-up select OnCancel and hit the "Add and Edit" button.
  5. Modify CBasePage::OnCancel() as follows:
      void CBasePage::OnCancel()
      {
            GetParent()->SendMessage(UM_CANCEL_RECEIVED, 0, 0);
      }
  6. Add a definition for UM_CANCEL_RECEIVED to the top of BasePage.h header file as follows:
      #define UM_CANCEL_RECEIVED          ((UINT)(WM_USER + 0x0101))

  7. Goto NewSheet.h and add an include to BasePage.h so that the value of UM_CANCEL_RECEIVED can be seen by all CNewSheet objects.
  8. In class view, right-click the CNewSheet class and select "Add Windows Message Handler ...", in the window that pops-up select WM_CLOSE and hit "Add and Edit"
  9. Modify the CNewSheet::OnClose() function to look lioke the following:
      void CNewSheet::OnClose()
      {
            CancelHandler(0, 0);
      }
  10. Open the NewSheet.h file and add the definition of the CancelHandler function ass follows:
      ...
      ...
      //}}AFX_MSG
      afx_msg LRESULT CancelHandler(WPARAM wParam, LPARAM lPARAM); //This line is new
      DECLARE_MESSAGE_MAP()
      ...
      ...

  11. Open NewSheet.cpp and add the following to the end of the file
      LRESULT CNewSheet::CancelHandler(WPARAM /*wParam*/, LPARAM /*lPARAM*/)
      {
             LRESULT lRet = 0;

             if(AfxMessageBox("Sure you wanna cancel ?", MB_YESNO | MB_ICONQUESTION) == IDYES)
             {
                        EndDialog(IDCANCEL);
             }

             return lRet;
      }
  12. Modify the message map of CNewSheet so that it looks like:
      BEGIN_MESSAGE_MAP(CNewSheet, CPropertySheet)
            //{{AFX_MSG_MAP(CNewSheet)
            ON_WM_CLOSE()
            //}}AFX_MSG_MAP
            ON_MESSAGE(UM_CANCEL_RECEIVED, CancelHandler)
      END_MESSAGE_MAP()

According to the above, I was able to capture all events when the user hits cancel button or hits the |x| button on the title bar.
I can send you the project I was working on to test my comment. Email me if you are interested, my email is khalid_omar@msn.com

Thanks,
Khalid Omar
0
 
win32Author Commented:
Ok please mail me the project to cb_priv@hotmail.com I cannot get this to wore, Sure I can debug into the OnCancel in the pages, but the sheet closes anyway, nomatter what I do.
0
 
komarCommented:
Hi,

I think you are right. After few more debugging i found that you can capture the required events but you cannot prevent the property sheet from closing.

So, I started looking for another way to achieve the requirement, and I think I found it. All you have to do is to derive a class (CBaseSheet) and provide handling for the following events:
  - Provide handling for BN_CLICKED when idButton = IDCANCEL
  - Provide handling for WM_SYSCOMMAND when uCmdType = SC_CLOSE.

According to the above, the message map for CBaseSheet becomes as follows:

      BEGIN_MESSAGE_MAP(CBaseSheet, CPropertySheet)
            //{{AFX_MSG_MAP(CBaseSheet)
            //}}AFX_MSG_MAP
            ON_BN_CLICKED(IDCANCEL, OnCancel)
            ON_WM_SYSCOMMAND()
      END_MESSAGE_MAP()

The implementation for the handlers is as follows:

      void CBaseSheet::OnCancel()
      {
            if(AfxMessageBox("Sure you wanna cancel ?", MB_YESNO | MB_ICONQUESTION) == IDYES)
            {
                  PressButton(PSBTN_CANCEL);
            }
      }

      void CBaseSheet::OnSysCommand(UINT uCmdType, LPARAM lParam)
      {
            if(nID == SC_CLOSE)
            {
                  OnCancel();
            }
            else
            {
                  CPropertySheet::OnSysCommand(uCmdType, lParam);
            }
      }

The definition of these handler in the .h file is as follows:

      virtual afx_msg void OnCancel();
      virtual afx_msg void OnSysCommand(UINT uCmdType, LPARAM lParam);

I'll send you the test project I was working on to test my solution via email to cb_priv@hotmail.com

Thanks,
Khalid Omar.
0

Featured Post

[Webinar] Cloud and Mobile-First Strategy

Maybe you’ve fully adopted the cloud since the beginning. Or maybe you started with on-prem resources but are pursuing a “cloud and mobile first” strategy. Getting to that end state has its challenges. Discover how to build out a 100% cloud and mobile IT strategy in this webinar.

  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now