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数组的建立等。 

2.记录的保存、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;   
//

MRU(最近使用的)文件 
问:我想将最近使用过的几个文件名(以及路径)显示出来,该怎么办? 
答:一个由向导生成器生成的文档视图结图已经包含MRU列表操作.

具体是放在注 册表的 HKEY_CURRENT_USER/Software/Your Company Name/ Your App Name/Recent File List/File1, File2, File3, etc. 
1)你所要做的是用程序中的GetProfileString()读入第一个MRU文件的位置, 
剩下的由 CRecentFileList::ReadList()完成所有的工作.CRecentFileList类 
包含了所有操作 的代码象分析路径,管理MRU文件等,用不着为此费心. 

2)在AFXWIN.H中定义了一个变量CRecentFileList* m_pRecentFileList; 
你可以通过使用CRecentFileList的成员变量m_arrNames[n]来取得某个MRU文件. 
比如: 

#include 
// needed for access to MRU list 

Cfile mruFile; 
if ( !mruFile.Open( m_pRecentFileList->m_arrNames[index], 
Cfile::modeRead )
.... 

3)你不需要建立一个CRecentFileList类,它已经由CWinApp基类完成了.

你 只要保证你在 initinstance中调用LoadStdProfileSettings() 

函数就可以了. CRecentFileList类中有一个CWinApp保护成员变量 
(如m_pRecentFileList) 所以你应该在你的继承类中处理它.下面的代码在 
我这儿工作很正常 
void CMdiApp::OnFileMruFile1() 
{ 
// TODO: Add your command handler code here 
Cstring vl_name ; 
ASSERT( m_pRecentFileList->GetSize() > 0); 
vl_name = (*m_pRecentFileList)[0]; 
CWinApp::OnOpenRecentFile(ID_FILE_MRU_FILE1); 
} 
OnOpenRecentFile()函数必须要调用缺省处理,其它的就随便了   
   

如何重载MRU文件? 
我创建了一个应用程序可以载入图象文件,但当我点击FILE菜单下MRU文件列表 
时,却不能从磁盘载入以前曾经打开过的文件. 
下面是我所能想到的解决方案: 

(1)在文档类中定义一个成员函数(例如:CMyDoc::Reopen)来处理重新打开这个问 
题,指明参数和返回值. 
(2)产生一个CMultiDocTemplate的继承类(如CMyDocTemplate),
定义一个构造函 
数,取和基类相同的参数,不做任何事,只是调用基类的构造函数. 
(3)重载MatchDocType: 

CMyDocTemplate::Confidence CMyDocTemplate::MatchDocType( 
LPCTSTR lpszPath, 
CDocument *&rpDocMatch 
) 
{ 
Confidence match = CMultiDocTemplate::MatchDocType(lpszPath, rpDocMatch); 

if(yesAlreadyOpen == match) // clear enough 
{ 
ASSERT_KINDOF(CMyDoc, rpDocMatch); 
((CMyDoc *) rpDocMatch)->Reopen(/* your parameters */); 

// you can take any other actions here... 
} 

return match; 
} 
当这个函数返回"yesAlreadyOpen"时,你的文档框架将会被激活.   

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值