第2章 菜单工具栏和状态栏的设计.docx
《第2章 菜单工具栏和状态栏的设计.docx》由会员分享,可在线阅读,更多相关《第2章 菜单工具栏和状态栏的设计.docx(88页珍藏版)》请在冰点文库上搜索。
第2章菜单工具栏和状态栏的设计
第2章菜单、工具栏和状态栏的设计
在Windows应用程序中,菜单、工具栏、状态栏等内容都是不可缺少的界面元素。
菜单是一系列可视的命令列表,用户能够选中其中的菜单项(命令)并执行相应任务。
工具栏提供图形按钮,实现快捷操作,用户可以通过工具栏执行最常用的命令,增强方便程度。
在状态栏中,可以显示动态的提示信息,便于用户的一些操作。
2.1设计菜单
菜单为用户控制程序提供了一套分级选项,无论是标准菜单及命令,还是热键或弹出式菜单,以及为菜单或其命令定义加速键和状态条提示,都可用菜单编辑器来完成;除此之外,菜单项作为一个普通的对象也可在编辑时进行移动、复制、删除等操作。
图2.1是一个典型的菜单实例,图中包含了标准菜单命令、快捷键、加速键、子菜单、核对符等。
这些都是编写程序时经常遇到的。
下面我们就介绍如何创建和编辑菜单项。
图2.1典型菜单实例
2.1.1用编辑器设计菜单
当用户使用AppWizard创建SDI或MDI应用程序时,系统将为用户自动生成默认的菜单栏。
用户需要做的工作仅仅是打开菜单编辑器,进行必要的修改,再编写菜单选项相应的消息处理函数即可。
当然也可在菜单编辑器中创建新的菜单或创建新的菜单资源,如快捷菜单等。
无论是编辑已有菜单资源还是创建新的菜单资源,首先应当进入菜单资源编辑器。
例2.1在菜单编辑器的”文件(F)”下拉的某个位置加一个菜单,其作用是单击它后,能在屏幕上显示一行字。
编程步骤如下:
(1)建一个SDI单文档应用程序名为:
显示一行字
(2)用编辑器设计菜单:
项目工作区ResourceView单击打开Menu双击IDR_MAINFRAME右面出现菜单编辑器,见图2.1.1单击“文件(F)”出现下拉菜单,见图2.1.2所示点中最后的空白菜单,双击它出现“菜单项属性对话框”在Caption处写菜单名:
“显示一行字(&C)”在ID处写ID_FILE_XS在prompt(注释)栏中写:
“点击新建菜单项,在窗口显示一行字”关闭该对话框。
图2.1.1菜单资源编辑器
图2.1.2菜单编辑器和修改菜单项属性的结果
(3)在文档的头文件CMyDoc.h的public下加:
CStringstr;//定义字符串变量
在文档的实现文件CMyDoc.cpp的构造函数里加:
str=””;//将字符串变量赋初值为”空”
(4)将菜单的标识ID_FILE_XS映射到视图类CMyView中。
View->Classvizard->MessageMaps->Classname置CMyView->ObjectIDs选中ID_FILE_XS->选中COMMAND->单击AddFunction->OK->EditCode。
在OnFileXS()映射函数中加代码:
voidCMyView:
:
OnFileXS()
{CMyDoc*pDoc=GetDocument();//获得文档类指针
ASSERT_VALID(pDoc);//检查pDoc指针是否有效
pDoc->str=“你成功的在File菜单下,建立了一个显示一行字菜单”;
Invalidate();//去强制执行OnDraw()函数
}
(5)再在视图实现文件CMyView.cpp里的OnDraw(CDC*Pdc)函数里加代码:
CMyView:
:
OnDraw(CDC*Pdc)
{pDC->TextOut(100,100,pDoc->str);//在窗口的x=100,y=100坐标处输出字符串
}
(6)编译运行
*在出现的文档窗口上,单击菜单的“文件”->单击你建的“显示一行字”菜单项,在屏幕上显示程序中写的一行字。
*单击“文件(F)”,出现下拉采单,直接按C键,也出现这行字。
*将鼠标放在“显示一行字”这个菜单上,下面状态栏会出现你在程序中写的注释:
“点击新建菜单项,在窗口显示一行字”。
说明:
1、TextOut(100,100,pDoc->str)是CDC类的输出函数,100,100是x,y坐标,pDoc->str是输出str内容。
2、改变菜单位置:
鼠标左键选中该菜单不放,拖到你想要加的位置即可。
3、想在哪个位置加菜单:
可选中后面的那个菜单,按Insert键即可。
4、“显示一行字(&C)”:
其中“&”用于将其后面的字符作为该菜单项的助记符,也就是它后面的字符成
了快捷键字符。
打开这个菜单,直接按这个助记符键,菜单命令就执行。
注意:
快捷键字符C不能与同一级快捷键字符重复,例如:
若写“显示一行字 (&X)”则与下面的“退出(&X)”重复,系统无法判别是哪个X,则不能执行。
图2.1.2中的小对话框(MenuItemProperties)是双击“文件(F)”下的空白菜单出现的菜单属性对话框,我们用它建立了“显示一行字(&C)”菜单,菜单General属性的各项含义如表2.1所示。
例2.2在顶层菜单栏里建立一个菜单项,并在其下面建立带有子菜单的菜单项,使有的子菜单具有加速键、变灰和核对符,又使每个子菜单都能显示信息。
步骤如下:
(1)建一个单文档的应用程序(或用例2.1程序),名为:
山东旅游
(2)建立菜单:
1)ResourceViewMenuIDR_MAINFRAME右面出现菜单编辑器左键选中顶层最后的空白菜单不放,将其拖到“帮助”的前面,松开鼠标(或选中“帮助”菜单,按Insert键)。
双击这个空白菜单,出现“菜单属性对话框”,在Caption处写:
山东旅游(&S)Pop_up处于选中状态(屏蔽ID)退出。
2)双击下面出现的空白菜单,出现“菜单属性对话框”,选中Pop_up(屏蔽ID)Capton处写:
烟台(&Y)
3)右边出现空白子菜单,双击它,出现“菜单属性对话框”ID处写:
ID_SD_YT_PLCapton处写:
蓬莱Ctrl+F5(Ctrl+F5是加速键标识)注释栏prompt处写:
蓬莱仙境
4)双击“蓬莱”下面的子菜单,双击它,出现“菜单属性对话框”ID处写:
ID_SD_YT_NSCapton处写:
南山(&N)prompt处写:
南山大佛
5)双击“烟台”下面的空白菜单,出现“菜单属性对话框”选中Popup(屏蔽ID)Capton处写:
青岛(&Q)
6)右边出现空白子菜单,双击它,出现“菜单属性对话框”ID处写:
ID_SD_QD_LSCapton处写:
崂山Ctrl+F6prompt处写:
崂山道士
表2.1菜单General属性对话框的各项含义
项目含义
ID菜单的资源ID标识符
Caption(标题)用于标识菜单项显示文本,助记符字母前面须有一个&符号,这个字
母与Alt构成组合键
Separator(分隔符)选中时,菜单项是一个分隔符或一条水平线
Checked(选中的)选中时,菜单项文本前显示一个选中标记
Pop_up(弹出)选中时,菜单项含有一个弹出式子菜单
Grayed(变灰)选中时,菜单项显示是灰色的,用户不能选用
Inactive(非激活)选中时,菜单项没有被激活,用户不能选用
Help(帮助)选中时,菜单项在程序运行时被放在顶层菜单的最右端
Break(暂停)当为Column时,对于顶层菜单项来说,被放置在另外一行上,而
对于弹出式子菜单的菜单项来说,则被放置在另外一列上,当为Bar
时,与Column相同,只不过对于弹出式子菜单来说,它还在新列
与原来的列之间增加一条竖直线,注意:
这些效果只能在程序运行
后才能看到。
Prompt(提示)用于指明光标移至该菜单项时,在状态栏上显示的提示信息
7)双击“青岛”下面的空白菜单,出现“菜单属性对话框”选中Popup(屏蔽ID)Capton处写:
泰安(&T)
8)右边出现空白子菜单,双击它,出现“菜单属性对话框”ID处写:
ID_SD_TA_TSCapton处写:
泰山Ctrl+F7prompt处写:
泰山日出
9)双击“泰安”下面的空白菜单,出现“菜单属性对话框”选中Popup(屏蔽ID)Capton处写:
济南(&J)
10)右边出现空白子菜单,双击它,出现“菜单属性对话框”ID处写:
ID_SD_JN_BTQ
Capton处写:
趵突泉Ctrl+F8prompt处写:
天下第一泉
图2.1.3加速键资源列表
(3)填加加速键表:
1)单击项目工作区的资源界面ResourceView打开Accelerator双击IDR_MAINFRAME出现加速键表,双击最下面的空白格,见图2.1.3所示出现加速键属性对话框AcclPropertiesID处下拉找到ID_SD_YT_PL置好key处下拉,找到VK_F5置好(或置好ID后,单击[NextKeyTyped],出现一个小对话框后,再按下Ctrl+5键也可)见图2.1.4所示,这样就为“蓬莱”菜单置好了加速键。
“加速键General属性”对话框的各项含义如表2.2所示。
图2.1.4“AccelProperties”(加速键属性)对话框
2)你再双击最下面的空白格,按上步的方法,分别将青岛的“崂山”、泰安的“泰山”,济南的“趵突泉”菜单分别置好VK_F6,VK_F7,VK_F8的加速键。
注意:
图2.1.4中Modifiers处,选中Ctrl,说明是Ctrl键,选中Alt说明是Alt键,选中Shift说明是Shift键,小对话框“Pressakeytobeysedastheaccelerator”是单击“NextKeyTyped”弹出来的对话框。
表2.2“加速键General属性”对话框的各项含义
项目含义
ID指定资源ID号的列表项,为了能和菜单联用,通常选择某菜单项的ID号
Modifiers用于确定Ctrl、Alt、Shift是否是构成加速键的组成部分
Type用于确定该加速键的值是虚拟键(VirKey),还是ASCII
Key是指启动加速键的键盘按键
下一键(NextKeyType)单击此按钮后,用户操作的任何按键将成为此加速键的键值。
(4)使菜单变灰(不被激活,不起作用)
ViewClassWizardClassname选CMyView在ObjectIDS里找到你想要变灰的菜单,这里选中ID_SD_TA_TS右边Messages里选中UPDATECOMMANDUIAddFoutionOKEditCode在该函数里写:
voidCMyView:
:
OnSdTaTs()
{pCmdUI->Enable(false);
}
说明:
pCmdUI是CCmdUI类的指针对象。
CCmdUI类只是被用在一个CCmdTarget派生类中的ON_UPDATE_COMMAND_UI处理程序中。
当用户拉出一个菜单时,每个菜单项都需要知道它应该被显示为可用还是禁用。
当菜单被拉出时,(框架)会寻找并调用各个ON_UPDATE_COMMAND_UI处理程序,每个处理程序都调用CCmdUI类中像Enable和Check这样的成员函数,然后框架将(按照其合适的方式)显示各个菜单项。
(5)核对菜单项,使这个菜单名字的前面加个“√”号
ViewClassWizardClassname选CMyView在ObjectIDS里找到你想要核对的菜单,
这里选中ID_SD_YD_NS右边Messages里选中UPDATECOMMANDUIAddFoution
OKEditCode在该函数里写:
voidCMyView:
:
OnUpdateSdYtNs(CCmdUI*pCmdUI)
{pCmdUI->Enable(true);//这里如果是Enable(false)则该菜单变灰
pCmdUI->SetCheck
(1);//设置核对符,如果括弧里写0是删除核对符
}
(6)菜单命令响应
1)在View.h里的public:
下定义变量:
CStringstr;
在View.cpp的构造函数里将变量值赋空:
str=“”;
2)将烟台的子菜单“蓬莱”的ID标识符ID_SD_YT_PL映射到视图类View里:
ViewClassWizard在LassName置View在ObjectIDs里找到ID_SD_YT_PL选中COMMANDAddFunctionEditCode加代码:
voidCMyView:
:
OnSdYtPl()
{str=“蓬莱仙境”;
Invalidate();
}
3)将烟台的子菜单“南山”的ID_SD_YT_NS映射到视图类View里,并加代码:
voidCMyView:
:
OnSdYtNs()
{str=“南山大佛”;
Invalidate();
}
4)分别将青岛的子菜单“崂山”ID_SD_QD_LS、泰安的子菜单“泰山”ID_SD_TA_TS、济南的子菜单“趵突泉”ID_SD_JN_BTQ映射到视图类中,并加代码:
voidCMyView:
:
OnSdQdLs()//青岛崂山
{str=“崂山道士”;
Invalidate();
}
voidCMyView:
:
OnSdTaTs()//泰安泰山
{str=“泰山日出”;
Invalidate();
}
voidCMyView:
:
OnSdJnBtq()//济南趵突泉
{str="天下第一泉";
Invalidate();
}
5)在视图类实现文件CMyView.cpp的OnDraw()函数里加代码:
voidCMyView:
:
OnDraw(CDC*pDC)
{CMyDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
pDC->TextOut(50,50,str);
}
(7)编译运行,,结果见图2.1所示
1)打开山东旅游菜单烟台,见菜单“南山”前面有“√”号
2)打开山东旅游菜单,分别点“蓬莱”、“南山”、“崂山”、“趵突泉”便出现各自的信息。
而“泰山”是灰色的,不能显示信息。
3)程序运行后,出项空白窗口,你按Ctrl+F5、Ctrl+F6、Ctrl+F8分别在窗口中显示“蓬莱仙境”,“崂山道士”,“天下第一泉”。
Ctrl+F7变灰不能显示信息。
4)打开山东旅游菜单,按相应的助机记符(烟台)Y、(青岛)Q、(泰山)T、(济南)J键,便出现各自的子菜单,将鼠标放在子菜单“南山”上,按助记符N,便在文档窗口上显示出:
南山大佛。
说明:
voidInvalidate(BOOLbErase=TRUE);该函数的作用是使整个窗口客户区无效。
窗口的客户区无效意味着需要重绘,例如,如果一个被其它窗口遮住的窗口变成了前台窗口,那么原来被遮住的部分就是无效的,需要重绘。
这时Windows会在应用程序的消息队列中放置WM_PAINT消息。
MFC为窗口类提供了WM_PAINT的消息处理函数OnPaint,OnPaint负责重绘窗口。
视图类有一些例外,在视图类的OnPaint函数中调用了OnDraw函数,实际的重绘工作由OnDraw来完成。
参数bErase为TRUE时,重绘区域内的背景将被擦除,否则,背景将保持不变。
它和UpdateWindow()区别在于:
UpdateWindow()的作用是使窗口立即重绘。
调用Invalidate等函数后窗口不会立即重绘,这是由于WM_PAINT消息的优先级很低,它需要等消息队列中的其它消息发送完后才能被处理。
调用UpdateWindow函数可使WM_PAINT被直接发送到目标窗口,从而导致窗口立即重绘。
2.1.2菜单的编程控制
在交互式软件设计中,菜单有时会随着用户操作的改变而改变,这时的菜单就需要在程序中进行控制。
MFC提供的菜单类CMenu可在程序运行时,处理有关菜单的操作,如:
创建菜单、装入菜单、删除菜单、获取菜单或设置菜单的状态等。
下面给出了CMenu类的常用成员函数。
1、创建菜单:
CMenu类的CreateMenu()和CreatePopupMenu()函数分别用于创建一个菜单或子菜单框架,它们的原型是:
BOOLCreateMenu();产生一个空菜单
BOOLCreatePopupMenu();产生一个空的弹出式子菜单
2、装入菜单
将菜单从资源装入应用程序中,需要调用Cmenu类成员函数LoadMenu或者用SetMenu对应用程序菜单进行重新设置。
BOOLLoadMenu(LPCTSTRlpszResourceName);
BOOLLoadMenu(UINTnIDResource);
参数:
lpszResourceName:
菜单资源名称
nIDResource:
菜单资源ID标识号
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);
参数:
nIDNewItem表示新菜单项的资源ID号
lpszNewItem表示新菜单项的内容
pBmp用于菜单项的位图指针
nPosition表示新菜单项要插入的菜单项位置
nFlags表示要增加的新菜单项的状态信息,其含义见表2.3所示。
表2.3nFlags的值及其对其他参数的影响
nFlage值含义nPosition值nIDNewItem值lpszNewItem
MF_BYCOMMAND菜单项以ID标识符来标识菜单项资源ID
MF_BYPOSITION菜单项以位置来标识菜单项的位置
MF_POPUP菜单项有弹出式子菜单弹出式菜单句柄
MF_SEPARATOR分割线忽略忽略
MF_OWNERDRAW自画菜单项自画所需的数据
MF_STRING字符串标志字符串指针
MF_CHECKED设置菜单项的选中标记
MF_UNCHECKED取消菜单项的选中标记
MF_DISABLED禁用菜单项
MF_ENABLED允许使用菜单项
MF_GRAYED菜单项灰显
注意:
(1)当nFlags为MF_BYPOSITION时,nPosition表示新菜单项要插入的具体位置,为0时表示第1个菜单项,为-1时,将菜单项添加至菜单的末尾处。
(2)在nFlags的标志中,可以用”|”(按位或)来组合,例如MF_CHECKED|MF_STRING等。
但有些组合是不允许的,例如MF_DISABLED、MF_ENABLED和MF_GRAYED,MF_STRING、MF_OWNERDRAW、MF_SEPARATOR和位图,MF_CHECKED和MF_UNCHECKED都不能组合在一起。
(3)当菜单项增加、改变或删除后,不管菜单依附的窗口是否改变,都应调用CWnd:
:
DrawMenuBar来更新菜单。
4、删除菜单项
调用DeleteMenu函数可将指定的菜单项删除。
函数DeleteMenu的原型如下:
BOOLDeleteMenu(UINTnPosition,UINTnFlags);
参数:
nPosition表示要删除的菜单项位置,它由nFlags进行说明。
当:
Flags为MF_BYCOMMAND时,nPosition表示菜单项的ID标识符。
当:
Flags为MF_BYPOSITION时,nPosition表示菜单项的位置(第一个菜单项为0)
5、获取菜单项
以下三个CMenu成员函数分别获得菜单的项数、菜单项的ID标识符以及弹出式子菜单的句柄。
UINTGetMenuItemCount()const;获得菜单项的项数,调用失败返回-1。
UINTGetMenuItemID(intnPos)const;获得由nPos指定菜单项位置(以0为基数)的菜单项的标识号,若nPos是SEPARATOR(分隔符)则返回-1。
CMenu*GetSubMenu(intnPos)const;获得指定菜单的弹出式菜单的菜单句柄,该弹出式菜单位置由参数nPos指定,开始位置为0,若选单不存在,则创建一个临时菜单指针。
例2.3用编写程序的方法添加并处理一个新的菜单项
(1)创建一个单文档(SDI)应用程序(或用例2.2程序),名为:
添加菜单项
(2)ViewResourceSymbols弹出图2.1.5的对话框。
(3)单击“New”按钮,弹出“NewSymbol”对话框New在名字(Name)框中输入一个新的标识符ID_NEW_MENUITEM。
在值(Value)框中,输入该ID的值,如图2.1.6所示。
系统要求用户定义的ID值应大于15(0X000F)而小于61440(0XF000)。
这里保留默认的ID值101,单击“OK”按钮。
图2.1.5“资源符号”对话框
图2.1.6“NewSymbol”对话框
(4)关闭“资源符号”对话框,在CMainFrame:
:
OnCreate函数中添加下列代码,该函
数在框架窗口创建时自动调用。
intCMainFrame:
:
OnCreate(LPCREATESTRUCTlpCreateStruct)
{……
CMenu*pSysMenu=GetMenu();//获得主菜单句柄指针
CMenu*pSubMenu=pSysMenu->GetSubMenu
(1);//获得第二个子菜单指针
CStringStrMenuItem(“新的菜单项”);//字符串对象
pSubMenu->AppendMenu(MF_SEPARATOR);//增加一水平分割线(见表2.3)
//在子菜单末尾增加一菜单项,允许使用ON_UPDATE_COMMAND_UI或ON_COMMAND的菜单项
//下面MF_STRING是字符串标志,ID_NEW_MENUITEM是新的菜单标识符,StrMenuItem是新菜单项内容
pSubMenu->AppendMenu(MF_STRING,ID_NEW_MENUITEM,StrMenuItem);
m_bAutoMenuEnable=FALSE;//关闭系统自动更新菜单状态,见下面说明3
pSysMenu->EnableMenuItem(ID_NEW_MENUITEM,MF_BYCOMMAND|
MF_ENABLED);//激活菜单项
DrawMenuBar();//更新菜单
return