码迷,mamicode.com
首页 > 其他好文 > 详细

自绘制菜单带图标

时间:2016-06-16 01:25:50      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:

## 个性定制菜单带图标 ##

今天把程序托到xp虚拟机,打算看下在xp的表现,发现菜单的小图标16*16的显示3/4左右,很丑,便有了此篇文章

## 实现方法 ##
有点像Listview的item重绘(自绘)实现。3点

1. 设置菜单为MF_OWNERDRAW风格,(自绘风格)
2. 处理WM_MEASUREITEM消息来设置菜单ITEM的高度
3. 处理WM_DRAWITEM消息来绘制图表文字。。

是不是和listview item重绘如出一辙呀!(有空分享下listview的重绘)

### 设置菜单为MF_OWNERDRAW风格 ###
1. 循环遍历菜单的每个item设置风格

        void ModifyMenuOwnDraw(HMENU hMen)
        {
            HMENU hSubMenu = NULL ;
            int iMenuIdx =  0 ;
            WCHAR wszString[MAX_PATH];
            int iMenuItemCount = 0;
            while ((hSubMenu = GetSubMenu(hMen,iMenuIdx)))
            {
                iMenuItemCount = GetMenuItemCount(hSubMenu);
                for (int i=0;i < iMenuItemCount;i++)
                {
                    ModifyMenu(hSubMenu,i,MF_BYPOSITION|MF_OWNERDRAW,NULL,NULL);
                }
                iMenuIdx ++;
            }
        }
2. 调用时机

        我在WM_CREATE消息处理中调用的
3. 效果

        每个menu的item都变成小白框了

### 处理WM_MEASUREITEM消息来设置菜单ITEM的高度 ###

1. 增加 WM_MEASUREITEM 处理函数

        void OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT * lpMeasureItem)
        {
            if (lpMeasureItem->CtlType == ODT_MENU )
            {
                // 有ID是正常项,没ID的是分割线 
                if ( lpMeasureItem->itemID)
                {
                    lpMeasureItem->itemHeight =24;//  GetSystemMetrics(SM_CYMENU);
                }
                else
                {    
                    // 分割线就矮点 
                    lpMeasureItem->itemHeight = 3;
                }
                
                lpMeasureItem->itemWidth = 120 ;  
                
            }
        
        }
2. 效果 

        每个menu的item都变成长条白框了


###处理WM_DRAWITEM消息来绘制图表文字###
1. 添加 WM_DRAWITEM 处理函数
    
    void OnDrawItem(HWND hwnd,const DRAWITEMSTRUCT * lpDrawItem)
    {
        HDC hDc = lpDrawItem->hDC;
    
        MENUITEMINFO miinfo ={0} ;
        WCHAR wszString[MAX_PATH];
        RECT rect;
    
        memcpy(&rect,&(lpDrawItem->rcItem),sizeof(RECT));
        // 这里来判断是自绘的BUTTON 、listview 、MENU 等,可以看看ODT_MENU的定义,就能看到有多少种了
        if (lpDrawItem->CtlType == ODT_MENU )
        {
            
    
            HBRUSH hBrush ;
            // 菜单的item有id的是正常选项,没ID的就是分割线;分开对待
            if (lpDrawItem->itemID)
            {
                // 对于选中的item 我们要 画个大红框
                if (lpDrawItem->itemState & ODS_SELECTED )
                {
    
                    hBrush =CreateSolidBrush(RGB(255,20,147));
                }
                else
                {
                    // 没选中的 要 在绘制回原色 
                    hBrush =CreateSolidBrush(GetSysColor(COLOR_MENU));
                }
    
                FrameRect(hDc,&rect,hBrush);
                DeleteBrush(hBrush);
            }else
            {
                // 分割线我们就 只画根大杠杠 
                SetDCBrushColor(hDc,getsyscolor(COLOR_MENUTEXT));
                rect.top +=1;
                rect.bottom -= 1;
                Rectangle(hDc,rect.left,rect.top,rect.right,rect.bottom);
            }
            
            
            if (lpDrawItem->itemID)
            {
                // draw img 
                int iAlign = (rect.bottom -rect.top - 16)/2 ;
                int x = rect.left + iAlign ;
                int y = rect.top + iAlign ;
                BITMAP bmp;  
                HDC hdcMem  = CreateCompatibleDC(hDc);   
                HBITMAP hBmp = LoadBitmap(hInst,MAKEINTRESOURCE(lpDrawItem->itemID - ID_FILE_LISTENER + IDB_BMP_LISTENER));
                //HBITMAP hBmp = (HBITMAP)LoadImage(NULL, "1.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);  
                GetObject(hBmp, sizeof(BITMAP), &bmp);  
    
                SelectObject(hdcMem, hBmp);  
                BitBlt(hDc, x, y, 16, 16, hdcMem, 0, 0, SRCCOPY);   
    
                DeleteDC(hdcMem);  
                DeleteObject(hBmp);  
    
    
                //draw text
                // 要绘制字的先获取下高度
                TEXTMETRIC tm;
                GetTextMetrics(hDc,&tm);
                // 计算下字所在的rect 这里要是字体上下居中 
                int iAlignTop = (rect.bottom -rect.top-tm.tmHeight)/2 ;
                iAlignTop = iAlignTop > 0 ? iAlignTop : -iAlignTop ;
                rect.top += iAlignTop;
                rect.bottom -= iAlignTop ;
    
                // 留出绘制的 图标 位置来
                rect.left+=24;
                // 先获取字符串
                GetMenuString((HMENU)lpDrawItem->hwndItem,lpDrawItem->itemID,wszString,MAX_PATH,MF_BYCOMMAND);
                // 还要判断是否有 \t 有的话就要分开写了
                WCHAR* lpFind = wcschr(wszString,L\t);
                if (lpFind)
                {
                    *lpFind = L\0;
                    lpFind+=1 ;
                }
    
    
                DrawTextEx(hDc,wszString,wcslen(wszString),(LPRECT)&(rect),DT_LEFT,NULL);
                // 有 \t的话
                if (lpFind)
                {
    
                    rect.left += 50  ;
                    rect.right -= 10;
                    DrawTextEx(hDc,lpFind,wcslen(lpFind),(LPRECT)&(rect),DT_RIGHT,NULL);
                }
            }
            
            
        }
    }

2. 以上代码发布时改动过,没有测试,如果有出入还请自行改制

- 实在想偷懒的,还是设置小图标吧,大小12*12的在xp下不会不适应的。
    

    HBITMAP hBmpShow = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_BMP_SHOW));
    SetMenuItemBitmaps(hTrayMenu, ID_NOTIFY_SHOWXMAN, MF_BYCOMMAND, hBmpShow,hBmpShow);

 

技术分享

 

自绘制菜单带图标

标签:

原文地址:http://www.cnblogs.com/witty/p/DRAW_MENU.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!