第6章菜单、工具栏和状态栏6.1菜单6.2工具栏6.3状态栏6.4交互对象的动态更新6.1菜单对于菜单的显示都遵循下列一些规则:若点击某菜单项会弹出一对话框,那么在该菜单项文本后有“…”。若某项菜单有子菜单,那么在该菜单项文本后有“”。菜单项需要助记符,用括号将带下划线的字母括起来。助记符与Alt构成一个组合键,当按住“Alt”键不放,再敲击该字母时,对应的菜单项就会被选中。若某项菜单需要快捷键的支持,则一般将其列在相应菜单项文本之后。任何时候按下快捷键,相应的菜单命令都会被执行。图6.1File菜单6.1菜单6.1.1用编辑器设计菜单编辑菜单在菜单的空位置上双击鼠标左键,则出现它的属性对话框,如图。图6.2菜单编辑器菜单的空位置6.1菜单图6.3菜单属性对话框6.1菜单需要注意的是:当菜单项的属性中选中了Pop_up时,对话框中ID、Separator和Prompt项无效。增加新的菜单项后,用户可以用鼠标将菜单项拖到其他位置,而当菜单项位置改变时,其属性并没改变。菜单项被拖动的位置图6.4拖动菜单项图6.5添加的菜单项6.1菜单菜单命令的消息映射[例Ex_Mmenu]“成绩输入”菜单项的映射。(1)选择“View”菜单“ClassWizard”命令项或按Ctrl+w快捷键,则出现MFCClassWizard对话框,切换到MessageMaps页面。(2)从“Classname”列表中选择CMainFrame,在IDs列表中选择ID_SCORE_IN,然后在Messages框中选择COMMAND消息,如图。图6.6消息的选择6.1菜单(3)单击[AddFunction]按钮或双击COMMAND消息,输入成员函数的名称。如图。(4)单击[OK]。选择新增加的成员函数,单击[EditCode]按钮(或直接在函数名双击鼠标左键),就可以在此成员函数中添加一些代码。例如:voidCMainFrame::OnScoreIn(){//TODO:AddyourcommandhandlercodehereAfxMessageBox(现在就输入成绩吗?);}(5)编译并运行。在应用程序的顶层菜单上,单击“成绩输入”菜单项或按Alt+S组合键,如图。图6.7添加成员函数对话框图6.8菜单命令执行的结果6.1菜单6.1.2使用键盘快捷键(1)先打开上例的项目工作区窗口中Accelerator的资源项,双击IDR_MAINFRAME,如图。图6.9示例Ex_Sdi的加速键资源最下端的空行6.1菜单(2)要建立一新的加速键,双击加速键列表的最下端的空行,如图,其中可设置的属性如表(3)在上述对话框中,选择在Ex_Sdi示例中添加的“成绩输入”菜单项的ID号ID_SCORE_IN作为要联用的加速键的ID号,单击[NextKeyTyped],按下Ctrl+1作为此加速键的键值。图6.10“AccelProperities”对话框6.1菜单6.1.3菜单的编程控制菜单的基本操作(1)创建菜单CMenu类的CreateMenu和CreatePopupMenu用来创建一个菜单或子菜单框架,原型如下:BOOLCreateMenu();//产生一个空菜单BOOLCreatePopupMenu();//产生一个空的弹出式子菜单(2)装入菜单将菜单从资源装入应用程序中,需调用CMenu成员函数LoadMenu,或者用SetMenu对应用程序菜单进行重新设置。BOOLLoadMenu(LPCTSTRlpszResourceName);BOOLLoadMenu(UINTnIDResource);(3)添加菜单项菜单创建后,可调用AppendMenu或InsertMenu函数添加一些菜单项。AppendMenu是将菜单项添加在菜单的末尾处,InsertMenu在菜单的指定位置处插入菜单项,并将后面的菜单项依次下移。BOOLAppendMenu(UINTnFlags,UINTnIDNewItem=0,LPCTSTRlpszNewItem=NULL);BOOLAppendMenu(UINTnFlags,UINTnIDNewItem,constCBitmap*pBmp);BOOLInsertMenu(UINTnPosition,UINTnFlags,UINTnIDNewItem=0,LPCTSTRlpszNewItem=NULL);BOOLInsertMenu(UINTnPosition,UINTnFlags,UINTnIDNewItem,constCBitmap*pBmp);6.1菜单需要注意的是:nFlags为MF_BYPOSITION时,nPosition表示新菜单项要插入的具体位置,为0时表示第一个菜单项,为-1时,将菜单项添加菜单的末尾处。nFlags的标志中,可以用“|”(按位或)来组合,例如MF_CHECKED|MF_STRING等。有些组合是不允许的,例如MF_DISABLED、MF_ENABLED和MF_GRAYED,MF_STRING、MF_OWNERDRAW、MF_SEPARATOR和位图,MF_CHECKED和MF_UNCHECKED都不能组合在一起。当菜单项增加后,不管菜单依附的窗口是否改变,都应调用CWnd::DrawMenuBar来更新菜单。6.1菜单(4)删除菜单项调用DeleteMenu函数可将指定的菜单项删除,需要注意的是:调用该函数后,不管菜单依附的窗口是否改变,都应调用CWnd::DrawMenuBar使菜单更新。函数DeleteMenu的原型如下:BOOLDeleteMenu(UINTnPosition,UINTnFlags);nPosition表示要删除的菜单项位置,它由nFlags进行说明。若当nFlags为MF_BYCOMMAND时,nPosition表示菜单项的ID号,而当nFlags为MF_BYPOSITION时,nPosition表示菜单项的位置(第一个菜单项位置为0)。(5)获取菜单项下面的三个CMenu成员函数分别获得菜单的项数、菜单项的ID号以及弹出式子菜单的句柄。UINTGetMenuItemCount()const;该函数用来获得菜单的菜单项数,调用失败后返回-1。UINTGetMenuItemID(intnPos)const;该函数用来获得由nPos指定菜单项位置(以0为基数)的菜单项的标识号,若nPos是SEPARATOR,则返回-1。CMenu*GetSubMenu(intnPos)const;该函数获得指定菜单的弹出式菜单的菜单句柄。该弹出式菜单位置由参数nPos指定,开始的位置为0。若菜单不存在,则创建一个临时的菜单指针。6.1菜单给系统菜单添加一个菜单项[例Ex_SysMenu]向应用系统菜单中添加一个菜单项。(1)打开一个单文档应用程序项目,若没有可按前面提及的方法进行创建。(2)选择“View”菜单“ResourceSymbols…”命令,如图。(3)单击[New],如图。在Name框中,可以指定一个用于菜单项的ID号。在Value框中,可以定义该ID的值,系统要求定义的ID值应大于15(0X000F)而小于61440(0XF000)。选择默认的ID值101,单击[OK]按钮。图6.11“ResourceSymbols”对话框图6.12“NewSymbol”对话框6.1菜单(4)在CMainFrame::OnCreate函数体(或自定义的函数)中加入代码:intCMainFrame::OnCreate(LPCREATESTRUCTlpCreateStruct){...CMenu*pSysMenu=GetMenu();//获得主菜单句柄CMenu*pSubMenu=pSysMenu-GetSubMenu(1);//获得第二个子菜单的句柄CStringStrMenuItem(新的菜单项);pSubMenu-AppendMenu(MF_SEPARATOR);//增加一水平分隔线pSubMenu-AppendMenu(MF_STRING,ID_NEW_MENUITEM,StrMenuItem);//允许使用ON_UPDATE_COMMAND_UI或ON_COMMAND的菜单项m_bAutoMenuEnable=FALSE;//使添加的菜单处于允许状态,默认为灰显pSysMenu-EnableMenuItem(ID_NEW_MENUITEM,MF_BYCOMMAND|MF_ENABLED);DrawMenuBar();//更新菜单return0;}(5)使用ClassWizard处理OnCommand消息并检测用户菜单的nID参数。BOOLCMainFrame::OnCommand(WPARAMwParam,LPARAMlParam){//wParam的低字节表示菜单、控件、加速键的命令IDif(LOWORD(wParam)==ID_NEW_MENUITEM)MessageBox(你选中了新的菜单项);returnCFrameWnd::OnCommand(wParam,lParam);}(6)编译运行并测试。6.1菜单6.1.4使用快捷菜单用资源编辑器和MFC库的CMenu::TrackPopupMenu函数创建这样的菜单,CMenu::TrackPopupMenu函数原型如下:BOOLTrackPopupMenu(UINTnFlags,intx,inty,CWnd*pWnd,LPCRECTlpRect=NULL);x和y表示菜单的水平坐标和菜单的顶端的垂直坐标。pWnd表示弹出菜单的窗口。lpRect是一个RECT结构或CRect对象指针,表示一个矩形区域,单击这个区域时,弹出菜单不消失。当lpRect为NULL时,若击在菜单外面,菜单立刻消失。6.1菜单[例Ex_Menu]创建弹出菜单。(1)选择“Insert”菜单“Resource”命令或按Ctrl+R快捷键,向应用程序项目添加一个新的菜单资源(默认的ID号为IDR_MENU1)。(2)用菜单编辑器,为该菜单资源中的顶层菜单的第一项加一任意标题(实际上该标题无用),在此菜单项下依次添加如下表所示的菜单项。(3)将此菜单资源ID号改为IDR_MYFLOATMENU。(4)按Ctrl+W快捷键打开ClassWizard,将出现一对话框,询问是“选择一个已存在的类”,还是“创建一个新类”。选择“选择一个已存在的类”项并选定CMainFrame类。6.1菜单(5)在CMainFrame类中,选择上表中所列的菜单ID,双击COMMAND消息。这是仅为菜单ID_MENU_SCOREIN映射COMMAND消息,添加代码:voidCMainFrame::OnMenuScorein(){AfxMessageBox(现在就输入成绩吗?);}(6)在CMainFrame类加入WM_CONTEXTMENU消息处理函数,代码。voidCMainFrame::OnContextMenu(CWnd*pWnd,CPointpoint){CMenumenu;menu.LoadMenu(IDR_MYFLOATMENU);menu.GetSubMenu(0)-TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);}(7)运行并测试。在应用程序的窗口客户区中单击鼠标右键,弹出如图菜单。“成绩打印”菜单命令没有消息处理函数,因此它是灰显的,用户不能使用它们。若用户选中“成绩输入”菜单命令,则会执行相应的代码。图6.13快捷菜单6.2工具栏6.2.1使用工具栏编辑器选择“File”“OpenWorkspace”,将单文档应用程序Ex_Sdi调入或重新创建。在项目工作区窗口中选择ResourceView标签,双击“Toolbar”项中的IDR_MAINFRAME,则工具栏编辑器出现在主界面的右边,如图。图6.14工具栏编辑器窗口空按钮6.2工具栏(1)创建一个