第七课:菜单(二) 一、系统菜单: 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消息交由父类去处理

评论