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()函數以實現更多的功能。
文章來源于領測軟件測試網 http://www.kjueaiud.com/