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

Ранее я использовал 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, позволяющую мне указать, что я хочу), но это будет уродливо и подвержено ошибкам. Кто-нибудь знает, есть ли другой способ сделать это?

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

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

Спасибо

Ответы [ 4 ]

1 голос
/ 01 октября 2009

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

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

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

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

0 голосов
/ 01 октября 2009

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

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 в другом месте, пока я его удаляю до выхода из документа.

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

0 голосов
/ 01 октября 2009

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

CMyView *pView = new CMyView( PARAM );

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

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

0 голосов
/ 01 октября 2009

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

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

...