MFC 框架、文档、视图操作常用函数用法简析
1. 跟窗口刷新有关的几个MFC函数
//重绘窗口
1) RecalcLayout();
/*RecalcLayout()--
The default implementation of this member function
calls the CWnd member function RepositionBars to reposition all the
control bars in the frame as well as in the main client window
(usually a CView or MDICLIENT).
*/
2) Invalidate();
/*Invalidate()--
Invalidates the entire client area of CWnd.
*/
3) UpdateWindow();
/*UpdateWindow()--
The UpdateWindow member function sends a WM_PAINT message directly,
bypassing the application queue. If the update region is empty, WM_PAINT
is not sent.
*/
对话框数据交换函数UpdateData(FALSE/TRUE)
4) UpdateData()
/*
BOOL UpdateData(BOOL bSaveAndValidate = TRUE );
Parameters
bSaveAndValidate
Flag that indicates whether dialog box is being initialized (FALSE) or data is being retrieved (TRUE).
Return Value
Nonzero if the operation is successful; otherwise 0. If bSaveAndValidate is TRUE, then a return value of nonzero means that the data is successfully validated.
*/
2. 跟文档Document操作相关的几个MFC函数
1) BOOL CNetGenixDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
/*具体的MFC CDocument::OnNewDocument()实现
BOOL CDocument::OnNewDocument()
{
if (IsModified())
TRACE0("Warning: OnNewDocument replaces an unsaved document./n");
DeleteContents();
m_strPathName.Empty(); // no path name yet
SetModifiedFlag(FALSE); // make clean
return TRUE;
}
*/
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
return TRUE;
}
2) BOOL CNetGenixDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
/* 具体的MFC CDocuemnt::OnOpenDocument()实现
BOOL CDocument::OnOpenDocument(LPCTSTR lpszPathName)
{
if (IsModified())
TRACE0("Warning: OnOpenDocument replaces an unsaved document./n");
CFileException fe;
CFile* pFile = GetFile(lpszPathName,
CFile::modeRead|CFile::shareDenyWrite, &fe);
if (pFile == NULL)
{
ReportSaveLoadException(lpszPathName, &fe,
FALSE, AFX_IDP_FAILED_TO_OPEN_DOC);
return FALSE;
}
DeleteContents();
SetModifiedFlag(); // dirty during de-serialize
CArchive loadArchive(pFile, CArchive::load | CArchive::bNoFlushOnDelete);
loadArchive.m_pDocument = this;
loadArchive.m_bForceFlat = FALSE;
TRY
{
CWaitCursor wait;
if (pFile->GetLength() != 0)
Serialize(loadArchive); // load me
loadArchive.Close();
ReleaseFile(pFile, FALSE);
}
CATCH_ALL(e)
{
ReleaseFile(pFile, TRUE);
DeleteContents(); // remove failed contents
TRY
{
ReportSaveLoadException(lpszPathName, e,
FALSE, AFX_IDP_FAILED_TO_OPEN_DOC);
}
END_TRY
DELETE_EXCEPTION(e);
return FALSE;
}
END_CATCH_ALL
SetModifiedFlag(FALSE); // start off with unmodified
return TRUE;
}
*/
// TODO: Add your specialized creation code here
return TRUE;
}
3) BOOL CNetGenixDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
// TODO: Add your specialized code here and/or call the base class
/*具体的MFC CDocument::OnSaveDocument()实现
BOOL CDocument::OnSaveDocument(LPCTSTR lpszPathName)
{
CFileException fe;
CFile* pFile = NULL;
pFile = GetFile(lpszPathName, CFile::modeCreate |
CFile::modeReadWrite | CFile::shareExclusive, &fe);
if (pFile == NULL)
{
ReportSaveLoadException(lpszPathName, &fe,
TRUE, AFX_IDP_INVALID_FILENAME);
return FALSE;
}
CArchive saveArchive(pFile, CArchive::store | CArchive::bNoFlushOnDelete);
saveArchive.m_pDocument = this;
saveArchive.m_bForceFlat = FALSE;
TRY
{
CWaitCursor wait;
Serialize(saveArchive); // save me
saveArchive.Close();
ReleaseFile(pFile, FALSE);
}
CATCH_ALL(e)
{
ReleaseFile(pFile, TRUE);
TRY
{
ReportSaveLoadException(lpszPathName, e,
TRUE, AFX_IDP_FAILED_TO_SAVE_DOC);
}
END_TRY
DELETE_EXCEPTION(e);
return FALSE;
}
END_CATCH_ALL
SetModifiedFlag(FALSE); // back to unmodified
return TRUE; // success
}
*/
return CDocument::OnSaveDocument(lpszPathName);
}
4) void CNetGenixDoc::OnCloseDocument()
{
/*
void CDocument::OnCloseDocument()
// must close all views now (no prompting) - usually destroys this
{
// destroy all frames viewing this document
// the last destroy may destroy us
BOOL bAutoDelete = m_bAutoDelete;
m_bAutoDelete = FALSE; // don't destroy document while closing views
while (!m_viewList.IsEmpty())
{
// get frame attached to the view
CView* pView = (CView*)m_viewList.GetHead();
ASSERT_VALID(pView);
CFrameWnd* pFrame = pView->GetParentFrame();
ASSERT_VALID(pFrame);
// and close it
PreCloseFrame(pFrame);
pFrame->DestroyWindow();
// will destroy the view as well
}
m_bAutoDelete = bAutoDelete;
// clean up contents of document before destroying the document itself
DeleteContents();
// delete the document if necessary
if (m_bAutoDelete)
delete this;
}
*/
// TODO: Add your specialized code here and/or call the base class
CDocument::OnCloseDocument();
}
3. MDI每一文档多视图的实现方式之CCreateContext
1) 我查找很多MDI多视图的例子,总结写出下面这个函数以实现MDI架构下一个文档的多个视图创建:
版本1:int CMainFrame::CreateNewView()//可以对CxChildFrame/CxView再进行抽象出来作为形式参数出现
{
CMyHtmlChildFrame* pHtmlChild=new CMyHtmlChildFrame();//use CRuntimeClass* is also OK
CMDIDemoDoc* pDoc=(CMDIDemoDoc*)(MDIGetActive()- >GetActiveDocument());
ASSERT_VALID(pDoc);
CMultiDocTemplate* pTemplate=(CMultiDocTemplate*)(pDoc- >GetDocTemplate());
ASSERT_VALID(pTemplate);
CCreateContext context;
context.m_pCurrentDoc=pDoc;// use existing document
context.m_pCurrentFrame=pHtmlChild;// new child frame to be upon
context.m_pNewViewClass=RUNTIME_CLASS(CMyHtmlView);// new view to be created
context.m_pNewDocTemplate=pTemplate;// use existing document
context.m_pLastView=NULL;// no
if (!pHtmlChild- >LoadFrame(IDI_ICON1,WS_OVERLAPPEDWINDOW ¦FWS_ADDTOTITLE,this,&context))
{
TRACE0("Warning: Couldn 't load frame window!/n");
return -1;
}
//pHtmlChild- >ShowWindow(SW_SHOWMAXIMIZED);
pHtmlChild- >InitialUpdateFrame(pDoc,TRUE);
//pTemplate- >InitialUpdateFrame(pHtmlChild,pDoc,TRUE);
//it worked!
return 0;
}
void CMainFrame::OnCreateView()
{
// TODO: Add your command handler code here
CreateNewView();
}
2) 版本2:int CMainFrame::CreateNewView(UINT nIDResource,CRuntimeClass* pFrameClass,CRuntimeClass* pViewClass,CDocument* pDoc)
{
/***********************************************************
* 函数名: CreateNewView
* 参数: UINT nIDResource,CRuntimeClass* pFrameClass,CRuntimeClass* pViewClass,CDocument* pDoc
* 功能描述:
* 1. 根据框架/视图/文档动态创建视图
* 2. 利用CCreateContext context关联文档/视图
* 3. 可以再进一步的抽象参数为CCreateContext* pContext
* 4. 具体可以参考CMDIChildWnd* CMDIFrameWnd::CreateNewChild()进行进一步的改写
* 返回值:
* 作者:
* 日期:
* 注释:
* 日志:
* 1.
* 2.
* 3.
***********************************************************/
//1 CMyHtmlChildFrame* pHtmlChild=new CMyHtmlChildFrame();
//use CRuntimeClass is also OK
//1 CMyHtmlChildFrame* pHtmlChild=(CMyHtmlChildFrame*)pFrameClass->CreateObject();
CMDIChildWnd* pFrame=(CMDIChildWnd*)pFrameClass->CreateObject();
ASSERT_KINDOF(CMDIChildWnd, pFrame);
//1 CMDIDemoDoc* pDoc=(CMDIDemoDoc*)(MDIGetActive()->GetActiveDocument());
ASSERT_VALID(pDoc);
//1 CMultiDocTemplate* pTemplate=(CMultiDocTemplate*)(pDoc->GetDocTemplate());
CDocTemplate* pTemplate=pDoc->GetDocTemplate();
//ASSERT_VALID(pTemplate);
CCreateContext context;
context.m_pCurrentDoc=pDoc;// use existing document
context.m_pCurrentFrame=pFrame;// new child frame to be upon
context.m_pNewViewClass=pViewClass;// RUNTIME_CLASS(CMyHtmlView);// new view to be created
context.m_pNewDocTemplate=pTemplate;// use existing document template
context.m_pLastView=NULL;// no
TRACE0("Before LoadFrame()/n");
if (!pFrame->LoadFrame(nIDResource,WS_OVERLAPPEDWINDOW|FWS_ADDTOTITLE,AfxGetMainWnd()/*this*/,&context))
{
TRACE0("Warning: Couldn't load frame window!/n");
return -1;
}
TRACE0("After LoadFrame()/n");
//pHtmlChild->ShowWindow(SW_SHOWNORMAL);
pFrame->InitialUpdateFrame(pDoc,TRUE);
//pHtmlChild->InitialUpdateFrame(pDoc,TRUE);
//just delagate to implementation in CFrameWnd
//pTemplate->InitialUpdateFrame(pHtmlChild,pDoc,TRUE);
//it worked!
return 0;
}
void CMainFrame::OnCreateNewView()
{
// TODO: Add your command handler code here
CDocument* pDoc=MDIGetActive()->GetActiveDocument();
ASSERT_VALID(pDoc);
//create html view
CreateNewView(IDI_ICON1,RUNTIME_CLASS(CMyHtmlChildFrame),RUNTIME_CLASS(CMyHtmlView),pDoc);
//create tree view
//CreateNewView(IDI_ICON2,RUNTIME_CLASS(CMyTreeChildFrame),RUNTIME_CLASS(CMyTreeView),pDoc);
}
4. MFC MDI框架视图的创建参考LoadFrame()
1) BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext)
// only do this once
ASSERT_VALID_IDR(nIDResource);
ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);
m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOURCE)
CString strFullString;
if (strFullString.LoadString(nIDResource))
AfxExtractSubString(m_strTitle, strFullString, 0); // first sub-string
VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
// attempt to create the window
LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);
LPCTSTR lpszTitle = m_strTitle;
if (!Create(lpszClass, lpszTitle, dwDefaultStyle, rectDefault,
pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext))
{
return FALSE; // will self destruct on failure normally
}
// save the default menu handle
ASSERT(m_hWnd != NULL);
m_hMenuDefault = ::GetMenu(m_hWnd);
// load accelerator resource
LoadAccelTable(MAKEINTRESOURCE(nIDResource));
if (pContext == NULL) // send initial update
SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
return TRUE;
}
2) BOOL CMDIFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext)
{
if (!CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle,
pParentWnd, pContext))
return FALSE;
// save menu to use when no active MDI child window is present
ASSERT(m_hWnd != NULL);
m_hMenuDefault = ::GetMenu(m_hWnd);
if (m_hMenuDefault == NULL)
TRACE0("Warning: CMDIFrameWnd without a default menu./n");
return TRUE;
}
3) BOOL CMDIChildWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext)
{
// only do this once
ASSERT_VALID_IDR(nIDResource);
ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);
ASSERT(m_hMenuShared == NULL); // only do once
m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOURCE)
// parent must be MDI Frame (or NULL for default)
ASSERT(pParentWnd == NULL || pParentWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd)));
// will be a child of MDIClient
ASSERT(!(dwDefaultStyle & WS_POPUP));
dwDefaultStyle |= WS_CHILD;
// if available - get MDI child menus from doc template
ASSERT(m_hMenuShared == NULL); // only do once
CMultiDocTemplate* pTemplate;
if (pContext != NULL &&
(pTemplate = (CMultiDocTemplate*)pContext->m_pNewDocTemplate) != NULL)
{
ASSERT_KINDOF(CMultiDocTemplate, pTemplate);
// get shared menu from doc template
m_hMenuShared = pTemplate->m_hMenuShared;
m_hAccelTable = pTemplate->m_hAccelTable;
}
else
{
TRACE0("Warning: no shared menu/acceltable for MDI Child window./n");
// if this happens, programmer must load these manually
}
CString strFullString, strTitle;
if (strFullString.LoadString(nIDResource))
AfxExtractSubString(strTitle, strFullString, 0); // first sub-string
ASSERT(m_hWnd == NULL);
if (!Create(GetIconWndClass(dwDefaultStyle, nIDResource),
strTitle, dwDefaultStyle, rectDefault,
(CMDIFrameWnd*)pParentWnd, pContext))
{
return FALSE; // will self destruct on failure normally
}
// it worked !
return TRUE;
}
4) CMDIChildWnd* CMDIFrameWnd::CreateNewChild(CRuntimeClass* pClass, UINT nResources, HMENU hMenu /* = NULL */, HACCEL hAccel /* = NULL */)
{
ASSERT(pClass != NULL);
CMDIChildWnd* pFrame = (CMDIChildWnd*) pClass->CreateObject();
ASSERT_KINDOF(CMDIChildWnd, pFrame);
// load the frame
CCreateContext context;
context.m_pCurrentFrame = this;
if (!pFrame->LoadFrame(nResources,
WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, &context))
{
TRACE0("Couldn't load frame window./n");
delete pFrame;
return NULL;
}
CString strFullString, strTitle;
if (strFullString.LoadString(nResources))
AfxExtractSubString(strTitle, strFullString, CDocTemplate::docName);
// set the handles and redraw the frame and parent
pFrame->SetHandles(hMenu, hAccel);
pFrame->SetTitle(strTitle);
pFrame->InitialUpdateFrame(NULL, TRUE);
return pFrame;
}
5) void CMDIFrameWnd::OnWindowNew()
{
CMDIChildWnd* pActiveChild = MDIGetActive();
CDocument* pDocument;
if (pActiveChild == NULL ||
(pDocument = pActiveChild->GetActiveDocument()) == NULL)
{
TRACE0("Warning: No active document for WindowNew command./n");
AfxMessageBox(AFX_IDP_COMMAND_FAILURE);
return; // command failed
}
// otherwise we have a new frame !
CDocTemplate* pTemplate = pDocument->GetDocTemplate();
ASSERT_VALID(pTemplate);
CFrameWnd* pFrame = pTemplate->CreateNewFrame(pDocument, pActiveChild);
if (pFrame == NULL)
{
TRACE0("Warning: failed to create new frame./n");
return; // command failed
}
pTemplate->InitialUpdateFrame(pFrame, pDocument);
}
5. DECLARE_DYNCREATE动态创建宏
注:揭示了CraeteObject()和New的联系
1) DECLARE_DYNCREATE(CMDIDemoView)
/*
#define DECLARE_DYNCREATE(class_name) /
DECLARE_DYNAMIC(class_name) /
static CObject* PASCAL CreateObject();
*/
2) IMPLEMENT_DYNCREATE(CMDIDemoView, CView)
/*
#define IMPLEMENT_DYNCREATE(class_name, base_class_name) /
CObject* PASCAL class_name::CreateObject() /
{ return new class_name; } /
IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, /
class_name::CreateObject)
*/
6. MFC Windows消息路由机制OnCmdMsg()
// CFrameWnd command/message routing
1) BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
CPushRoutingFrame push(this);
// pump through current view FIRST
CView* pView = GetActiveView();
if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// then pump through frame
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// last but not least, pump through app
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return FALSE;
}
// Command routing
2) BOOL CMDIFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
CMDIChildWnd* pActiveChild = MDIGetActive();
// pump through active child FIRST
if (pActiveChild != NULL)
{
CPushRoutingFrame push(this);
if (pActiveChild->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
}
// then pump through normal frame
return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
// Command routing
3) BOOL CView::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
// first pump through pane
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// then pump through document
if (m_pDocument != NULL)
{
// special state for saving view before routing to document
CPushRoutingView push(this);
return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
return FALSE;
}
// command routing
4) BOOL CDocument::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
if (CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// otherwise check template
if (m_pDocTemplate != NULL &&
m_pDocTemplate->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return FALSE;
}
5) BOOL CDocTemplate::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
BOOL bReturn;
CCmdTarget* pFactory = DYNAMIC_DOWNCAST(CCmdTarget, m_pAttachedFactory);
if (nCode == CN_OLE_UNREGISTER && pFactory != NULL)
bReturn = pFactory->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
else
bReturn = CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
return bReturn;
}