ccidnet????

出版日期:2001-09-17 总期号:1055 本年期号:70

本期导读
要闻综合
电脑工作室
渠道与市场
产品与应用
软件与服务
InfoTimes
把选单加到工具栏

薛瑛

  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()函数以实现更多的功能。


  通过工具栏中的按钮可以直接调出打印界面