1

I am making a doc/view arch SDI application. I invoke a COptionsDialog in CSquaresView.

void CSquaresView::OnOptions()
{
 COptionsDialog dlg(this);
 if (dlg.DoModal() == IDOK) 
 ...
}

In COptionsDialog I want to access CSquaresView.

BOOL COptionsDialog::OnInitDialog()
{
 CDialog::OnInitDialog();
 CWnd *pParent = GetParent();
 if (pParent) {
  CSquaresView *pView = dynamic_cast<CSquaresView*>(pParent); //pView is always NULL
  if (pView != NULL) 
  {
    CSquaresDoc* pDoc = pView->GetDocument();
 ...
 }

But I always get pView as NULL; Please help me to solve this problem.

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
mmj
  • 139
  • 8

3 Answers3

3

The observed behavior makes sense. A (modal) dialog's owner must be

an overlapped or pop-up window [...]; a child window cannot be an owner window.

CView-derived class instances generally are child windows. As such they cannot be the owner of a (modal) dialog. When you pass a child window into the c'tor of a CDialog-derived class, the system walks up the window hierarchy until it finds an overlapped or pop-up window, and uses that as the owner of the dialog. Regardless of whether you then call GetParent, GetAncestor, or CWnd::GetOwner, it is this true owner (usually your CFrameWnd-derived implementation) where window traversal starts.


Thus, you cannot generally use standard window traversal to find the window passed into a (modal) dialog's constructor. However, MFC records the CWnd(-derived) class instance you pass into your COptionsDialog constructor and stores it in a protected member variable m_pParentWnd, inherited from the CDialog class.

As long as COptionsDialog derives public/protected from CDialog or CDialogEx, the implementation can access this class member.

The following OnInitDialog implementation will do what you're looking for:

BOOL COptionsDialog::OnInitDialog()
{
    CDialog::OnInitDialog();
    CSquaresView *pView = dynamic_cast<CSquaresView*>(m_pParentWnd);
    if (pView != NULL) 
    {
        CSquaresDoc* pDoc = pView->GetDocument();
        ...
    }

There are other options available. For example, you could supply a COptionsDialog constructor that takes both a CWnd* and a CSquaresDoc*, delegating the first onto the base class c'tor and storing the document pointer in a (private) class member. This makes for code that's easier to follow in that it explicitly spells out, that the dialog depends on the document.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
2

Add a static method GetCurrentView() to your view class:

.cpp file

CSquaresView* CSquaresView::GetCurrentView()
{
    CFrameWnd* pFrame = (CFrameWnd*)(AfxGetApp()->m_pMainWnd);
    return dynamic_cast<CSquaresView*>(pFrame->GetActiveView());
}

.h file

class CSquaresView : public CView
{
    ...  
    static CSquaresView* GetCurrentView();
    ...
};

Now you can just call GetCurrentView() from anywhere you want:

...
CSquaresView *pView = CSquaresView::GetCurrentView();
...

This works for SDI applications. For MDI applications the solution might be somewhat different.


Another thing you could do is just create a public member CSquaresView *m_pView in COptionsDialog and set that to this like:

void CSquaresView::OnOptions()
{
  COptionsDialog dlg(this);
  dlg.m_pView = this;
  if (dlg.DoModal() == IDOK) 
    ...
}

or modify the COptionsDialog constructor so m_pView is set directly by the constructor, or something similar.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
0

Use GetOwner(). Only WS_CHILD windows have parents, other windows have owners.

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
SoronelHaetir
  • 14,104
  • 1
  • 12
  • 23
  • I used GetOwner() . The result is same. The problem is i can't cast it to CSquaresView pointer – mmj Jun 17 '22 at 05:24