首页 > 代码库 > VC 菜单栏的自绘(二)

VC 菜单栏的自绘(二)

没人看我代码一贴完事

//cpp文件

#include "StdAfx.h"
#include "MenuBar.h"
#include "resource.h"


HHOOK gMsgFilterHook=NULL;
CMenuBar* g_MenuBar;
CMenuItem* gOldMenuItem = NULL;
CMenuItem* gNewMenuItem = NULL;
BOOL g_bPressed = FALSE;

LRESULT CALLBACK MessageProc( int code, WPARAM wParam, LPARAM lParam)
{
    if ( code == MSGF_MENU )
    {
        MSG *pMsg = (MSG *)lParam;
        switch ( pMsg->message )
        {
        case WM_MOUSEMOVE:
            {
                CPoint pt;
                pt.x = LOWORD(pMsg->lParam);
                pt.y = HIWORD(pMsg->lParam);

                if ( NULL == g_MenuBar ) break;
                g_MenuBar->ScreenToClient(&pt);

                int nItem = g_MenuBar->HitTest(pt);
                if ( nItem >= 0 )
                {
                    CMenuItem *pMenuItem = g_MenuBar->m_vecMenuItem.at(nItem);
                    if ( pMenuItem == gOldMenuItem ) break;

                    ::SendMessage(g_MenuBar->m_hWnd, WM_CANCELMODE, 0, 0);

                    gNewMenuItem = pMenuItem;
                    g_MenuBar->OnMouseMove(0, pt);
                }
            }
            break;

        default:
            break;
        }
    }
    return ::CallNextHookEx(gMsgFilterHook, code, wParam, lParam);
}

CMenuItem::CMenuItem()
{

}

CMenuItem::~CMenuItem()
{

}

void CMenuItem::DrawMenu(CDC* pDC)
{
    int OldbkMode = pDC->SetBkMode(TRANSPARENT);
    switch(m_state)
    {
    case Normal:
        {
            
        }
        break;

    case Pressed:
        {
            CPen pen(PS_SOLID,1,0x123456);
            CPen*pOldPen = pDC->SelectObject(&pen);
            pDC->Rectangle(m_rcMenu);
            pDC->SelectObject(pOldPen);
        }
        break;

    case Hover:
        {
            CPen pen(PS_SOLID,1,0x888888);
            CPen*pOldPen = pDC->SelectObject(&pen);
            pDC->Rectangle(m_rcMenu);
            pDC->SelectObject(pOldPen);
        }
        break;
    default:
        ASSERT(FALSE);
        break;
    }
    pDC->DrawTextEx(m_strText,m_rcMenu,DT_SINGLELINE|DT_CENTER|DT_VCENTER,NULL);
    pDC->SetBkMode(OldbkMode);
}

void CMenuItem::ShowPopUpMenu(CWnd* pWnd)
{
    CMenuBar* pMenuBar = (CMenuBar*)pWnd;
    CPoint pt;
    pt.x = m_rcMenu.left;
    pt.y = m_rcMenu.bottom;
    pMenuBar->ClientToScreen(&pt);

    if (m_hPopUpMenu)
    {            
        DWORD dwThreadId = GetCurrentThreadId();

        if (gMsgFilterHook == NULL )
        {
            gMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER,MessageProc,NULL, dwThreadId);
        }
        BOOL bRet = ::TrackPopupMenuEx(m_hPopUpMenu,TPM_VERTICAL|TPM_LEFTBUTTON|TPM_RIGHTBUTTON|TPM_LEFTALIGN,pt.x,pt.y,pMenuBar->m_hWnd,NULL);        
        if (gMsgFilterHook)
        {
            UnhookWindowsHookEx(gMsgFilterHook);
            gMsgFilterHook = NULL;
        }
    }
}

CMenuBar::CMenuBar(void)
{
    g_MenuBar = this;
}

CMenuBar::~CMenuBar(void)
{
    int nCount = GetMenuItemCount();
    if (nCount==0) return;
    for (int i = 0;i<nCount;i++)
    {
        CMenuItem* pMenuItem = m_vecMenuItem.at(i);
        delete    pMenuItem ;
    }
}
BEGIN_MESSAGE_MAP(CMenuBar, CPanel)
    ON_WM_PAINT()
    ON_WM_CREATE()
    ON_WM_MOUSEMOVE()
    ON_MESSAGE(WM_MOUSELEAVE,OnMouseLeave)
    ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()

void CMenuBar::OnPaint()
{
    CPaintDC dc(this); // device context for painting
    
    int nCount = GetMenuItemCount();//子项个数
    CRect rcClient;
    GetClientRect(rcClient);
    //m_imgBk.Draw(dc.m_hDC,rcClient);
    CFont font;
    font.CreateFont(14,0,0,0,FW_MEDIUM,FALSE,FALSE,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,
        CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,DEFAULT_PITCH | FF_SWISS,_T("Arial"));
    dc.SelectObject(&font);
    for (int i = 0; i<nCount;i++)
    {
        CMenuItem * pMenuItem = m_vecMenuItem.at(i);
        pMenuItem->DrawMenu((CDC*)&dc);
    }
}

int CMenuBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CPanel::OnCreate(lpCreateStruct) == -1)
        return -1;

    return 0;
}

void CMenuBar::LoadMenuFromResource(UINT nIDResource)
{
    m_Menu.LoadMenu(nIDResource);
    int nCount = m_Menu.GetMenuItemCount();
    for (int i = 0;i<nCount;i++)
    {
        CString strText;
        m_Menu.GetMenuString(i,strText,MF_BYPOSITION);
        CMenuItem* pMenuItem = new CMenuItem;
        pMenuItem->m_strText = strText;
        pMenuItem->m_hPopUpMenu = m_Menu.GetSubMenu(i)->m_hMenu;
        pMenuItem->m_rcMenu = CRect(i*50,0,i*50+50,22);
        pMenuItem->m_state = CMenuItem::Normal;
        m_vecMenuItem.push_back(pMenuItem);
    }
    Invalidate();
}

int CMenuBar::GetMenuItemCount()
{
    return (int)m_vecMenuItem.size();
}

int CMenuBar::HitTest(CPoint pt)
{
    int nItem = HTERROR;
    int nCount = GetMenuItemCount();
    for (int i = 0;i<nCount;i++)
    {
        CMenuItem* pMenuItem = m_vecMenuItem.at(i);
        if (pMenuItem)
        {
            BOOL bInRect = pMenuItem->m_rcMenu.PtInRect(pt);
            if (bInRect)
            {
                if (pMenuItem->m_state != CMenuItem::Hover)
                {
                    pMenuItem->m_state = CMenuItem::Hover;
                    InvalidateRect(pMenuItem->m_rcMenu);
                }
                nItem = i;
            }
            else
            {
                if (pMenuItem->m_state != CMenuItem::Normal)
                {
                    pMenuItem->m_state = CMenuItem::Normal;
                    InvalidateRect(pMenuItem->m_rcMenu);
                }    
            }
        }        
    }
    if (nItem == HTERROR)
    {
        if (gMsgFilterHook)
        {
            UnhookWindowsHookEx(gMsgFilterHook);
            gMsgFilterHook = NULL;
            g_bPressed = FALSE;
        }
        else
        {
            g_bPressed = TRUE;
        }
        gOldMenuItem = NULL;
    }

    return nItem;
}
void CMenuBar::OnMouseMove(UINT nFlags, CPoint point)
{
    TRACKMOUSEEVENT tme;
    tme.cbSize = sizeof(TRACKMOUSEEVENT);
    tme.dwFlags = TME_LEAVE;
    tme.dwHoverTime = 1;
    tme.hwndTrack= this->m_hWnd;
    TrackMouseEvent(&tme);

    int nItem = HitTest(point);
    if (nItem>=0)
    {
        if (gOldMenuItem!=NULL)
        {
            if (gNewMenuItem !=NULL && g_bPressed == TRUE)
            {
                gNewMenuItem->ShowPopUpMenu(this);
                gOldMenuItem = gNewMenuItem;
            }
        }
    }
    CPanel::OnMouseMove(nFlags, point);
}

LRESULT CMenuBar::OnMouseLeave(WPARAM,LPARAM)
{
    int nCount = GetMenuItemCount();
    for (int i = 0;i<nCount;i++)
    {
        CMenuItem* pMenuItem = m_vecMenuItem.at(i);
        if (pMenuItem)
        {
            if (pMenuItem->m_state != CMenuItem::Normal)
            {
                pMenuItem->m_state = CMenuItem::Normal;
                InvalidateRect(pMenuItem->m_rcMenu);
            }    
        }        
    }
    return 0;
}

void CMenuBar::OnLButtonDown(UINT nFlags, CPoint point)
{
    g_bPressed = TRUE;
    int nItem = HitTest(point);
    if (nItem>=0)
    {    
        gOldMenuItem = m_vecMenuItem.at(nItem);
        gOldMenuItem->m_state = CMenuItem::Pressed;
        InvalidateRect(gOldMenuItem->m_rcMenu);

        if (gOldMenuItem)
        {
            BOOL bInRect = gOldMenuItem->m_rcMenu.PtInRect(point);
            if (bInRect)
            {
                gOldMenuItem->ShowPopUpMenu(this);    
            }
        }

    }
    CPanel::OnLButtonDown(nFlags, point);
}

头文件

#pragma once
#include "panel.h"
#include <vector>
using namespace std;

class CMenuItem
{
public:
    CMenuItem();
    ~CMenuItem();
public:
    void DrawMenu(CDC* pDC);
public:
    enum STATE{Normal=1,Hover,Pressed};
public:
    CRect m_rcMenu;
    STATE m_state;
    CString m_strText;
    HMENU m_hPopUpMenu;
public:
    void Draw(CDC* pDc);
    void ShowPopUpMenu(CWnd* pWnd);
};


class CMenuBar :
    public CPanel
{
public:
    CMenuBar(void);
    ~CMenuBar(void);
public:
    void LoadMenuFromResource(UINT nIDResource);
    int GetMenuItemCount();
    int HitTest(CPoint pt);
public:
    CMenu m_Menu;
    vector<CMenuItem*> m_vecMenuItem;
public:
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnPaint();
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
public:
    afx_msg void onm ouseMove(UINT nFlags, CPoint point);
    afx_msg LRESULT onm ouseLeave(WPARAM,LPARAM);
public:
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
};