Is there a way to create a view in CSplitterWnd without using (MFC) dynamic object creation?

I have previously used CSplitterWnd

in MFC application using it CreateView

. Everything works 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 need an empty constructor.

After doing a little searching on the internet, I found an example 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 that would be ugly and error prone. Does anyone know if there is another way to do this?

Edit: adding more details after ee's answer:

Your right is that the initialize method will work, but it makes me forget to call that initialize method, but as you pointed out, I probably won't create these views many times, so that should be fine. Another thing I might like is managing the lifetime of the view so this is not possible using CreateView.

thank

+2


source to share


4 answers


After checking Javier De Pedro's answer, although I could override the create function, so did (semi-pseudocode):

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 works, but there is a problem that it will destroy my class on closure, and I said that I might want to track the memory, so I overloaded PostNcDestroy in CMyView to do nothing, instead of calling this:

CMyView::PostNcDestroy(){}

      



It should now prevent deletion, but now it crashes on exit, so I override 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, in theory, I should be holding the myView pointer somewhere else while I delete it before the document exits.

Thanks for the help guys.

0


source


When you say that 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 partly agree with you.

However, if you only have two cases where you create a view when the application starts up, then the "ugly" and "error prone" ones boil down to two extra 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);

      

It's not that bad for me. Perhaps there is a specific situation you are trying to avoid?

+1


source


I don't think there is a way to just pass the view pointer to the splitter window. Instead, you will need to infer the class from CWplitterWnd

and override the virtual method CreateView

.

The default method does something like pClass->CreateObject()

, but your version can create the object however you want. However, you will need to take care of any other details handled by this method, as you will not be able to call the default implementation.

0


source


I haven't tried it 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.

0


source







All Articles