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;
VC中有关最近文件列表的相关操作
最新推荐文章于 2015-04-01 22:02:20 发布