第4章 菜单工具栏和状态栏.docx
《第4章 菜单工具栏和状态栏.docx》由会员分享,可在线阅读,更多相关《第4章 菜单工具栏和状态栏.docx(32页珍藏版)》请在冰豆网上搜索。
第4章菜单工具栏和状态栏
第4章菜单、工具栏和状态栏
菜单、工具栏和状态栏是Windows文档应用程序中不可缺少的界面元素,其风格和外观有时直接影响着用户对软件的评价。
许多优秀的软件(如MicrosoftOffice)为增加对用户的吸引力,将它们做得多姿多彩,甚至达到真三维的效果。
本章将从它们最简单的用法开始入手,逐步深入直到对其进行编程控件。
4.1菜单
像对话框一样,菜单也是一种资源模板(容器),其上可包含多级的菜单项(顶层、下拉)。
通过菜单项的选择可产生相应的命令消息,通过消息映射实现要执行的相应任务。
4.1.1菜单一般规则
为了使应用程序更容易操作,对于菜单系统的设计还应遵循下列一些规则:
1若单击某菜单项后,将弹出一个对话框,那么在该菜单项文本后有“…”。
2若某项菜单有子菜单,那么在该菜单项文本后有“►”。
3若菜单项需要助记符,则用括号将带下划线的字母括起来。
助记符与Alt构成一个组合键,当按住Alt键不放,再敲击该字母时,对应的菜单项就会被选中。
若某项菜单需要快捷键的支持,则一般将其列在相应菜单项文本之后。
所谓“快捷键”是一个组合键,如Ctrl+N键,使用时是先按下Ctrl键不放,然后再按N键。
任何时候按下快捷键,相应的菜单命令都会被执行。
下图是一个菜单样例,注意它们的规则含义。
需要强调的是,在常见的菜单系统中,最上面的一层水平排列的菜单称为顶层菜单,每一个顶层菜单项可以是一个简单的菜单命令,也可以是下拉(Popup)菜单,在下拉菜单中的每一个菜单项也可是菜单命令或下拉菜单,这样一级一级下去可以构造出复杂的菜单系统。
4.1.2更改并切换应用程序菜单
前面的章节多处说明了用菜单编辑器添加和修改菜单项的过程和方法,这里进一步地说明,并为应用程序重新指定一个菜单,然后切换。
【例4.1】创建一个名为MenuDemo的单文档应用程序,演示菜单的创建及作用。
1.创建名为MenuDemo的单文档应用程序。
2.添加并设计菜单
(1)将工作区切换到ResourceView选项卡,展开资源结点,双击资源Menu结点下的IDR_MAINFRAME项,则菜单编辑窗口出现在主界面的右边,项目MenuDemo相应的菜单资源也显示出来。
(2)按Ctrl+R,弹出InsertResource对话框,在资源类型中选Menu,单击New按纽,系统会为应用程序添加一个新的菜单资源,并自动赋给它一个默认的标识符名称(第一次为IDR_MENU1,以后依次为IDR_MENU2、IDR_MENU3、…),同时自动打开这个新的菜单资源模板。
(3)用鼠标选定空白菜单项并双击,则出现它的属性对话框。
通过此为菜单ID_MENU1添加一个标题为“测试(&T)”,属性为Pop-up(下拉)的顶层菜单项。
并在该菜单项下面添加一个标题为“返回(&R)”,ID号为ID_TEST_RETURN的子菜单项。
需要再次强调的是,符号&用来指定后面的字符是一个助记符。
(4)双击IDR_MAINFRAME,在“查看”菜单下后添加一个子菜单项“显示测试菜单(&M)”,ID号为ID_VIEW_TEST。
3.完善代码
(1)将工作区切换到ClassView选项卡,展开类结点,右击CMainFrame类名,从弹出的快捷菜单中选择AddMemberVariables(添加成员变量),在对话框中,为CMainFrame类添加一个CMenu类型的成员变量m_newMenu(CMenu类是用来处理菜单的一个MFC类)。
(2)按Ctrl+W,打开ClassWIzard,切换到MessageMaps选项卡,从Classname列表中选CMainFrame,分别为菜单项ID_VIEW_TEST和ID_TEST_RETURN添加COMMAND消息映射,使用默认的消息映射函数名,并添加以下代码:
voidCMainFrame:
:
OnViewTest()//新菜单装载试验
{
//应用程序默认的启动菜单是主菜单IDR_MAINFRAME,故m_newMenu为主菜单句柄
m_newMenu.Detach();//使m_newMenu与主菜单句柄分离
m_newMenu.LoadMenu(IDR_MENU1);//m_newMenu获得新菜单IDR_MENU1句柄
SetMenu(NULL);//清除应用程序主菜单
SetMenu(&m_newMenu);//启用以m_newMenu所代表的新菜单
}
voidCMainFrame:
:
OnTestReturn()//返回主菜单试验
{
//本段代码与前段代码完全一样,只是对象完全返过来了
m_newMenu.Detach();
m_newMenu.LoadMenu(IDR_MAINFRAME);
SetMenu(NULL);
SetMenu(&m_newMenu);
}
其中,LoadMenu和Detach都是CMenu类成员函数,LoadMenu用来装载菜单资源,而Detach是使菜单对象与菜单句柄分离。
在调用LoadMenu后,菜单对象m_newMenu应拥有一个菜单句柄,当再次调用LoadMenu时,由于菜单对象的句柄已经创建,因而会发生运行错误,但当菜单对象与菜单句柄分离后,就可以再次创建菜单了。
SetMenu是CWnd类的一个成员函数,用来设置应用程序的菜单。
4.编译运行后,选择应用程序的“查看|显示测试菜单”命令,菜单栏变成了新添加的IDR_MENU1,选择“测试|返回”菜单命令,程序又变回到原来默认的菜单。
4.1.3使用键盘快捷键
通过菜单,用户可以选择几乎所有可用的命令和选项。
但菜单也有不足之处,如操作效率不高等。
尤其对于那些反复使用的命令,很有必要进一步提高效率,于是快捷键应运而生。
一个快捷键就是一个按键或几个按键的组合,它用于激活特定的命令。
快捷键也是一种资源,它的显示、编辑过程和菜单相似。
【例4.2】为MenuDemo的两个用户自定义菜单项,设置快捷键。
1.启动VisualC++6.0,点击菜单File|OpenWorkspace,在弹出的对话框,找到文件夹MenuDemo下的MenuDemo.dsw,按“打开”按纽。
2.将工作区切换到ResourceView选项卡,展开所有资源结点,双击Accelerator结点下的IDR_MAINFRAME项,出现下图所示的快捷键资源列表。
3.要建立一个新的快捷键,双击快捷键列表的最下端的空行,弹出下图所示的Accel属性对话框,可设置的属性含义如表4.1所示。
表4.1快捷键General属性对话框的各项含义
项目
含义
ID
指定资源ID号的列表项,为了能和菜单联用,通常选择某菜单项的ID号
辅助键(Modifiers)
用来确定Ctrl、Alt、Shift是否构成快捷键的组成部分
类型(Type)
用来确定该快捷键的值是虚拟键(VirKey)还是ASCII码
键(Key)
是指启动快捷键的键盘按键
下一个按下的键(NextKeyTyped)
单击此按纽后,用户操作的任何按键将成为此快捷键的键值
4.按下图为两个菜单项(ID号)设置快捷键。
5.为了让用户知道两个菜单项的快捷键的设置,返回菜单编辑器,将标题分别修改成为“显示测试菜单(&M)\tCtrl+1”和“返回(&R)\tCtrl+2”。
6.编译运行。
当程序运行后,按Ctrl+1键将执行“显示测试菜单”菜单项,按Ctrl+2键将执行“返回”菜单项。
4.1.4菜单的编程控件
在交互式软件的设计中,菜单有时会随着用户的操作的改变而改变,这时的菜单就需要在程序中进行控制。
前面已简单地讨论了MFC菜单类CMenu的成员函数LoadMenu的使用,事实上,CMenu的功能还不止这些,它可在程序运行时处理有关菜单的操作,如创建菜单、装载菜单、删除菜单项、获取或设置菜单项的状态等。
1.创建菜单
CMenu类的CreateMenu和CreatePopupMenu分别用来创建一个菜单或子菜单框架,它们的原型如下:
BOOLCreateMenu();//生成一个空菜单
BOOLCreatePopupMenu();//生成一个空的弹出式子菜单
2.装入菜单源
将菜单资源装入应用程序中,需调用CMenu成员函数LoadMenu,然后用SetMenu对应用程序菜单进行重新设置。
BOOLLoadMenu(LPCTSTRlpszSourceName);
BOOLLoadMenu(UINTnIDResource);
其中,lpszResourceName为菜单资源名称,nIDResource为菜单资源ID号。
3.添加菜单项
当菜单创建后,用户可以调用AppeendeMenu或InsertMenu函数来添加一些菜单项。
但每次添加时,AppendMenu是将菜单项添加在菜单的未尾处,而InsertMenu在菜单的指定位置处插入菜单项,并将后面的菜单项依次下移。
BOOLAppendMenu(UINTnFlags,UINTnIDNewItem=0,LPCTSTRipszNewItem=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表示要增加的新菜单项的状态信息,它的值影响其他参数的含义,如表4.2所示。
表4.2nFlags的值及其对其他参数的影响
nFlags值
含义
nPosition值
nIDNewItem值
lpszNewItem值
MF_BYCOMMAND
菜单项以ID号来标识
菜单项资源ID
MF_BYPOSITION
菜单项以位置来标记
菜单项的位置
MF_POPUP
菜单项有弹出式子菜单
弹出式菜单句柄
MF_SEPARATOR
分隔线
忽略
忽略
MF_OWNERATOR
自画菜单项
自画所需的数据
MF_STRING
字符串标记
字符串指针
MF_CHECKED
设置菜单项的选中标记
MF_UNCHECKED
取消菜单项的选中标记
MF_DISABLED
禁用菜单项
MF_ENABLED
允许使用菜单项
MF_GRAYED
菜单项灰显
注意:
(1)当nFlags为MF_BYPOSITION时,nPosition表示新菜单项要插入的具体位置,为0时表示第一个菜单项,为-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函数可将指定的菜单项删除,其原型如下:
BOOLDeleteMenu(UINTnPosition,UINTnFlags);
其中,参数nPosition表示要删除的菜单项位置,它由nFlags进行说明。
若当nFlags为MF_BYCOMMAND时,nPosition表示菜单项的ID号,而当nFlags为MF_BYPOSITION时,nPosition表示菜单项的位置(第一个菜单项位置为0)。
需要注意是:
调用该函数后,不管菜单依附的窗口是否改变,都应调用CWnd:
:
DrawMenuBar使菜单更新。
5.获取菜单项
下面的4个CMenu成员函数分别获得菜单的项数、菜单的ID号、菜单项的文本内容以及弹出式子菜单的句柄。
UINTGetMenuItemCount()const;
该函数用来获得菜单项数,调用失败后返回-1。
UINTGetMenuItemID(intnPos)const;
该函数用来获得由nPos指定菜单项位置(以0为基数)的菜单项的标识号,若nPos是SEPARATOR,则返回-1。
intGetMenuString(UINTnIDItem,CString&rString,UINTnFlags)const;
该函数用来获得由nIDItem指定菜单项位置(以0为基数)的菜单项的文本内容(字符串),并由rString参数返回,当nFlags为MF_BYPOSITION时,nPosition表示菜单项的位置(第一个菜单项位置为0)。
CMenu*GetSubMenu(intnPos)const;
该函数用来获得指定菜单的弹出式菜单的菜单句柄。
该弹出式菜单位置由参数nPos指定,开始的位置为0。
若菜单不存在,则创建一个临时的菜单指针。
【例4.3】创建一个名为EditMenu的单文档应用程序,演示如何用程序代码来实现菜单。
1.创建单文档应用程序EditMen。
2.选View|ResourceSymbols菜单项,弹出“资源符号”的对话框,它能对应用程序中的资源标识符进行管理。
由于程序中要添加的菜单项需要一个标识值,因此最好用一个标识符来代替这个值,这是一个好习惯。
因此这里通过“资源符号”对话框来创建一个新的标识符。
3.单击New按纽,在弹出的对话框的名称(Name)框中输入一个新标识符ID_NEW_MENUITEM。
在“值”(Value)框中,输入该ID的值,系统要求用户定义的ID值应大于15(OX000F)而小于61440(OXF0000)。
保留默认的ID值为101。
按Close按纽,关闭“资源符号”对话框。
4.将工作区切换到ClassView,展开CMainFrame类结点,双击OnCreate(),为该成员函数添加以下代码。
intCMainFrame:
:
OnCreate(LPCREATESTRUCTlpCreateStruct)
{
…
//TODO:
Deletethesethreelinesifyoudon'twantthetoolbarto
//bedockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
CMenu*pSysMenu=GetMenu();//获得程序菜单指针
CMenu*pSubMenu=pSysMenu->GetSubMenu
(1);//获得第二个子菜单的指针
CStringStrMenuItem("新的菜单项");//定义字符变量并赋初值
//在子菜单中增加一菜单项
pSubMenu->AppendMenu(MF_STRING,ID_NEW_MENUITEM,StrMenuItem);
//允许使用ON_UPDATE_COMMADN_UI或ON_COMMAND的菜单项
m_bAutoMenuEnable=FALSE;//关闭系统自动更新菜单状态
//激活菜单项
pSysMenu->EnableMenuItem(ID_NEW_MENUITEM,MF_BYCOMMAND|MF_ENABLED);
DrawMenuBar();//更新菜单
return0;
}
5.打开ClassWizard,在Classname栏选CMainFrame,在ObjectIDs栏选CMainFrame,在Messages栏选OnCommand,按AddFunction按纽,再按EditCode按纽,进入该函数的编辑环境,并添加以下代码。
BOOLCMainFrame:
:
OnCommand(WPARAMwParam,LPARAMlParam)
{
}
6.编译运行并测试。
当选择“编辑|新的菜单项”菜单命令后,就会弹出一个对话框,显示“你选中了新的菜单项”消息。
4.1.5使用快捷菜单
快捷菜单是一种浮动的弹出式菜单,它是一种新的用户界面设计风格。
当有户按下鼠标右键时,就会相应地弹出一个浮动菜单,其中提供了几个与当前选择内容相关的选项。
用资源编辑器和MFC库的CMenu:
:
TrackPopupMenu函数可以很容易创建这样的菜单,CMenu:
:
TrackPopupMenu函数原型如下;
BOOLTtackPopupMenu(UINTnFlags,intx,inty,CWnd*pWnd,LPCRECTlpRect=NULL);
该函数用来显示一个浮动的弹出式菜单,其位置由各参数决定。
其中,nFlags表示变量在屏幕在屏幕显示的位置以及鼠标按纽标志,如表4.3所示。
x和y表示菜单的水平坐标和菜单的顶端的垂直坐标。
pWnd表示弹出菜单的窗口,此窗口将收到菜单全部的WM_COMMAND消息。
lpRect是一个RECT结构或CRet对象指针,它表示一个矩形区域,用户单击这个区域时,弹出菜单不消失。
而当lpRect为NULL时,若用户在菜单外面单击鼠标,菜单立刻消失。
表4.3nFlags的值及其对其他参数的影响
nFlags值
含义
TPM_CENTERALIGN
屏幕位置标志,表示菜单的水平中心位置由x坐标确定
TPM_LEFTALIGN
屏幕位置标志,表示菜单的左边位置由x坐标确定
TPM_RIGHTALIGN
屏幕位置标志,表示菜单的右边位置由x坐标确定
TPM_LEFTBUTTON
鼠标按纽标志,表示当用户单击鼠标左键时弹出菜单
TMP_RIGHTBUTTON
鼠标按纽标志,表示当用户单击银票右键时弹出菜单
【例4.4】为MenuDemo增添一项新功能:
当程序运行时,如果显示的菜单为IDR_MAINFRAME时,右击鼠标则可弹出“查看”菜单的子菜单;如果显示的菜单为IDR_MENU1,右击鼠标则弹出“测试”菜单的子菜单。
1.打开前面的单文档应用程序MenuDemo。
2.打开ClassWizard,选MessageMaps选项卡,在Classname栏选CMainFrame类,在ObjectIDs栏选CMainFrame,在Messages栏选WM-CONTEXTMENU,按AddFunction按纽,取缺省函数名,再按EditCode按纽,添加以下代码:
voidCMainFrame:
:
OnContextMenu(CWnd*pWnd,CPointpoint)
{
CMenu*pSysMenu=GetMenu();//获取程序菜单指针
intnCount=pSysMenu->GetMenuItemCount();//获取项层菜单项的项数
intnSubMenuPos=-1;//定义子菜单索引号初值,即无子菜单项
for(inti=0;i{
CStringstr;//定义存储菜单名称的字符变量
pSysMenu->GetMenuString(i,str,MF_BYPOSITION);//获取顶层菜单项的名称
if((str.Left(4)=="查看")||(str.Left(4)=="测试"))//如果菜单名为“查看”或“测试”
{
nSubMenuPos=i;//得到了“查看”或“测试”菜单项所在的位置
break;
}
}
if(nSubMenuPos<0)
return;//没有找到则什么都不做,返回
//创建“查看”或“测试”的快捷菜单
pSysMenu->GetSubMenu(nSubMenuPos)
->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);
}
3.编译运行,其效果如下图所示。
4.2工具栏
工具栏是一系列工具按纽的组合,借助它们可以提高用户的工作效率。
VisualC++6.0系统保存了每个工具栏相应的位图,共中包括所有按纽的图像,而所有的按纽图像具有相同的尺寸(15像素高,16像素宽),它们在位图中的排列次序与在工具栏上的次序相同。
4.2.1使用工具栏编辑器
创建一个单文档的应用程序,将项目工作区窗口切换到ReSsourceView选项卡,展开资源结点,双击Toolbar(工具栏)结点中的IDR_MAINFRAME项,则工具栏编辑器出现在主界面的右边,如下图所示。
现在,用户就可以用它对工具栏进行操作了,默认情况下,工具栏在最初创建时,其右端有一个空的按纽,在进行编辑之前,该按纽可以拖放移动到工具栏中其他位置。
当创建一个新的按纽后,在工具栏右端又会自动出现一个新的空按纽(有时,新的空按纽会紧挨着刚创建的按纽出现),当保存此工具栏资源时,空按纽不会被保存。
下面就工具栏按纽的一般操作进行说明。
1.创建一个新的工具栏按纽
在新建的工具栏中,最右端总有一个空按纽,双击该按纽弹出其属性对话框,在ID框中输入其标识符名称,则在其最右端又出现一个新的空按纽。
单击该按纽,在资源编辑器的工具按纽设计窗口内进行编辑,这个编辑就是绘制一个工具按纽的位图,它同一般图形编辑器操作相同(如Windows系统中的“画图”附件)。
2.移动一个按纽
在工具栏中移动一个按纽,用鼠标左键点中它并拖动至相应位置即可。
如果用户拖动它离开工具栏位置,则此按纽从工具栏中消失(即被删除)。
若在移动一个按纽的同时,按下Ctrl键,则在新位置复制一个按纽,新位置可以是同一个工具栏中的其他位置,也可以在不同的工具栏中。
3.删除一个按纽
前面已提到过,将选取中的按纽拖离工具栏,则该按纽就消失了。
但若选中按纽后单击Delete键并不能删除一个按纽,只是将按纽中的图形全部以背景色填充。
4.在工具栏中插入空格
在工具栏中插入空格有以下几种情况:
(1)如果按纽前没有任何空格,拖动该按纽向右移动并当覆盖相邻按纽的一半以上时,释放鼠标,则此按纽前出现空格。
(2)如果按纽前有空格而按纽后没有空格,拖动该按纽向左移动并当按纽的左边界接触到前面按纽时,释放鼠标键,则此按纽后将出现空格。
(3)如果按纽前后均有空格,拖动该按纽向右移动并当接触到相邻按纽时,则按纽前的空格保留,按纽后的空格消失。
相反,拖动该按纽向左移动并当接触到前一个相邻按纽时,则此按纽前面的空格消失,后面的空格保留。
5.工具栏按纽属性的设置
双击按纽图标弹出属性对话框,如下图所示,属性对话框中的各项说明如表4.4所示。
表4.4工具栏按纽属性对话框的各项