自绘制菜单带图标

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

今天把程序托到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);

时间: 06-15

自绘制菜单带图标的相关文章

给Notepad++ 加右键菜单带图标

从网上下载下来的Notepad++ http://download.tuxfamily.org/notepadplus/6.3.3/npp.6.3.3.bin.zip 解压之后,可以直接使用, 但是右键菜单中没有它,非常不方便, 本文使用三种方式给Notepad++注册右键菜单功能,他们只有稍微的区别: 方式一: 如下建立一个reg文件,拷贝如下内容并替换相关路径,  保存,双击运行加入注册表就好了. Windows Registry Editor Version 5.00 [HKEY_CLAS

将 notepad++ 添加到鼠标右键菜单 带图标

1.打开注册表编辑器,HKEY_CLASSES_ROOT\*\shell目录点击右键.新建-->项,这里命名的项则就是鼠标右键列表里面显示的内容,这里起名为[Edit With Notepad++] 2.在[Edit With Notepad++]上右键新建字符串,分别是名称为[Icon]值为notepad++.exe的路径地址,和名称为[MultiSelectModel]值为Single.这一步设置的意义是设置鼠标右键列表中的图标 3.在这里起名为[Edit With Notepad++]的目

002带图标的程序菜单

技术要点: 要实现带图标的菜单,需要从CMenu类派生一个子类,并在子类中改写DrawItem方法和MeasureItem方法.基本思路如下: 首先,定义一个记录菜单项信息的结构CMenuItemInfo,该结构包含了菜单项的文本.图像索引.ID等信息. 然后,从CMenu中派生一个子类CIconMenu.在该类中定义一个方法ChangeMenuItem,利用递归的方式修改所有的菜单项信息,使其具有自绘风格(MF_OWNERDRAW). 接着,在CIconMenu类中定义绘制菜单项文本.绘制菜单

添加右键菜单命令 在此处打开命令窗口(W)(带图标)

@color 0A @title 添加右键菜单命令 在此处打开命令窗口(W)(带图标) by wjshan0808 @echo off reg add HKCR\Directory\Background\shell\在此处打开命令窗口(W) /v Icon /t reg_expand_sz /d %ComSpec% /f reg add HKCR\Directory\Background\shell\在此处打开命令窗口(W)\command /ve /t reg_sz /d "%ComSpec%

为系统菜单添加图标--------暴力反射

1 import java.lang.reflect.Method; 2 3 import android.os.Bundle; 4 import android.provider.Settings; 5 import android.app.Activity; 6 import android.content.Intent; 7 import android.view.Menu; 8 import android.view.MenuItem; 9 import android.widget.T

Win32编程API 基础篇 -- 6.菜单和图标

菜单和按钮 例子:菜单1 本小节仅仅向你展示如果向你的窗口中加入一个基本的菜单,通常你会用到一个提前制作好的菜单资源,这会是一份.rc文件并且会被编译链接进你的.exe可执行程序中.这是具体的流程做法,而商业编译器将会有一个资源编辑器,你可以通过这个编辑器来创建菜单,但是在这个例子中我会向你展示如何用.rc文件的手动写法.通常我会配合使用一个头文件,在资源文件和源文件中我们需要引入这个头文件,这个头文件中包含了控制和菜单选项等的标识符. 在本小节的栗子中,你可以按照指示在simple_windo

【Android】编写Drawable XML绘制底部带指示条的背景

要实现的就是类似于Actionbar标签的那种效果,底部有一条指示条. 实现代码: <?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:top="-6dp" android:left="-6d

[转]Android有趣的全透明效果--Activity及Dialog的全透明(附android系统自带图标大全

原文:http://blog.csdn.net/sodino/article/details/5822147 1.Activity全透明 同学zzm给了这个有趣的代码,现在公布出来. 先在res/values下建colors.xml文件,写入: <? xml   version = "1.0"   encoding = "UTF-8" ?>    < resources >        < color   name = "t

Android实现“是否退出”对话框和“带图标的列表”对话框

今天我们学习的内容是实现两种对话框(Dialog),第一种是询问是否退出对话框,另外一种是带图标的列表对话框,程序的执行效果是,我们点击button1的时候,弹出第一种对话框,我们点击button2的时候,弹出另外一种对话框. (1)  首先是布局方面,有三个xml文件,一个是Activity的布局文件,一个是Dialog的布局文件,一个是ListView的布局文件,内容分别例如以下: activity_main.xml <LinearLayout xmlns:android="http: