文档管理器
应用程序CWinApp对文档模板的管理是通过文档管理器(CDocManager)实现的。在应用程序CWinApp类中定义了一个文档管理器对象指针m_pDocManager,应用程序通过它来管理文档模板。为了让用户了解文档管理器的作用,下面介绍文档管理器的主要数据成员和方法。
在文档管理器CDocManager中定义了一个文档模板列表m_templateList,用于存储多个模板。同时,文档管理器还维护了一个全局的文档管理器和全局文档模板列表,代码如下。
protected:
CPtrList m_templateList;
public:
static CPtrList* pStaticList;
static BOOL bStaticInit;
static CDocManager* pStaticDocManager;
静态成员变量pStaticInit确定是否将文档模板放入全局的文档模板列表(pStaticList)中。默认情况下,MFC向导在创建文档视图结构时,将不通过全局文档模板列表存储文档模板。下面一段代码利用全局文档模板列表存储文档模板。需要说明的是,全局文档模板列表只是临时的存储文档模板,文档管理器最终会将全局文档模板列表中的文档模板放入m_temp lateList中。
CCMyVeiwApp theApp;
BOOL CDocManager::bStaticInit =TRUE;
CSingleDocTemplate pDocTemplate (IDR_MAINFRAME,RUNTIME_CLASS(CCMyVeiwDoc),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CCMyVeiwView));
BOOL CCMyVeiwApp::InitInstance()
{
AfxEnableControlContainer();
#ifdef _AFXDLL
Enable3dControls();
#else
Enable3dControlsStatic();
#endif
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings();
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
if (!ProcessShellCommand(cmdInfo))
return FALSE;
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
}
首先在全局作用域将CDocManager::bStaticInit设置为TRUE,然后定义一个单文档模板pDocTemplate。运行程序,发现一切正常。对于上面的代码,许多用户会产生疑问:文档模板如何被存储在全局文档模板列表中?没有发现应用程序调用AddDocTemplate方法,应用程序的文档管理器m_pDocManager是如何添加文档模板的呢?
对于第一个问题,可以在文档模板CDocTemplate的构造函数中找到答案。
CDocTemplate::CDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass,
CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass)
{
……//代码省略
if (CDocManager::bStaticInit)
{
m_bAutoDelete = FALSE;
if (CDocManager::pStaticList == NULL)
CDocManager::pStaticList = new CPtrList;
if (CDocManager::pStaticDocManager == NULL)
CDocManager::pStaticDocManager = new CDocManager;
CDocManager::pStaticList->AddTail(this);
}
else
{
m_bAutoDelete = TRUE;
LoadTemplate();
}
}
当在程序中定义一个全局的文档模板对象时,会执行黑体部分代码,创建全局文档模板列表和全局文档管理器,然后将文档模板添加到全局文档模板列表中。
对于第二个问题,可以在应用程序的InitApplication方法中得到答案。
BOOL CWinApp::InitApplication()
{
if (CDocManager::pStaticDocManager != NULL)
{
if (m_pDocManager == NULL)
m_pDocManager = CDocManager::pStaticDocManager;
CDocManager::pStaticDocManager = NULL;
}
if (m_pDocManager != NULL)
m_pDocManager->AddDocTemplate(NULL);
else
CDocManager::bStaticInit = FALSE;
return TRUE;
}
在应用程序启动时,会执行InitApplication方法,将应用程序的文档管理器m_pDocManager指向全局的文档管理器,然后调用文档管理器的AddDocTemplate方法开始创建文档、框架、视图,再次分析该方法。
void CDocManager::AddDocTemplate(CDocTemplate* pTemplate)
{
if (pTemplate == NULL)
{
if (pStaticList != NULL)
{
POSITION pos = pStaticList->GetHeadPosition();
while (pos != NULL)
{
CDocTemplate* pTemplate =
(CDocTemplate*)pStaticList->GetNext(pos);
AddDocTemplate(pTemplate);
}
delete pStaticList;
pStaticList = NULL;
}
bStaticInit = FALSE;
}
else
{
ASSERT_VALID(pTemplate);
ASSERT(m_templateList.Find(pTemplate, NULL) == NULL);
pTemplate->LoadTemplate();
m_templateList.AddTail(pTemplate);
}
}
由于在InitApplication方法中调用AddDocTemplate时,传递的是NULL参数,所以程序将执行黑体部分代码,利用递归的方式将全局文档模板列表中的数据添加到文档模板列表m_templateList中。
为了管理文档模板,文档管理器还提供了多个方法。
(1)GetFirstDocTemplatePosition方法
该方法获取文档管理器中第一个文档模板的位置。
语法:
virtual POSITION GetFirstDocTemplatePosition() const;
(2)GetNextDocTemplate方法
该方法返回指定位置的文档模板,然后将位置指向下一个文档模板。
语法:
virtual CDocTemplate* GetNextDocTemplate(POSITION& pos) const;
pos:标识文档的位置。
(3)GetOpenDocumentCount方法
该方法用于获取文档模板列表中的文档对象数量。
语法:
virtual int GetOpenDocumentCount();
(4)CloseAllDocuments方法
该方法用于关闭文档模板列表中的所有文档。
语法:
virtual void CloseAllDocuments(BOOL bEndSession);
bEndSession:标识会话是否被结束,如果为TRUE,会话将要被结束。
(5)SaveAllModified方法
该方法保存所有修改的文档。
语法:
virtual BOOL SaveAllModified();
(6)OpenDocumentFile方法
该方法用于创建或打开一个文档。
语法:
virtual CDocument* OpenDocumentFile(LPCTSTR lpszFileName);
lpszFileName:如果为NULL,将创建一个新的文档对象,否则根据文件名打开文档。