Reputation: 1521
I was previously using a CSplitterWnd
in a MFC application, using it's CreateView
function. Everything was working fine but now I would like to pass a parameter to the constructor of my views, so I cannot use MFC dynamic object creation (DECLARE_DYNCREATE
and IMPLEMENT_DYNCREATE
) because they require an empty constructor.
After searching a little on the internet I found an exemple that looks like this:
m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CMyView), CSize(0,0), pContext);
m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CMyView), CSize(0,0), pContext);
m_pView0=(CMyView *)m_wndSplitter.GetPane(0,0);
m_pView1=(CMyView *)m_wndSplitter.GetPane(0,1);
This could be a workaround (i.e.: create a new function in CMyView
letting me specify what I want) but this would be ugly and error prone. Anyone know if there is another way I could do this?
Edit: Adding more details after ee's answer:
Your right that the initialize method would work but this force me to remember to call that initialize method, but like you pointed out I will probably not create these views many times so that should be ok. Another thing I would maybe like is to manage the lifetime of the view myself so again this is not possible using CreateView.
Thanks
Upvotes: 3
Views: 3903
Reputation: 2239
I haven't tried myself but I think something like this should work:
CMyView *pView = new CMyView( PARAM );
splitter.CreateView( 0,
0,
pView->GetRuntimeClass(),
size,
0);
Obviously you still need to use DECLARE_DYNCREATE in your view (CMyView) and you will need to provide a default constructor but you will be able to use a parameterized constructor.
Upvotes: 0
Reputation: 1521
After checking Javier De Pedro's answer I though I could override the creation function so I did (semi-pseudo-code):
class ObjGetter
{
static CObject* obj;
public:
ObjGetter(CObject* obj_){obj = obj_;}
static CObject* __stdcall getObj() { return obj; }
};
CObject* ObjGetter::obj = NULL;
BOOL CMyFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
//...
myView = new CMyView(NULL);
CRuntimeClass rt(*myView->GetRuntimeClass());
ObjGetter objGetter(myView);
rt.m_pfnCreateObject = &ObjGetter::getObj;
m_wndSplitter.CreateView(0,0, &rt, CSize(0,0), pContext);
}
Now this work but there is the problem that it will destroy my class when closing and I said I would maybe want to track memory myself so I overloaded PostNcDestroy in CMyView to do nothing instead of calling delete this:
CMyView::PostNcDestroy(){}
Now it should prevent it from getting deleted but now it crash when exiting so I overriden CMyFrame::OnClose like this:
void CMyFrame::OnClose()
{
m_wndSplitter.DeleteView(0, 0);
delete myView; myView = NULL; //seems to be needed to be deleted before
//CFrameWnd::OnClose or it crash
CFrameWnd::OnClose();
}
Now theorically I should be able to keep the myView pointer elsewhere as long as I delete it before the document exit.
Thanks for your help guys.
Upvotes: 0
Reputation: 6616
When you say it would be ugly and error prone, do you mean that the creation of your view will happen many times in many places? If so, then I would partially agree with you.
However, if you just have two cases wherein you create view on app startup, then "ugly" and "error prone" boils down to two additional lines:
m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CMyView), CSize(0,0), pContext);
m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CMyView), CSize(0,0), pContext);
m_pView0=(CMyView *)m_wndSplitter.GetPane(0,0);
m_pView1=(CMyView *)m_wndSplitter.GetPane(0,1);
//additional stuff
m_pView0->Initialize(v1, v2, v3);
m_pView1->Initialize(v4, v5, v6);
That doesn't seem so bad to me. Perhaps there is a specific situation you are trying to avoid?
Upvotes: 1
Reputation: 23148
I don't think there's any way to just hand a view pointer to the splitter window. Instead you will need to derive a class from CWplitterWnd
and override the CreateView
virtual method.
The default method does something like pClass->CreateObject()
, but your version can create the object however you want. You will need to take care of any other details handled by that method, however, since you will not be able to call the default implementation.
Upvotes: 0