现在的位置: 首页 > 综合 > 正文

VC 动态生成菜单

2013年05月11日 ⁄ 综合 ⁄ 共 2665字 ⁄ 字号 评论关闭

动态生成菜单

这是一段根据字符串动态生成菜单的程序,字符串的格式是这样的:一个数字+一个字符串组成一个菜单项,一项一项的排开,用逗号,分隔,组成一个大字符串。数字表示菜单的层次,0是主菜单,1是1级子菜单...n+1是离它最近的左边的n级菜单的子菜单。最多可以表示9级子菜单,这已经足够了。字符串是菜单显示的内容。举个例子,比如0a,1b,1c,0d表示主菜单是a和d,a有2个子菜单b和c。
再比如 0a,1a1,2a11,2a12,1a2,2a21,3e,2a22,0b,0c,0d,1d1,2d11 表示出的菜单是这样的:

具体做起来很简单。

在头文件里:
由于要用到vector和map,所以先include他俩:
#include

定一个结构体,存储菜单项相关信息。
struct node_t
{
int level;//菜单项的层次
CString name;//菜单项显示的字符串
int nID;//该菜单项的id,用于处理选某个菜单项
};
typedef std::vector

别忘了还得有个成员变量:
CMenu* m_pMenu;

在cpp文件:
//这是个功能函数,把输入字符串解析成结构体数组,以便后面生成菜单用。
bool CQuickmenuDlg::ParseStringToVector( CString csparse, arNode& arlist )
{
arlist.clear();
node_t node;
for (;;){
int npos = csparse.Find( _T(','));
if ( -1 == npos ){
   csparse.TrimLeft();
   csparse.TrimRight();
   if(csparse.IsEmpty()){
    return false;
   }
   CString cst=csparse.Left(1);
   LPCTSTR tmp=LPCTSTR(cst);

   node.level = _ttoi(tmp);
   node.name = csparse.Mid(1);
   arlist.push_back( node );
   break;
}
CString csadd = csparse.Left( npos );
csadd.TrimLeft();
csadd.TrimRight();
if(csadd.IsEmpty()){
   return false;
}
CString cst=csadd.Left(1);
LPCTSTR tmp=LPCTSTR(cst);

node.level = _ttoi(tmp);
node.name = csadd.Mid(1);
arlist.push_back( node );
csparse = csparse.Mid( npos + 1 );
}
return true;
}

//在对话框初始化函数里,开始生成菜单了。
BOOL CQuickmenuDlg::OnInitDialog()
{
...
//前面的省略
// TODO: Add extra initialization here
//这是生成菜单所用的字符串。他的来源可以是消息,可以是文件,这只是个例子,写个固定值。
CString cs=_T("0a,1a1,2a11,2a12,1a2,2a21,2a22,0b,0c,0d,1d1");

//分解成结构体数组
arNode menulist;
if(!ParseStringToVector(cs,menulist)){
return TRUE;
}
//创建菜单
m_pMenu=new CMenu;
if(!m_pMenu->CreatePopupMenu()){
return TRUE;
}
//这是核心代码了,根据结构体数组创建菜单项。
std::map<int,CMenu*> menumap;
std::map<int,int> levelcountmap;
levelcountmap[0]=0;
menumap[0]=m_pMenu;
int n=menulist.size();
for (int i=0;i<n-1;i++){
node_t node=menulist[i];
levelcountmap[node.level]++;
node_t nodenext=menulist[i+1];
if (nodenext.level>node.level){
   HMENU hmenu=CreatePopupMenu();
   menumap[node.level]->AppendMenu(MF_STRING|MF_POPUP,(long)hmenu,node.name);
   menumap[nodenext.level]=menumap[node.level]->GetSubMenu(levelcountmap[node.level]-1);
}else{
   if (nodenext.level<node.level){
    for (int j=node.level;j>nodenext.level;j--){
     levelcountmap[j]=0;
    }
   }
//这里的i是该菜单项的id,可以根据node.name设定,以便后面弹出菜单后选某一项时处理。
   menumap[node.level]->AppendMenu(MF_STRING,i,node.name);
}
}
//最后一项,这个i也是它的id。
menumap[menulist[n-1].level]->AppendMenu(MF_STRING,i,menulist[n-1].name);

return TRUE; // return TRUE unless you set the focus to a control
}

//最后在右键响应函数里加上TrackPopupMenu弹出菜单。
void CQuickmenuDlg::OnRButtonUp(UINT nFlags, CPoint point)
{
ClientToScreen(&point);
int nID=m_pMenu->TrackPopupMenu(TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTALIGN
| TPM_LEFTBUTTON | TPM_RIGHTBUTTON,point.x,point.y,this);
//process selection nID...
//这个nID就是创建时设的,用个switch case结构分别处理。
switch(nID)
{
case 1:
break;
   //...
}

CDialog::OnRButtonUp(nFlags, point);
}

抱歉!评论已关闭.