最近需要做了菜单栏,替换多文档试图结构的菜单栏。最后需模拟一个,参照了网上的资料,完成了所需菜单栏,谢谢goodboyws在论坛的帖子, 展示如下: 首先在窗口的任意一个区域画出菜单的效果,这个区域我们称为菜单区,我们把每个菜单项在窗口中的位置保存下来
CRect m_rcMenu[3];
程序主要要处理三个消息: WM_LBUTTONDOWN、WM_MOUSEMOVE、WM_ENTERIDLE
BEGIN_MESSAGE_MAP(CMyDlg, CDialog) //{{AFX_MSG_MAP(CMyDlg) ON_WM_LBUTTONDOWN( ) ON_WM_MOUSEMOVE() ON_WM_ENTERIDLE() //}}AFX_MSG_MAP END_MESSAGE_MAP()
当鼠标在菜单区内按下的时候,开始用弹出菜单模拟窗口菜单。
void CMyDlg::OnLButtonDown(UINT nFlags, CPoint ptStart) { for (i=0 ;i<3; i++) { if (PtInRect(m_rcMenu[i], point)) { if (!PtInRect(m_rcMenu[m_iMenuIndex], point)) { InvalidateRect(&m_rcMenu[m_iMenuIndex], TRUE); UpdateWindow(); }
//这个是菜单索引,用它来标示显示那个菜单 m_iMenuIndex = i; m_bShowMenu = TRUE;
//菜单显示,如果m_bMenuContinue为TRUE, 不断显示新的菜单,旧的在WM_ENTERIDLE中清除,之所以做这样的处理,是因为窗口菜单要求当菜单弹出时,随着鼠标在菜单区的移动,菜单变更为相应的子菜单
do {
//画菜单的按下效果 CDC* pDC = GetDC(); pDC->Draw3dRect(&m_rcMenu[m_iMenuIndex], RGB(100, 100, 100), RGB(160, 160, 160)); ReleaseDC(pDC); m_bMenuContinue = FALSE; ShowMenu(); } while(m_bMenuContinue); InvalidateRect(&m_rcMenu[m_iMenuIndex], TRUE); UpdateWindow(); m_bShowMenu = FALSE; CWnd::OnLButtonDown(nFlags, point); return; } } if ( i== 3) m_iMenuIndex = -1; CDialog::OnLButtonDown(nFlags, point);
}
然后在OnMouseMove里更新菜单索引
void CMyDlg::OnMouseMove(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default //把原来的菜单按下效果清除掉 if (m_iMenuIndex != -1) { if (!PtInRect(m_rcMenu[m_iMenuIndex], point)) InvalidateRect(&m_rcMenu[m_iMenuIndex], TRUE);
}
UpdateWindow();
m_iMenuIndex = -1; for (i=0 ;i<3; i++) { if (PtInRect(m_rcMenu[i], point)) { //确定当前菜单索引 m_iMenuIndex = i; //画菜单的抬起效果 CDC* pDC = GetDC(); pDC->Draw3dRect(&m_rcMenu[i], RGB(160, 160, 160), RGB(100, 100, 100)); ReleaseDC(pDC); break; } }
CDialog::OnMouseMove(nFlags, point); }
在OnEnterIdle将菜单取消并重新显示
void CGameBoxShell::OnEnterIdle(UINT nWhy, CWnd* pWho) { CWnd::OnEnterIdle(nWhy, pWho); // TODO: Add your message handler code here if (nWhy == MSGF_MENU) {
if (!m_bShowMenu) return; CPoint point; GetCursorPos(&point); ScreenToClient(&point); for (int i=0 ;i<3; i++) { if (PtInRect(m_rcMenu[i], point)) { if (m_iMenuIndex != i) { if (m_iMenuIndex != -1) { if (!PtInRect(m_rcMenu[m_iMenuIndex], point)) { InvalidateRect(&m_rcMenu[m_iMenuIndex], TRUE); UpdateWindow(); } } m_iMenuIndex = i; m_bMenuContinue = TRUE; SendMessage(WM_CANCELMODE); } break; } }
} }
最后,把显示菜单的代码补充完整 void CMyDlg::ShowMenu() { if (m_PopupMenu.GetSafeHmenu()) m_PopupMenu.DestroyMenu(); m_PopupMenu.LoadMenu(IDR_POPUP); CMenu* pSub = m_PopupMenu.GetSubMenu(m_iMenuIndex); CPoint pt(m_rcMenu[m_iMenuIndex].left, m_rcMenu[m_iMenuIndex].bottom+2); ClientToScreen(&pt); TrackPopupMenu(pSub->GetSafeHmenu(), TPM_LEFTALIGN | TPM_LEFTBUTTON, pt.x, pt.y, NULL, m_hWnd, NULL); }
(###)
|