自绘菜单的问题

exceed_me 2010-10-12 04:00:21
我想进行菜单的自绘,然后学着写了一个自绘的菜单类,称之为 CCustomMenu 类,效果还可以,但是问题也随之出现了,在程序中有两个菜单,一个是主框架的菜单,还有弹出式菜单,而且我要求这两个菜单的菜单项是不一样的,问题就出来了,涉及到图标的显示时,就出问题了,假设主框架的菜单为 m_CustomMenu,弹出式菜单为 m_PopMenu,当两者都是自绘菜单时,m_CustomMenu 有自己的 CImageList 关联,m_PopMenu 也有自己的 CImageList 关联,两者的 CImageList 中的图标是不一样的,但是只要两者都自绘,两者出现的图标会是一样的,而且和主框架中的 OnDrawItem 中两个菜单的调用顺序有关,如下:

void CMainFrame::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
m_CustomMenu.DrawItem(lpDrawItemStruct);
// m_PopMenu.DrawItem(lpDrawItemStruct);
CFrameWnd::OnDrawItem(nIDCtl, lpDrawItemStruct);
}

当这样时,虽然 m_PopMenu 没有主动调用 DrawItem 函数,但是也会自绘,而且图标使用的是 m_CustomMenu 的 CImageList 变量的,如果是把注释那一样去掉,也就是在 m_CustomMenu.DrawItem 之后又执行 m_PopMenu.DrawItem ,则结果就是 m_CustomMenu 的图标会使用 m_PopMenu 的 CImageList 里的图标,很奇怪,这个问题去年的时候就存在,后来由于各种原因就先搁置了,现在又遇到了,不知是和原因,想解决这个问题并知道原因,大家看看!
关键代码如下,如果需要整个工程目录文件,就麻烦些,到 CSDN 下载,
http://download.csdn.net/source/2750768
代码是两年前写的,没有更新过,所以比较乱,见谅:

#if !defined(AFX_CUSTOMMENU_H__3AF0EF07_A6CE_47D9_8840_A15350F03607__INCLUDED_)
#define AFX_CUSTOMMENU_H__3AF0EF07_A6CE_47D9_8840_A15350F03607__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// CustomMenu.h : header file
//

#define MAXLIST 50
#define HEIGHT 28
#define WIDTH 120
/////////////////////////////////////////////////////////////////////////////
// CCustomMenu window

typedef struct
{
CString m_Text;
UINT m_MenuID;
UINT m_Icon;
}MenuItemInfo;
//m_MenuID -2:顶层菜单条 -1:弹出菜单 0:分隔条 >0:一般的菜单
//注意顶层菜单条和弹出菜单的区别

class CCustomMenu : public CMenu
{
// Construction
public:
CCustomMenu();

// Attributes
public:

// Operations
public:

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CCustomMenu)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
//}}AFX_VIRTUAL

// Implementation
public:
void SetMenuImageList(CImageList *pImageList);
void DrawMenuIcon(CDC *m_dc,CRect m_rect,UINT IconIndex);
void DrawItemText(CDC *m_dc,CString str,CRect m_rect,BOOL m_Com,
BOOL bGray,BOOL bTop);
void DrawTopMenu(CDC *m_dc,CRect m_rect,BOOL bSelect);
void DrawComMenu(CDC* m_dc,CRect m_rect,BOOL bSelect,BOOL bGray);
void DrawSeparate(CDC *m_dc,CRect m_rect);
MenuItemInfo m_MenuInfoList[MAXLIST];
UINT m_Index;//用于m_MenuInfoList
UINT m_IconIndex;
CImageList *pImageList;
BOOL ChangeMenuItem(CMenu *m_Menu, BOOL bTop);
virtual ~CCustomMenu();

// Generated message map functions
protected:
//{{AFX_MSG(CCustomMenu)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CUSTOMMENU_H__3AF0EF07_A6CE_47D9_8840_A15350F03607__INCLUDED_)



// CustomMenu.cpp : implementation file
//

#include "stdafx.h"
#include "CustomMenu.h"
#include "CMenuTest.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CCustomMenu

CCustomMenu::CCustomMenu()
{
m_IconIndex = 0;
m_Index = 0;
}

CCustomMenu::~CCustomMenu()
{
}

/////////////////////////////////////////////////////////////////////////////
// CCustomMenu message handlers

void CCustomMenu::SetMenuImageList(CImageList *pImageList)
{
this->pImageList = pImageList;
}

void CCustomMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: Add your code to draw the specified item
if(lpDrawItemStruct->itemData == NULL)
return;
CDC *pDC=CDC::FromHandle(lpDrawItemStruct->hDC);
MenuItemInfo *info=(MenuItemInfo*)(lpDrawItemStruct->itemData);
UINT m_MenuID=info->m_MenuID;
CString m_text=info->m_Text;
UINT IconIndex=info->m_Icon;
UINT m_state=lpDrawItemStruct->itemState;
CRect rect=lpDrawItemStruct->rcItem;
pDC->SetBkMode(TRANSPARENT);

switch(m_MenuID)
{
case -2://顶层菜单
// DrawTopMenu(pDC,rect,(m_state& ODS_SELECTED)||
// (lpDrawItemStruct->itemAction & (ODA_SELECT)));
DrawTopMenu(pDC,rect,(m_state & ODS_SELECTED)||(m_state & 0x0040));
//这里也不要用(m_state& ODS_SELECTED)||
// (lpDrawItemStruct->itemAction & (ODA_SELECT)));
//(m_state&0x0040)也要加上,否则鼠标移入没反应
//0x0040 ==ODS_HOTLIGHT
DrawItemText(pDC,m_text,rect,FALSE,FALSE,TRUE);
break;
case -1://弹出菜单
DrawComMenu(pDC,rect,(m_state & ODS_SELECTED)||(m_state & 0x0040),FALSE);
DrawItemText(pDC,m_text,rect,TRUE,FALSE,FALSE);
DrawMenuIcon(pDC,rect,IconIndex + 1);
break;//记住一定要break,否则,呵呵,后果自负
case 0:
DrawSeparate(pDC,rect);
break;
default:
//||(lpDrawItemStruct->itemAction & (ODA_SELECT))
//这个不要加,加了之后会出现一直处于高亮显示
if(m_state & ODS_GRAYED) //菜单不可用
{
DrawComMenu(pDC,rect,(m_state & ODS_SELECTED),TRUE);
DrawItemText(pDC,m_text,rect,TRUE,TRUE,FALSE);
}
else
{
DrawComMenu(pDC,rect,(m_state & ODS_SELECTED),FALSE);
DrawItemText(pDC,m_text,rect,TRUE,FALSE,FALSE);
}

if(m_state & ODS_CHECKED)//被 Check
DrawMenuIcon(pDC,rect,0);
else
DrawMenuIcon(pDC,rect,IconIndex + 1);

break;
}
}

void CCustomMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
// TODO: Add your code to determine the size of specified item
if(lpMeasureItemStruct->CtlType == ODT_MENU)
{
lpMeasureItemStruct->itemHeight = HEIGHT;
lpMeasureItemStruct->itemWidth = WIDTH;
MenuItemInfo *info = (MenuItemInfo*)lpMeasureItemStruct->itemData;
if(lpMeasureItemStruct->itemID == -2)
lpMeasureItemStruct->itemWidth = info->m_Text.GetLength() * 8;
else
lpMeasureItemStruct->itemWidth = info->m_Text.GetLength() * 8 + 32;
if(info->m_MenuID == 0)
lpMeasureItemStruct->itemHeight = 1;
}
}

BOOL CCustomMenu::ChangeMenuItem(CMenu *pMenu, BOOL bTop = FALSE)
{
if(pMenu != NULL)
{
int m_Count = pMenu->GetMenuItemCount();

for( int i=0 ; i < m_Count ; i++ )
{
int m_ID = pMenu->GetMenuItemID(i);

CMenu *pSubMenu = pMenu->GetSubMenu(i);

if(m_ID < 0 && bTop)//顶层菜单
{
m_MenuInfoList[m_Index].m_MenuID = -2;
}
else if(pSubMenu && m_ID != -2 && !bTop)//弹出菜单
{
m_MenuInfoList[m_Index].m_MenuID = -1;
m_MenuInfoList[m_Index].m_Icon = m_IconIndex;
m_IconIndex++;
}
else if(m_ID == 0)//分隔线
m_MenuInfoList[m_Index].m_MenuID = 0;
else if(m_ID > 0)//普通菜单
{
m_MenuInfoList[m_Index].m_MenuID = m_ID;
m_MenuInfoList[m_Index].m_Icon = m_IconIndex;
m_IconIndex++;
}

pMenu->GetMenuString(i,m_MenuInfoList[m_Index].m_Text,MF_BYPOSITION);
pMenu->ModifyMenu(i,MF_BYPOSITION|MF_OWNERDRAW|MF_STRING,
m_MenuInfoList[m_Index].m_MenuID,(LPCTSTR)(&m_MenuInfoList[m_Index]));

m_Index++;

if(pSubMenu)
ChangeMenuItem(pSubMenu);
}
}
return TRUE;
}

void CCustomMenu::DrawSeparate(CDC *m_dc, CRect m_rect)
{
m_rect.left = m_rect.left + 30;
m_dc->Draw3dRect(m_rect,RGB(255,255,255),RGB(255,255,255));
}

void CCustomMenu::DrawComMenu(CDC *m_dc, CRect m_rect, BOOL bSelect,BOOL bGray)
{
CRect rect(m_rect);
//rect.DeflateRect(20,1,0,1);

if(bSelect)
{
m_dc->FillSolidRect(rect,RGB(186,211,252));//208,235,255
}
else
{
if(bGray)
m_dc->FillSolidRect(rect,RGB(240,238,225));
else
m_dc->FillSolidRect(rect,RGB(255,255,255));
}
}

void CCustomMenu::DrawTopMenu(CDC *m_dc, CRect m_rect, BOOL bSelect)
{
if(bSelect)
{
m_dc->SelectStockObject(BLACK_PEN);
CRect rect(m_rect);
m_dc->Rectangle(rect);
rect.DeflateRect(1,1,1,1);
m_dc->FillSolidRect(rect,RGB(255,235,181));
}
else
{
CRect rect;
AfxGetMainWnd()->GetClientRect(&rect);
rect.left = 390;
rect.bottom = m_rect.bottom;
rect.top = m_rect.top;
rect.right += 4;
m_dc->FillSolidRect(m_rect,RGB(186,211,252));
m_dc->FillSolidRect(rect,RGB(186,211,252));//画出射剩余的部分
}
}

void CCustomMenu::DrawItemText(CDC *m_dc, CString str, CRect m_rect,BOOL m_Com,
BOOL bGray,BOOL bTop)
{
if(bGray)
m_dc->SetTextColor(RGB(127,127,127));

CRect rect(m_rect);

if(m_Com)
rect.DeflateRect(36,0,0,0);

if(bTop)
m_dc->DrawText(str,rect,DT_CENTER|DT_VCENTER|DT_SINGLELINE);
else
m_dc->DrawText(str,rect,DT_LEFT|DT_VCENTER|DT_SINGLELINE);
}

void CCustomMenu::DrawMenuIcon(CDC *m_dc,CRect m_rect, UINT IconIndex)
{
pImageList->Draw(m_dc,IconIndex,CPoint(m_rect.left+2,m_rect.top+2),
ILD_TRANSPARENT);
//ILD_MASK不要加
}
...全文
782 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
exceed_me 2011-05-18
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 uta1314 的回复:]

工程下载不下来啊
[/Quote]

怎么下不下来了?
uta1314 2011-05-13
  • 打赏
  • 举报
回复
工程下载不下来啊
tj_swjtu 2011-01-25
  • 打赏
  • 举报
回复
谢谢楼主分享源码!!!!
exceed_me 2010-10-20
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 ynwlgh 的回复:]

在哪里下的?
[/Quote]
http://download.csdn.net/source/2750768

晕,你明显没有认真看贴么!
ynwlgh 2010-10-20
  • 打赏
  • 举报
回复
在哪里下的?
exceed_me 2010-10-19
  • 打赏
  • 举报
回复
还没解决吗?
exceed_me 2010-10-19
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 ynwlgh 的回复:]

菜单栏的最右边有一段白色的.
[/Quote]

去下载啊,白色的区域是这样的,你可以获取主框架的大小,然后绘制顶层菜单的时候 right 值用主框架的 right 就可!
ynwlgh 2010-10-19
  • 打赏
  • 举报
回复
菜单栏的最右边有一段白色的.
ynwlgh 2010-10-19
  • 打赏
  • 举报
回复
有代码没有.发给我分享分享啊.ynwlgh@foxmail.com
exceed_me 2010-10-14
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 xianglitian 的回复:]

C/C++ code
void CMainFrame::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
m_CustomMenu.DrawItem(lpDrawItemStruct);
// m_PopMenu.DrawItem(lpDrawItemStruct);
CFrameWnd::OnDra……
[/Quote]

不行的,这句不注释掉的话,就会呈现另一种现象,就是主框架的菜单的图标会变成和弹出式菜单的一样,就是两个菜单不能同时使用,就是这个问题。
向立天 2010-10-14
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 exceed_me 的回复:]
引用 7 楼 xianglitian 的回复:

C/C++ code
void CMainFrame::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
m_CustomMenu.DrawItem(lpDrawItemStruct);
// m_PopMenu.DrawItem(lpDrawItemStruct);……
[/Quote]
有空我再仔细看看吧
不过感觉上你指定图标的机制是不是有问题
好象没看到不同菜单项和图标相关联的设置
我知道你是通过ChangeMenuItem实现的
不过......
具体的还得分析代码后才知道
看不见的裂痕 2010-10-13
  • 打赏
  • 举报
回复
我也去看看,加楼主好友了
向立天 2010-10-13
  • 打赏
  • 举报
回复
void CMainFrame::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
m_CustomMenu.DrawItem(lpDrawItemStruct);
// m_PopMenu.DrawItem(lpDrawItemStruct);
CFrameWnd::OnDrawItem(nIDCtl, lpDrawItemStruct);
}

这个位置不注释m_PopMenu.DrawItem(lpDrawItemStruct);就好了
其他的没仔细看
不过你东西做的确实是不错
学习了
exceed_me 2010-10-13
  • 打赏
  • 举报
回复
没人知道吗?
exceed_me 2010-10-12
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 xianglitian 的回复:]

感觉你做的挺好的
有时间帮你调一下试试
[/Quote]

谢谢!
m_tornado 2010-10-12
  • 打赏
  • 举报
回复
很清新的感觉啊~
向立天 2010-10-12
  • 打赏
  • 举报
回复
感觉你做的挺好的
有时间帮你调一下试试
exceed_me 2010-10-12
  • 打赏
  • 举报
回复
给出程序效果,也就是 BUG 的效果如下:

1.主框架菜单效果


2.弹出式菜单预计图标的效果,图标是随便弄的,为了区分主框架的菜单图标


3.但是实际上的效果,和主框架的图标关联一起了,也就是 BUG 所在
exceed_me 2010-10-12
  • 打赏
  • 举报
回复

void CMainFrame::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
m_CustomMenu.DrawItem(lpDrawItemStruct);
// m_PopMenu.DrawItem(lpDrawItemStruct);
CFrameWnd::OnDrawItem(nIDCtl, lpDrawItemStruct);
}

void CMainFrame::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
m_CustomMenu.MeasureItem(lpMeasureItemStruct);
CFrameWnd::OnMeasureItem(nIDCtl, lpMeasureItemStruct);
}


int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
...
m_MainMenuImage.Create(24,24,ILC_COLOR24|ILC_MASK,0,0);
m_MainMenuImage.Add(AfxGetApp()->LoadIcon(IDI_CHECK));//第一个图标为钩
m_MainMenuImage.Add(AfxGetApp()->LoadIcon(IDI_ADD_USER));
m_MainMenuImage.Add(AfxGetApp()->LoadIcon(IDI_USER));
...

m_PopMenuImage.Create(24,24,ILC_COLOR24|ILC_MASK,0,0);
m_PopMenuImage.Add(AfxGetApp()->LoadIcon(IDI_ICON_TEST));
m_PopMenuImage.Add(AfxGetApp()->LoadIcon(IDI_ICON_TEST));
...

//自定义菜单
m_CustomMenu.Attach(this->GetMenu()->GetSafeHmenu());
m_CustomMenu.ChangeMenuItem(&m_CustomMenu,TRUE);
m_CustomMenu.SetMenuImageList(&m_MainMenuImage);


//弹出式菜单
m_PopMenu.LoadMenu(IDR_MENU_TRACK);
m_PopMenu.ChangeMenuItem(&m_PopMenu,TRUE);
m_PopMenu.SetMenuImageList(&m_PopMenuImage);

...


void CMainFrame::OnContextMenu(CWnd* pWnd, CPoint point)
{
CMenu *pMenu;
pMenu = m_PopMenu.GetSubMenu(0);

pMenu->TrackPopupMenu(TPM_RIGHTBUTTON|TPM_LEFTALIGN,point.x,point.y,this);
}

15,976

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧