Есть ли способ создать представление в CSplitterWnd без использования динамического объекта (MFC)?

Я ранее использовал CSplitterWnd в приложении MFC, используя его CreateView функция. Все работало нормально, но теперь я хотел бы передать параметр конструктору моих представлений, поэтому я не могу использовать создание динамического объекта MFC (DECLARE_DYNCREATE а также IMPLEMENT_DYNCREATE) потому что они требуют пустой конструктор.

После небольшого поиска в интернете я нашел пример, который выглядит так:

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);

Это может быть обходной путь (т.е. создать новую функцию в CMyView позвольте мне указать, что я хочу), но это было бы некрасиво и подвержено ошибкам. Кто-нибудь знает, есть ли другой способ, которым я мог бы сделать это?

Редактировать: Добавление более подробной информации после ее ответа:

Вы правы в том, что метод initialize будет работать, но это заставляет меня не забывать вызывать этот метод initialize, но, как вы указали, я, вероятно, не буду создавать эти представления много раз, так что все должно быть в порядке. Еще одна вещь, которую я, возможно, хотел бы, - это сам управлять временем жизни представления, поэтому, опять же, это невозможно с помощью CreateView.

Спасибо

4 ответа

Решение

После проверки ответа Хавьера Де Педро я решил переопределить функцию создания, поэтому я сделал (полупсевдокод):

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);
}

Теперь это работает, но есть проблема, что он закрывает мой класс при закрытии, и я сказал, что, возможно, захочу самостоятельно отслеживать память, поэтому я перегрузил PostNcDestroy в CMyView, чтобы ничего не делать вместо вызова delete this:

CMyView::PostNcDestroy(){}

Теперь это должно предотвратить его удаление, но теперь происходит сбой при выходе, поэтому я переопределил CMyFrame::OnClose следующим образом:

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();
}

Теперь теоретически я должен иметь возможность хранить указатель myView в другом месте, пока я его удаляю до выхода документа.

Спасибо за помощь ребята.

Когда вы говорите, что это будет уродливо и подвержено ошибкам, вы имеете в виду, что создание вашего представления будет происходить много раз во многих местах? Если так, то я бы с тобой частично согласился.

Однако, если у вас есть только два случая, когда вы создаете представление при запуске приложения, то "уродливые" и "подверженные ошибкам" сводятся к двум дополнительным строкам:

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);

Это не так уж плохо для меня. Возможно, есть конкретная ситуация, которую вы пытаетесь избежать?

Я не думаю, что есть какой-либо способ просто передать указатель вида на окно сплиттера. Вместо этого вам нужно будет извлечь класс из CWplitterWnd и переопределить CreateView виртуальный метод.

Метод по умолчанию делает что-то вроде pClass->CreateObject(), но ваша версия может создать объект, как вы хотите. Однако вам необходимо позаботиться о любых других деталях, обрабатываемых этим методом, поскольку вы не сможете вызвать реализацию по умолчанию.

Я не пробовал себя, но я думаю, что-то вроде этого должно работать:

CMyView *pView = new CMyView( PARAM );

splitter.CreateView(    0, 
                0, 
                pView->GetRuntimeClass(),
                size,  
                0);

Очевидно, вам все еще нужно использовать DECLARE_DYNCREATE в вашем представлении (CMyView), и вам нужно будет предоставить конструктор по умолчанию, но вы сможете использовать параметризованный конструктор.

Другие вопросы по тегам