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.
CodePudding user response:
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.
CodePudding user response:
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.
CodePudding user response:
Use GetOwner()
. Only WS_CHILD
windows have parents, other windows have owners.