一、UpdateAllViews
如果文檔的數(shù)據(jù)改變了,所有的視圖都要通知到,所以一般在派生類的文檔類調(diào)用UpdateAllViews函數(shù),
注意:
(1)、UpdateAllViews(this)表示不在通知當前的視圖,當然這里已經(jīng)假定當前視圖(GetActiveView)已經(jīng)更新
(2)、UpdateAllViews(NULL)通知所有的視圖
void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint, CObject* pHint)
// walk through all views
{
ASSERT(pSender == NULL || !m_viewList.IsEmpty());
// must have views if sent by one of them
POSITION pos = GetFirstViewPosition();
while (pos != NULL)
{
CView* pView = GetNextView(pos);
ASSERT_VALID(pView);
if (pView != pSender)
pView->OnUpdate(pSender, lHint, pHint);
}
}
CDocument::UpdateAllViews調(diào)用了pView->OnUpdate(pSender, lHint, pHint);
在 CView::OnUpdate中
void CView::OnUpdate(CView* pSender, LPARAM /*lHint*/, CObject* /*pHint*/)
{
ASSERT(pSender != this);
UNUSED(pSender); // unused in release builds
// invalidate the entire pane, erase background too
Invalidate(TRUE); //使整個視圖無效,發(fā)出WM_PAINT消息
}
促使OnPaint()被調(diào)用
void CView::OnPaint()
{
// standard paint routine
CPaintDC dc(this); //在構(gòu)造函數(shù)中,BeginPaint函數(shù)被調(diào)用,聯(lián)想WIN32 API中響應WM_PAINT消息的做法
OnPrepareDC(&dc); //如果不是打印工作,什么都不做
OnDraw(&dc);
//在dc(堆棧變量,要自動釋放)的析構(gòu)函數(shù)中,調(diào)用了EndPaint函數(shù)
}
然后調(diào)用OnDraw(&dc)虛函數(shù),這里就是通常我們在C**View中看到的C**View::OnDraw(CDC* pDC)。在這里面做一些顯示工作。
二、OnInitialUpdate
到用戶選擇了FILE 中的NEW,則會引起CView::OnInitialUpdate的調(diào)用
void CView::OnInitialUpdate()
{
OnUpdate(NULL, 0, NULL); // initial update
}
默認的CView::OnInitialUpdate除了調(diào)用OnUpdate什么都不做,可以重寫這個虛函數(shù),對視圖對象進行初始化,OnInitialUpdate可以被調(diào)用多次。
三、OnNewDocument
調(diào)用時機:
(1)、在文檔對象被構(gòu)造之后(應用程序第一次啟動時,實質(zhì)是執(zhí)行了一個file/new 命令,只是沒有構(gòu)造)
(2)、選擇了file/new 命令
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;
}
設(shè)置是文檔數(shù)據(jù)成員初始值的好地方,OnNewDocument要調(diào)用虛函數(shù)DeleteContents()。在CDocument中
void CDocument::DeleteContents()
{
}
該函數(shù)什么都不做,需要派生文檔類去重寫它,
特別提醒:
1、因為SDI中,只有在關(guān)閉應用程序的時候,文檔對象才會調(diào)用析構(gòu)函數(shù),所以在析構(gòu)函數(shù)中完成所有文檔共有的成員變量的刪除工作,而在DeleteContents函數(shù)中完成與某個特定文檔相關(guān)的數(shù)據(jù)的刪除工作。
2、在MDI中,則沒有必要注意這點,因為文檔對象可以被多次創(chuàng)建
四、簡單的SDI程序啟動時候的流程如下:
1、CHelloApp::CHelloApp() 全局變量的構(gòu)造函數(shù)
在int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)函數(shù)中
{
...............
...............
if (!pThread->InitInstance()) //一般在應用程序派生類重寫InitInstance虛函數(shù)
{
if (pThread->m_pMainWnd != NULL)
{
TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run(); //進入消息循環(huán)
................
}
2、
在CHelloApp::InitInstance()虛函數(shù)中
{
創(chuàng)建了文檔模版,并加入文檔模版鏈
before call ProcessShellCommand
CHelloDoc::CHelloDoc()
CMainFrame::CMainFrame()
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
BOOL CHelloView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
BOOL CHelloView::PreCreateWindow(CREATESTRUCT& cs)
int CHelloView::OnCreate(LPCREATESTRUCT lpCreateStruct)
BOOL CHelloDoc::OnNewDocument()
void CHelloDoc::DeleteContents()
void CHelloView::OnInitialUpdate()
after call ProcessShellCommand
}
注意:
(1)、SDI程序啟動時,默認的ShellCommand是:file/new, 啟動的時候只是構(gòu)造空的文檔對象
(2)、在SDI中,文檔、主框架、視圖對象都只被創(chuàng)建一次,所以再次使用file/new的時候,只完成
BOOL CHelloDoc::OnNewDocument()
void CHelloDoc::DeleteContents()
void CHelloView::OnInitialUpdate(),這3個步驟
五、打開文件(file/open)
1、選擇文件
2、調(diào)用CDocument::OnOpenDocument函數(shù)(其中:刪除文檔的內(nèi)容,并進行了序列化)
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); //打開文件
DeleteContents(); //刪除文檔的內(nèi)容
SetModifiedFlag(); // dirty during de-serialize //表明改變了文檔內(nèi)容
CArchive loadArchive(pFile, CArchive::load | CArchive::bNoFlushOnDelete);
loadArchive.m_pDocument = this;
loadArchive.m_bForceFlat = FALSE; //把CArchive對象與文件關(guān)聯(lián)起來,用于序列化
TRY
{
CWaitCursor wait;
if (pFile->GetLength() != 0)
Serialize(loadArchive); // load me //序列化
loadArchive.Close();
ReleaseFile(pFile, FALSE);
}
.......
........
SetModifiedFlag(FALSE); // start off with unmodified //設(shè)置文檔沒有被改變
return TRUE;
}
3、調(diào)用void CHelloView::OnInitialUpdate() 函數(shù)
六、保存文件(file/save file/save as)
void CDocument::OnFileSave()
{
DoFileSave(); //DoFileSave()調(diào)用了DoSave()
}
void CDocument::OnFileSaveAs()
{
if (!DoSave(NULL))
TRACE0("Warning: File save-as failed.\n");
}
DoSave()調(diào)用了OnSaveDocument()函數(shù),在OnSaveDocument()函數(shù)中進行了序列化操作
七、特別注意:
file/new file/open 被映射到了應用程序類
file/save fi