VC++的MFC对最近文件进行了包装,它使用户无需编写任何代码就可实现最近文件菜单。但这种方法也有缺陷:
①用户程序必须使用文档、视图结构,只能利用它提供的文档打开和保存文件,如果你使用自己编写的函数打开和保存文件,绕过了它的文档,则最近文件将无法使用。
②这种最近文件保存在注册表中,不易清除,容易形成注册表中垃圾,也没有提供用户清除最近文件的权利,不利于用户隐私的保护。
用ini文件实现最近文件可以解决上述问题,而且用编程控制MRU更灵活,可以提供更多功能。
用ini文件实现最近文件MRU:
类CMruFile是自定义的一个MRU文件管理类,在它的头文件中有如下定义:
源文件:
// MruFile.h: interface for the CMruFile class.
// MruFile.h: interface for the CMruFile class.
//
//
#if !defined(AFX_MRUFILE_H__671CC55F_A571_4732_B0E9_8E33F33E3AFC__INCLUDED_)
#define AFX_MRUFILE_H__671CC55F_A571_4732_B0E9_8E33F33E3AFC__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define MAXNUM 4 //最大MRU文件数
class CMruFile
{
public:
CMruFile();
virtual ~CMruFile();
CString m_IniFileName; //ini文件名
CString m_PathName[MAXNUM]; //MRU文件路径名
int m_CurNum; //当前最近文件数
void ReadMru(); //读取ini文件中的最近文件
void WriteMru(); //最近文件写入ini文件
void AddMru(CString nPathName); //添加最近文件
void ClearMru(); //清除最近文件
void SetMruMenu(); //修改最近文件菜单
};
#endif // !defined(AFX_MRUFILE_H__671CC55F_A571_4732_B0E9_8E33F33E3AFC__INCLUDED_)
// MruFile.cpp: implementation of the CMruFile class.
// MruFile.cpp: implementation of the CMruFile class.
//
//
#include "stdafx.h"
#include "Import.h"
#include "MruFile.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
CMruFile::CMruFile()
{
m_IniFileName=L"";
for(int i=0;i<MAXNUM;i++) m_PathName[i]=L"";
m_CurNum=0;
}
CMruFile::~CMruFile()
{
}
//读取ini文件中的最近文件
void CMruFile::ReadMru()
{
m_CurNum=::GetPrivateProfileInt(L"Mru File",L"FileNum",0,m_IniFileName); //读取当前文件数
CString no;
for( int i=0; i<m_CurNum; i++)
{
no.Format(L"%d",i+1); //求项名
::GetPrivateProfileString(L"Mru File", no, L"",m_PathName[i].GetBuffer(MAX_PATH),MAX_PATH, m_IniFileName); //读取路径名
m_PathName[i].ReleaseBuffer();
}
SetMruMenu(); //修改MRU菜单
}
//最近文件写入ini文件
void CMruFile::WriteMru()
{
CString no;
no.Format(L"%d", m_CurNum );
::WritePrivateProfileString(L"Mru File",L"FileNum", no, m_IniFileName ); //写当前文件数
for( int i=0; i<MAXNUM; i++)
{
no.Format(L"%d", i+1 );
::WritePrivateProfileString(L"Mru File", no, m_PathName[i], m_IniFileName); //写路径名
}
}
//添加最近文件(nPathName-添加的文件路径名)
//设计思路:当nPathName在m_PathName[]列表中已存在,须把它提升到表头;若它不存在,则添加到表头,如果表已满,删除表尾的元素。
void CMruFile::AddMru(CString nPathName)
{
int i;
CString str1, str2;
if( m_CurNum )
{
if( nPathName.CompareNoCase(m_PathName[0])==0 ) //如果nPathName已在表头,结束
return;
}
str1 = nPathName;
i = 0;
while( i<m_CurNum && nPathName.CompareNoCase(m_PathName[i])!=0 ) //在表中查找,不相等的元素下移
{
str2 = m_PathName[i];
m_PathName[i] = str1;
str1 = str2;
i++;
}
if( i<m_CurNum )
m_PathName[i] = str1; //nPathName已存在
else if( m_CurNum<MAXNUM )
{
m_PathName[m_CurNum] = str1; //表未满
m_CurNum++;
}
SetMruMenu(); //修改MRU菜单
WriteMru(); //最近文件写入ini文件
}
//清除最近文件
void CMruFile::ClearMru()
{
m_CurNum = 0;
for( int i=0; i<MAXNUM; i++) m_PathName[i].Empty();
SetMruMenu(); //修改MRU菜单
WriteMru();
}
//修改最近文件菜单
void CMruFile::SetMruMenu()
{
CMenu *pMenu = AfxGetMainWnd()->GetMenu(); //主菜单指针
CMenu *pFileMenu = pMenu->GetSubMenu(0); //“文件”菜单指针
CMenu *pMruMenu = pFileMenu->GetSubMenu(4); //“最近文件”菜单指针(4为最近文件菜单项在文件菜单中的位置)
pMruMenu->RemoveMenu( ID_MRU1, MF_BYCOMMAND ); //删除各菜单项 pMruMenu->RemoveMenu( ID_MRU2, MF_BYCOMMAND );
pMruMenu->RemoveMenu( ID_MRU3, MF_BYCOMMAND );
pMruMenu->RemoveMenu( ID_MRU4, MF_BYCOMMAND );
if( m_CurNum>0 ) //重新插入各菜单项
pMruMenu->InsertMenu( ID_MRU_CLR, MF_BYCOMMAND,ID_MRU1, m_PathName[0] );
if( m_CurNum>1 )
pMruMenu->InsertMenu( ID_MRU_CLR, MF_BYCOMMAND,ID_MRU2, m_PathName[1] );
if( m_CurNum>2 )
pMruMenu->InsertMenu( ID_MRU_CLR, MF_BYCOMMAND,ID_MRU3, m_PathName[2] );
if( m_CurNum>3 )
pMruMenu->InsertMenu( ID_MRU_CLR, MF_BYCOMMAND,ID_MRU4, m_PathName[3] );
}
应用举例:
// MainFrm.h : CMainFrame类借口
1)在CMainFrame 类中定义成员变量
CMruFile m_CMruFile;
2)在 CMainFrame::OnInitialUpdate(void) 初始化中 初始化ini文件地址,并读入最近使用的文件
void CMainFrame::OnInitialUpdate(void)
{
wchar_t nCurDir[256];
GetCurrentDirectory(256,nCurDir);
m_CMruFile.m_IniFileName.Format(L"%s\\%s",nCurDir,L"MruFile.ini");
m_CMruFile.ReadMru();
//...
}
3) 新打开文件时 添加文件
m_CMruFile.AddMru(m_XMLFolder);
4)清楚最近文件
ON_UPDATE_COMMAND_UI(ID_MRU_CLR, OnUpdateMruClr) //确定 【清楚最近任务】 菜单 --是处于无效状态中还是处于有效状态中
ON_COMMAND(ID_MRU_CLR, OnMruClr) //清楚最近任务
void CMainFrame::OnUpdateMruClr(CCmdUI *pCmdUI)
{
pCmdUI->Enable(m_CMruFile.m_CurNum);
}
//------------------------------清除最近任务---------------------------------------
void CMainFrame::OnMruClr()
{
m_CMruFile.ClearMru();
}
5) 打开最近使用的文件
ON_COMMAND(ID_MRU1, OnMru1) // 打开最近使用的菜单1
ON_COMMAND(ID_MRU2, OnMru2) // 打开最近使用的菜单2
ON_COMMAND(ID_MRU3, OnMru3) // 打开最近使用的菜单3
ON_COMMAND(ID_MRU4, OnMru4) // 打开最近使用的菜单4
//-----------------------------打开最近任务1---------------------------------------
void CMainFrame::OnMru1()
{
OpenMruFile(0);
}
//-----------------------------打开最近任务2---------------------------------------
void CMainFrame::OnMru2()
{
OpenMruFile(1);
}
//-----------------------------打开最近任务3---------------------------------------
void CMainFrame::OnMru3()
{
OpenMruFile(2);
}
//-----------------------------打开最近任务4---------------------------------------
void CMainFrame::OnMru4()
{
OpenMruFile(3);
}
void CMainFrame::OpenMruFile(int nMru)
{
m_XMLFolder=m_CMruFile.m_PathName[nMru];
//...
}