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

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;
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值