MFC有关菜单的编程实现

本节学习了菜单编程方面的内容,包括静态菜单操作和动态菜单操作两大块。

静态菜单操作包括标记菜单,默认菜单,图形菜单的实现原理及具体实现,快捷弹出菜单的实现方式及其命令响应函数的添加。

动态菜单操作主要包括:如何让程序运行时产生新的子菜单和菜单项,以及如何手工地为这些新产生的菜单项命令添加消息响应处理函数。

本节还实现了如何在顶层窗口,即框架类窗口中截获对菜单命令的处理。

通过这节还应该了解Windows中消息的分类,以及菜单命令消息的路由过程,进一步熟悉Cstring类的应用。

 

静态菜单操作

//1.标记菜单(2种方法)

       //GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_BYPOSITION| MF_CHECKED);     //通过菜单项的索引设置一个标记菜单

       //GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_BYCOMMAND| MF_CHECKED);  //通过菜单项的标识设置一个标记菜单

 

       //2.默认菜单

       //GetMenu()->GetSubMenu(0)->SetDefaultItem(1,TRUE);      //通过菜单项的索引设置一个默认菜单,最后一个参数为TRUE

       //GetMenu()->GetSubMenu(0)->SetDefaultItem(ID_FILE_OPEN,FALSE);   //通过菜单项的标识设置一个默认菜单最后一个参数为FALSE

       //GetMenu()->GetSubMenu(0)->SetDefaultItem(5,TRUE);  //设置打印菜单项时索引时5,不是4,因为分隔栏在子菜单中是占据索引位置的

       //一个子菜单只能有一个默认菜单项

 

       //3.图形标记菜单

 

       /*CStringstr;

       str.Format("x=%d,y=%d",GetSystemMetrics(SM_CXMENUCHECK),GetSystemMetrics(SM_CYMENUCHECK));

       //CString类的Format函数可以按照一定的格式把内容格式化,然后将结果保存到CString类型的字符串对象中

       //GetSystemMetrics()函数可以取得窗口上各种资源的尺寸,根据参数决定

       //根据取得的尺寸信息可知,位图大小应该是13*13;

       MessageBox(str);*/

 

       //m_bitmap.LoadBitmap(IDB_BITMAP1);

       //GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(0,MF_BYPOSITION,&m_bitmap,&m_bitmap);//运行程序发现不显示位图,

       //原因在于位图太大,只是显示了位图左上角的一小部分内容。

 

       //4.禁用菜单项

   //GetMenu()->GetSubMenu(0)->EnableMenuItem(1,MF_BYPOSITION |MF_DISABLED | MF_GRAYED);

       //GetMenu()->GetSubMenu(0)->EnableMenuItem(ID_FILE_OPEN,MF_BYCOMMAND| MF_DISABLED | MF_GRAYED);

       //在构造函数中修改成员变量才能使这行代码起作用m_bAutoMenuEnable= FALSE;

       //MF_DISABLED| MF_GRAYED这两个标志一起使用

 

   //5.移除和装载菜单

       //SetMenu(NULL);//移除

   //装载

       //CMenumenu;

   //menu.LoadMenu(IDR_MAINFRAME);

       //SetMenu(&menu);  

       //menu是个局部变量,在程序运行时,点击“打印预览”,关闭“打印预览”,再关闭程序,程序会报错

       //解决办法是把menu定义为CMainFram类的成员变量

       //还可以用Detach函数把菜单句柄与这个菜单对象分离

       //menu.Detach();

 

 

       return0;

}

 

       //m_bAutoMenuEnable= FALSE;  

       //一旦在CMainFrame类的构造函数中把成员变量m_bAutoMenuEnable =FALSE;后,就不需要对ON_UPDATE_COMMAND_UI

       //或ON_COMMAND消息进行响应处理了,CMenu类的EnableMenuItem函数将能正常工作。

       //但是在Menu程序编辑子菜单下的几个菜单项不在以灰色显示了,因为m_bAutoMenuEnable= FALSE后,

       //MFC就不在利用它的菜单命令更新机制去判断哪个菜单可以使用,哪个菜单不能够使用,所以其也就不能根据菜单项的状态以不同的外观

       //来显示。而菜单能否使用这些判断操作,就需要我们自己去完成了

       //说实话,命令更新机制讲的不清楚啊!不明白啊!

 

//6.MFC菜单命令更新机制

//在消息映射中添加ON_UPDATE_COMMAND_UI宏来捕获CN_UPDATE_COMMAND_UI消息

void CMainFrame::OnUpdateEditCut(CCmdUI*pCmdUI)

{

       //TODO: Add your command update UI handler code here

       //pCmdUI->Enable();//在这样的消息中带有一个指向CCmdUI对象的指针,可以用它调用相应的功能函数

       //在工具栏中剪切的标识和菜单栏中的剪切标识是一样,所以两者都被启用了。

       if(2== pCmdUI->m_nIndex) //判断当前是否是新建菜单项,实际中无需判断,MFC调用菜单命令更新函数时,已经确定了特定的菜单项。

              pCmdUI->Enable();  

}

 

void CMainFrame::OnUpdateFileNew(CCmdUI*pCmdUI)

{

       //TODO: Add your command update UI handler code here

       //if(ID_FILE_NEW== pCmdUI->m_nID)  //根据标识判断,工具栏中,菜单栏中的剪切都被禁用

       if(0== pCmdUI->m_nIndex)    //根据索引判断,工具栏中的剪切不被禁用,两者索引不同!

              pCmdUI->Enable(FALSE);

}

//如果要在程序中设置某个菜单项的状态,首先通过ClassWizard为这个菜单项添加ON_UPDATE_COMMAND_UI消息响应函数,然后再这个

//函数中进行状态的设置即可!

 

void CMainFrame::OnShow()

{

       //TODO: Add your command handler code here

       MessageBox("Mainshow");

}

 

//动态菜单操作

       //1.添加菜单项目

       /*CMenumenu;

       menu.CreateMenu();//创建一个菜单,然后将其与一个CMenu对象相关联起来。

       GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"Test");  //添加菜单项

       menu.Detach();//将菜单句柄与菜单对象之间的关联断开*/

 

       //2.插入菜单项目

       /*CMenumenu;

       menu.CreateMenu();//创建一个菜单,然后将其与一个CMenu对象相关联起来。

       GetMenu()->InsertMenu(2,MF_POPUP|MF_BYPOSITION, (UINT)menu.m_hMenu,"Test");

       menu.AppendMenu(MF_STRING,IDM_HELLO,"Hello");

       menu.AppendMenu(MF_STRING,112,"Bye");

       menu.AppendMenu(MF_STRING,113,"Mybole");

       menu.Detach();

       GetMenu()->GetSubMenu(0)->AppendMenu(MF_STRING,114,"Welcome");

       GetMenu()->GetSubMenu(0)->InsertMenu(ID_FILE_OPEN,MF_STRING| MF_BYCOMMAND,115,"VC编程");

       //3.删除菜单

       GetMenu()->DeleteMenu(1,MF_BYPOSITION);

       GetMenu()->GetSubMenu(0)->DeleteMenu(2,MF_BYPOSITION);*/

 

//4.动态添加的菜单项的命令响应

void CMainFrame::OnHello()

{

       MessageBox("Hello");

}

 

ON_COMMAND(IDM_HELLO,OnHello)

afx_msg void OnHello();

 

//5.电话本示例程序

void CMenu2View::OnChar(UINT nChar, UINTnRepCnt, UINT nFlags)

{

       CClientDCdc(this);

       if(0x0d== nChar)

       {

              if(0== ++m_nIndex)

              {

                     m_menu.CreatePopupMenu();

                     GetParent()->GetMenu()->AppendMenu(MF_POPUP,(UINT)m_menu.m_hMenu,"phoneBook");//菜单是框架类窗口的,要用GetParent()

                     //取到框架窗口的指针

           GetParent()->DrawMenuBar();//取得框架窗口的指针,然后重绘菜单栏,才会在按下回车键后显示先添加的菜单!

                     //在CMainFrame中不需要这样做,是因为代码是在OnCreate中添加的,窗口还未创建完成

                     //而此时窗口已经创建完成

              }

              m_menu.AppendMenu(MF_STRING,IDM_PHONE1+ m_nIndex,m_strLine.Left(m_strLine.Find(' ')));//取得输入的内容空格以前的内容,添加到菜单项中

              m_strArray.Add(m_strLine);//m_strArray是定义的一个CStringArray的集合类

              //MFC为我们提供了一些非常有用的集合类,这些集合类类似于数组的功能,但他们可以很方便的动态增加和删除元素。

              m_strLine.Empty();//在按下回车键后,清空字符串的内容,再次输入时显示的就是新输入的,不会在先前的后面输出了

              Invalidate();//让窗口的整个客户区无效,这样,当下一条WM_PAINT消息发生时,窗口就会被更新。不然再次输入的内容

              //会再先前输入的内容上面显示。默认参数是TRUE,在窗口重绘时就会把窗口的背景擦除掉。为FALSE时保留窗口的背景

       }

       else

       {

              m_strLine+= nChar;

              dc.TextOut(0,0,m_strLine);

       }

       CView::OnChar(nChar,nRepCnt, nFlags);

}

 

void CMenu2View::OnPhone1()

{

       //TODO: Add your command handler code here

       CClientDCdc(this);

       dc.TextOut(0,0,m_strArray.GetAt(0));

}

 

void CMenu2View::OnPhone2()

{

       //TODO: Add your command handler code here

       CClientDCdc(this);

       dc.TextOut(0,0,m_strArray.GetAt(1));

}

 

void CMenu2View::OnPhone3()

{

       //TODO: Add your command handler code here

       CClientDCdc(this);

       dc.TextOut(0,0,m_strArray.GetAt(2));

}

 

void CMenu2View::OnPhone4()

{

       //TODO: Add your command handler code here

       CClientDCdc(this);

       dc.TextOut(0,0,m_strArray.GetAt(3));

}

 

       ON_COMMAND(IDM_PHONE1,OnPhone1)   //这些代码要放到注释宏外面,如果放在里面,在ClassWizard对话框中,在Message Maps选项卡下

       ON_COMMAND(IDM_PHONE2,OnPhone2)   //的Member functions列表中就会列出这些函数,放在外面就不会列出来。当ClassWizard发现

       ON_COMMAND(IDM_PHONE3,OnPhone3)   //菜单项已经被删除了的时候,它就会把已为该菜单项添加的消息映射宏也删除了,这样,消息映射宏

       ON_COMMAND(IDM_PHONE4,OnPhone4)   //的三个环节就断了一环,程序就会出错。

 

       afx_msgvoid OnPhone1();   //放在两个注释宏之间也没有错

       afx_msgvoid OnPhone2();   //但为了区分这是自己手动添加的,可以把它们拿出来放在两个AFX_MSG注释宏之后。

       afx_msgvoid OnPhone3();

       afx_msgvoid OnPhone4();

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章