Windows以其良好的用户界面深受广大用户的喜爱,尤其是其IE4的推出增加了新颖的控制。选单栏就是其中一项,它结合了以往的选单和工具栏的特性,如果能将选单放置在工具栏上,既能响应选单消息又能随意拖动,那该多好!
由于在MFC类库中并没有提供CMenuBar类,用户不能像制作工具条那样定制选单栏,这给不少的开发人员带来了不便。本文提供了一种简单快速的方法很好地实现了选单栏的功能。
按钮是工具条的组成元素,它能够响应用户的点击,相应地进行处理。我们就利用这一特性来实现选单控制。程序的开发环境是VC++ 6.0,Windows 98/2000/NT。
通过工具栏中的按钮可以直接调出打印界面
新建工程
首先在Visual Studio中选择NEW生成新的工程,我们选择单文档界面SDI。在资源编辑器中生成自己的选单,ID号为IDR_TOOL_MENU。接下来生成自己的工具栏。在主界面窗口MainFrame.h中加入工具栏定义:
class CMainFrame : public CFrameWnd
{...
Protected:
CToolBar m_wndMenuBar;
...
}
在MainFrame.cpp的类CmainFrame::OnCreate()函数中加入生成代码:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndMenuBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD
WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS |
CBRS_FLYBY| CBRS_SIZE_DYNAMIC ))
{
TRACE0("Failed to create Menubar\n");
return -1; // fail to create
}
m_wndMenuBar.SetSizes(CSize(30,20),CSize(1,1));//设置工具栏按钮的大小
……
添加按钮及响应程序
工具栏生成后,下一步我们就要在工具栏中加入按钮。按钮的数量是根据选单项的多少来决定的。
TBBUTTON button;
CString strItem;
CMenu mTopMenu;
mTopMenu.LoadMenu(IDR_TOOL_MENU);
UINT iPos;
for (iPos = 0; iPos < mTopMenu.GetMenuItemCount(); iPos++)
{ mTopMenu.GetMenuString(iPos, strItem, MF_BYPOSITION);
button.idCommand = iPos+1;
button.iBitmap = -1;
button.fsState = 0;
button.fsStyle = TBSTYLE_BUTTON;
button.iString = -1;
m_wndMenuBar.GetToolBarCtrl().InsertButton(iPos,&&button);
m_wndMenuBar.SetButtonText(iPos,strItem);
}
这里,我们用到了结构TBBUTTON,它定义了按钮的一些特性。其中最重要的是idCommand属性,它定义了按钮的ID命令号,用于在按钮按下时触发ON_ONCOMMAND 命令,我们将其定义成选单项的索引号(Index),fsStyle为按钮的风格,fsState为按钮的状态。通过调用GetToolBarCtrl获得ToolBar的Control类。此类提供了工具栏的通用控制。利用CtoolBarCtrl类可将按钮加入到工具栏中,用SetButtonText可设置按钮的显示文本。下面我们将编写处理按钮命令,以实现我们的选单控制。首先定义消息响应函数OnMenu(),代码如下:
MainFrame.h
CmainFrame::Public CframeWnd
{...
protected:
//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG
afx_msg void OnMenu(UINT nID);
DECLARE_MESSAGE_MAP()
...
}
在MainFrame.cpp 中加入如下代码:
#define MAX_MENU_SUBMENUS 20
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code !
ON_WM_CREATE()
//}}AFX_MSG_MAP
ON_COMMAND_RANGE(1,MAX_MENU_SUBMENUS, OnMenu)
END_MESSAGE_MAP()
其中,ON_COMMAND_RANGE宏将按钮事件的消息ID映射到相应的OnMenu(uID)函数上。再利用OnMenu(uID)函数来进行选单控制。
void CMainFrame::OnMenu(UINT nID)
{
CMenu m_mnuTopMenu;
CRect rWindow,rButton;
m_mnuTopMenu.LoadMenu(IDR_MAINFRAME);
UINT iPos;
for (iPos = 0; iPos < m_mnuTopMenu.GetMenuItemCount(); iPos++)
{
if (iPos == nID-1)
{
m_wndMenuBar.GetWindowRect(&&rWindow);
m_wndMenuBar.GetItemRect( iPos, &&rButton);
rWindow.top += rButton.bottom;
rWindow.left += rButton.left;
m_wndMenuBar.GetToolBarCtrl().SetState(iPos+1,TBSTATE_PRESSED|TBSTATE_ENABLED);
// show popup menu
m_mnuTopMenu.GetSubMenu(iPos)-> TrackPopupMenu(
TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL,
rWindow.left,rWindow.top,this);
m_wndMenuBar.GetToolBarCtrl().SetState(iPos+1,TBSTATE_ENABLED);
break;
}
}
}
OnMenu()函数用按钮的ID号作为参数,首先判断发出命令的是哪一个按钮,计算出响应的选单项及显示位置,用CtoolBarCtrl类的SetState()设置按钮的状态,并调用Cmenu类的TrackPopupMenu()显示选单项。最后我们加入实现选单栏的任意拖放的程序代码:
m_wndMenuBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&&m_wndMenuBar);
本文所用方法简单、实用,用户可定制OnMenu()函数以实现更多的功能。
文章来源于领测软件测试网 https://www.ltesting.net/