【文档说明】Visual-C++基础教程-[142页]课件.ppt,共(142)页,5.786 MB,由小橙橙上传
转载请保留链接:https://www.ichengzhen.cn/view-44715.html
以下为本文档部分文字说明:
第11章菜单、工具栏和状态栏第11章菜单、工具栏和状态栏11.1菜单11.2工具栏11.3状态栏习题第11章菜单、工具栏和状态栏11.1菜单11.1.1菜单基础Windows应用程序中,菜单的结构如图11-1所示。第11章菜单、工具栏和状态栏顶层菜单项顶层菜单下拉菜单分隔条菜单项子菜单子菜单项
图11-1菜单结构第11章菜单、工具栏和状态栏出现在窗口标题栏下的菜单栏叫做应用程序“顶层菜单”,其中的项称为“顶层菜单项”。单击顶层菜单项一般会打开一个“下拉菜单”。根据需要,顶层菜单项也可以是一个命令。下拉菜单中的菜单项称为“菜单项”。菜单项后面如果有“…”,则单击时一般会打开一个对话框,若后
面带有“”,则此菜单项带有子菜单。菜单项中带下划线的字符为菜单项的键盘助记符,对于顶层菜单,同时按下Alt+带下划线的字符则会打开其下拉菜单,对于下拉菜单中的菜单项,如果其没有子菜单,在菜单打开的情况下在键盘上按下带下划线的字符即执行此菜单项,若有子菜单则会打
开子菜单。有些菜单项后还带有快捷键,如“Compile”菜单项带有快捷键Ctrl+F7,当在键盘上按下快捷键时,就会执行此菜单命令。带有子菜单的菜单项同时作为子菜单的菜单名。第11章菜单、工具栏和状态栏Windows还支持“弹出式菜单”,当右击鼠标时弹出菜单。弹出式菜单实际上就是下拉式菜单
。MFC提供了CMenu类,用于对菜单进行控制和操作。在MFC应用程序中创建菜单时可以有如下三种方法:(1)利用菜单编辑器创建菜单资源,并在应用程序运行时加载生成的菜单。(2)用编程方法创建菜单,调用CreateMenu、Insert
Menu和CMenu类的其它函数创建、插入和操作菜单。(3)创建菜单模板,并用CMenu::LoadMenuIndirect创建菜单。第11章菜单、工具栏和状态栏11.1.2创建菜单创建菜单最简单的方法是使用VisualC++提供的菜
单编辑器。当使用AppWizard生成应用程序框架时,默认情况下已经为应用程序创建了一个菜单ID为IDR_MAINFRAME的菜单资源。可以在此菜单资源的基础上修改、添加自己的菜单项和子菜单,也可以添加
新的菜单资源。下面以实例来说明如何利用菜单编辑器创建菜单。第11章菜单、工具栏和状态栏【例11.1】编写一个单文档界面应用程序,通过菜单选择在视图窗口中画不同的图形和设置图形的颜色。程序的创建过程如下:(1)利用MFCAppW
izard[exe]创建SDI应用程序,项目名设置为MyDraw。(2)单击项目工作区窗口下的“ResourceView”标签,打开资源列表。展开“Menu”,双击Menu下的IDR_MAINFRAME即可打开菜单编辑器,如图11-2所
示。第11章菜单、工具栏和状态栏图11-2菜单编辑器第11章菜单、工具栏和状态栏(3)为程序添加顶层菜单项。双击菜单编辑器中的新菜单项框(具有虚线的空白框),打开菜单项属性对话框,如图11-3所示。在Captio
n中输入菜单项标题“画图[&D]”,菜单标题中的“&”表示“&”后面的一个字符为此菜单项的键盘助记符,并在此字符下自动添加下划线。在同一层的菜单项不允许有重复的助记符。对于顶层菜单项,属性Pop-up缺省是选中的,表示其含有下拉菜单,此时菜单项没有菜单ID。如果取消Pop-u
p属性,则此菜单即为可以执行的菜单命令。第11章菜单、工具栏和状态栏(4)为顶层菜单项添加下拉菜单项。在菜单编辑器中单击“画图[&D]”,双击下方的新菜单项框,弹出菜单项属性对话框。在ID框中输入ID_DRAW_ELLIPSE,在Caption框中输入菜单项标题“椭圆[&E]\tC
trl+E”。“&”后面的“E”为此菜单项的键盘助记符,“\t”后的“Ctrl+E”为此菜单项的快捷键。在Prompt框中输入此菜单的提示信息“在视图窗口画一个椭圆”。程序运行时,当用鼠标指向此菜单项时
,在状态栏上会显示此提示信息。第11章菜单、工具栏和状态栏图11-3菜单项属性对话框第11章菜单、工具栏和状态栏(5)重复第(3)、(4)步,设计完成的菜单如图11-4所示。图11-4程序中创建的画图和颜色菜单第11章菜单、工具栏和状态栏各菜单项的ID值
如表11-1所示。表11-1各菜单项的ID值菜单ID菜单项标题ID_DRAW_ELLIPSE椭圆[&E]\tCtrl+EID_DRAW_TRIANGLE三角形[&T]ID_DRAW_RECTANGLE矩形[&R]ID_COLOR_RED红色[&R]ID
_COLOR_GREEN绿色[&G]ID_COLOR_BLUE蓝色[&B]ID_COLOR_CUSTOM自定义...第11章菜单、工具栏和状态栏菜单属性对话框中其它属性的含义为:◆Separator:选中该属性,则菜单项将变成一个分隔
条。◆Pop-up:选中该属性,表示此菜单项包含子菜单,即创建一个弹出式菜单,否则该菜单为可执行的命令。◆Inactive:指明菜单项是不活动的。◆Break:若选择Column,则此菜单项以及下面的菜单项在新的一列显示。
当菜单项较多时,可以利用此属性将菜单项分两列显示。◆Checked:选中此属性,则在菜单项前面添加一个选中标志。◆Grayed:选中此属性,则此菜单项为灰色,禁止使用。在菜单编辑器中,用鼠标拖动菜单项可以移动位置,选中菜单项然后
单击Delete键可以删除菜单项,还可以对菜单项进行复制和粘贴。第11章菜单、工具栏和状态栏11.1.3添加菜单命令处理函数在基于MFC框架的应用程序中,如果没有为创建的菜单命令添加相应的命令消息处理函数,则此菜单命令将呈现灰色,禁止用户使用。应用程序运行时,若用户执行一
个菜单命令(通过鼠标单击或按下快捷键等方式),则向应用程序框架发送WM_COMMAND消息,消息的参数wParam的低位字保存着该菜单项的菜单ID。在基于MFC框架的应用程序中,可以在任何地方处理命令消息WM_COMMAND。实
际上,框架窗口是大多数命令消息的接收者,但命令消息可以在视图类、文档类甚至在应用程序类中被处理,只要在该类的消息映射表中添加要处理的消息的映射项即可。从CCmdTaret派生出来的所有类都可以处理命令消息。第11章菜单、工具栏和状态栏在SDI应用程序中,
命令消息的传递过程如图11-5所示。当MFC应用程序的框架窗口接收到命令消息WM_COMMAND时,它首先将消息传递给活动视图窗口,如果视图类中有此命令的处理函数,则调用此处理函数,消息传递结束,否则此命令消息传递给与视图相关联的文档。因此
,活动视图窗口首先处理命令消息,接着是与视图关联的文档、框架窗口,最后是应用程序对象。如果传递路径上的某个对象可以处理此消息,则消息传递终止。如果传递路径上所有对象都没有此消息的处理函数,则它会被传递给::DefWindowProc进行缺
省处理。第11章菜单、工具栏和状态栏∷DefWindowProc应用程序对象框架窗口文档活动视图窗口⑤④③②①图11-5SDI应用程序中命令消息的传递路径第11章菜单、工具栏和状态栏需要说明的是,只有命令消息WM_COMMAND和用户界面更新命令消息UPDATE_COMMAND_UI才遵循上述
传递机制。标准Windows消息如WM_CREATE、WM_LBUTTONDOWN等必须在接收这些消息的窗口中处理。由于命令消息可以被传递给路径上的多个对象来进行处理,因此用户应该根据命令的功能来决定将命令消息映射到哪个类中。如果菜单命令与视图的显示有关,则应该将其映
射到视图类中,即在视图类中应该只响应特定于该视图窗口的命令,如copy等。在文档类中响应对该文档修改立即有效的命令消息,然后根据消息处理的结果,更新与该文档关联的所有视图,如文档的读/写命令等。对于完成一些通用功能的命令,一般映射到框架窗口类中。第11章菜单、工具栏和状态栏添加菜单命
令处理函数可以利用类向导ClassWizard。下面给例11.1的MyDraw添加必要的代码和菜单命令处理函数,完成应用程序的功能。在视图类CMyDrawView的定义中添加如下的数据成员:protected:intm_nSh
ape;COLORREFm_crColor;在视图类CMyDrawView的构造函数中对数据成员进行初始化:CMyDrawView::CMyDrawView(){m_nShape=0;//缺省绘制椭圆m_crColor=RGB(0,0,0);//缺省图形颜色为黑色}第11章菜单、
工具栏和状态栏利用ClassWizard在视图类CMyDrawView中为菜单命令添加消息处理函数。执行“View”→“ClassWizard”菜单命令或按下Ctrl+W快捷键打开ClassWizard对话框,选中“MessageMaps”标签,在Classname框中选择类名CMyDrawV
iew,在ObjectsIDs下选择ID_DRAW_ELLIPSE(“画图”→“椭圆”菜单项的ID),在Messages框中选择COMMAND,单击“AddFunction”按钮为椭圆菜单项添加消息处理函
数,单击“EditCode”按钮打开代码编辑窗口,编辑ClassWizard生成的消息处理函数:voidCMyDrawView::OnDrawEllipse(){m_nShape=0;Invalidate();//产生WM_PAINT消
息更新视图}第11章菜单、工具栏和状态栏同样为其它菜单项添加WM_COMMAND消息处理函数如下:voidCMyDrawView::OnDrawTriangle(){m_nShape=1;Invalidate();}void
CMyDrawView::OnDrawRectangle(){m_nShape=2;Invalidate();}第11章菜单、工具栏和状态栏voidCMyDrawView::OnColorRed(){m_crColor=RGB(255,0,0);Invalidate();}voi
dCMyDrawView::OnColorGreen(){m_crColor=RGB(0,255,0);Invalidate();}voidCMyDrawView::OnColorBlue(){m_crColo
r=RGB(0,0,255);Invalidate();}第11章菜单、工具栏和状态栏voidCMyDrawView::OnColorCustom(){CColorDialogcolorDlg;//定义公用颜色对话框对象colorDlg.DoMo
dal();//显示颜色对话框m_crColor=colorDlg.GetColor();//获取用户在对话框中选择的颜色Invalidate();}第11章菜单、工具栏和状态栏编辑视图类OnDraw函数,在其中添加如下黑体代码:voidCMyDrawView::O
nDraw(CDC*pDC){CMyDrawDoc*pDoc=GetDocument();ASSERT_VALID(pDoc);//TODO:adddrawcodefornativedatahereCPointpoints[3];CRectrcClient;GetClientRect(&
rcClient);intcx=rcClient.Width()/2;intcy=rcClient.Height()/2;CRectrcShape(cx-45,cy-45,cx+45,cy+45);C
Brushbrush,*pOldBrush;brush.CreateSolidBrush(m_crColor);pOldBrush=pDC->SelectObject(&brush);第11章菜单、工具栏和状态栏switch(m_nShape){case0:rcS
hape.InflateRect(30,0);pDC->Ellipse(rcShape);break;case1:points[0].x=cx-45;points[0].y=cy+45;points[1].x=cx;points[1].y=cy-45;points[2].x=cx+45;poi
nts[2].y=cy+45;pDC->Polygon(points,3);break;第11章菜单、工具栏和状态栏case2:pDC->Rectangle(rcShape);break;}pDC->Sel
ectObject(pOldBrush);}第11章菜单、工具栏和状态栏编译、链接和运行程序,程序运行结果如图11-6所示。图11-6程序MyDraw的运行结果第11章菜单、工具栏和状态栏11.1.4更新菜单项在许多应用程序中,必须不断更新菜单中的菜单
项,使它能反映出应用程序的内部状态和数据的变化。例如在MyDraw中,当从颜色菜单中选择了一种颜色后,相应的菜单就应该加上复选标记,指明当前选中的颜色。当某个菜单命令执行的条件不具备时,应该使菜单项无效。在Windows应用程序中,经常看到灰色
的菜单项,以及菜单项前面的复选标记。MFC提供了一种简单方便的机制更新菜单项。利用ClassWizard可以为菜单项添加用户界面更新命令消息UPDATE_COMMAND_UI的处理函数,当用户打开下拉菜单时,应用程序框架调用菜单中所有菜单项的更新命令处理函数。每个更新命令处理函数都
有一个指向CCmdUI对象的指针,在处理函数中利用该对象的成员函数修改菜单项。第11章菜单、工具栏和状态栏类CCmdUI只用作在CCmdTarget派生类的用户界面更新命令消息UPDATE_COMMAND_UI的处理函
数中,类中包含有指向用户界面对象的ID值或指针,其成员函数如表11-2所示。用户界面更新处理函数只能应用于下拉菜单的菜单项,而不能应用于顶层菜单项。例如,不能使用用户界面更新处理函数来禁止一个“文件”
菜单项。第11章菜单、工具栏和状态栏表11-2CCmdUI成员函数成员函数说明Enable使用户界面对象有效或无效SetCheck设置或取消选中用户界面对象SetRadio给用户界面对象添加或删除单选标记SetTe
xt改变菜单项标题文本第11章菜单、工具栏和状态栏下面为例11.1的程序MyDraw的“画图”下拉菜单项添加用户界面更新处理函数。利用类向导ClassWizard添加用户界面更新处理函数的方法与添加命令处理函数的方法相同,区别只是在Messages列表框中选择UPDATE_COMMAND_
UI。为“画图”下拉菜单项添加的用户界面更新处理函数如下:第11章菜单、工具栏和状态栏voidCMyDrawView::OnUpdateDrawEllipse(CCmdUI*pCmdUI){pCmdUI->Enable(m
_nShape!=0);//执行“椭圆”菜单后禁用}voidCMyDrawView::OnUpdateDrawTriangle(CCmdUI*pCmdUI){pCmdUI->Enable(m_nShape!=1
);}voidCMyDrawView::OnUpdateDrawRectangle(CCmdUI*pCmdUI){pCmdUI->Enable(m_nShape!=2);}第11章菜单、工具栏和状态栏11.1.5键盘快捷键快捷键利用键盘输入方式代替执行应用程序的菜单命令或工具栏命令,可提高使用效率
。当在键盘上按下快捷键时,也会发送WM_COMMAND命令消息。在给菜单项输入标题时,字符“\t”后的字符串为此菜单项的快捷键,但要使此快捷键起作用,还需要做一些工作。在基于MFC框架的应用程序中,给菜单项或工具栏上的按钮添加键盘快捷键非常方便简单。第11章菜
单、工具栏和状态栏单击项目工作区窗口下的“ResourceView”标签,打开资源列表。展开Accelerator,双击Accelerator下的IDR_MAINFRAME,打开快捷键编辑器。用鼠标双击快捷键编辑器中的快捷键列表项可打开“AccelProperties”对话框,
可在此对话框中对快捷键进行设置。要添加新的快捷键,双击快捷键列表底部的空白行,在打开的属性对话框中即可进行设置。选中快捷键列表中的项,按Delete键可以删除快捷键。下面为MyDraw程序的“椭圆”菜单添加快捷键。双击快捷键列表底部的空白行,打开属性
对话框,如图11-7所示。第11章菜单、工具栏和状态栏图11-7快捷键属性对话框第11章菜单、工具栏和状态栏在ID下拉列表框中选中“画图”菜单的ID值ID_DRAW_ELLIPSE,在Key栏中输入“E”
,在Modifiers中选中Ctrl,则“画图”菜单项的快捷键为Ctrl+E。由于快捷键总是配合菜单或工具栏命令按钮使用,因此,不必为快捷键添加命令处理函数,它共用与其ID值相同的菜单或工具栏命令按钮的消息处理函数。第11章菜单、工具栏和状态栏11.1.6快捷菜单快捷菜
单也称为弹出式菜单或上下文菜单,当用户右击鼠标时,快捷菜单出现在鼠标指针所在位置。快捷菜单可以利用菜单栏上的已有下拉菜单创建,也可为快捷菜单添加新的菜单资源。当用户单击鼠标右键时会产生WM_CONTEXTMENU消息,可以
在应用程序中为此消息添加消息处理函数,在消息处理函数中调用CMenu::TrackPopupMenu可显示快捷菜单。函数原型为:BOOLTrackPopupMenu(UINTnFlags,intx,int
y,CWnd*pWnd,LPCRECTlpRect=NULL);第11章菜单、工具栏和状态栏其中,参数“nFlags”确定快捷菜单相对于x值的水平对齐方式以及哪一个鼠标按钮用来选中菜单中的菜单项。对齐标志TPM_CENTERALIGN、TPM_L
EFTALIGN和TPM_RIGHTALIGN分别指定快捷菜单与x值水平居中、左对齐和右对齐。TPM_LEFTBUTTON和TPM_RIGHTBUTTON标志确定鼠标左键或右键是否能进行菜单项选择。参数“x”和“y”确定菜单在屏幕上的位置。参数“pWnd”标识拥有此快
捷菜单的窗口。第11章菜单、工具栏和状态栏在使用菜单栏上的下拉菜单创建快捷菜单时,首先要获得指向下拉菜单的指针,这可以通过调用CWnd::GetMenu和CMenu::GetSubMenu函数获得。函数GetMenu可以获得指向菜单栏的指针(菜单栏位于框架窗口内,子窗
口没有菜单)。函数GetSubMenu获得指向下拉菜单的指针,其参数指定包含下拉菜单的菜单项在菜单中的位置,第一个菜单项位置为0。下面为例11.1的MyDraw添加快捷菜单,当用户右击视图窗口时,弹出“颜色
”菜单。利用ClassWizard在视图类中添加消息WM_CONTEXTMENU的处理函数,在函数中添加如下黑体代码:第11章菜单、工具栏和状态栏voidCMyDrawView::OnContextMenu
(CWnd*pWnd,CPointpoint){CWnd*pParent=GetParent();//获得指向视图窗口父窗口(框架窗口)的指针CMenu*pMenu=pParent->GetMenu();//获得指向顶层菜单的指针//获得颜色菜单的指针,颜色菜单在顶层
菜单中位于第6项CMenu*pSubMenu=pMenu->GetSubMenu(5);pSubMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON,point.x,point.y,this);}第11章菜单、工具
栏和状态栏编译、链接和运行程序,当在视图窗口中右击鼠标时,弹出快捷菜单,如图11-8所示。图11-8MyDraw的快捷菜单第11章菜单、工具栏和状态栏11.1.7动态修改菜单MFC应用程序可以在程序运行过程中动态增加、修
改和删除菜单。CMenu类中提供了对菜单进行操作的相应的成员函数。CMenu类中用于增加、修改和删除菜单的成员函数如表11-3所示。第11章菜单、工具栏和状态栏表11-3CMenu类中用于修改菜单的成员函数成员函数说明AppendMenu在菜单尾部添加一个菜单项I
nsertMenu在菜单指定位置插入一个菜单项ModifyMenu修改指定菜单项的ID、标题或其它属性RemoveMenu删除指定的菜单项,但不删除其子菜单DeleteMenu删除指定的菜单项及其子菜单第11章菜单、工具栏和状态栏11.1.8用代码创建菜单除了利用菜单编辑器
创建菜单外,用MFC的CMenu类和它的成员函数通过编程也可以创建菜单。CMenu类中用于创建菜单的成员函数有CreateMenu、CreatePopupMenu和AppendMenu。函数CreateMenu用于创建菜单,CreatePopupMenu用于创建子菜单,AppendMen
u用于向子菜单中添加菜单项或将子菜单挂接到顶层菜单上。第11章菜单、工具栏和状态栏【例11.2】在应用程序MyDraw中通过编程增加两个菜单“缩放”和“修改菜单”。编程和实现方法如下:(1)为将要新增的菜单定义ID值。由于每一个菜单项都必须有唯一的一个ID值,因此,在增加菜单之前必须为新的
菜单项定义一个ID值。单击项目工作区窗口下的FileView标签,展开SourceFiles,双击Resource.h打开资源头文件,在其中添加如下的菜单ID值的定义:#defineID_ZOOM_IN
110#defineID_ZOOM_OUT120#defineID_MODIFY_ADD130#defineID_MODIFY_DEL140#defineID_DRAW_TEXT150第11章菜单、工具栏和状态栏(2)编程创建两个子菜单,并将其添加到顶层菜单中。由于在SDI中菜单
属于主框架窗口,因此将创建菜单的代码添加在主框架窗口类中。在CMainFrame类的OnCreate成员函数中添加如下的代码:intCMainFrame::OnCreate(LPCREATESTRUCT
lpCreateStruct){CMenu*pmainMenu;pmainMenu=GetMenu();//获取指向主菜单的指针CMenusubMenu;subMenu.CreatePopupMenu();//创建子菜单subMe
nu.AppendMenu(MF_STRING,ID_ZOOM_IN,“放大”);//添加菜单项subMenu.AppendMenu(MF_STRING,ID_ZOOM_OUT,“缩小”);//将子菜单挂接到主菜单上pmainMenu->AppendMenu(MF_P
OPUP,(UINT)subMenu.Detach(),"缩放(&Z)");第11章菜单、工具栏和状态栏subMenu.CreatePopupMenu();subMenu.AppendMenu(MF_STRING,ID_MODIFY_ADD,"增加");subMenu.A
ppendMenu(MF_STRING,ID_MODIFY_DEL,"删除");pmainMenu->AppendMenu(MF_POPUP,(UINT)subMenu.Detach(),"修改菜单");pmainMenu->Detach();//将主菜单与CMenu对象分离return
0;}第11章菜单、工具栏和状态栏(3)通过第(2)步,已经创建了两个下拉菜单“缩放”和“修改菜单”,下面需要给创建的子菜单项添加命令处理函数,否则,创建的菜单在运行时禁止使用。对于通过编程创建的菜单项
,不能利用ClassWizard为其添加命令消息处理函数,因此只能手工添加消息处理函数。对于每一个消息处理函数,需要添加函数原型、消息映射项和函数体。打开视图类的头文件MyDrawView.h,在其中找到DECLARE_MESSAGE_MAP,在
DECLARE_MESSAGE_MAP之上、注释“//}}AFX_MSG”之下添加消息处理函数原型:第11章菜单、工具栏和状态栏classCMyDrawView:publicCView{protected://{{AFX_MSG(CMyDrawView)//}}AFX_M
SGafx_msgvoidOnZoomIn();afx_msgvoidOnZoomOut();afx_msgvoidOnModifyAdd();afx_msgvoidOnModifyDel();afx_msgvo
idOnDrawText();DECLARE_MESSAGE_MAP()};第11章菜单、工具栏和状态栏手工添加的消息处理函数原型应该添加在注释对“//}}AFX_MSG”的外面,注释对中间的部分为ClassWiz
ard添加和管理。在视图类的实现文件MyDrawView.cpp中添加消息映射项。打开MyDrawView.cpp文件,在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间添加消息映射项。手工添加的消息映射项应该在注释对“//}}AFX_MSG_MAP”之外:第11章菜单
、工具栏和状态栏BEGIN_MESSAGE_MAP(CMyDrawView,CView)//{{AFX_MSG_MAP(CMyDrawView)//}}AFX_MSG_MAPON_COMMAND(ID_ZOOM_IN,OnZoomIn)ON_COMMAND(ID_ZOOM_OUT,On
ZoomOut)ON_COMMAND(ID_MODIFY_ADD,OnModifyAdd)ON_COMMAND(ID_MODIFY_DEL,OnModifyDel)ON_COMMAND(ID_DRAW_TEXT,OnDrawTe
xt)//StandardprintingcommandsEND_MESSAGE_MAP()第11章菜单、工具栏和状态栏在视图类的实现文件MyDrawView.cpp中添加消息处理函数的函数体如下:voidCMyDrawView::OnZoomIn(){m_nFl
ag=1;//设置放大标志Invalidate();//更新视图}voidCMyDrawView::OnZoomOut(){m_nFlag=2;Invalidate();}第11章菜单、工具栏和状态栏voidCMyDraw
View::OnModifyAdd(){//在“画图”菜单下增加菜单项“文本”CWnd*pParent=GetParent();CMenu*pMenu=pParent->GetMenu();CMenu*pSubMenu=pMenu->GetSubMenu(4);pSubM
enu->AppendMenu(MF_STRING,ID_DRAW_TEXT,"文本");}第11章菜单、工具栏和状态栏voidCMyDrawView::OnModifyDel(){//删除“画图”菜单下增
加的菜单项CWnd*pParent=GetParent();CMenu*pMenu=pParent->GetMenu();CMenu*pSubMenu=pMenu->GetSubMenu(4);pSubMenu->RemoveMenu(ID_DRAW_TEXT,MF_BYCOMM
AND);}//新增菜单的命令消息处理函数voidCMyDrawView::OnDrawText(){m_nShape=3;Invalidate();}第11章菜单、工具栏和状态栏(4)修改视图类的OnDraw以适应菜单的变化。在
CMyDrawView类的定义中增加一个int数据成员m_nFag,用于记录执行创建菜单“缩放”的情况,并在构造函数中将其初始化为0。修改OnDraw,在其中增加如下的黑体代码:voidCMyDrawView::OnDraw(CDC*pDC){switch(m_nFlag){cas
e1:rcShape.InflateRect(50,50);break;case2:rcShape.DeflateRect(10,10);break;}第11章菜单、工具栏和状态栏switch(m_nShape){case3:pDC->Dr
awText("执行了增加的菜单",rcShape,DT_WORDBREAK|DT_CENTER|DT_VCENTER);break;}pDC->SelectObject(pOldBrush);}第11章菜
单、工具栏和状态栏编译、链接和运行程序,运行结果如图11-9所示。图11-9用代码创建菜单的执行结果第11章菜单、工具栏和状态栏11.1.9使用菜单资源使用AppWizard创建应用程序框架时,应用程序框架中已经添加了IDR_MAINFRAME的菜单资
源,可以在此菜单资源的基础上修改和添加应用程序的菜单。除了可以使用缺省生成的菜单资源外,在应用程序中还可以创建用户自己的菜单资源。第11章菜单、工具栏和状态栏为了在程序中使用自己的菜单资源,首先需要利用CMenu::Load
Menu从应用程序中装载菜单资源并与CMenu对象关联,函数原型为:BOOLLoadMenu(UINTnIDResource);其中,参数“nIDResource”指定装载的菜单资源ID。然后利用CWnd::SetMenu将与菜单资
源关联的CMenu对象设置为当前菜单,函数原型为:BOOLSetMenu(CMenu*pMenu);其中,参数“pMenu”指定新的菜单对象。第11章菜单、工具栏和状态栏【例11.3】在应用程序MyDraw中创建一个英文的菜单资源
,并允许在中、英文菜单之间进行切换。编程和实现方法如下:(1)在IDR_MAINFRAME菜单资源中增加一个“英文”顶层菜单命令。在项目工作区窗口中选中“ResourceView”标签,在窗口中双击IDR_MAINFRAME打开菜单资源,增加顶层菜单命令“英文”,取消其Pop-u
p属性,指定其ID值为ID_ENGLISH,Caption标题为“英文”。(2)插入新的菜单资源,创建新菜单。单击项目工作区窗口的“ResourceView”标签,在窗口中右击Menu,选择“InsertMenu”菜单命令,插入新
的菜单资源。右击插入的菜单资源ID,选择“Properties”菜单命令,在弹出的对话框中将插入的菜单资源的ID修改为IDR_ENGLISH。第11章菜单、工具栏和状态栏在插入的菜单资源中添加如图11-10所示的菜单。为了与中文菜单共用相同的菜单命令消息处理
函数,各对应菜单的ID值与IDR_MAINFRAME中的菜单ID值应相同。“Draw”菜单“Color”菜单“Chinese”菜单命令图11-10在新菜单资源中添加的菜单第11章菜单、工具栏和状态栏取消
菜单命令“Chinese”的Pop-up属性,指定其ID值为ID_CHINESE。(3)为菜单命令“英文”和“Chinese”添加命令消息处理函数,在两个菜单资源中进行切换。利用ClassWizard在主框架窗口类CMainFrame中添加两个菜单
命令的消息处理函数:voidCMainFrame::OnChinese(){CMenum_Menu;//定义菜单对象m_Menu.LoadMenu(IDR_MAINFRAME);//装载菜单资源SetMenu(&m_
Menu);//将装载的菜单资源设置为当前菜单m_Menu.Detach();//将菜单与CMenu对象分离}第11章菜单、工具栏和状态栏voidCMainFrame::OnEnglish(){CMenu
m_Menu;m_Menu.LoadMenu(IDR_ENGLISH);SetMenu(&m_Menu);m_Menu.Detach();}编译、链接和运行程序,当执行“英文”命令时切换到英文菜单(如图11-11所示),执行“Chinese”命令时切换到中文菜单
。两套菜单命令使用相同的消息处理函数。第11章菜单、工具栏和状态栏图11-11切换到英文菜单的结果第11章菜单、工具栏和状态栏11.2工具栏11.2.1工具栏编辑器在工具栏上,所有工具栏按钮都存储于一个位图资源中。默认方式下,每个按
钮图像都是16个像素宽、15个像素高。应用程序框架给按钮提供了一个边框,并通过改变这些边框和按钮的图像颜色来反映当前按钮的状态。图11-12显示了工具栏位图和与之对应的工具栏。第11章菜单、工具栏和状态栏图11-12工具栏位图和实际的工具栏第11章菜
单、工具栏和状态栏在VisualC++中,可以使用工具栏编辑器对工具栏进行编辑和修改,也可以插入新的工具栏资源。选中项目工作区窗口中的“ResourceView”标签,在窗口中展开“Toolbar”,双击其中的工具栏资源,出现如图11-13所示的工具栏编辑器和绘图工具栏
(Graphics)、调色板(Colors)工具栏。工具栏编辑器实际上是一个图像编辑器,利用它可以在工具栏上添加按钮、编辑按钮和删除按钮。第11章菜单、工具栏和状态栏图11-13工具栏编辑器第11章菜单、工具栏和状态栏1.添加新的工具栏执行“I
nsert”→“Resource”菜单命令(或按快捷键Ctrl+R),在“插入资源”对话框中双击Toolbar,或者在项目工作区窗口的ResourceView标签窗口中右击Toolbar,选择“InsertToolbar”菜单命令。新添加的工具栏自动在工具栏编辑器中打开,其
中有一个空白按钮。第11章菜单、工具栏和状态栏2.添加和编辑按钮打开要编辑的工具栏,在工具栏最右侧会显示一个空白按钮,用鼠标单击此按钮即可在按钮编辑窗口中设计按钮。当创建和编辑一个新的按钮时,在工具栏右侧会自动出现一个新的空白
按钮。要编辑修改已有的按钮,只需要单击选中该按钮,即可在按钮编辑窗口中进行编辑和修改。第11章菜单、工具栏和状态栏在工具栏上拖动并将其放在工具栏中的新位置就可以移动按钮。在工具栏上拖动按钮离开工具栏可以删除按钮。3.按钮属性设置按钮的属性包括按钮ID值、宽度、高度以及工具
提示信息。选中要设置属性的按钮,然后在按钮显示窗口或按钮编辑窗口的空白处双击或选中按钮后按Alt+Enter快捷键,或者直接双击工具栏上相应的按钮,可打开如图11-14所示的工具栏按钮属性对话框。第11章菜单、工具栏和状态栏图11-14工具栏按钮属性对话框第11章
菜单、工具栏和状态栏ID框中的下拉列表中列出了当前应用程序中已有的ID值,如果需要按钮与某个菜单命令对应,可以在此列表中选择相应菜单项的ID值,则此按钮与对应的菜单命令共用同一个命令消息处理函数。如果按钮没有对应的菜单命令,则可以输
入一个新的ID值。按钮图像的缺省大小为16个像素宽、15个像素高,可以在属性对话框中进行修改。当修改一个按钮的大小后,工具栏上所有的按钮会同时变化。在Prompt框中可以为按钮添加说明和提示信息,输入的内容可以分为两个部分,中间用“\n”分隔,前面部
分为鼠标指向该按钮时状态栏上的显示信息,后面部分为按钮工具提示,即当鼠标停留在按钮上时鼠标下面显示的提示。第11章菜单、工具栏和状态栏4.在工具栏按钮间添加空格工具栏按钮间的空格对应程序运行时按钮间的垂直或水平分隔条。在按钮间插入空格的方法如下:如果要在按钮左侧插入空格且
此按钮右侧没有空格,拖动此按钮向右移动直到其覆盖下一个按钮的一半时释放。如果要在按钮左侧插入空格且此按钮右侧已有空格,则拖动此按钮向右移动直到其右边界接触到下一个按钮的左边界时释放。此时,会保留按钮右侧的空格。如果拖动按钮直到覆盖下一个按钮的一半时才释放,则会删除按钮右侧的
空格。如果要删除按钮间的空格,则拖动空格一侧的按钮向另一侧移动直到覆盖下一个按钮将近一半时释放。第11章菜单、工具栏和状态栏【例11.4】为例11.3的程序MyDraw的“绘图”菜单添加工具栏按钮。(1)打开应用程序项目MyDraw,单击项目工作区窗口的“Resou
rceView”标签,在窗口中展开Toolbar,双击下面的IDR_MAINFRAME打开工具栏编辑器。在工具栏的右侧添加如图11-15所示的三个按钮,同时在“矩形”按钮左侧插入一个空格。第11章菜单、工具栏和状态栏插入的空格添加的按钮图11-15为应用程序My
Draw添加的按钮第11章菜单、工具栏和状态栏(2)为添加的按钮设置属性。双击“矩形”按钮,打开属性对话框,在ID框中选择菜单“绘图”→“矩形”的ID值,在Prompt栏中输入“在视图窗口画一个矩形\n画矩形”。采用相同的方法设置其它按钮的
属性,其ID值选择与其对应菜单项的ID值。由于添加的每个按钮都有对应的菜单命令,因此不需要为按钮添加命令消息处理函数,当单击这些按钮时,其功能与执行相应菜单命令的功能相同。编译、链接和运行程序,即可以通过工具栏
按钮绘制不同的图形。第11章菜单、工具栏和状态栏11.2.2创建工具栏Windows应用程序运行时可以同时拥有多个工具栏。利用AppWizard创建应用程序框架时,默认设置已经生成了一个工具栏,在应用程
序中根据需要还可以创建新的工具栏。在MFC应用程序中创建工具栏的步骤如下:(1)在应用程序的项目工作区窗口中插入一个工具栏资源,并利用工具栏编辑器添加和编辑按钮,设置按钮属性。(2)构造一个CToolBar类的对象。(3)调用CToolBar::Create或CreateEx函数创建工具栏。第11
章菜单、工具栏和状态栏CToolBar::Create函数原型为:BOOLCreate(CWnd*pParentWnd,DWORDdwStyle=WS_CHILD|WS_VISIBLE|CBRS_TOP,UINTnID=AFX_IDW_TOOLBAR);其中,参数“pParentWn
d”为指向工具栏窗口父窗口的指针,参数“dwStyle”指明工具栏的风格。由于工具栏本身也是一个窗口,因此参数dwStyle可以指明窗口的风格,如WS_CHILD|WS_VISIBLE指明是一个子窗口并可见。同时工具栏还有一些附加
的风格,如表11-4所示。参数“nID”是工具栏子窗口ID。调用CreateEx创建工具栏时,除了可以指明Create中使用的工具栏风格外,还可以给工具栏指明附加的风格,如TBSTYLE_FLAT创建扁平的
工具栏。第11章菜单、工具栏和状态栏表11-4CToolBar::Create工具栏风格工具栏风格说明CBRS_TOP工具栏放置在框架窗口的顶端CBRS_BOTTOM工具栏放置在框架窗口的底部CBRS_NOALIGN当调整工具栏父窗口大小时不调整工具栏的位置CBRS_TO
OLTIPS当鼠标光标停留在工具栏按钮上时,显示工具提示CBRS_SIZE_FIXED工具栏的大小固定CBRS_FLOATING工具栏是浮动的CBRS_FLYBY当鼠标光标指向工具栏按钮时,状态栏上显示按钮的说明CBRS_HIDE_I
NPLACE工具栏不显示给用户第11章菜单、工具栏和状态栏除了可以在Create或CreateEx函数中指定工具栏的风格外,还可以在创建工具栏后调用SetBarStyle(CToolBar从CControlBar类
继承来的成员函数)设置或改变工具栏的风格。例如,如果要用CBRS_BOTTOM风格取代CBRS_TOP风格,使工具栏和框架窗口的底部对齐,可以调用如下语句(w_wndToolbar为CToolBar的对象):w_wndToolbar.Create(this,WS_CHILD|WS_VISI
BLE|CBRS_BOTTOM);也可以按如下方式创建工具栏:w_wndToolbar.Create(this);w_wndToolbar.SetBarStyle((w_wndToolbar.GetBarStyle()
&~CBRS_TOP|CBRS_BOTTOM);第11章菜单、工具栏和状态栏因为工具栏是应用程序主框架窗口的子窗口,通常随框架窗口的创立而创建,因此一般在框架窗口类中添加一个CToolBar的对象成员,并在框架窗口的OnCreate处理程序中调
用Create或CreateEx。(4)调用CToolBar::LoadToolBar装入工具栏资源。函数原型为:BOOLLoadToolBar(UINTnIDResource);其中,参数“nIDResource”指定被装入的资源ID。第11章菜单、工具栏和状态栏11.2.3停靠和浮动工具栏默认
情况下,CToolBar工具栏停靠在框架窗口的一侧,且不能移动,只能通过程序控制来移动。实际上,CToolBar允许用户拖动工具栏移动,使它脱离原来的位置,并将其放在窗口的另一侧,或让它浮动在自己的框架窗口中。为了使工具栏成为可停靠的工具栏,需要调用CToolBar::EnableDocking(
从CControlBar继承来的成员函数)和CFrameWnd::EnableDocking。CToolBar::EnableDocking函数使工具栏成为可停靠的或禁止停靠的,函数原型为:voidEnableDocking(DWORDdwStyle);其
中,参数“dwStyle”设置工具栏是否支持停靠和工具栏能够停靠在父窗口的位置,其取值可以是表11-5所列的一个或多个的组合。如果为0(即没有标志),则工具栏不能拖动停靠。这里指定的停靠位置必须与框架窗口允许的停靠位置相匹配。第11章菜单、工具栏和状态栏CF
rameWnd::EnableDocking函数决定工具栏停靠的位置,函数原型为:voidEnableDocking(DWORDdwDockStyle);其中,参数“dwDockStyle”指定框架窗口的哪一侧可作为工具栏的停靠位置,取值为表11-5所列的一个或多
个值的组合。第11章菜单、工具栏和状态栏表11-5工具栏的停靠标志停靠标志说明CBRS_ALIGN_TOP允许停靠在框架窗口顶部CBRS_ALIGN_BOTTOM允许停靠在框架窗口底部CBRS_ALIGN_LEFT允许停靠在框
架窗口左侧CBRS_ALIGN_RIGHT允许停靠在框架窗口右侧CBRS_ALIGN_ANY允许停靠在框架窗口任意一侧第11章菜单、工具栏和状态栏CToolBar::EnableDocking和CFrameWnd::
EnableDocking都要指定停靠位置,但其含义不同,前者指明工具栏可以停靠的位置,而后者指明框架窗口允许工具栏停靠的位置。如果框架窗口包含多个工具栏,并且每个工具栏都有不同的停靠位置,则分别指定工具栏和框架窗口的停靠位置参数就显得比较方便了。例如,如果
m_wndToolBar1和m_wndToolBar2属于同一个框架窗口,则m_wndToolBar1.EnableDocking(CBRS_ALIGN_TOP|CBRS_ALIGN_BOTTOM);m_wndToolBar2.EnableDocking(CBRS_AL
IGN_LEFT|CBRS_ALIGN_RIGHT);EnableDocking(CBRS_ALIGN_ANY);将m_wndToolBar1停靠在顶部或底部,而将m_wndToolBar2停靠在左侧或右
侧。第11章菜单、工具栏和状态栏执行完CToolBar::EnableDocking和CFrameWnd::EnableDocking函数后,应调用CFrameWnd::DockControlBar停靠工
具栏,函数原型为:voidDockControlBar(CControlBar*pBar,UINTnDockBarID=0,LPCRECTlpRect=NULL);其中,参数“pBar”为指向被停靠的工具栏指
针。参数“nDockBarID”决定框架窗口的哪一侧用于停靠,可以为0或表11-6所列的一个或多个值的组合,若为0(缺省值),则工具栏可以在目标框架窗口中任意可停靠的位置停靠。参数“lpRect”以屏幕坐标表示目标框架窗口非客户区中可以被工具
栏停靠的位置。第11章菜单、工具栏和状态栏表11-6DockControlBar函数的停靠位置停靠位置说明AFX_IDW_DOCKBAR_TOP停靠到框架窗口的顶部AFX_IDW_DOCKBAR_BOTTOM停靠到框架窗口的底部AFX_IDW_DOCKBA
R_LEFT停靠到框架窗口的左侧AFX_IDW_DOCKBAR_RIGHT停靠到框架窗口的右侧第11章菜单、工具栏和状态栏【例11.5】为应用程序MyDraw创建一个新的工具栏,用于执行“颜色”菜单中的命令。(1)在项目中添加和编辑新的工具栏资源。打开项目M
yDraw,单击项目工作区窗口的“ResourceView”标签,插入一个新的工具栏资源,设置其资源ID为IDR_COLORS,添加和编辑如图11-16所示的4个按钮,并按表11-7设置按钮的属性。各按钮的ID值与“颜色”菜单中各菜单项的ID值相同,因此,此工具栏上的按钮成为菜单命令的快捷方式
。第11章菜单、工具栏和状态栏绿色自定义红色蓝色图11-16项目MyDraw添加的工具栏资源第11章菜单、工具栏和状态栏表11-7按钮的属性设置按钮大小(宽,高)IDPrompt红色16,15ID_C
OLOR_RED设置图形为红色\n红色绿色16,15ID_COLOR_GREEN设置图形为绿色\n绿色蓝色16,15ID_COLOR_BLUE设置图形为蓝色\n蓝色自定义16,15ID_COLOR_CUSTOM通过颜色对话框设置图形颜色\n自定义第11章菜单、工具栏和状态栏(2)在应用程序主框
架窗口中创建、装入和停靠工具栏。在框架窗口类CMainFrame中添加CToolBar类的数据成员:protected://controlbarembeddedmembersCStatusBarm_wndStatusBa
r;CToolBarm_wndToolBar;CToolBarm_colorToolBar;在CMainFrame::OnCreate函数中添加代码,创建工具栏、装入工具栏资源IDR_COLORS并允许工具栏停靠在窗口的任意位置。第11章菜单、工具栏和状态栏i
ntCMainFrame::OnCreate(LPCREATESTRUCTlpCreateStruct){//创建工具栏m_colorToolBar.CreateEx(this,TBSTYLE_FLAT,WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_GRIPPER
|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC);m_colorToolBar.LoadToolBar(IDR_COLORS);//装入工具栏资源//工具栏可以停靠在任意位置m_colorToolBa
r.EnableDocking(CBRS_ALIGN_ANY);EnableDocking(CBRS_ALIGN_ANY);//允许工具栏停靠在任意位置DockControlBar(&m_colorToolBar);
//停靠工具栏return0;}第11章菜单、工具栏和状态栏(3)编译、链接和运行程序,程序运行结果如图11-17所示。单击工具栏按钮可以设置图形颜色,可以拖动工具栏使其浮动在框架窗口内或停靠在窗口任意一侧。图11-17添加工具栏后的运行结果第11章菜单、工具栏和状态栏11.
2.4显示和隐藏工具栏工具栏可以提高用户操作程序的效率,但工具栏占用了框架窗口的客户区域,因此,当不需要使用工具栏时,应该将其隐藏起来。大部分包含工具栏的Windows应用程序都设置有显示或隐藏工具栏的命令
。MFC缺省的工具栏可以通过执行“查看”→“工具栏”菜单命令来显示或隐藏。在显示或隐藏工具栏之前应该知道工具栏当前的可见状态,这可以通过调用CWnd的成员函数GetStyle查询工具栏的所有风格。要确定工具栏的可见性,可以简单地用风格标志WS_VISIBLE和GetSty
le函数的执行结果进行按位与运算,如果结果非0,则工具栏当前是可见的。第11章菜单、工具栏和状态栏应用程序中一般通过菜单命令或快捷键来显示或隐藏工具栏,因此,可以通过编写菜单命令的命令消息处理函数,在其中调用CFrameWnd::ShowControlBar来隐藏或显
示工具栏。其函数原型为:voidShowControlBar(CControlBar*pBar,BOOLbShow,BOOLbDelay);其中,参数“pBar”为指向要显示或隐藏的工具栏的指针;参数“bShow”指定是显示还是隐藏工具栏,若为TRUE则显示工具栏,为FALSE则隐藏工具栏;参
数“bDelay”为TRUE时则延迟显示工具栏,为FALSE时则立即显示。一般不要通过简单地打开或关闭工具栏的WS_VISIBLE标志切换工具栏。工具栏被显示或隐藏时,MFC会调整视图窗口的大小以适应框架窗口客户区中可见区域的变化。Show
ControlBar在显示或隐藏工具栏时已经考虑了这些因素。第11章菜单、工具栏和状态栏【例11.6】在MyDraw中添加菜单命令来显示或隐藏颜色设置工具栏。(1)添加菜单项。打开项目MyDraw,单击项目工作区窗口的“ResourceVie
w”标签,双击菜单资源IDR_MAINFRAME,在“查看”菜单下添加“颜色工具栏”菜单项,设置其ID为ID_VIEW_COLORBAR。第11章菜单、工具栏和状态栏(2)利用ClassWizard为菜单命令“颜色工具栏”在框架窗口类中添加
命令消息处理函数和用户界面更新命令消息UPDATE_COMMAND_UI的处理函数,并添加代码:voidCMainFrame::OnViewColorbar(){ShowControlBar(&m_colorTo
olBar,(m_colorToolBar.GetStyle()&WS_VISIBLE)==0,FALSE);}voidCMainFrame::OnUpdateViewColorbar(CCmdUI*pCmdUI){//设置检查标志pCmdUI->SetCheck((m_col
orToolBar.GetStyle()&WS_VISIBLE)?1:0);}(3)编译、链接和运行程序,测试“颜色工具栏”命令。第11章菜单、工具栏和状态栏11.2.5给按钮添加文字在默认情况下,工具栏按
钮只包含图像,不包含文字。可以通过以下步骤给按钮表面添加文字:(1)利用工具栏编辑器调整按钮图像的大小,使其适合添加文本的长度。(2)调用CToolBar::SetButtonText给按钮添加字符串。函数原型为:BOOLS
etButtonText(intnIndex,LPCTSTRlpszText);其中,参数“nIndex”指定了设置文本的按钮的索引,其中0代表工具栏最左端位置上的按钮,工具栏上的分隔条也占用一个对应的索引。参数“lpszText”指定设置给按钮的文本字符串。(
3)调用CToolBar::SetSizes调整按钮尺寸。第11章菜单、工具栏和状态栏例如,给例11.5创建的颜色设置工具栏上的按钮添加文本。首先利用工具栏编辑器调整按钮位图的大小为40个像素宽、19个像素高,然后在
CMainFrame::OnCreate函数的语句m_colorToolBar.LoadToolBar(IDR_COLORS);后添加如下代码:m_colorToolBar.SetButtonText(0,"红色");m_color
ToolBar.SetButtonText(1,"绿色");m_colorToolBar.SetButtonText(2,"蓝色");m_colorToolBar.SetButtonText(3,"自定义");m_colorTool
Bar.SetSizes(CSize(48,42),CSize(40,19));生成的工具栏如图11-18所示。第11章菜单、工具栏和状态栏图11-18带文字的工具栏按钮第11章菜单、工具栏和状态栏11.2.6在工具栏中添加非按钮控件工具栏上最常见的是按钮,但
工具栏上除了按钮外,还可以添加非按钮控件。例如,在工具栏上常见到组合框,用于设置字体、字号等。要在工具栏上添加非按钮控件,一般需按以下步骤进行:(1)利用工具栏编辑器在工具栏上添加一个分隔条或其它按钮。该按钮可具有任意ID和按钮图像,此位置将作为非按钮控件的预留位置
。(2)调用CToolBar::SetButtonInfo调整预留位置分隔条或其它按钮的宽度。第11章菜单、工具栏和状态栏函数SetButtonInfo用于设置按钮的命令ID、风格和图像号。函数原型为:voidSetButtonInfo(intnIndex
,UINTnID,UINTnStyle,intiImage);其中,参数“nIndex”为要设置信息的按钮或分隔条的索引;参数“nID”为给按钮设置的ID值;参数“nStyle”指明设置按钮的新风格,可以为以下值:·TBBS_B
UTTON:标准下压式按钮(缺省设置)。·TBBS_SEPARATOR:分隔条。·TBBS_CHECKBOX:自动复选按钮。·TBBS_GROUP:标记一个按钮组的开始。·TBBS_CHECKGROUP:标记一个
复选按钮组的开始。参数“iImage”为按钮的图像在位图中的新索引。对于具有TBBS_SEPARATOR风格的分隔条,此参数用于设置分隔条的像素宽度。第11章菜单、工具栏和状态栏(3)调用控件类的Create函数在工具栏窗口的预留位置创建控件。(4)为创建的控件添加消息处理
函数。为了给非按钮控件添加工具提示,可以在字符串表中为其添加一个字符串资源,则当光标停留在非按钮控件上时会自动出现工具提示。第11章菜单、工具栏和状态栏【例11.7】工具栏使用示例。在工具栏上添加一个组合框,用于设置视图窗口中文本显示的字体。程序实现过程如下:(
1)利用AppWizard创建SDI应用程序框架,项目名设置为ToolBarSample。(2)利用工具栏编辑器编辑工具栏。单击项目工作区窗口的“ResourceView”标签,双击Toolbar下的IDR_MAIN
FRAME工具栏资源打开工具栏,首先删除“打印”和“关于”两个按钮,然后添加如图11-19所示的4个按钮,并按表11-8所示设置各按钮的属性。第11章菜单、工具栏和状态栏保留此空格倾斜预留位置加粗下划线图11-19添加的按钮第11章菜单、工具栏和状态栏表11-8按钮属性设置按钮IDPr
ompt加粗ID_BOLD\n加粗倾斜ID_ITALIC\n倾斜下划线ID_UNDERLINE\n下划线预留位置缺省第11章菜单、工具栏和状态栏(3)在视图类CToolBarSampleView的头文件中增加如下描述文本属性的数据成员:protect
ed:BOOLm_bItalic;//是否倾斜BOOLm_bUnderline;//是否加下划线BOOLm_bBold;//是否加粗CStringm_strFont;//字体名然后在视图类CToolB
arSampleView的构造函数中初始化新增的数据成员:CToolBarSampleView::CToolBarSampleView(){m_bBold=FALSE;//缺省不加粗m_bItalic=FALSE;//缺省不倾斜
m_bUnderline=FALSE;//缺省不加下划线m_strFont="宋体";//缺省字体为宋体}第11章菜单、工具栏和状态栏(4)编辑视图类CToolBarSampleView的OnDraw成员函数,创建字体并选入设备环境,在视图窗口的中心显示文本:voidCToolBarSam
pleView::OnDraw(CDC*pDC){intnWeight;if(m_bBold)nWeight=FW_BOLD;elsenWeight=FW_NORMAL;CFont*pOldFont,font;第11章菜单、工具栏和状态栏font.CreateFont(48,0,0,0,n
Weight,m_bItalic,m_bUnderline,0,DEFAULT_CHARSET,OUT_CHARACTER_PRECIS,CLIP_CHARACTER_PRECIS,DEFAULT_QUALITY,DEFAULT_
PITCH|FF_DONTCARE,m_strFont);pOldFont=pDC->SelectObject(&font);CRectrect;GetClientRect(&rect);pDC->DrawText("工具栏使用示例
",&rect,DT_CENTER|DT_VCENTER|DT_SINGLELINE);pDC->SelectObject(pOldFont);}第11章菜单、工具栏和状态栏(5)利用ClassWizard为工具栏按钮添加命令消息处理函数和用户界面更新命令处理函数:voidCToolBa
rSampleView::OnBold(){m_bBold=!m_bBold;//单击“加粗”按钮,将文本加粗属性取反Invalidate();//更新视图窗口}voidCToolBarSampleView::OnUpdateBold(CCmdUI*p
CmdUI){pCmdUI->SetCheck(m_bBold);//更新按钮状态}第11章菜单、工具栏和状态栏voidCToolBarSampleView::OnItalic(){m_bItalic
=!m_bItalic;Invalidate();}voidCToolBarSampleView::OnUpdateItalic(CCmdUI*pCmdUI){pCmdUI->SetCheck(m_bItalic);}第11章菜单、工具栏和状态栏voidCToolBarSam
pleView::OnUnderline(){m_bUnderline=!m_bUnderline;Invalidate();}voidCToolBarSampleView::OnUpdateUnder
line(CCmdUI*pCmdUI){pCmdUI->SetCheck(m_bUnderline);}第11章菜单、工具栏和状态栏(6)在工具栏上的预留位置处添加组合框。首先在主框架窗口类CMainFrame的头文件中增加CComboBox类的对象成员:public:CComboBox
m_wndComboBox;然后要为增加的组合框定义一个ID值,方法是执行“View”→“ResourceSymbols…”菜单命令,在弹出的对话框中单击“New…”按钮,添加名称为“IDC_COMBOBOX”的
ID标识,其值取缺省值。第11章菜单、工具栏和状态栏编辑CMainFrame类的OnCreate函数,在其中增加创建组合框控件的代码:intCMainFrame::OnCreate(LPCREATESTRUCTlpCreateStruct){DockControlBar(&m_
wndToolBar);//将预留位置的按钮设置为分隔条,设置其宽度为100个像素宽,ID值任意m_wndToolBar.SetButtonInfo(11,111,TBBS_SEPARATOR,100);CRectrect;m_wndToolBar.GetItemRect
(11,&rect);//获取预留位置的矩形区域rect.bottom+=100;//增加矩形高度以便容纳组合框的列表//创建组合框第11章菜单、工具栏和状态栏m_wndComboBox.Create
(CBS_DROPDOWNLIST|WS_VISIBLE|CBS_AUTOHSCROLL,rect,&m_wndToolBar,IDC_COMBOBOX);m_wndComboBox.AddString("宋体");//初始化组合框m_wndComboBox.AddString("
黑体");m_wndComboBox.AddString("楷体_GB2312");m_wndComboBox.SetCurSel(0);//缺省选中宋体return0;}第11章菜单、工具栏和状态栏(7)在CToolBarSampleView中添加组合框的CBN_SELCHANGE消息
处理函数。对于通过代码创建的控件,不能使用ClassWizard为其添加消息处理函数,只能通过手工方式添加。在视图类的头文件的DECLARE_MESSAGE_MAP()宏的上面增加消息处理函数OnSelChangeCombo原型:afx_msgvoidOnSelC
hangeCombo();在视图类CToolBarSampleView的实现文件中添加组合框的CBN_SELCHANGE消息的消息映射项。在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP()之间添加如下消息映射项:ON_CBN_SELCHANGE(IDC_COMBOB
OX,OnSelChangeCombo)第11章菜单、工具栏和状态栏最后在视图类CToolBarSampleView的实现文件中编辑新增的组合框消息处理函数:voidCToolBarSampleView:
:OnSelChangeCombo(){//获取主框架窗口的指针CMainFrame*pFrame=(CMainFrame*)AfxGetMainWnd();//获取组合框当前选择项的字符串pFrame->m_wndComboBox.GetLBText(pFrame->m_
wndComboBox.GetCurSel(),m_strFont);Invalidate();//更新视图}第11章菜单、工具栏和状态栏在类CToolBarSampleView的实现文件的开始处包含主框架窗
口类CMainFrame的头文件:#include"MainFrm.h"(8)编译、链接和运行程序,程序运行结果如图11-20所示。第11章菜单、工具栏和状态栏图11-20程序ToolBarSample的运行结果第11章菜单、
工具栏和状态栏11.3状态栏状态栏一般位于框架窗口的底部,用于显示菜单项或工具按钮的提示信息和程序的运行状态。用MFCAppWizard创建的应用程序框架中,状态栏用于显示菜单提示信息和CapsLock、NumLock和Scr
ollLock键的状态。可以修改状态栏,使其显示不同的信息,例如显示鼠标指针的坐标、系统时间。甚至可以在状态栏上包含其它控件,例如包含进度条控件,用于显示如保存、加载文档等操作的进度。第11章菜单、工具栏和状态栏11.3.1创建和初始化状态栏在MFC应用程序中,状态栏是类CStatu
sBar的一个对象。由于状态栏是框架窗口的子窗口,因此要创建一个状态栏,首先要在应用程序的框架窗口类中定义一个CStatusBar的对象,然后在框架窗口类的OnCreate函数中调用CStatusBar::Create创建状态栏。函数原型为:BOOLCreate(CWnd*pPar
entWnd,DWORDdwStyle=WS_CHILD|WS_VISIBLE|CBRS_BOTTOM,UINTnID=AFX_IDW_STATUS_BAR);其中,参数“pParentWnd”指明状态栏父窗口的指针,“dwStyle”指明状态栏的风格,“nID”指明状态栏窗口的ID
值。第11章菜单、工具栏和状态栏状态栏一般分为若干个窗格,每个窗格显示不同的信息。状态栏创建后,应调用CStatusBar::SetIndicators函数初始化状态栏。函数原型为:BOOLSetIndicators(constUINT*lpI
DArray,intnIDCount);其中,参数“lpIDArray”为由状态栏窗格指示符ID值构成的数组,“nIDCount”为数组lpIDArray中元素的个数。函数SetIndicators根据数组lpIDArray中指示符的个数确定状态栏窗格的个数,并同时赋给各窗格字符串资源。第11
章菜单、工具栏和状态栏例如,AppWizard在主框架窗口类的实现文件MainFrm.cpp文件中定义了一个静态数组indicators,并用此数组初始化状态栏:staticUINTindicators[]={ID
_SEPARATOR,//状态栏窗格指示符ID_INDICATOR_CAPS,ID_INDICATOR_NUM,ID_INDICATOR_SCRL,};m_wndStatusBar.SetIndicators(indicators,size
of(indicators)/sizeof(UINT)));indicators数组与状态栏的关系如图11-21所示。第11章菜单、工具栏和状态栏staticUINTindicators[]={ID_SEPARATOR,ID_INDICAT
OR_CAPS,ID_INDICATOR_NUM,ID_INDICATOR_SCRL,};图11-21indicators数组与状态栏的关系第11章菜单、工具栏和状态栏ID_SEPARATOR是一个通用ID,说明没有字符串资源与其对应的窗格关联。此窗格显
示应用程序动态提供的字符串。如果需要状态栏显示键盘状态,则可以利用MFC预定义的如下指示符ID:·ID_INDICATOR_CAPS:显示CapsLock键的当前状态。·ID_INDICATOR_NUM:显示NumLock键的当前状态。·I
D_INDICATOR_SCRL:显示ScrollLock键的当前状态。如果使用这些预定义的指示符ID,则由应用程序框架自动跟踪相应键的状态并更新对应的状态栏窗格。对于每一个状态栏窗格,可以调用CStat
us的成员函数SetPaneStyle设置风格,调用SetPaneInfo调整大小。第11章菜单、工具栏和状态栏11.3.2创建自定义状态栏窗格除了可以使用ID_SEPARATOR和预定义的指示符ID定义状
态栏的窗格外,还可以使用自定义的指示符ID来定义状态栏窗格。例如,可以创建状态栏窗格来显示当前系统的时间、鼠标光标的坐标等。创建自定义状态栏窗格一般需要如下几个步骤:(1)为自定义状态栏窗格定义指示符ID。窗格指示符ID实际上是一个字符串资源(ID_SEPARATOR除外),因此,要定义
指示符ID只需要在应用程序的字符串表资源中添加相应的字符串资源即可。第11章菜单、工具栏和状态栏添加字符串资源的方法:选中项目工作区窗口的“ResourceView”标签,在窗口中展开StringTable,双击其下的“StringTable”,打开字符串表,双击字符串表最下面的空行,打开字符串属
性对话框,输入ID值和Caption标题字符串。缺省时,由自定义指示符ID确定的窗格的宽度是相应字符串资源中指定的字符串的长度。在程序中可以使用SetPaneInfo重新设置窗格的宽度。(2)用自定义的指示符ID重新定义窗格指示符数组indicators。(3)设置自定义窗格显示
的内容。有两种方法可以在窗格中显示文本。一种方法是调用CStatusBar::SetPaneText直接设置文本,其函数原型为:BOOLSetPaneText(intnIndex,LPCTSTRlpszNewText,BOOLbUpdate=TR
UE);其中,参数“nIndex”为以0开始的窗格索引,最左边的窗格为0。第11章菜单、工具栏和状态栏如果要在除框架窗口类的其它类中调用CStatusBar::SetPaneText函数,首先必须能够访问状态栏对象,然后调用CStatusBar::SetPaneText。例如,在视图类设置窗格的
值可以使用如下代码:CMainFrame*pFrame=(CMainFrame*)AfxGetApp()->m_pMainWnd;CStatusBar*pStatus=&pFrame->m_wndStatusBar;pS
tatus->SetPaneText(0,"ID_SEPARATOR对应窗格显示的字符串");第二种方法是为窗格映射一个用户界面更新命令UPDATE_COMMAND_UI消息处理函数,在此函数中调用CCmdUI::SetText设定文本。由于ClassWizard不支持在字符串表中定义的ID,
因此必须手工添加自定义指示符ID的消息处理函数。第11章菜单、工具栏和状态栏【例11.8】编写一个SDI应用程序,在状态栏中添加两个窗格,分别显示系统当前时间和鼠标指针在视图窗口中的坐标及左右键的状态。程序实现过程如下:(1)利用MFCAppWizard[exe]向
导创建一个SDI应用程序框架,项目名设置为StatusBarSample,其它采用缺省设置。(2)定义窗格指示符ID。打开字符串表,在其中添加如表11-9所示的三个字符串。第11章菜单、工具栏和状态栏表1
1-9添加的字符串资源字符串IDCaption说明ID_INDICATOR_TIMEHH:MM:SS用于定义显示时间的窗格ID_INDICATOR_LEFT左键用于定义显示鼠标左键状态的窗格ID_INDICATOR_RIGHT右键用于定
义显示鼠标右键状态的窗格第11章菜单、工具栏和状态栏(3)修改状态栏窗格指示符数组indicators。打开应用程序主框架窗口类的实现文件MainFrm.cpp,将其中的indicators数组修改为如下形式:staticUINTindicators[]={ID_SEPARATOR,ID_
SEPARATOR,//显示鼠标坐标的窗格ID_INDICATOR_LEFT,//显示鼠标左键状态的窗格ID_INDICATOR_RIGHT,//显示鼠标右键状态的窗格ID_INDICATOR_TIME,/
/显示时间的窗格};第11章菜单、工具栏和状态栏(4)设置定时器,用于自动更新时间窗格内的时间。在CMainFrame::OnCreate函数中添加如下语句:SetTimer(150,200,NULL);此语句用于设置一个定时器,其ID
值为150,定时器每隔200ms发送一个WM_TIMER消息。利用ClassWizard在应用程序框架类CMainFrame中添加WM_TIMER消息处理函数,此函数每隔200ms执行一次,并利用SetPaneText在窗格中显示时间。第11章菜
单、工具栏和状态栏voidCMainFrame::OnTimer(UINTnIDEvent){CTimetime=CTime::GetCurrentTime();//获取系统当前时间intnSecond=time.GetSecond();//获取当前时间的秒int
nMinute=time.GetMinute();intnHour=time.GetHour();CStringstring;string.Format("%0.2d:%0.2d:%0.2d",nHour,nMi
nute,nSecond);m_wndStatusBar.SetPaneText(2,string);//设置第3个窗格的文本}第11章菜单、工具栏和状态栏(5)在框架窗口类CMainFrame中添加窗格指示符ID_INDICATOR_LEFT和ID_INDICA
TOR_RIGHT的用户界面更新命令消息处理函数。由于ClassWizard不支持在字符串表中定义的ID,因此必须手工添加自定义指示符ID的消息处理函数。在MainFrm.h头文件的DECLARE_MESSAGE_MAP()前添加函数原型:
afx_msgvoidOnUpdateLeft(CCmdUI*pCmdUI);afx_msgvoidOnUpdateRight(CCmdUI*pCmdUI);在MainFrm.cpp实现文件中的BEGIN_MESSAG
E_MAP和END_MESSAGE_MAP之间添加消息映射项:ON_UPDATE_COMMAND_UI(ID_INDICATOR_LEFT,OnUpdateLeft)ON_UPDATE_COMMAND_UI(ID_
INDICATOR_RIGHT,OnUpdateRight)第11章菜单、工具栏和状态栏接着添加消息处理函数的定义:voidCMainFrame::OnUpdateLeft(CCmdUI*pCmdUI){p
CmdUI->Enable(::GetKeyState(VK_LBUTTON)<0);}voidCMainFrame::OnUpdateRight(CCmdUI*pCmdUI){pCmdUI->Enable(::Ge
tKeyState(VK_RBUTTON)<0);}鼠标的左键和右键与键盘上的键一样具有虚拟键编码,当鼠标左键或右键按下时,GetKeyState函数返回的值小于0,使对应的窗格显示字符串表中指定的字符串。第11章菜单、工具栏和状态栏(6)利用ClassWiza
rd在视图类CStatusBarSample中添加WM_MOUSEMOVE消息处理函数,在其中设置第2个窗格的文本,显示鼠标坐标。处理函数如下:voidCStatusBarSampleView::OnMouseMove(UINTnFlags,C
Pointpoint){CStringstr;//获取指向主框架窗口的指针CMainFrame*pFrame=(CMainFrame*)AfxGetApp()->m_pMainWnd;CStatusBar*pSt
atus=&pFrame->m_wndStatusBar;str.Format("(x,y)=(%d,%d)",point.x,point.y);pStatus->SetPaneText(1,str);//设置第2个窗格的文本,显示坐标}第11章
菜单、工具栏和状态栏由于缺省时m_wndStatusBar的访问权限在CMainFrame类中定义成protected,因此还需要将其访问权限更改为public:public:CStatusBarm_wndStatusBar;最后,在文件StatusBarsam
pleView.cpp的顶部加入如下的包含命令:#include"MainFrm.h"第11章菜单、工具栏和状态栏(7)在视图类CStatusBarSampleView的OnDraw函数中输出提示信息:voidCStatusB
arSampleView::OnDraw(CDC*pDC){pDC->TextOut(0,0,"在视图窗口中移动鼠标、单击左右键,观察状态栏变化");}(8)编译、链接和运行程序,程序运行结果如图11-22所示。第11章菜单、工具栏和状态栏图11-22程序StatusBarSampl
e的运行结果第11章菜单、工具栏和状态栏习题1.在MFC应用程序中创建菜单有哪几种方法?2.为例11.1增加一个“画笔”菜单,并添加“实线”、“虚线”和“点划线”三个菜单项,用于设置图形边界的样式。分别为每个菜单项添加命令处理函数和用户界面更新
命令处理函数,当执行某个命令后禁用该命令,启用其它命令。3.在MFC应用程序中命令消息按什么路径传递?若在不同类中对同一个菜单项映射了命令处理函数,则会产生什么结果?4.为例11.1的菜单项“自定义”添加快捷键。5.如何创建快捷菜单?一般应在什么消息的处理函数中弹出快捷菜单?6.在MFC应用
程序中如何为编程创建的菜单添加命令消息处理函数?第11章菜单、工具栏和状态栏7.在MFC应用程序中如何创建新的菜单资源,并将创建的菜单资源用作程序的菜单?8.在应用程序MyDraw中创建一个新的工具栏,添加与
习题2对应的按钮,用于设置图形边框的样式。让新创建的工具栏停靠在框架窗口的右侧。9.在应用程序中如何隐藏/显示工具栏?10.给习题8创建的工具栏按钮上添加文字。11.在例11.7的程序ToolBarSample的工具栏上添加一个组合框,用于设置文本的字号。1
2.说明静态数组indicators的组成和功能,如何使用该数组?13.若状态栏只有一个用户定义的窗格(其指示符ID为ID_TEXT_PANE),应如何定义?如何实现当用户在视图窗口中双击鼠标时,在该窗格中显示“双击
鼠标”?