打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
VC++通过ini文件实现记录最近打开文件菜单
    VC++的MFC对最近文件进行了包装,它使用户无需编写任何代码就可实现最近文件菜单。但这种方法也有缺陷:

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

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

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

示例程序界面:

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


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

INI code复制代码
[INSTALLED]FWBASE2K=1FWBASENT=1ToInstall=CodePage=936Closed=[Setup]ShowBgBmp=0[Skin]Current=1Path=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=路径名12=路径名23=路径名34=路径名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

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
vc中常用文件操作(转载)
VC积累
C++读取INI文件
GetPrivateProfileString()函数
VC下打印机的使用
VC常用数据类型使用转换详解
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服