

Программирование на языке MFC
Мой второй блог в серии программирования
Структура типа CCreateContext
Обратите внимание, читатель, что указатель на структуру типа CCreateContext (в нее чуть раньше мы записали наши указатели на документ,шаблон документа, а также указатели на фрейм и на окно представления документа) записывается сначала в поле lpCreateParams структуры cs типа CREATESTRUCT, а потом в поле IParam структуры mcs типа MDICREATESTRUCT Указатель на структуру mcs посылается окну типа MDICLIENT посредством сообщения WM_MDICREATE. Что же происходит дальше? После получения этого сообщения создается дочернее окно MDI, которое будет играть роль окна фрейма. Естественно, при своем создании оно получает сообщение WM_CREATE, на что реагирует вызовом метода CMDIChildWnd::OnCreate():
int CMDIChildWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {
// call base class with IParam context (not MDI one) MDICREATESTRUCT* lpmcs;
lpmcs = (MDICREATESTRUCT*)lpCreateStruct->lpCreateParams; CCreateContext* pContext = (CCreateContext*)lpmcs->lParam;
return OnCreateHelper(lpCreateStruct, pContext);
Из переданной окну структуры типа CREATESTRUCT выбирается указатель на CCreateContext, после чего указатели на структуры типов CREATESTRUCT и CCreateStruct передаются методу CFrameWnd::OnCreateHelper:
int CFrameWnd::OnCreateHelper(LPCREATESTRUCT lpcs.
CCreateContext* pContext)
if (CWnd::OnCreate(lpcs) == -1) return -1;
// create special children first
if (!OnCreateClie*nt (lpcs, pContext) ) {
TRACEO("Failed to create client pane/view for frame.\n") ; return -1;
}
// post message for initial message string
PostMessage(WM_SETMESSAGESTRING, AFX__IDS_IDLEMESSAGE);
// make sure the child windows have been properly sized RecalcLayout();
return 0; // create ok
}
BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT,
CCreateContext* pContext)
{
// default create client will create a view if asked for it if (pContext != NULL && pContext->m_pNewViewClass != NULL) {
if (CreateView (pContext, AFX_IDW_PANE_FIRST) == NULL) return FALSE;
}
return TRUE;
}
CWnd* CFrameWnd::CreateView(CCreateContext* pContext,
UINT nID)
{
ASSERT(m_hWnd != NULL); ASSERT(::IsWindow(m_hWnd)); ASSERT(pContext != NULL);
ASSERT(pContext->m_pNewViewClass != NULL);
// Note: can be a CWnd with PostNcDestroy self cleanup CWnd* pView =
(CWnd*)pContext->m_pNewViewClass->CreateObject() ; if (pView == NULL) {
TRACE1("Warning: Dynamic create of view type
%hs failed.\n",
pContext->m_pNewViewClass->m_lpszClassName) ; return NULL;
ASSERT_KINDOF(CWnd, pView);
// views are always created with a border! if (!pView->Create(NULL, NULL,
AFX_WS_DEFAULT_VIEW, CRect(0,0,0, 0), this, nID,
pContext))
{
TRACEO("Warning: could not create view for frame.\n");
return NULL; // can’t continue without a view
}
if (afxData.bWin4 && (pView->GetExStyle () &
WS_EX_CLIENTEDGE))
{
// remove the 3d style from the frame, since the view is // providing it.
// make sure to recalc the non-client area
ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);
}
return pView;
}
Смотрите внимательно, читатель! Сначала создается объект (представление) того класса, который мы указали при создании шаблона документа. После этого создается непосредственно окно представления. При этом видно, родительским окном объявляется окно фрейма! Так что же получается? MFC решило за программиста одну из достаточно часто встречавшихся задач -расположение дочернего окна поверх клиентской области родительского окна. Теперь программисту нет необходимости самому создавать дочернее окно и отслеживать изменения размеров родительского окна – эти задачи решает за него MFC. Единственное, что в этом случае требуется от программиста, так это написать приложение в соответствии с требованиями архитектуры «документ/представление»!
Осталось понять одну «мелочь» – как осуществляется отображение данных документа в окне представления.
Я опять старался рассуждать логически.
Похожие статьи: CMDIChildWnd
