用户登录  |  用户注册
首 页源码下载网络学院最新源码源码排行屏蔽广告
当前位置:新兴网络 > 网络学院 > 编程开发 > VC/MFC

VC++通过ini文件实现记录最近打开文件菜单

减小字体 增大字体 作者:风林  来源:风林的家  发布时间:2010-06-01 21:46:10
    VC++的MFC对最近文件进行了包装,它使用户无需编写任何代码就可实现最近文件菜单。但这种方法也有缺陷:

①用户程序必须使用文档、视图结构,只能利用它提供的文档打开和保存文件,如果你使用自己编写的函数打开和保存文件,绕过了它的文档,则最近文件将无法使用。

②这种最近文件保存在注册表中,不易清除,容易形成注册表中垃圾,也没有提供用户清除最近文件的权利,不利于用户隐私的保护。

用ini文件实现最近文件可以解决上述问题,而且用编程控制MRU更灵活,可以提供更多功能。

示例程序界面:

一、ini文件的结构和访问方法


    ini文件是纯文本文件,我们可以编程访问它,也可用任一种文本编辑软件打开它。如某RAV.ini文件打开后如下:

INI code复制代码
[INSTALLED]
FWBASE2K=1
FWBASENT=1
ToInstall=
CodePage=936
Closed=

[Setup]
ShowBgBmp=0

[Skin]
Current=1
Path=D:\Program Files\Rising\Rav\Skin\Skin1\Skin.xml

[RAVMON]
MONSTATUS=255 

其中[]括起的称为段,段下面的各部分称为项,访问时用(段名,项名)可访问指定项的值。我们可利用API函数直接读写ini文件。

㈠ 读ini文件中的项值

① 读整数值:

UINT GetPrivateProfileInt(LPCTSTR lpAppName,LPCTSTR lpKeyName,INT nDefault,LPCSTR lpFileName); 

lpAppName为段名,lpKeyName为项名,nDefault为找不到该项时返回的默认值,lpFileName为ini文件名
    返回值:若成功,返回指定项后的整数值,若该项不存在,返回nDefault的值

    如:读取RAV.ini文件中[INSTALLED]段的FWBASE2K项的值

int FwbBase2K = ::GetPrivateProfileInt("INSTALLED", "FWBASE2K", 0, "RAV.ini");

如果[INSTALLED]段的FWBASE2K项存在,则FwbBase2K的值为读出的值,若不存在,则为函数调用中指定的0。

② 读字符串:

DWORD GetPrivateProfileString(LPCTSTR lpAppName,LPCTSTR lpKeyName,LPCTSTR lpDefault,LPTSTR lpReturnedString,DWORD nSize,LPCTSTR lpFileName);

lpAppName为段名,lpKeyName为项名,lpDefault为找不到该项时返回的默认值,lpReturnedString指向接收结果的字符串缓冲区,nSize为缓冲区长度,lpFileName为ini文件名

执行结果:若成功,lpReturnedString指示的串中为读出的项值,若该项不存在,lpReturnedString中为lpDefault的值

如:读取RAV.ini文件中[Skin]段的Path项的值

C/C++ code复制代码
CString PathName;   //接收串的变量

::GetPrivateProfileString("Skin", "Path", "", PathName.GetBuffer(MAX_PATH), MAX_PATH, "RAV.ini");

PathName.ReleaseBuffer();   //释放多余空间 

MAX_PATH为系统预定义的常数,其值可能是255。

㈡ 把数据写入ini文件

写入时没有写入整数的函数,只有写入字符串的函数

BOOL WritePrivateProfileString(LPCTSTR lpAppName,LPCTSTR lpKeyName,LPCTSTR lpString,LPCTSTR lpFileName);  

lpAppName为段名,lpKeyName为项名,lpString为写入的字符串,lpFileName为ini文件名

返回值:若成功,返回true,否则返回false

 若写入时,该ini文件不存在,则这个函数会自动建立这个文件,并建立相应的段和项。

如:把RAV.ini文件中[INSTALLED]段的FWBASE2K项的值设置为2,由于这是整数,应先转换为字符串后再写入

C/C++ code复制代码
CString str;

str.Format("%d", 2);    //把写入的整数转换为字符串

::WritePrivateProfileString( "INSTALLED", "FWBASE2K", str, "RAV.ini" );  //写入ini文件 

注意:实际应用中,ini文件名应采用绝对路径名,否则可能找不到要读写的ini文件。

二、用ini文件实现最近文件MRU

我设计了一个ini文件MruFile.ini保存最近文件,它的结构如下:

INI code复制代码
[Mru File]
FileNum=当前文件数
1=路径名1
2=路径名2
3=路径名3
4=路径名4  

[Mru File]为段名,项FileNum为当前Mru文件数,项1、2、3、4放置各Mru文件名。这里只设计了4个最近文件,应用时可根据需要添加。

用ClassWizard添加一个没有基类的新类,名字起为CMruFile,作为MRU文件管理类,在它的头文件中有如下定义:

C/C++ code复制代码
#define MAXNUM 4             //最大MRU文件数

CString m_IniFileName;       //ini文件名
CString m_PathName[MAXNUM];  //MRU文件路径名
int m_CurNum;                //当前最近文件数 

在MruFile.cpp中定义下列函数:

①读取ini文件中的最近文件

C/C++ code复制代码
void CMruFile::ReadMru()
{
    m_CurNum = ::GetPrivateProfileInt("Mru File", "FileNum", 0, m_IniFileName);    //读取当前文件数
    CString no;
    for( int i=0; i<m_CurNum; i++)
    {
        no.Format( "%d", i+1 );    //求项名
        ::GetPrivateProfileString("Mru File", no, "", m_PathName[i].GetBuffer(MAX_PATH),
            MAX_PATH, m_IniFileName);    //读取路径名
        m_PathName[i].ReleaseBuffer();
    }
  SetMruMenu();    //修改MRU菜单
}  

这个函数在程序一开始就执行,用来把ini文件中的最近文件名读入字符串数组m_PathName中,然后修改最近文件菜单,使它们可以由最近文件菜单选择打开。

②最近文件写入ini文件

C/C++ code复制代码
void CMruFile::WriteMru()
{
    CString no;
    no.Format( "%d", m_CurNum );
    ::WritePrivateProfileString( "Mru File", "FileNum", no, m_IniFileName );  //写当前文件数
    for( int i=0; i<MAXNUM; i++)
    {
        no.Format( "%d", i+1 );
        ::WritePrivateProfileString("Mru File", no, m_PathName[i], m_IniFileName);  //写路径名
    }
}  

这个函数在用户打开一个文件时执行,用来更新ini文件中的Mru列表。

③添加最近文件

设计思路:当打开的文件名nPathName在m_PathName[]列表中已存在,就把它提升到表头;若它不存在,则添加到表头,如果表已满(本例中最多可添加4个文件名),删除表尾的元素。

C/C++ code复制代码
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文件
} 

    这个函数也是在用户打开一个文件时执行,并且在WriteMru()函数之前进行,用于更新用数组m_PathName[]保存的Mru列表。

④清除最近文件

C/C++ code复制代码
void CMruFile::ClearMru()
{
    m_CurNum = 0;      //清除最近文件数
    for( int i=0; i<MAXNUM; i++)
        m_PathName[i].Empty();      //清空Mru列表
    SetMruMenu();      //清空Mru菜单
    WriteMru();        //清空ini文件中的Mru列表
} 

在Mru菜单中有一个“清除最近文件”选项,当用户单击这个菜单项时,执行本函数。这有利于保护用户隐私。

⑤修改最近文件菜单

C/C++ code复制代码
void CMruFile::SetMruMenu()
{
    CMenu *pMenu = AfxGetMainWnd()->GetMenu();    //主菜单指针
    CMenu *pFileMenu = pMenu->GetSubMenu(0);      //“文件”菜单指针
    CMenu *pMruMenu = pFileMenu->GetSubMenu(5);   //“最近文件”菜单指针(5为最近文件菜单项在文件菜单中的位置)
    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] );
} 

当Mru文件列表发生变化时调用此函数。Mru菜单是一个可以修改的动态菜单,它的菜单项数目随着Mru文件数的变化而变化,菜单内容也随着Mru列表的内容变化而变化。

在这里ID_MRU1~ID_MRU4和ID_MRU_CLR是各菜单项的ID号,它们需事先在资源的字符串表中进行定义。

这样,一个用ini文件管理的最近文件类就做好了。使用时,在程序的打开文件OnFileOpen()函数和另存为OnFileSaveAs()函数调用这个类的相关函数就可以管理最近文件了。

  本实例附件下载:http://www.newxing.com/Code/VC/wjcz/MruFile_55.html

Tags:VC 最近打开记录

作者:风林
  • 好的评价 如果您觉得此文章好,就请您
      100%(4)
  • 差的评价 如果您觉得此文章差,就请您
      0%(0)

网络学院评论评论内容只代表网友观点,与本站立场无关!

   评论摘要(共 1 条,得分 100 分,平均 100 分) 查看完整评论
[回复] 1游客   打分:100 分  发表时间:2010-10-07
· 超好的文章~~~