菜單和關閉時重要的 Windows 資源之一。SDK 中,用 HCURSOR 和 HMENU 分別表示菜單和光標的句柄。MFC 中,CMenu 類封裝了菜單的功能。
23 動態添加和刪除菜單項
添加菜單項可以調用 CMenu::AppendMenu 或 CMenu::InserMenu 函數,刪除菜單項可以調用 CMenu::RemoveMenu 或 CMenu::DeleteMenu 函數,最后調用 CWnd::DrawMenuBar 函數重畫菜單。
- CMenu::AppendMenu:在菜單末端添加菜單項。
- CMenu::InserMenu:在菜單指定位置添加菜單項。
- CMenu::RemoveMenu:移動菜單項,如果菜單項與彈出菜單相關聯,將不將銷毀彈出菜單的句柄,因此菜單可重用。
- CMenu::DeleteMenu:刪除菜單項,如果菜單項與彈出菜單相關聯,將銷毀彈出菜單的句柄,并釋放其占用的內存。
#define ID_TEST_MENU 10000
void CMainFrame::OnAppendMenu()
{//獲得主菜單CMenu* pMenu = GetMenu();//獲得子菜單CMenu* pSubMenu = pMenu->GetSubMenu(4);if (pSubMenu->GetMenuItemCount() == 4){//在菜單末端添加菜單項pSubMenu->AppendMenu(MF_STRING,ID_TEST_MENU,_T("New Menu"));//重畫菜單DrawMenuBar();}
}void CMainFrame::OnInsertMenu()
{//獲得主菜單CMenu* pMenu = GetMenu();//獲得子菜單CMenu* pSubMenu = pMenu->GetSubMenu(4);if (pSubMenu->GetMenuItemCount() == 4){//在菜單指定位置添加菜單項pSubMenu->InsertMenu(4,MF_BYPOSITION,ID_TEST_MENU,_T("New Menu"));//重畫菜單DrawMenuBar();}
}void CMainFrame::OnRemoveMenu()
{//獲得主菜單CMenu* pMenu = GetMenu();//獲得子菜單CMenu* pSubMenu = pMenu->GetSubMenu(4);if (pSubMenu->GetMenuItemCount() == 5){//刪除菜單項pSubMenu->RemoveMenu(4,MF_BYPOSITION);//重畫菜單DrawMenuBar();}
}void CMainFrame::OnDeleteMenu()
{//獲得主菜單CMenu* pMenu = GetMenu();//獲得子菜單CMenu* pSubMenu = pMenu->GetSubMenu(4);if (pSubMenu->GetMenuItemCount() == 5){//刪除菜單項pSubMenu->DeleteMenu(4,MF_BYPOSITION);//重畫菜單DrawMenuBar();}
}
void CMainFrame::OnTestMenu()
{AfxMessageBox(_T("測試菜單項命令"));
}
24 在系統菜單中添加和刪除菜單項
在系統菜單中添加和刪除菜單項,首先調用 CWnd::GetSystemMenu 函數獲得系統菜單的指針,然后調用 CMenu::AppendMenu 或 CMenu::InsertMenu,CMenu::RemoveMenu 或 CMenu::DeleteMenu 函數添加和刪除菜單項,最后調用 CWnd::DrawMenuBar 函數重畫菜單。對于添加的菜單項,可以在 CWnd::OnSysCommand 重載函數中處理菜單命令。
//在resource.h文件中添加宏定義
#define ID_TEST_MENU 10000
BOOL CDemoDlg::OnInitDialog()
{CDialog::OnInitDialog();//...//獲得系統菜單CMenu* pMenu = GetSystemMenu(FALSE);//刪除系統菜單項pMenu->RemoveMenu(SC_MOVE,MF_STRING);//添加菜單項pMenu->InsertMenu(0,MF_BYPOSITION,ID_TEST_MENU,_T("New Menu"));//重畫菜單DrawMenuBar();return TRUE;
}
void CDemoDlg::OnSysCommand(UINT nID, LPARAM lParam)
{if ((nID & 0xFFF0) == IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else if(nID == ID_TEST_MENU){AfxMessageBox(_T("測試菜單項命令"));}else{CDialog::OnSysCommand(nID, lParam);}
}
25 禁用關閉按鈕
禁用關閉按鈕可以調用 CMenu::EnableMenuItem 函數。
BOOL CDemoDlg::OnInitDialog()
{CDialog::OnInitDialog();//...//獲得系統菜單CMenu* pMenu = GetSystemMenu(FALSE);//禁用關閉按鈕pMenu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND | MF_GRAYED);return TRUE;
}
26 啟用和禁用菜單項
可以在類的 UPDATE_COMMAND_UI 消息處理函數中調用 CCmdUI::Enable 函數,啟用和禁用菜單項。
//在CMainFrame類中添加成員變量
public:BOOL m_bEnable1;BOOL m_bEnable2;
//在CMainFrame類的構造函數中初始化成員變量
CMainFrame::CMainFrame()
{m_bEnable1 = TRUE;m_bEnable2 = FALSE;
}
//在CMainFrame類中為菜單項添加命令處理函數void CMainFrame::OnTestMenu1()
{m_bEnable1 = FALSE;m_bEnable2 = TRUE;
}void CMainFrame::OnUpdateTestMenu1(CCmdUI* pCmdUI)
{//啟動或禁用菜單1pCmdUI->Enable(m_bEnable1);
}void CMainFrame::OnTestMenu2()
{m_bEnable1 = TRUE;m_bEnable2 = FALSE;
}void CMainFrame::OnUpdateTestMenu2(CCmdUI* pCmdUI)
{//啟動或禁用菜單2pCmdUI->Enable(m_bEnable2);
}
27 設置菜單項的檢查狀態
可以在類的 UPDATE_COMMAND_UI 消息處理函數中調用 CCmdUI::SetCheck 函數設置菜單項的檢查狀態(選中/不選中狀態)。
//在CMainFrame類中添加成員變量
public:int m_nCheck;
//在CMainFrame類的構造函數中初始化成員變量
CMainFrame::CMainFrame()
{m_nCheck = 0;
}
//在CMainFrame類中為菜單項添加命令處理函數
void CMainFrame::OnTestMenu()
{if (m_nCheck == 0){m_nCheck = 1;}else{m_nCheck = 0;}}void CMainFrame::OnUpdateTestMenu(CCmdUI* pCmdUI)
{//設置菜單項檢查狀態pCmdUI->SetCheck(m_nCheck);
}
28 快捷菜單
實現快捷菜單可以在 CWnd::OnContextMenu 重載函數中調用 CMenu::TrackPopupMenu 函數。
在資源中添加1個菜單資源,ID 為 IDR_MENU。在菜單資源中添加1個子菜單,并添加菜單項。
//在CDemoView類中重載CWnd::OnContextMenu函數
void CDemoView::OnContextMenu(CWnd* pWnd, CPoint point)
{CMenu menu;//加載菜單if (!menu.LoadMenu(IDR_MENU)){return;}//獲得子菜單CMenu* pPopupMenu = menu.GetSubMenu(0);//彈出菜單pPopupMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,point.x,point.y,pWnd);
}
void CDemoView::OnTestMenu1()
{AfxMessageBox(_T("快捷菜單項1命令"));
}void CDemoView::OnTestMenu2()
{AfxMessageBox(_T("快捷菜單項2命令"));
}
29 獲取光標的坐標
可以在 WM_MOUSEMOVE 消息處理函數中獲得光標的位置。
//在CDemoView類中添加成員變量
public:CPoint m_Point;
//在類中添加WM_MOUSEMOVE消息處理函數
void CDemoView::OnMouseMove(UINT nFlags, CPoint point)
{//保存光標坐標m_Point = point;//刷新客戶區Invalidate();CView::OnMouseMove(nFlags, point);
}
//在類中重載CView::OnDraw函數
void CDemoView::OnDraw(CDC* pDC)
{//獲得客戶區坐標CRect rect;GetClientRect(rect);//繪制十字光標pDC->MoveTo(0,m_Point.y);pDC->LineTo(rect.Width(),m_Point.y);pDC->MoveTo(m_Point.x,0);pDC->LineTo(m_Point.x,rect.Height());//輸出光標坐標CString strText = _T("");strText.Format(_T("%d,%d"),m_Point.x,m_Point.y);pDC->SetBkMode(TRANSPARENT);pDC->SetTextAlign(TA_RIGHT | TA_BOTTOM);pDC->TextOut(m_Point.x,m_Point.y,strText);
}
30 限制光標的移動范圍
限制光標的范圍可以調用 SDK 的 ClipCursor 函數。
//在CDemoView類中重載CView::OnDraw函數
void CDemoView::OnDraw(CDC* pDC)
{//獲得客戶區坐標CRect rect;GetClientRect(rect);rect.left = rect.left + rect.Width() / 4;rect.right = rect.right - rect.Width() / 4;rect.top = rect.top + rect.Height() / 4;rect.bottom = rect.bottom -rect.Height() / 4;//繪制光標移動范圍pDC->Rectangle(rect);
}
//在CDemoView類中分別添加WM_LBUTTONDOWN和WM_LBUTTONUP消息處理函數
void CDemoView::OnLButtonDown(UINT nFlags, CPoint point)
{//獲得客戶區坐標CRect rect;GetClientRect(rect);rect.left = rect.left + rect.Width() / 4;rect.right = rect.right - rect.Width() / 4;rect.top = rect.top + rect.Height() / 4;rect.bottom = rect.bottom - rect.Height() /4;//映射屏幕坐標ClientToScreen(rect);//限制光標移動范圍ClipCursor(&rect);CView::OnLButtonDown(nFlags, point);
}void CDemoView::OnLButtonUp(UINT nFlags, CPoint point)
{//光標自由移動ClipCursor(NULL);CView::OnLButtonUp(nFlags, point);
}
31 自定義光標
使用自定義光標,首先調用 CWinApp::LoadCursor函數加載光標,然后調用SDK的SetCursor函數設置光標。
//創建1個單文檔的應用程序,并添加2個光標資源,在CDemoView類中添加成員變量
public:HCURSOR m_hCursor;
//在CDemoView類中重載CView::OnInitialUpdate函數
void CDemo2View::OnInitialUpdate()
{CView::OnInitialUpdate();//加載光標m_hCursor = AfxGetApp()->LoadCursor(IDC_CURSOR1);
}
//在CDemoView類中添加WM_SETCURSOR消息處理函數
BOOL CDemo2View::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{//設置光標::SetCursor(m_hCursor);return TRUE;
}
//在CDemoView類中分別添加WM_LBUTTONDOWN和WM_LBUTTONUP消息處理函數
void CDemo2View::OnLButtonDown(UINT nFlags, CPoint point)
{//加載光標m_hCursor = AfxGetApp()->LoadCursor(IDC_CURSOR2);//設置光標::SetCursor(m_hCursor);CView::OnLButtonDown(nFlags, point);
}void CDemo2View::OnLButtonUp(UINT nFlags, CPoint point)
{//加載光標m_hCursor = AfxGetApp()->LoadCursor(IDC_CURSOR1);//設置光標::SetCursor(m_hCursor);CView::OnLButtonUp(nFlags, point);
}
32 等待光標
啟動等待光標可以調用 CCmdTarget::BeginWaitCursor函數,結束等待光標可以調用CCmdTarget::EndWaitCursor函數。
void CDemo2View::OnLButtonUp(UINT nFlags, CPoint point)
{//啟動等待光標BeginWaitCursor();//休眠Sleep(5000);//結束等待光標EndWaitCursor();CView::OnLButtonDown(nFlags,point);
}
?