第七课:菜单(二)
一、系统菜单:
1. 系统菜单是有鼠标点击应用程序图标弹出的菜单。点击系统菜单时,发出WM_SYSCOMMAND消息,可添加此消息的响应函数来进行控制。
2. 操作系统菜单:
在CMainFrame的OnCreate函数中加入代码:
CMenu *pMenu=GetSystemMenu(false);
//得到系统菜单
pMenu->RemoveMenu(pMenu->GetMenuItemCount()-1,MF_BYPOSITION);
//移除系统菜单的最后一项
pMenu->EnableMenuItem(SC_CLOSE,MF_DISABLED | MF_BYCOMMAND|MF_GRAYED);
//将系统菜单的“关闭”菜单项设置为失效,变灰
pMenu->AppendMenu(MF_STRING,1111,"HELLO");
//在系统菜单中添加一个菜单
GetSystemMenu(true);
//重置系统菜单到默认状态
二、运行时产生菜单:
在CMainFrame的OnCreate函数中加入代码:
mnu.CreatePopupMenu();
//产生一个弹出菜单,注意:在WIN2000下mnu应定义为成员变量,否则会报红框,WINNT下可以定义为局部变量
mnu.AppendMenu(MF_STRING,1111,"HELOO");
//向刚产生的弹出菜单加入一个菜单项
GetMenu()->AppendMenu(MF_POPUP,(INT)mnu.m_hMenu,"heha");
//将弹出菜单添加到主窗口的菜单上
GetMenu()->GetSubMenu(4)->EnableMenuItem(32771,
MF_DISABLED| MF_BYCOMMAND|MF_GRAYED);:
//将新添加的菜单设置为失效,变灰
说明:运行程序时,会发现上面代码的最后一句没有生效。应在CMainFrame的构造函数将成员变量m_bAutoMenuEnable设为FALSE。当这个成员变量设置为TRUE时,如果菜单项没有ON_UPDATE_COMMAND_UI 或者ON_COMMAND的处理函数,用户点击弹出菜单时系统自动将菜单项设为失效。如果菜单项有ON_COMMAND的处理函数,菜单项自动被设置为有效。
三、动态增长菜单程序的编写
想实现的功能是,输入名字和电话,用空格格开,当用户按下回车键时把名字加入主菜单中,点击相应的菜单显示相应的名字和电话信息。
1. 在CView中定义成员变量
CString m_strLine; //用于记录用户的键盘输入
CMenu m_mnuPhone; //用于产生弹出菜单
int m_nIndex; //用于为菜单产生可变的ID
CStringArray m_aInput; //用于保存用户所有的用户输入
2. 在ViewàResource Symbols 中New一个ID,用于为菜单的ID赋值,把它命名为IDM_PHONE。
3. 在CView中加入WM_CHAR消息的响应函数OnChar,加入以下代码:
if(0xd==nChar)
//如果输入的是回车键,就动态添加菜单
{
if(!m_mnuPhone.m_hMenu)
//如果弹出菜单没有产生
{
m_mnuPhone.CreatePopupMenu();
//产生弹出菜单
GetParent()->GetMenu()->AppendMenu(
MF_POPUP,
(UINT)m_mnuPhone.m_hMenu,
"Phone");
//将弹出菜单添加到主窗口的菜单上
GetParent()->DrawMenuBar();
//重绘菜单
}
m_mnuPhone.AppendMenu(MF_STRING,
IDM_PHONE+m_nIndex,
m_strLine.Left(m_strLine.Find(" ")));
//将用户输入的姓名(空格前面的字符)添加到弹出菜单上
m_aInput.Add(m_strLine);
//将用户输入的字符串保存到动态数组中
m_strLine.Empty();
//清空字符串,以便用户下次输入
m_nIndex++;//
Invalidate();
//使窗口重绘
}
else
{ //不是回车键
CClientDC dc(this); //生成DC
m_strLine+=nChar ; //将输入的字符保存
dc.TextOut(0,0,m_strLine); //输出到View上
}
说明:
a. 在窗口显示以后(如CView中的OnChar中)再添加菜单,需要调用DrawMenuBar()函数重绘一下菜单,否则新加入的菜单不会显示出来。而在在窗口显示之前(如CMainFrame的OnCreate中)则不用。
b. Invalidate()函数使窗口的全部客户区失效,它只是向窗口的消息队列中发送一个WM_PAINT消息,马上返回Invalidate()的下一句去执行,等Invalidate()所在的函数执行完毕之后,WM_PAINT消息才有机会被取到,去执行刷新操作。所以,如果在Invalidate()之后的代码中输出字符或图形,也将被稍后的刷新操作冲掉,不会看到输出效果。
4. 为动态产生的菜单添加响应函数
a. 手工添加:
i. 在CView中的消息映射表中添加消息映射:
ON_COMMAND(IDM_PHONE, OnPhone)
ii. 为CView添加成员函数OnPhone,
afx_msg void OnPhone1();
iii. 在OnPhone中添加代码:
void CMenu2View::OnPhone1()
{
MessageBox("phone1");
}
b. 利用ClassWizard添加:
i. 在资源面板里增加一个菜单,将其ID指定为IDM_PHONE
ii. 这时用ClassWizard可以为IDM_PHONE添加响应函数
iii. 从资源面板里删除刚刚增加的菜单项
c. 在OnCommand中添加控制代码:
所有的WM_COMMAND消息都会交给拥有菜单的窗口的成员函数OnCommand去处理,可以在其中处理所有的动态添加的菜单。
在CMainFrame中添加虚函数OnCommand,加入代码:
int nId=LOWORD(wParam); //取出菜单的ID
int nIndex=((CMenu2View*)GetActiveView())->m_nIndex;
//在CMainFrame中访问CView中的变量
if( nId >=IDM_PHONE && nId < IDM_PHONE+nIndex)
{ //判断如果是动态添加的菜单消息
CClientDC dc(GetActiveView());
//生成一个CView的DC
dc.TextOut(0,0,
((CMenu2View*)GetActiveView())->m_aInput.GetAt(nId-IDM_PHONE));
//在CMainFrame将保存在动态字符数组中的字符串打印到View上
return true;//返回,表示已经处理了WM_COMMAMD消息
}
else
return CFrameWnd::OnCommand(wParam, lParam);
//其它的WM_COMMAMD消息交由父类去处理
评论