一, 在单文档或者是多文档中,有默认的菜单,这里是这些菜单项默认处理,如下:
菜单内容 |
命令项ID |
默认的处理函数 |
预有关联 |
File |
|
|
|
New |
ID_FILE_NEW |
CWinApp::OnFileNew |
No |
Open |
ID_FILE_OPEN |
CWinApp::OnFileOpen |
No |
Close(MDI ONLY) |
ID_FILE_CLOSE |
CDocumemt::OnFileClose |
Yes |
Save |
ID_FILE_SAVE |
CDocument:OnFileSave |
Yes |
Save As |
ID_FILE_SAVEAS |
CDocument::OnFileSaveAs |
Yes |
|
ID_FILE_PRINT |
CView::OnFilePrint |
No |
Print Pre&view |
ID_FILE_PRINT_PREVIEW |
CView::OnFilePrintPreview |
No |
Print Setup |
ID_FILE_PRINT_SETUP |
CWinApp::OnFilePrintSetup |
No |
“Recent File Name” |
ID_FILE_MRU_FILE1~4 |
CWinApp::OnOpenRecentFile |
Yes |
Exit |
ID_APP_EXIT |
CWinApp::OnFileExit |
Yes |
Edit |
|
|
|
Undo |
ID_EDIT_UNDO |
None |
|
Cut |
ID_EDIT_CUT |
None |
|
Copy |
ID_EDIT_COPY |
None |
|
Paste |
ID_EDIT_PASTE |
None |
|
View |
|
|
|
Toolbar |
ID_VIEW_TOOLBAR |
FrameWnd::OnBarCheck |
Yes |
Status Bar |
ID_VIEW_STATUS_BAR |
FrameWnd::OnBarCheck |
Yes |
Window(MDI only) |
|
|
|
New Window |
ID_WINDOW_NEW |
MDIFrameWnd::OnWindowNew |
Yes |
Cascade |
ID_WINDOW_CASCADE |
MDIFrameWnd::OnWindowCmd |
Yes |
Tile |
ID_WINDOW_TILE_HORZ |
MDIFrameWnd::OnWindowCmd |
Yes |
Arrange Icons |
ID_WINDOW_ARRANGE |
MDIFrameWnd::OnWindowCmd |
Yes |
Help |
|
|
|
About AppName |
ID_APP_ABOUT |
None |
|
上图的最后一个字段“是否预有关联”,如果是Yes,意指只要你的菜单中有此命令项,当它被点击,自然就会引发命令处理程序,应用程序不需要再任何类的Message Map中拦截此命令消息,如果是No,则表示你必须在应用程序中拦截此消息,例如:
BEGIN_MESSAGE_MAP(CSingleApp, CWinApp)
ON_COMMAND(ID_APP_ABOUT, &CSingleApp::OnAppAbout)
// 基于文件的标准文档命令
ON_COMMAND(ID_FILE_NEW, &CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, &CWinApp::OnFileOpen)
// 标准打印设置命令
ON_COMMAND(ID_FILE_PRINT_SETUP, &CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
二,[FILE/OPEN],[FILE/NEW]的实现过程,如下图:
[FILE/NEW]具体如下:
1,CWinApp::OnFileOnew
void CWinApp::OnFileNew()
{
if (m_pDocManager != NULL)
m_pDocManager->OnFileNew();
}
2:CDocManager::OnFileNew()
void CDocManager::OnFileNew()
{
if (m_templateList.IsEmpty()){return;}
CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();
if (m_templateList.GetCount() > 1) //多个CDocTemplate弹出对话框让用户选择
{
INT_PTR nID = dlg.DoModal();
if (nID == IDOK)
pTemplate = dlg.m_pSelectedTemplate;
else
return; // none - cancel operation
}
//..............
pTemplate->OpenDocumentFile(NULL);
}
3(1)单文档:CSingleDocTemplate::OpenDocumentFile
CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,
BOOL bMakeVisible)
{
CDocument* pDocument = NULL;
CFrameWnd* pFrame = NULL;
BOOL bCreated = FALSE; // => doc and frame created
BOOL bWasModified = FALSE;
if (m_pOnlyDoc != NULL) //如果已经有文档,重新初始化
{
// already have a document - reinit it
pDocument = m_pOnlyDoc;
pFrame = (CFrameWnd*)AfxGetMainWnd();
}
else //否则创建一个新的文档
{
pDocument = CreateNewDocument();
bCreated = TRUE;
}
if (pFrame == NULL) //第一次创建Frame
{
ASSERT(bCreated);
pFrame = CreateNewFrame(pDocument, NULL);
}
//[FILE/NEW]
if (lpszPathName == NULL)
{
pDocument->OnNewDocument()
}
else //[FILE/OPEN]
{//如果打开文件失败,创建一个新的Document
if (!pDocument->OnOpenDocument(lpszPathName))
{
pDocument->OnNewDocument()
}
pDocument->SetPathName(lpszPathName);
}
CWinThread* pThread = AfxGetThread();
ASSERT(pThread);
if (bCreated && pThread->m_pMainWnd == NULL)
{
pThread->m_pMainWnd = pFrame;
}
InitialUpdateFrame(pFrame, pDocument, bMakeVisible);
return pDocument;
}
4.创建文档:CDocTemplate::CreateNewDocument()
CDocument* CDocTemplate::CreateNewDocument()
{//动态创建
CDocument* pDocument = (CDocument*)m_pDocClass->CreateObject();
AddDocument(pDocument);
return pDocument;
}
5.创建Frame:CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther)
CFrameWnd* CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther)
{
ASSERT(m_nIDResource != 0); // must have a resource ID to load from
CCreateContext context;
context.m_pCurrentFrame = pOther;
context.m_pCurrentDoc = pDoc;
context.m_pNewViewClass = m_pViewClass;
context.m_pNewDocTemplate = this;
CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject();
// 从资源里创建新的Frame
pFrame->LoadFrame(m_nIDResource,WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE,NULL, &context)
return pFrame;
}
6.CFrameWnd::LoadFrame
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);
Create(lpszClass, strTitle, dwDefaultStyle, rectDefault,pParentWnd, ATL_MAKEINTRESOURCE(nIDResource), 0L, pContext);
//......
return TRUE;
}
随着Create调用,会发出WM_CREATE消息,随后如下:
CFrameWnd::OnCreate-->CFameWnd::OnCreateHelper-->CFrameWnd::OnCreateClient(重载它可实现多个视图显示)
-->CreateView
CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID)
{
//动态创建
CWnd* pView = (CWnd*)pContext->m_pNewViewClass->CreateObject();
//创建窗口
pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,CRect(0,0,0,0), this, nID, pContext)
//...........
return pView;
}
7.新的文档内部操作初始化,可以重载添加需要的文档初始化:CDocument::OnNewDocument()
BOOL CDocument::OnNewDocument()
{
DeleteContents();
m_strPathName.Empty(); // no path name yet
SetModifiedFlag(FALSE); // make clean
return TRUE;
}
8.新的文档根据文件初始化CDocument::OnOpenDocument(LPCTSTR lpszPathName)可重载添加文档初始化信息
BOOL CDocument::OnOpenDocument(LPCTSTR lpszPathName)
{
//打开文件
CFileException fe;
CFile* pFile = GetFile(lpszPathName,CFile::modeRead|CFile::shareDenyWrite, &fe);
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); // 序列化
loadArchive.Close();
ReleaseFile(pFile, FALSE);
}
CATCH_ALL(e)
{
ReleaseFile(pFile, TRUE);
DeleteContents(); // remove failed contents
}
END_CATCH_ALL
SetModifiedFlag(FALSE); // start off with unmodified
return TRUE;
}
9.删除文档处理(重载添加自己的处理):CDocument::DeleteContents()
void CDocument::DeleteContents()
{
}
10.CDocTemplate::InitialUpdateFrame(CFrameWnd* pFrame, CDocument* pDoc,BOOL bMakeVisible)
void CDocTemplate::InitialUpdateFrame(CFrameWnd* pFrame, CDocument* pDoc,BOOL bMakeVisible)
{
// just delagate to implementation in CFrameWnd
pFrame->InitialUpdateFrame(pDoc, bMakeVisible);
}
11.CFrameWnd::InitialUpdateFrame(CDocument* pDoc, BOOL bMakeVisible)
void CFrameWnd::InitialUpdateFrame(CDocument* pDoc, BOOL bMakeVisible)
{
// 如果Frame没有Active视图,设置为第一个
CView* pView = NULL;
if (GetActiveView() == NULL)
{
CWnd* pWnd = GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE);
if (pWnd != NULL && pWnd->IsKindOf(RUNTIME_CLASS(CView)))
{
pView = (CView*)pWnd;
SetActiveView(pView, FALSE);
}
}
if (bMakeVisible)
{
//向这个Frame的所有视图发送WM_INITIALUPDATE消息
SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
//根据ON_MESSAGE_VOID(WM_INITIALUPDATE, CView::OnInitialUpdate),所有View都会调用OnInitialUpdate
//这是View初始化的地方。
}
//.......
}
3(2)多文档:CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL bMakeVisible)
CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL bMakeVisible)
{
CDocument* pDocument = CreateNewDocument(); //创建文档
CFrameWnd* pFrame = CreateNewFrame(pDocument, NULL); //创建Frame
//[FILE/NEW]
if (lpszPathName == NULL)
{
if (!pDocument->OnNewDocument())
{
pFrame->DestroyWindow();
return NULL;
}
m_nUntitledCount++;
}
else //[FILE/OPEN]
{
// 打开已存在的文档
if (!pDocument->OnOpenDocument(lpszPathName))
{
pFrame->DestroyWindow();
return NULL;
}
pDocument->SetPathName(lpszPathName);
}
InitialUpdateFrame(pFrame, pDocument, bMakeVisible);
return pDocument;
}
[FILE/OPEN]
和[FILE/NEW]不同之处在于:
void CDocManager::OnFileOpen()
{
// 弹出对话框选择文件
CString newName;
if (!DoPromptFileName(newName, AFX_IDS_OPENFILE,
OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, NULL))
return;
AfxGetApp()->OpenDocumentFile(newName);
}
CDocument* CWinApp::OpenDocumentFile(LPCSTR lpszFileName)
{
ASSERT(m_pDocManager != NULL)
//回到了和[FILE/OPEN]一样的地方
return m_pDocManager->OpenDocumentFile(lpszFileName);
}
在程序一运行是通过命令行信息类来处理的。
BOOL CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo)
{
AfxGetApp()->OnCmgMsg(ID_FILE_NEW,0,NULL,NULL);
//.......
}