1. 程式人生 > >VC選單命令詳解(檔案開啟、儲存與關閉)

VC選單命令詳解(檔案開啟、儲存與關閉)

第一部分:

五個命令ID: 處理函式  
ID_FILE_NEW CWinApp::OnFileNew   
ID_FILE_OPEN    CWinApp::OnFileOpen  
ID_FILE_SAVE    CDocument::OnFileSave  
ID_FILE_SAVEAS  CDocument::OnFileSaveAs  
ID_FILE_CLOSE   CDocument::OnFileClose   
  
1.ID_FILE_NEW  
CWinApp::OnFileNew呼叫CDocManager::OnFileNew。  
|  
CDocManager::OnFileNew判斷文件模板是否多於一個,是則顯示文件型別對話方塊(AFX_IDD_NEWTYPEDLG)  
讓使用者選擇要建立的文件型別。然後呼叫CDocTemplate::OpenDocumentFile(NULL)。  
|  
CDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL bMake_Visible=TRUE)對於SDI和MDI的  
處理不一樣。  
 
對於SDI,1,若已有文件開啟,對其重新初始化,呼叫CDocument::SaveModified()儲存當前文件;若沒  
有文件存在,則呼叫CreateNewDocument()建立文件物件,再呼叫CreateNewFrame(pDoucment,NULL)建立  
文件的框架視窗。2,若lpszPathName為NULL,則呼叫CDocument::OnNewDocument()處理新文件,用  
pDocument->SetPathName(lpszPathName)設定文件的路徑。3,判斷當前執行緒主框架視窗是否存在,不存  
在則將1中建立的新框架作為主框架。4,呼叫InitialUpdateFrame顯示框架視窗。  
 
對於MDI,與SDI基本相同,但是沒有第3步。  
|  
CDocument::OnNewDocument()首先呼叫DeleteContents()刪除原文件內容,使用m_strPathName.Empty()  
清除當前文件路徑,SetModifiedFlag(FALSE)。   
  
2.ID_FILE_OPEN  

CWinApp::OnFileOpen呼叫CDocManager::OnFileOpen。  
|  
CDocManager::OnFileOpen首先顯示檔案開啟對話方塊(AFX_IDS_OPENFILE),然後呼叫CWinApp::  
OpenDocumentFile(FileName)。  
|  
CWinApp::OpenDocumentFile(FileName)呼叫CDocManager::OpenDocumentFile。  
|  
CDocManager::OpenDocumentFile(LPCTSTR lpszFileName)遍歷文件模板,對每個模板用  
MatchDocType(szPath,pOpenDocument)匹配文件型別。匹配時主要根據副檔名判斷。若檔案已經在  
某個文件中開啟,則啟用文件的第一個檢視,否則用匹配的文件模板pBestTemplate->OpenDocumentFile  
(szPath)。  
|  
CDocTemplate::OpenDocumentFile呼叫CDocument::OnOpenDocument開啟檔案。  
|  
CDocument::OnOpenDocument開啟檔案,用DeleteContents刪除現有文件內容,建立檔案對應的CArchive  
物件loadArchive,Serialize(loadArchive)讀檔案內容,SetModifiedFlage(FALSE)。  
MDI: New Frame, New View?  
SDI: Update View?   
  
3.ID_FILE_SAVE
  
CDocument::OnFileSave呼叫CDocument::DoFileSave()。  
|  
CDocument::OnFileSave判斷檔案是否只讀,是則DoSave(NULL),否則DoSave(m_strPathName)。  
|  
CDocument::DoSave(LPCTSTR lpszPathName,BOOL bReplace=TRUE)的流程為:1,判斷lpszPathName不空  
則跳第二步,為空則獲取文件的路徑名,加上擴充套件符。bReplace為TRUE則顯示儲存檔案對話方塊(AFX_IDS_  
SAVEFILE),否則顯示拷貝儲存對話方塊(AFX_IDS+SAVEFILECOPY)。2,呼叫CDocument::OnSaveDocument保  
存文件。3,若bReplace==TRUE則SetPathName(newName)覆蓋當前路徑名。  
|  
CDocument::OnSaveDocument開啟檔案,建立CArchive物件saveArchive,Serialize(saveArchive)讀寫  
檔案,SetModifiedFlag(FALSE)。   
  
4.ID_FILE_SAVEAS
  
CDocument::OnFileSave呼叫DoSave(NULL)。   
  
5.ID_FILE_CLOSE  
CDocument::OnFileClose呼叫SaveModified()儲存檔案,再用OnCloseDocument處理文件關閉。  
|  
CDocument::SaveModified()用IsModified()判斷是否修改,是則顯示檔案儲存對話方塊(AFX_IDP_ASK_TO_  
SAVE),若使用者選擇“是”,則呼叫DoFileSave()儲存檔案。  
|  
CDocument::OnCloseDocument()首先銷燬文件框架,再用DeleteContents()刪除文件內容,若m_  
bAutoDelete則delete this。   
 
第二部分:

MDI開啟檔案的過程  
CWinApp::OnFileOpen()  
{  
    CDocManager::OnFileOpen()  
    {  
        CDocManager::DoPromptFileName()  
        {  
            CFileDialog::DoModal();  
        }  
        CWinApp::OpenDocumentFile()  
        {  
            ...選擇文件模板;  
            ...調整檢視和框架;  
            CDocTemplate::OpenDocumentFile();  
            {  
                判斷有無現存文件,是否需要儲存  
                新建框架  
                判斷檔案是否存在,呼叫CMyDoc::OnOpenDocunment/OnNewDocument  
            }  
        }  
    }  
}  
----------------------------------------  
Document/View命令處理流程  
ID_FILE_NEW  
CWinApp::OnFileNew()  
{  
    CDocManager::OnFileNew()  
    {  
        if(沒有文件模板)  
            return;  
        if(有多個文件模板)  
        {  
            彈出對話方塊讓使用者選擇;  
            取得模板指標;  
        }  
        CMultiDocTemplate::OpenDocumentFile()  
        {  
            new一個文件;  
            建立子框架;  
            構建frame,doc,view之間的關係;  
            CDocument::OnNewDocument()  
            {  
                DeleteContents();  
            }  
            InitialUpdateFrame();  
            return pDoc;  
        }  
    }  
}  
 
ID_FILE_OPEN  
CWinApp::OnFileOpen()  
{  
    CDocManager::OnFileOpen()  
    {  
        CDocManager::DoPromptFileName()  
        {  
            CFileDialog::DoModal();  
        }  
        CWinApp::OpenDocumentFile()  
        {  
            ...選擇文件模板;  
            ...調整檢視和框架;  
            CDocTemplate::OpenDocumentFile();  
            {  
                判斷有無現存文件,是否需要儲存  
                新建框架  
                判斷檔案是否存在  
                CMyDoc::OnOpenDocunment()  
                {  
                    開啟檔案;  
                    DeleteContents();  
                    建立CArchive;  
                    Serialize;  
                    關閉CArchive;  
                }  
            }  
        }  
    }  
}  
 
ID_FILE_SAVE  
CDocument::OnFileSave()  
{  
    DoFileSave(NULL)  
    {  
        CFileDialog::DoModal();  
        OnSaveDocument()  
        {  
            CArchive;  
            Serialize;  
        }  
    }  

***************************************************************

在這裡將講述SDI程式中application object、the main frame window、the document、the view、the document template object以及the associate string and menu resources之間的關係。
 
The Windows Application Object
在CWinApp派生類的Implement檔案中會有類似CMyApp theApp的語句。theApp是一個全域性變數,它就是啟動MFC應用程式的機制所在。
以下是MFC應用程式啟動的摘要:
1、Windows把應用程式載入到記憶體;
2、構造全域性變數theApp(所有全域性變數在程式被載入記憶體時被構造);
3、Windows呼叫全域性函式WinMain,它是MFC的一部分,等同於無視窗應用程式的main函式---主程式的入口;
4、WinMain尋找到CWinApp派生類的物件theApp;
5、WinMain為theApp呼叫InitInstance函式,InitInstance函式可以被過載;
6、過載的InitInstance函式啟動載入document、顯示the main frame and view windows;
7、WinMain為theApp啟動Run函式,Run函式負責分派window messages和command messages。
 
The Document Template Class
在CWinApp派生類的InitInstance中會有如下程式碼:
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
    IDR_MAINFRAME,
    RUNTIME_CLASS(CStudentDoc),
    RUNTIME_CLASS(CMainFrame),       // main SDI frame window
    RUNTIME_CLASS(CStudentView));
AddDocTemplate(pDocTemplate);
這段程式碼建立了the application class、the document class、the view window class、the main frame window四個類之間的聯絡。這時,application class的物件已經存在(theApp),但其他四個類的物件還沒有構造,MFC的動態建立機制就起到了作用。
一下兩個圖分別表示了以上四個類之間的關係、四個類的物件之間的關係:


 
Creating an Empty Document—The CWinApp::OnFileNew Function
當application class的InitInstance呼叫完AddDocTemplate以後,它將呼叫OnFileNew。
OnFileNew做如下事情:
1、構造Document物件,但不從硬碟中讀取資料;
2、構造the main frame物件和the main frame window,但不顯示它,它包括IDR_MAINFRAME、the toolbar、the status bar;
3、構造view物件和view視窗,但不顯示它;
4、建立the document、main frame、view物件之間的關係,這裡要藉助AddDocTemplate建立的類關係;
5、為document物件呼叫虛擬函式CDocument::OnNewDocument,CDocument::OnNewDocument函式將呼叫虛擬函式DeleteContent函式;
6、為view物件呼叫虛擬函式CView::OnInitialUpdate;
7、為frame物件呼叫CFrameWnd::ActivateFrame以顯示the main frame window(有the menus,view window,control bars)。
 
The Document Class's OnNewDocument Function
建構函式所完成的工作越少越好,這樣構造函數出錯的機率就會越來越小。而CDocument::OnNewDocument 和 CView::OnInitialUpdate 是做初始化的好地方。在這裡你可以彈出一個MessageBox。如果出錯,OnNewDocument還可以返回FALSE。值得注意的是,OnNewDocument可以被呼叫很多次,所以有些指令需只執行一次的話,就需要做一個“first time” flag成員變數。
 
Connecting File Open to Your Serialization Code—The OnFileOpen Function
檔案開啟選單對映到CWinApp::OnFileOpen函式,它將執行以下幾個步驟:
1、提示使用者選擇一個檔案;
2、呼叫虛擬函式CDocument::OnOpenDocument,CDocument::OnOpenDocument開啟檔案,呼叫CDocument::DeleteContents,並且構造一個CArchive物件。隨後呼叫document的Serialize函式從archive中載入資料;
3、呼叫view的OnInitialUpdate函式。
 
Connecting File Save and File Save As to Your Serialization Code
檔案儲存和另存為選單對映到CDocument的OnFileSave函式,OnFileSave函式依次呼叫Serialize函式,它使用一個archive物件進行儲存。
 
The Document's "Dirty" Flag
CDocument有一個protected成員函式m_bModified。可以通過CDocument的函式SetModifiedFlag和IsModified訪問m_bModified。當新建一個document或者讀取完硬碟上的資料後,m_bModified被Application Framework設為FALSE。當document的內容被改寫後要確保把m_bModified設為TRUE。
 
小結:OnFileNew和OnFileOpen都在Application類中,Application類裡面有DocumentTemplate,可以同時調動Document和View(OnInitialUpdate)。
OnFileSave和OnFileSaveAs都在Document類中,它只需做Serialization,不牽扯View的操作,故不需要把它們放在Application類中。