MFC框架中对最近文件列表的支持

http://www.fmdstudio.net/articles/mfcsrc/01912235946.htm

http://topic.csdn.net/t/20010917/21/291003.html

MFC框架中对最近文件列表的支持

MFC建立的标准框架程序中有记录最近操作文件的能力,这些最近文件的路径被记录到注册表,在程序运行时,又将添加到文件菜单中。  

在CWinApp中有个   CRecentFileList*   m_pRecentFileList;指针管理这些信息。  

以下对此过程进行分析,采用类似的方法,可以保存其他一些固定条数的最近数据。  


1.CRecentFileList对象的建立,记录读入、记录保存、对象销毁。  

①建立与记录的读入  

如果在CWinApp派生类中InitInstance()中调用了LoadStdProfileSettings,则CRecentFileList被建立,时程序具有管理最近文件列表的能力。  

同时,从注册表中读入以前的记录。  

void   CWinApp::LoadStdProfileSettings(UINT   nMaxMRU)   //缺省为4
{
...
if   (nMaxMRU   !=   0)
{
//建立CRecentFileList对象,初始化为管理nMaxMRU条文件信息
m_pRecentFileList   =   new   CRecentFileList(0,   _afxFileSection,   _afxFileEntry,nMaxMRU);
//读入记录
m_pRecentFileList->   ReadList();
}
...
}

CRecentFileList对象中的主要数据成员  

CRecentFileList包含一个CString指针   CString*   m_arrNames;   ,它用来指向一个CString对象数组,正是这个数组记录了最近的文件名。  

另外,成员   int   m_nSize   指出了记录的个数。  

在对象创建时,构造函数完成初始化,包括CString数组的建立等。  

②记录的保存、CRecentFileList的销毁。  

ExitInstance()中将调用SaveStdProfileSettings(),SaveStdProfileSettings()中有m_pRecentFileList-> WriteList();操作,完成记录的保存。  

在CWinApp析构时将delete   m_pRecentFileList;销毁对象。  

CRecentFileList::CRecentFileList(UINT   nStart,   LPCTSTR   lpszSection,
LPCTSTR   lpszEntryFormat,   int   nSize,   int   nMaxDispLen)
{
ASSERT(nSize   !=   0);
m_arrNames   =   new   CString[nSize];   //建立CString数组。
m_nSize   =   nSize;

m_nStart   =   nStart;
m_strSectionName   =   lpszSection;
m_strEntryFormat   =   lpszEntryFormat;
m_nMaxDisplayLength   =   nMaxDispLen;
}

3.记录的添加  

文档保存时,将调用SetPathName(..),SetPathName(..)中将调用应用程序类中的AddToRecentFileList  

AddToRecentFileList中执行m_pRecentFileList-> Add(lpszPathName)将文件名添加到字符串数组  

void   CRecentFileList::Add(LPCTSTR   lpszPathName)
{
ASSERT(m_arrNames   !=   NULL);
ASSERT(lpszPathName   !=   NULL);
ASSERT(AfxIsValidString(lpszPathName));

//   fully   qualify   the   path   name
TCHAR   szTemp[_MAX_PATH];
AfxFullPath(szTemp,   lpszPathName);     //得到文件全路径

//   查找,看是否已经有此文件名
for   (int   iMRU   =   0;   iMRU   <   m_nSize-1;   iMRU++)
{
if   (AfxComparePath(m_arrNames[iMRU],   szTemp))
break;             //   iMRU   will   point   to   matching   entry
}
//   其前面的各项后移
for   (;   iMRU   >   0;   iMRU--)
{
ASSERT(iMRU   >   0);
ASSERT(iMRU   <   m_nSize);
m_arrNames[iMRU]   =   m_arrNames[iMRU-1];
}
//添加到起始位置
m_arrNames[0]   =   szTemp;
}

4.记录的删除  

如果用户从菜单中选择打开某记录对应的文件,单该文件已经不存在,则将删除该无效记录。  

void   CRecentFileList::Remove(int   nIndex)
{
ASSERT(nIndex   > =   0);
ASSERT(nIndex   <   m_nSize);

m_arrNames[nIndex].Empty();
for   (int   iMRU   =   nIndex;   iMRU   <   m_nSize-1;   iMRU++)
m_arrNames[iMRU]   =   m_arrNames[iMRU+1];   //其后各项前移

ASSERT(iMRU   <   m_nSize);
m_arrNames[iMRU].Empty();
}

5.记录数据的保存  
void   CRecentFileList::WriteList()
{
ASSERT(m_arrNames   !=   NULL);
ASSERT(!m_strSectionName.IsEmpty());     //   m_strSectionName   :   _T( "Recent   File   List ")
ASSERT(!m_strEntryFormat.IsEmpty());     //   m_strEntryFormat   :   _T( "File%d ")    
LPTSTR   pszEntry   =   new   TCHAR[m_strEntryFormat.GetLength()+5];
CWinApp*   pApp   =   AfxGetApp();
pApp->   WriteProfileString(m_strSectionName,   NULL,   NULL);   //写入Recent   File   List键
for   (int   iMRU   =   0;   iMRU   <   m_nSize;   iMRU++)
{
wsprintf(pszEntry,   m_strEntryFormat,   iMRU   +   1);     //得到号吗字符串
if   (!m_arrNames[iMRU].IsEmpty())
{
pApp->   WriteProfileString(m_strSectionName,   pszEntry,       //在写值名pszEntry,对应值为文件名。
m_arrNames[iMRU]);
}
}
delete[]   pszEntry;
}

6.记录数据的读取  

void   CRecentFileList::ReadList()
{
ASSERT(m_arrNames   !=   NULL);
ASSERT(!m_strSectionName.IsEmpty());
ASSERT(!m_strEntryFormat.IsEmpty());
LPTSTR   pszEntry   =   new   TCHAR[m_strEntryFormat.GetLength()+5];
CWinApp*   pApp   =   AfxGetApp();
for   (int   iMRU   =   0;   iMRU   <   m_nSize;   iMRU++)
{
wsprintf(pszEntry,   m_strEntryFormat,   iMRU   +   1);     //得到值名字符串
m_arrNames[iMRU]   =   pApp->   GetProfileString( //取值名下的值,此即个记录,若值不存在,则为NULL
m_strSectionName,   pszEntry,   &afxChNil);
}
delete[]   pszEntry;
}


7.将记录添加到菜单项  

菜单资源中文件菜单下有ID为ID_FILE_MRU_FILE1的菜单项,用于在此处添加最近文件菜单项。  

命令更新机制根据ON_UPDATE_COMMAND_UI(ID_FILE_MRU_FILE1,   OnUpdateRecentFileMenu)将经常调用到

CWinApp::OnUpdateRecentFileMenu(..)  

OnUpdateRecentFileMenu中调用void   CRecentFileList::UpdateMenu(CCmdUI*   pCmdUI)  

void   CRecentFileList::UpdateMenu(CCmdUI*   pCmdUI)
{
ASSERT(m_arrNames   !=   NULL);

CMenu*   pMenu   =   pCmdUI->   m_pMenu;   //由pCmdUI直接找到菜单
if   (m_strOriginal.IsEmpty()   &&   pMenu   !=   NULL)
pMenu->   GetMenuString(pCmdUI->   m_nID,   m_strOriginal,   MF_BYCOMMAND);

if   (m_arrNames[0].IsEmpty())
{
//   no   MRU   files
if   (!m_strOriginal.IsEmpty())
pCmdUI->   SetText(m_strOriginal);
pCmdUI->   Enable(FALSE);
return;
}

if   (pCmdUI->   m_pMenu   ==   NULL)
return;

for   (int   iMRU   =   0;   iMRU   <   m_nSize;   iMRU++)       //删除所有最新文件菜单项
pCmdUI->   m_pMenu->   DeleteMenu(pCmdUI->   m_nID   +   iMRU,   MF_BYCOMMAND);

TCHAR   szCurDir[_MAX_PATH];
GetCurrentDirectory(_MAX_PATH,   szCurDir);
int   nCurDir   =   lstrlen(szCurDir);
ASSERT(nCurDir   > =   0);
szCurDir[nCurDir]   =   '\\ ';
szCurDir[++nCurDir]   =   '\0 ';

CString   strName;
CString   strTemp;
for   (iMRU   =   0;   iMRU   <   m_nSize;   iMRU++)
{
if   (!GetDisplayName(strName,   iMRU,   szCurDir,   nCurDir))
break;

//   double   up   any   '& '   characters   so   they   are   not   underlined
LPCTSTR   lpszSrc   =   strName;
LPTSTR   lpszDest   =   strTemp.GetBuffer(strName.GetLength()*2);
while   (*lpszSrc   !=   0)
{
if   (*lpszSrc   ==   '& ')
*lpszDest++   =   '& ';
if   (_istlead(*lpszSrc))
*lpszDest++   =   *lpszSrc++;
*lpszDest++   =   *lpszSrc++;
}
*lpszDest   =   0;
strTemp.ReleaseBuffer();

//   insert   mnemonic   +   the   file   name
TCHAR   buf[10];
wsprintf(buf,   _T( "&%d   "),   (iMRU+1+m_nStart)   %   10);
pCmdUI->   m_pMenu->   InsertMenu(pCmdUI->   m_nIndex++,
MF_STRING   |   MF_BYPOSITION,   pCmdUI->   m_nID++,
CString(buf)   +   strTemp);     //添加菜单项
}

//   update   end   menu   count
pCmdUI->   m_nIndex--;   //   point   to   last   menu   added
pCmdUI->   m_nIndexMax   =   pCmdUI->   m_pMenu->   GetMenuItemCount();

pCmdUI->   m_bEnableChanged   =   TRUE;         //   all   the   added   items   are   enabled
}

8.对最近文件菜单项的相应  

系统通过消息映射   ON_COMMAND_EX_RANGE(ID_FILE_MRU_FILE1,   ID_FILE_MRU_FILE16,   OnOpenRecentFile)  

调用OnOpenRecentFile,命令ID作为参数传入  

BOOL   CWinApp::OnOpenRecentFile(UINT   nID)
{
ASSERT_VALID(this);
ASSERT(m_pRecentFileList   !=   NULL);

ASSERT(nID   > =   ID_FILE_MRU_FILE1);
ASSERT(nID   <   ID_FILE_MRU_FILE1   +   (UINT)m_pRecentFileList->   GetSize());
int   nIndex   =   nID   -   ID_FILE_MRU_FILE1;
ASSERT((*m_pRecentFileList)[nIndex].GetLength()   !=   0);

TRACE2( "MRU:   open   file   (%d)   '%s '.\n ",   (nIndex)   +   1,
(LPCTSTR)(*m_pRecentFileList)[nIndex]);

if   (OpenDocumentFile((*m_pRecentFileList)[nIndex])   ==   NULL)
m_pRecentFileList->   Remove(nIndex);

return   TRUE;


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/carl2380/archive/2010/07/07/5717466.aspx

原文地址:https://www.cnblogs.com/carl2380/p/1995012.html