一、前言:
当你在单击窗口标题栏图标或点击鼠标右键时,系统会弹出一个默认菜单,如果在我们自己的程序中需要统一界面风格,则需要对这个弹出菜单进行些美化处理。
先上效果图,下面再演示实现方法:
二、实现方法:
1、首先初始化这个菜单,修改背景及添加MFT_OWNERDRAW类型风格。
初始化步骤可以是在%WM_INITDIALOG或者%WM_INITMENU消息中完成,我这里选择是在%WM_INITMENU时,对系统菜单进行初始化工作。
GLOBAL oldID AS LONG
GLOBAL oldText AS RECT
GLOBAL oldRSelect AS RECT
GLOBAL oldLSelect AS RECT
GLOBAL oldIcon AS DWORD
CASE %WM_INITMENU
LOCAL lpMenuInfo AS MENUINFO
LOCAL mii AS MENUITEMINFO
LOCAL hMenu AS DWORD
hMenu = GetSystemMenu ( CB.HNDL, %FALSE ) '取得系统菜单句柄
'设置默认背景色
lpMenuInfo.cbSize = SIZEOF(MENUINFO)
lpMenuInfo.fMask = %MIM_BACKGROUND
lpMenuInfo.hbrBack = CreateSolidBrush(RGB(46,46,46)) '背景色
SetMenuInfo ( hMenu, lpMenuInfo )
DrawMenuBar ( CB.HNDL )
'设置菜单栏项目为自绘模式
ZeroMemory BYVAL VARPTR(lpMenuInfo), SIZEOF(MENUINFO)
mii.cbSize = SIZEOF(mii)
mii.fMask = %MIIM_FTYPE OR %MIIM_BITMAP OR %MIIM_DATA
mii.fType = %MFT_OWNERDRAW
mii.hbmpItem = %HBMMENU_CALLBACK
FOR i = 0 TO GetMenuItemCount ( hMenu ) - 1
IF i=0 THEN
mii.dwItemData = LoadImage(%NULL, "icon\menu_restore_a.ico", %IMAGE_ICON, 16, 16, %LR_DEFAULTCOLOR OR %LR_CREATEDIBSECTION OR %LR_LOADFROMFILE )
END IF
IF i=3 THEN
mii.dwItemData = LoadImage(%NULL, "icon\menu_min_a.ico", %IMAGE_ICON, 16, 16, %LR_DEFAULTCOLOR OR %LR_CREATEDIBSECTION OR %LR_LOADFROMFILE )
END IF
IF i=4 THEN
mii.dwItemData = LoadImage(%NULL, "icon\menu_max_a.ico", %IMAGE_ICON, 16, 16, %LR_DEFAULTCOLOR OR %LR_CREATEDIBSECTION OR %LR_LOADFROMFILE )
END IF
IF i=6 THEN
mii.dwItemData = LoadImage(%NULL, "icon\menu_exit_a.ico", %IMAGE_ICON, 16, 16, %LR_DEFAULTCOLOR OR %LR_CREATEDIBSECTION OR %LR_LOADFROMFILE )
END IF
SetMenuItemInfo ( hMenu, i, %true, mii )
NEXT i
DrawMenuBar ( CB.HNDL )
oldID = 0
oldIcon = 0
ZeroMemory BYVAL VARPTR(oldText), SIZEOF(oldText)
ZeroMemory BYVAL VARPTR(oldRSelect), SIZEOF(oldRSelect)
ZeroMemory BYVAL VARPTR(oldLSelect), SIZEOF(oldLSelect)
FUNCTION = %TRUE
EXIT FUNCTION
2、初始化菜单项规格。在菜单收到MFT_OWNERDRAW标识通知后,便可以接收到 %WM_DRAWITEM 及 %WM_MEASUREITEM 消息,其中%WM_MEASUREITEM 消息下完成菜单项宽、高的定义。
CASE %WM_MEASUREITEM
LOCAL pdis AS MEASUREITEMSTRUCT PTR
pdis = CB.LPARAM
IF @pdis.CtlType = %ODT_MENU THEN
@pdis.itemWidth = 161
@pdis.itemHeight = 20
END IF
FUNCTION = %TRUE
EXIT FUNCTION
3、完成上述两个步骤后,我既可以开始在 %WM_DRAWITEM消息体下,去绘制自己设定的样式风格了(直接在HDC上绘制即可)。
CASE %WM_DRAWITEM
LOCAL hvBrush AS DWORD
LOCAL lpdis AS DRAWITEMSTRUCT PTR
lpdis = CB.LPARAM
IF @lpdis.CtlType = %ODT_MENU THEN
LOCAL hFont AS DWORD
LOCAL ItemCount AS LONG
LOCAL MenuWidth AS LONG
LOCAL MenuHigh AS LONG
LOCAL rcRight AS RECT
LOCAL rcLeft AS RECT
LOCAL rcRSelect AS RECT
LOCAL rcLSelect AS RECT
hMenu = @lpdis.hwndItem
MenuWidth = @lpdis.rcItem.right-@lpdis.rcItem.left
MenuHigh = @lpdis.rcItem.bottom-@lpdis.rcItem.top
ItemCount = GetMenuItemCount ( hMenu )
hFont = GetStockObject( %DEFAULT_GUI_FONT ) '菜单字体
SelectObject ( @lpdis.hdc, hFont )
SetBkMode @lpdis.hdc, %TRANSPARENT
SetTextColor @lpdis.hdc, RGB(112,112,112)
'-------------------------------
'绘制左MenuBar
'-------------------------------
SetRect(rcLeft, 0, @lpdis.rcItem.top, 28, @lpdis.rcItem.bottom)
hvBrush = CreateSolidBrush(RGB(113,96,232))
FillRect(@lpdis.hdc,rcLeft,hvBrush)
DeleteObject hvBrush
SELECT CASE @lpdis.itemID
CASE %SC_RESTORE
DrawIconEx(@lpdis.hdc, 7, 2, @lpdis.itemData, 0, 0, 0, %NULL, %DI_NORMAL OR %DI_COMPAT )
CASE %SC_MINIMIZE
DrawIconEx(@lpdis.hdc, 7, 62, @lpdis.itemData, 0, 0, 0, %NULL, %DI_NORMAL OR %DI_COMPAT )
CASE %SC_MAXIMIZE
DrawIconEx(@lpdis.hdc, 7, 82, @lpdis.itemData, 0, 0, 0, %NULL, %DI_NORMAL OR %DI_COMPAT )
CASE %SC_CLOSE
DrawIconEx(@lpdis.hdc, 7, 122, @lpdis.itemData, 0, 0, 0, %NULL, %DI_NORMAL OR %DI_COMPAT )
END SELECT
'-------------------------------
'绘制右文本区
'-------------------------------
SetRect(rcRSelect, 30, @lpdis.rcItem.top, MenuWidth, @lpdis.rcItem.bottom)
SetRect(rcRight, 32, @lpdis.rcItem.top, MenuWidth, @lpdis.rcItem.bottom)
hvBrush = CreateSolidBrush(RGB(46,46,46)) '背景色
FillRect(@lpdis.hdc,rcRight,hvBrush)
DeleteObject hvBrush
GetMenuString( hMenu, @lpdis.itemID, czText, 256, %MF_BYCOMMAND )
ReplaceHotkeys(VARPTR(czText),LEN(czText))
DrawText(@lpdis.hdc, czText, -1, rcRight, %DT_SINGLELINE OR %DT_LEFT OR %DT_VCENTER )
'-------------------------------
'绘制分割线
'-------------------------------
IF @lpdis.itemID = 0 THEN
hvBrush = CreateSolidBrush(RGB(112,112,112))
SetRect(rc,30,@lpdis.rcItem.top+10,@lpdis.rcItem.right,@lpdis.rcItem.top+11)
FillRect(@lpdis.hdc,rc,hvBrush)
DeleteObject hvBrush
END IF
'-------------------------------
'绘制选择菜单项时的鼠标移动效果
'-------------------------------
IF @lpdis.itemAction = %ODA_SELECT AND @lpdis.itemID > 0 THEN
'--绘制左半部选项条--
hvBrush = CreateSolidBrush(RGB(255,0,0))
FillRect(@lpdis.hdc,rcRSelect,hvBrush)
DeleteObject hvBrush
'--绘制右半部选项条--
hvBrush = CreateSolidBrush(BGR(220,240,120))
FillRect(@lpdis.hdc,rcLeft,hvBrush)
DeleteObject hvBrush
'--绘制文本--
SetTextColor @lpdis.hdc, RGB(255,255,255)
GetMenuString( hMenu, @lpdis.itemID, czText, 256, %MF_BYCOMMAND )
DrawText( @lpdis.hdc, czText, -1, rcRight, %DT_SINGLELINE OR %DT_LEFT OR %DT_VCENTER )
'--绘制选项条左部图标--
SELECT CASE @lpdis.itemID
CASE %SC_RESTORE
DrawIconEx(@lpdis.hdc, 7, 2, @lpdis.itemData, 0, 0, 0, %NULL, %DI_NORMAL OR %DI_COMPAT )
CASE %SC_MINIMIZE
DrawIconEx(@lpdis.hdc, 7, 62, @lpdis.itemData, 0, 0, 0, %NULL, %DI_NORMAL OR %DI_COMPAT )
CASE %SC_MAXIMIZE
DrawIconEx(@lpdis.hdc, 7, 82, @lpdis.itemData, 0, 0, 0, %NULL, %DI_NORMAL OR %DI_COMPAT )
CASE %SC_CLOSE
DrawIconEx(@lpdis.hdc, 7, 122, @lpdis.itemData, 0, 0, 0, %NULL, %DI_NORMAL OR %DI_COMPAT )
END SELECT
'--恢复鼠标移动后,上一个选项的背景及文本--
hvBrush = CreateSolidBrush(RGB(46,46,46)) '背景色
FillRect(@lpdis.hdc,oldRSelect,hvBrush)
DeleteObject hvBrush
hvBrush = CreateSolidBrush(RGB(113,96,232)) '
FillRect(@lpdis.hdc,oldLSelect,hvBrush)
DeleteObject hvBrush
'--绘制文本--
SetTextColor @lpdis.hdc, RGB(112,112,112)
GetMenuString( hMenu, oldID, czText, 256, %MF_BYPOSITION )
DrawText( @lpdis.hdc, czText, -1, oldText, %DT_SINGLELINE OR %DT_LEFT OR %DT_VCENTER )
'--绘制选项条左部移动后上一个图标--
SELECT CASE oldID
CASE 0
DrawIconEx(@lpdis.hdc, 7, 2, oldIcon, 0, 0, 0, %NULL, %DI_NORMAL OR %DI_COMPAT )
CASE 3
DrawIconEx(@lpdis.hdc, 7, 62, oldIcon, 0, 0, 0, %NULL, %DI_NORMAL OR %DI_COMPAT )
CASE 4
DrawIconEx(@lpdis.hdc, 7, 82, oldIcon, 0, 0, 0, %NULL, %DI_NORMAL OR %DI_COMPAT )
CASE 6
DrawIconEx(@lpdis.hdc, 7, 122, oldIcon, 0, 0, 0, %NULL, %DI_NORMAL OR %DI_COMPAT )
END SELECT
oldID = GetMenuItemPos(hMenu,@lpdis.itemID)
oldIcon = @lpdis.itemData
CopyRect(oldText,rcRight)
CopyRect(oldRSelect,rcRSelect)
CopyRect(oldLSelect,rcLeft)
END IF
DeleteObject hFont
END IF
FUNCTION = %TRUE
EXIT FUNCTION
'-------------------------------
'取消快捷键定义字母下划线
'-------------------------------
SUB ReplaceHotkeys(BYVAL s AS BYTE PTR, BYVAL k AS LONG)
DIM i AS INTEGER
FOR i = 0 TO k
IF @s[i] = 38 THEN
@s[i] = 9
END IF
NEXT i
END SUB
'-------------------------------
'根据ID返回序号
'-------------------------------
FUNCTION GetMenuItemPos(BYVAL hMenu AS DWORD, ItemID AS DWORD) AS LONG
LOCAL i AS LONG
LOCAL ItemCount AS LONG
ItemCount = GetMenuItemCount ( hMenu ) - 1
FOR i=0 TO ItemCount
IF GetMenuItemID(hMenu,i)=ItemID THEN
FUNCTION = i
EXIT FUNCTION
END IF
NEXT i
END FUNCTION
三、自此一个具有个性化的标题菜单就绘制完成了。由于水平有限代码未必严谨,仅供大家交流学习。