VB打造超酷個性化菜單(3)
發(fā)表時間:2024-02-23 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]VB打造超酷個性化菜單(三) 現(xiàn)在到了最關(guān)鍵,最精彩,也是最復雜的部分了。我們最關(guān)心的就是怎樣“畫”菜單,怎樣處理菜單事件,在MenuWndProc這個處理消息的函數(shù)里,我們要處理如下消息:WM_COMMAND(單擊菜單項),WM_MEASUREITEM(處理菜單高度和寬度),WM_MEN...
VB打造超酷個性化菜單(三)
現(xiàn)在到了最關(guān)鍵,最精彩,也是最復雜的部分了。我們最關(guān)心的就是怎樣“畫”菜單,怎樣處理菜單事件,在MenuWndProc這個處理消息的函數(shù)里,我們要處理如下消息:WM_COMMAND(單擊菜單項),WM_MEASUREITEM(處理菜單高度和寬度),WM_MENUSELECT(選擇菜單項),WM_DRAWITEM(繪制菜單項)。
打開上次建好的工程,添加一個標準模塊,并將其名稱設(shè)置為mMenu,代碼如下:
'**************************************************************************************************************
'* 本模塊配合 cMenu 菜單類模塊
'*
'* 版權(quán): LPP軟件工作室
'* 作者: 盧培培(goodname008)
'* (******* 復制請保留以上信息 *******)
'**************************************************************************************************************
Option Explicit
' -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- API 函數(shù)聲明 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Public Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Public Declare Function CreatePen Lib "gdi32" (ByVal nPenStyle As Long, ByVal nWidth As Long, ByVal crColor As Long) As Long
Public Declare Function CreatePopupMenu Lib "user32" () As Long
Public Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long
Public Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Public Declare Function DeleteMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Public Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Public Declare Function DestroyMenu Lib "user32" (ByVal hMenu As Long) As Long
Public Declare Function DrawEdge Lib "user32" (ByVal hdc As Long, qrc As RECT, ByVal edge As Long, ByVal grfFlags As Long) As Long
Public Declare Function DrawIconEx Lib "user32" (ByVal hdc As Long, ByVal xLeft As Long, ByVal yTop As Long, ByVal hIcon As Long, ByVal cxWidth As Long, ByVal cyWidth As Long, ByVal istepIfAniCur As Long, ByVal hbrFlickerFreeDraw As Long, ByVal diFlags As Long) As Long
Public Declare Function DrawState Lib "user32" Alias "DrawStateA" (ByVal hdc As Long, ByVal hBrush As Long, ByVal lpDrawStateProc As Long, ByVal lParam As Long, ByVal wParam As Long, ByVal n1 As Long, ByVal n2 As Long, ByVal n3 As Long, ByVal n4 As Long, ByVal un As Long) As Long
Public Declare Function DrawText Lib "user32" Alias "DrawTextA" (ByVal hdc As Long, ByVal lpStr As String, ByVal nCount As Long, lpRect As RECT, ByVal wFormat As Long) As Long
Public Declare Function FillRect Lib "user32" (ByVal hdc As Long, lpRect As RECT, ByVal hBrush As Long) As Long
Public Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Public Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Public Declare Function GetMenuItemID Lib "user32" (ByVal hMenu As Long, ByVal nPos As Long) As Long
Public Declare Function GetMenuItemInfo Lib "user32" Alias "GetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long, ByVal b As Long, lpMenuItemInfo As MENUITEMINFO) As Long
Public Declare Function GetSysColor Lib "user32" (ByVal nIndex As Long) As Long
Public Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long
Public Declare Function InflateRect Lib "user32" (lpRect As RECT, ByVal x As Long, ByVal y As Long) As Long
Public Declare Function InsertMenuItem Lib "user32" Alias "InsertMenuItemA" (ByVal hMenu As Long, ByVal un As Long, ByVal bool As Boolean, ByRef lpcMenuItemInfo As MENUITEMINFO) As Long
Public Declare Function LineTo Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long
Public Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" (ByVal lpString As String) As Long
Public Declare Function MoveToEx Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, lpPoint As Long) As Long
Public Declare Function Rectangle Lib "gdi32" (ByVal hdc As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Public Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As Long
Public Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Public Declare Function SetBkMode Lib "gdi32" (ByVal hdc As Long, ByVal nBkMode As Long) As Long
Public Declare Function SetMenuItemInfo Lib "user32" Alias "SetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long, ByVal bool As Boolean, lpcMenuItemInfo As MENUITEMINFO) As Long
Public Declare Function SetTextColor Lib "gdi32" (ByVal hdc As Long, ByVal crColor As Long) As Long
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
' -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- API 常量聲明 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Public Const GWL_WNDPROC = (-4) ' SetWindowLong 設(shè)置窗口函數(shù)入口地址
Public Const SM_CYMENU = 15 ' GetSystemMetrics 獲得系統(tǒng)菜單項高度
Public Const WM_COMMAND = &H111 ' 消息: 單擊菜單項
Public Const WM_DRAWITEM = &H2B ' 消息: 繪制菜單項
Public Const WM_EXITMENULOOP = &H212 ' 消息: 退出菜單消息循環(huán)
Public Const WM_MEASUREITEM = &H2C ' 消息: 處理菜單高度和寬度
Public Const WM_MENUSELECT = &H11F ' 消息: 選擇菜單項
' ODT
Public Const ODT_MENU = 1 ' 菜單
Public Const ODT_LISTBOX = 2 ' 列表框
Public Const ODT_COMBOBOX = 3 ' 組合框
Public Const ODT_BUTTON = 4 ' 按鈕
' ODS
Public Const ODS_SELECTED = &H1 ' 菜單被選擇
Public Const ODS_GRAYED = &H2 ' 灰色字
Public Const ODS_DISABLED = &H4 ' 禁用
Public Const ODS_CHECKED = &H8 ' 選中
Public Const ODS_FOCUS = &H10 ' 聚焦
' diFlags to DrawIconEx
Public Const DI_MASK = &H1 ' 繪圖時使用圖標的MASK部分 (如單獨使用, 可獲得圖標的掩模)
Public Const DI_IMAGE = &H2 ' 繪圖時使用圖標的XOR部分 (即圖標沒有透明區(qū)域)
Public Const DI_NORMAL = DI_MASK Or DI_IMAGE ' 用常規(guī)方式繪圖 (合并 DI_IMAGE 和 DI_MASK)
' nBkMode to SetBkMode
Public Const TRANSPARENT = 1 ' 透明處理, 即不作上述填充
Public Const OPAQUE = 2 ' 用當前的背景色填充虛線畫筆、陰影刷子以及字符的空隙
Public Const NEWTRANSPARENT = 3 ' 在有顏色的菜單上畫透明文字
' MF 菜單相關(guān)常數(shù)
Public Const MF_BYCOMMAND = &H0& ' 菜單條目由菜單的命令I(lǐng)D指定
Public Const MF_BYPOSITION = &H400& ' 菜單條目由條目在菜單中的位置決定 (零代表菜單中的第一個條目)
Public Const MF_CHECKED = &H8& ' 檢查指定的菜單條目 (不能與VB的Checked屬性兼容)
Public Const MF_DISABLED = &H2& ' 禁止指定的菜單條目 (不與VB的Enabled屬性兼容)
Public Const MF_ENABLED = &H0& ' 允許指定的菜單條目 (不與VB的Enabled屬性兼容)
Public Const MF_GRAYED = &H1& ' 禁止指定的菜單條目, 并用淺灰色描述它. (不與VB的Enabled屬性兼容)
Public Const MF_HILITE = &H80&
Public Const MF_SEPARATOR = &H800& ' 在指定的條目處顯示一條分隔線
Public Const MF_STRING = &H0& ' 在指定的條目處放置一個字串 (不與VB的Caption屬性兼容)
Public Const MF_UNCHECKED = &H0& ' 檢查指定的條目 (不能與VB的Checked屬性兼容)
Public Const MF_UNHILITE = &H0&
Public Const MF_BITMAP = &H4& ' 菜單條目是一幅位圖. 一旦設(shè)入菜單, 這幅位圖就絕對不能刪除, 所以不應(yīng)該使用由VB的Image屬性返回的值.
Public Const MF_OWNERDRAW = &H100& ' 創(chuàng)建一個物主繪圖菜單 (由您設(shè)計的程序負責描繪每個菜單條目)
Public Const MF_USECHECKBITMAPS = &H200&
Public Const MF_MENUBARBREAK = &H20& ' 在彈出式菜單中, 將指定的條目放置于一個新列, 并用一條垂直線分隔不同的列.
Public Const MF_MENUBREAK = &H40& ' 在彈出式菜單中, 將指定的條目放置于一個新列. 在頂級菜單中, 將條目放置到一個新行.
Public Const MF_POPUP = &H10& ' 將一個彈出式菜單置于指定的條目, 可用于創(chuàng)建子菜單及彈出式菜單.
Public Const MF_HELP = &H4000&
Public Const MF_DEFAULT = &H1000
Public Const MF_RIGHTJUSTIFY = &H4000
' fMask To InsertMenuItem ' 指定 MENUITEMINFO 中哪些成員有效
Public Const MIIM_STATE = &H1
Public Const MIIM_ID = &H2
Public Const MIIM_SUBMENU = &H4
Public Const MIIM_CHECKMARKS = &H8
Public Const MIIM_TYPE = &H10
Public Const MIIM_DATA = &H20
Public Const MIIM_STRING = &H40
Public Const MIIM_BITMAP = &H80
Public Const MIIM_FTYPE = &H100
' fType To InsertMenuItem ' MENUITEMINFO 中菜單項類型
Public Const MFT_BITMAP = &H4&
Public Const MFT_MENUBARBREAK = &H20&
Public Const MFT_MENUBREAK = &H40&
Public Const MFT_OWNERDRAW = &H100&
Public Const MFT_SEPARATOR = &H800&
Public Const MFT_STRING = &H0&
' fState to InsertMenuItem ' MENUITEMINFO 中菜單項狀態(tài)
Public Const MFS_CHECKED = &H8&
Public Const MFS_DISABLED = &H2&
Public Const MFS_ENABLED = &H0&
Public Const MFS_GRAYED = &H1&
Public Const MFS_HILITE = &H80&
Public Const MFS_UNCHECKED = &H0&
Public Const MFS_UNHILITE = &H0&
' nFormat to DrawText
Public Const DT_LEFT = &H0 ' 水平左對齊
Public Const DT_CENTER = &H1 ' 水平居中對齊
Public Const DT_RIGHT = &H2 ' 水平右對齊
Public Const DT_SINGLELINE = &H20 ' 單行
Public Const DT_TOP = &H0 ' 垂直上對齊 (僅單行時有效)
Public Const DT_VCENTER = &H4 ' 垂直居中對齊 (僅單行時有效)
Public Const DT_BOTTOM = &H8 ' 垂直下對齊 (僅單行時有效)
Public Const DT_CALCRECT = &H400 ' 多行繪圖時矩形的底邊根據(jù)需要進行延展, 以便容下所有文字; 單行繪圖時, 延展矩形的右側(cè), 不描繪文字, 由lpRect參數(shù)指定的矩形會載入計算出來的值.
Public Const DT_WORDBREAK = &H10 ' 進行自動換行. 如用SetTextAlign函數(shù)設(shè)置了TA_UPDATECP標志, 這里的設(shè)置則無效.
Public Const DT_NOCLIP = &H100 ' 描繪文字時不剪切到指定的矩形
Public Const DT_NOPREFIX = &H800 ' 通常, 函數(shù)認為 & 字符表示應(yīng)為下一個字符加上下劃線, 該標志禁止這種行為.
Public Const DT_EXPANDTABS = &H40 ' 描繪文字的時候, 對制表站進行擴展. 默認的制表站間距是8個字符. 但是, 可用DT_TABSTOP標志改變這項設(shè)定.
Public Const DT_TABSTOP = &H80 ' 指定新的制表站間距, 采用這個整數(shù)的高 8 位.
Public Const DT_EXTERNALLEADING = &H200 ' 計算文本行高度的時候, 使用當前字體的外部間距屬性.
' nIndex to GetSysColor 標準: 0--20
Public Const COLOR_ACTIVEBORDER = 10 ' 活動窗口的邊框
Public Const COLOR_ACTIVECAPTION = 2 ' 活動窗口的標題
Public Const COLOR_APPWORKSPACE = 12 ' MDI桌面的背景
Public Const COLOR_BACKGROUND = 1 ' Windows 桌面
Public Const COLOR_BTNFACE = 15 ' 按鈕
Public Const COLOR_BTNHIGHLIGHT = 20 ' 按鈕的3D加亮區(qū)
Public Const COLOR_BTNSHADOW = 16 ' 按鈕的3D陰影
Public Const COLOR_BTNTEXT = 18 ' 按鈕文字
Public Const COLOR_CAPTIONTEXT = 9 ' 窗口標題中的文字
Public Const COLOR_GRAYTEXT = 17 ' 灰色文字; 如使用了抖動技術(shù)則為零
Public Const COLOR_HIGHLIGHT = 13 ' 選定的項目背景
Public Const COLOR_HIGHLIGHTTEXT = 14 ' 選定的項目文字
Public Const COLOR_INACTIVEBORDER = 11 ' 不活動窗口的邊框
Public Const COLOR_INACTIVECAPTION = 3 ' 不活動窗口的標題
Public Const COLOR_INACTIVECAPTIONTEXT = 19 ' 不活動窗口的文字
Public Const COLOR_MENU = 4 ' 菜單
Public Const COLOR_MENUTEXT = 7 ' 菜單文字
Public Const COLOR_SCROLLBAR = 0 ' 滾動條
Public Const COLOR_WINDOW = 5 ' 窗口背景
Public Const COLOR_WINDOWFRAME = 6 ' 窗框
Public Const COLOR_WINDOWTEXT = 8 ' 窗口文字
' un to DrawState
Public Const DST_COMPLEX = &H0 ' 繪圖在由lpDrawStateProc參數(shù)指定的回調(diào)函數(shù)期間執(zhí)行, lParam和wParam會傳遞給回調(diào)事件.
Public Const DST_TEXT = &H1 ' lParam代表文字的地址(可使用一個字串別名),wParam代表字串的長度.
Public Const DST_PREFIXTEXT = &H2 ' 與DST_TEXT類似, 只是 & 字符指出為下各字符加上下劃線.
Public Const DST_ICON = &H3 ' lParam包括圖標的句柄
Public Const DST_BITMAP = &H4 ' lParam包括位圖的句柄
Public Const DSS_NORMAL = &H0 ' 普通圖像
Public Const DSS_UNION = &H10 ' 圖像進行抖動處理
Public Const DSS_DISABLED = &H20 ' 圖象具有浮雕效果
Public Const DSS_MONO = &H80 ' 用hBrush描繪圖像
Public Const DSS_RIGHT = &H8000 ' 無任何作用
' edge to DrawEdge
Public Const BDR_RAISEDOUTER = &H1 ' 外層凸
Public Const BDR_SUNKENOUTER = &H2 ' 外層凹
Public Const BDR_RAISEDINNER = &H4 ' 內(nèi)層凸
Public Const BDR_SUNKENINNER = &H8 ' 內(nèi)層凹
Public Const BDR_OUTER = &H3
Public Const BDR_RAISED = &H5
Public Const BDR_SUNKEN = &HA
Public Const BDR_INNER = &HC
Public Const EDGE_BUMP = (BDR_RAISEDOUTER Or BDR_SUNKENINNER)
Public Const EDGE_ETCHED = (BDR_SUNKENOUTER Or BDR_RAISEDINNER)
Public Const EDGE_RAISED = (BDR_RAISEDOUTER Or BDR_RAISEDINNER)
Public Const EDGE_SUNKEN = (BDR_SUNKENOUTER Or BDR_SUNKENINNER)
' grfFlags to DrawEdge
Public Const BF_LEFT = &H1 ' 左邊緣
Public Const BF_TOP = &H2 ' 上邊緣
Public Const BF_RIGHT = &H4 ' 右邊緣
Public Const BF_BOTTOM = &H8 ' 下邊緣
Public Const BF_DIAGONAL = &H10 ' 對角線
Public Const BF_MIDDLE = &H800 ' 填充矩形內(nèi)部
Public Const BF_SOFT = &H1000 ' MSDN: Soft buttons instead of tiles.
Public Const BF_ADJUST = &H2000 ' 調(diào)整矩形, 預留客戶區(qū)
Public Const BF_FLAT = &H4000 ' 平面邊緣
Public Const BF_MONO = &H8000 ' 一維邊緣
Public Const BF_RECT = (BF_LEFT Or BF_TOP Or BF_RIGHT Or BF_BOTTOM)
Public Const BF_TOPLEFT = (BF_TOP Or BF_LEFT)
Public Const BF_TOPRIGHT = (BF_TOP Or BF_RIGHT)
Public Const BF_BOTTOMLEFT = (BF_BOTTOM Or BF_LEFT)
Public Const BF_BOTTOMRIGHT = (BF_BOTTOM Or BF_RIGHT)
Public Const BF_DIAGONAL_ENDTOPLEFT = (BF_DIAGONAL Or BF_TOP Or BF_LEFT)
Public Const BF_DIAGONAL_ENDTOPRIGHT = (BF_DIAGONAL Or BF_TOP Or BF_RIGHT)
Public Const BF_DIAGONAL_ENDBOTTOMLEFT = (BF_DIAGONAL Or BF_BOTTOM Or BF_LEFT)
Public Const BF_DIAGONAL_ENDBOTTOMRIGHT = (BF_DIAGONAL Or BF_BOTTOM Or BF_RIGHT)
' nPenStyle to CreatePen
Public Const PS_DASH = 1 ' 畫筆類型:虛線 (nWidth必須是1) -------
Public Const PS_DASHDOT = 3 ' 畫筆類型:點劃線 (nWidth必須是1) _._._._
Public Const PS_DASHDOTDOT = 4 ' 畫筆類型:點-點-劃線 (nWidth必須是1) _.._.._
Public Const PS_DOT = 2 ' 畫筆類型:點線 (nWidth必須是1) .......
Public Const PS_SOLID = 0 ' 畫筆類型:實線 _______
' -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- API 類型聲明 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Public Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Public Type DRAWITEMSTRUCT
CtlType As Long
CtlID As Long
itemID As Long
itemAction As Long
itemState As Long
hwndItem As Long
hdc As Long
rcItem As RECT
itemData As Long
End Type
Public Type MENUITEMINFO
cbSize As Long
fMask As Long
fType As Long
fState As Long
wID As Long
hSubMenu As Long
hbmpChecked As Long
hbmpUnchecked As Long
dwItemData As Long
dwTypeData As String
cch As Long
End Type
Public Type MEASUREITEMSTRUCT
CtlType As Long
CtlID As Long
itemID As Long
itemWidth As Long
itemHeight As Long
itemData As Long
End Type
Public Type Size
cx As Long
cy As Long
End Type
' 自定義菜單項數(shù)據(jù)結(jié)構(gòu)
Public Type MyMenuItemInfo
itemIcon As StdPicture
itemAlias As String
itemText As String
itemType As MenuItemType
itemState As MenuItemState
End Type
' 菜單相關(guān)結(jié)構(gòu)
Private MeasureInfo As MEASUREITEMSTRUCT
Private DrawInfo As DRAWITEMSTRUCT
Public hMenu As Long
Public preMenuWndProc As Long
Public MyItemInfo() As MyMenuItemInfo
' 菜單類屬性
Public BarWidth As Long ' 菜單附加條寬度
Public BarStyle As MenuLeftBarStyle ' 菜單附加條風格
Public BarImage As StdPicture ' 菜單附加條圖像
Public BarStartColor As Long ' 菜單附加條過渡色起始顏色
Public BarEndColor As Long ' 菜單附加條過渡色終止顏色
Public SelectScope As MenuItemSelectScope ' 菜單項高亮條的范圍
Public TextEnabledColor As Long ' 菜單項可用時文字顏色
Public TextDisabledColor As Long ' 菜單項不可用時文字顏色
Public TextSelectColor As Long ' 菜單項選中時文字顏色
Public IconStyle As MenuItemIconStyle ' 菜單項圖標風格
Public EdgeStyle As MenuItemSelectEdgeStyle ' 菜單項邊框風格
Public EdgeColor As Long ' 菜單項邊框顏色
Public FillStyle As MenuItemSelectFillStyle ' 菜單項背景填充風格
Public FillStartColor As Long ' 菜單項過渡色起始顏色
Public FillEndColor As Long ' 菜單項過渡色終止顏色
Public BkColor As Long ' 菜單背景顏色
Public SepStyle As MenuSeparatorStyle ' 菜單分隔條風格
Public SepColor As Long ' 菜單分隔條顏色
Public MenuStyle As MenuUserStyle ' 菜單總體風格
' 攔截菜單消息 (frmMenu 窗口入口函數(shù))
Function MenuWndProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Select Case Msg
Case WM_COMMAND ' 單擊菜單項
If MyItemInfo(wParam).itemType = MIT_CHECKBOX Then
If MyItemInfo(wParam).itemState = MIS_CHECKED Then
MyItemInfo(wParam).itemState = MIS_UNCHECKED
Else
MyItemInfo(wParam).itemState = MIS_CHECKED
End If
End If
MenuItemSelected wParam
Case WM_EXITMENULOOP ' 退出菜單消息循環(huán)(保留)
Case WM_MEASUREITEM ' 處理菜單項高度和寬度
MeasureItem hwnd, lParam
Case WM_MENUSELECT ' 選擇菜單項
Dim itemID As Long
itemID = GetMenuItemID(lParam, wParam And &HFF)
If itemID <> -1 Then
MenuItemSelecting itemID
End If
Case WM_DRAWITEM ' 繪制菜單項
DrawItem lParam
End Select
MenuWndProc = CallWindowProc(preMenuWndProc, hwnd, Msg, wParam, lParam)
End Function
' 處理菜單高度和寬度
Private Sub MeasureItem(ByVal hwnd As Long, ByVal lParam As Long)
Dim TextSize As Size, hdc As Long
hdc = GetDC(hwnd)
CopyMemory MeasureInfo, ByVal lParam, Len(MeasureInfo)
If MeasureInfo.CtlType And ODT_MENU Then
MeasureInfo.itemWidth = lstrlen(MyItemInfo(MeasureInfo.itemID).itemText) * (GetSystemMetrics(SM_CYMENU) / 2.5) + BarWidth
If MyItemInfo(MeasureInfo.itemID).itemType <> MIT_SEPARATOR Then
MeasureInfo.itemHeight = GetSystemMetrics(SM_CYMENU)
Else
MeasureInfo.itemHeight = 6
End If
End If
CopyMemory ByVal lParam, MeasureInfo, Len(MeasureInfo)
ReleaseDC hwnd, hdc
End Sub
' 繪制菜單項
Private Sub DrawItem(ByVal lParam As Long)
Dim hPen As Long, hBrush As Long
Dim itemRect As RECT, barRect As RECT, iconRect As RECT, textRect As RECT
Dim i As Long
CopyMemory DrawInfo, ByVal lParam, Len(DrawInfo)
If DrawInfo.CtlType = ODT_MENU Then
SetBkMode DrawInfo.hdc, TRANSPARENT
' 初始化菜單項矩形, 圖標矩形, 文字矩形
itemRect = DrawInfo.rcItem
iconRect = DrawInfo.rcItem
textRect = DrawInfo.rcItem
' 設(shè)置菜單附加條矩形
With barRect
.Left = 0
.Top = 0
.Right = BarWidth - 1
For i = 0 To GetMenuItemCount(hMenu) - 1
If MyItemInfo(i).itemType = MIT_SEPARATOR Then
.Bottom = .Bottom + 6
Else
.Bottom = .Bottom + MeasureInfo.itemHeight
End If
Next i
.Bottom = .Bottom - 1
End With
' 設(shè)置圖標矩形, 文字矩形
If BarStyle <> LBS_NONE Then iconRect.Left = barRect.Right + 2
iconRect.Right = iconRect.Left + 20
textRect.Left = iconRect.Right + 3
With DrawInfo
' 畫菜單背景
itemRect.Left = barRect.Right
hBrush = CreateSolidBrush(BkColor)
FillRect .hdc, itemRect, hBrush
DeleteObject hBrush
' 畫菜單左邊的附加條
Dim RedArea As Long, GreenArea As Long, BlueArea As Long
Dim red As Long, green As Long, blue As Long
Select Case BarStyle
Case LBS_NONE ' 無附加條
Case LBS_SOLIDCOLOR ' 實色填充
hBrush = CreateSolidBrush(BarStartColor)
FillRect .hdc, barRect, hBrush
DeleteObject hBrush
Case LBS_HORIZONTALCOLOR ' 水平過渡色
BlueArea = Int(BarEndColor / &H10000) - Int(BarStartColor / &H10000)
GreenArea = (Int(BarEndColor / &H100) And &HFF) - (Int(BarStartColor / &H100) And &HFF)
RedArea = (BarEndColor And &HFF) - (BarStartColor And &HFF)
For i = 0 To BarWidth - 1
red = Int(BarStartColor And &HFF) + Int(i / BarWidth * RedArea)
green = (Int(BarStartColor / &H100) And &HFF) + Int(i / BarWidth * GreenArea)
blue = Int(BarStartColor / &H10000) + Int(i / BarWidth * BlueArea)
hPen = CreatePen(PS_SOLID, 1, RGB(red, green, blue))
Call SelectObject(.hdc, hPen)
Call MoveToEx(.hdc, i, 0, 0)
Call LineTo(.hdc, i, barRect.Bottom)
Call DeleteObject(hPen)
Next i
Case LBS_VERTICALCOLOR ' 垂直過渡色
BlueArea = Int(BarEndColor / &H10000) - Int(BarStartColor / &H10000)
GreenArea = (Int(BarEndColor / &H100) And &HFF) - (Int(BarStartColor / &H100) And &HFF)
RedArea = (BarEndColor And &HFF) - (BarStartColor And &HFF)
For i = 0 To barRect.Bottom
red = Int(BarStartColor And &HFF) + Int(i / (barRect.Bottom + 1) * RedArea)
green = (Int(BarStartColor / &H100) And &HFF) + Int(i / (barRect.Bottom + 1) * GreenArea)
blue = Int(BarStartColor / &H10000) + Int(i / (barRect.Bottom + 1) * BlueArea)
hPen = CreatePen(PS_SOLID, 1, RGB(red, green, blue))
Call SelectObject(.hdc, hPen)
Call MoveToEx(.hdc, 0, i, 0)
Call LineTo(.hdc, barRect.Right, i)
Call DeleteObject(hPen)
Next i
Case LBS_IMAGE ' 圖像
If BarImage.Handle <> 0 Then
Dim barhDC As Long
barhDC = CreateCompatibleDC(GetDC(0))
SelectObject barhDC, BarImage.Handle
BitBlt .hdc, 0, 0, BarWidth, barRect.Bottom - barRect.Top + 1, barhDC, 0, 0, vbSrcCopy
DeleteDC barhDC
End If
End Select
' 畫菜單項
If MyItemInfo(.itemID).itemType = MIT_SEPARATOR Then
' 畫菜單分隔條(MIT_SEPARATOR)
If MyItemInfo(.itemID).itemType = MIT_SEPARATOR Then
itemRect.Top = itemRect.Top + 2
itemRect.Bottom = itemRect.Top + 1
itemRect.Left = barRect.Right + 5
Select Case SepStyle
Case MSS_NONE ' 無分隔條
Case MSS_DEFAULT ' 默認樣式
DrawEdge .hdc, itemRect, EDGE_ETCHED, BF_TOP
Case Else ' 其它
hPen = CreatePen(SepStyle, 0, SepColor)
hBrush = CreateSolidBrush(BkColor)
SelectObject .hdc, hPen
SelectObject .hdc, hBrush
Rectangle .hdc, itemRect.Left, itemRect.Top, itemRect.Right, itemRect.Bottom
DeleteObject hPen
DeleteObject hBrush
End Select
End If
Else
If Not CBool(MyItemInfo(.itemID).itemState And MIS_DISABLED) Then ' 當菜單項可用時
If .itemState And ODS_SELECTED Then ' 當鼠標移動到菜單項時
' 設(shè)置菜單項高亮范圍
If SelectScope And ISS_ICON_TEXT Then
itemRect.Left = iconRect.Left
ElseIf SelectScope And ISS_TEXT Then
itemRect.Left = textRect.Left - 2
Else
itemRect.Left = .rcItem.Left
End If
' 處理菜單項無圖標或為CHECKBOX時的情況
If (MyItemInfo(.itemID).itemType = MIT_CHECKBOX Or MyItemInfo(.itemID).itemIcon = 0) And SelectScope <> ISS_LEFTBAR_ICON_TEXT Then
itemRect.Left = iconRect.Left
End If
' 畫菜單項邊框
Select Case EdgeStyle
Case ISES_NONE ' 無邊框
Case ISES_SUNKEN ' 凹進
DrawEdge .hdc, itemRect, BDR_SUNKENOUTER, BF_RECT
Case ISES_RAISED ' 凸起
DrawEdge .hdc, itemRect, BDR_RAISEDINNER, BF_RECT
Case Else ' 其它
hPen = CreatePen(EdgeStyle, 0, EdgeColor)
hBrush = CreateSolidBrush(BkColor)
SelectObject .hdc, hPen
SelectObject .hdc, hBrush
Rectangle .hdc, itemRect.Left, itemRect.Top, itemRect.Right, itemRect.Bottom
DeleteObject hPen
DeleteObject hBrush
End Select
' 畫菜單項背景
InflateRect itemRect, -1, -1
Select Case FillStyle
Case ISFS_NONE ' 無背景
Case ISFS_HORIZONTALCOLOR ' 水平漸變色
BlueArea = Int(FillEndColor / &H10000) - Int(FillStartColor / &H10000)
GreenArea = (Int(FillEndColor / &H100) And &HFF) - (Int(FillStartColor / &H100) And &HFF)
RedArea = (FillEndColor And &HFF) - (FillStartColor And &HFF)
For i = itemRect.Left To itemRect.Right - 1
red = Int(FillStartColor And &HFF) + Int((i - itemRect.Left) / (itemRect.Right - itemRect.Left + 1) * RedArea)
green = (Int(FillStartColor / &H100) And &HFF) + Int((i - itemRect.Left) / (itemRect.Right - itemRect.Left + 1) * GreenArea)
blue = Int(FillStartColor / &H10000) + Int((i - itemRect.Left) / (itemRect.Right - itemRect.Left + 1) * BlueArea)
hPen = CreatePen(PS_SOLID, 1, RGB(red, green, blue))
Call SelectObject(.hdc, hPen)
Call MoveToEx(.hdc, i, itemRect.Top, 0)
Call LineTo(.hdc, i, itemRect.Bottom)
Call DeleteObject(hPen)
Next i
Case ISFS_VERTICALCOLOR ' 垂直漸變色
BlueArea = Int(FillEndColor / &H10000) - Int(FillStartColor / &H10000)
GreenArea = (Int(FillEndColor / &H100) And &HFF) - (Int(FillStartColor / &H100) And &HFF)
RedArea = (FillEndColor And &HFF) - (FillStartColor And &HFF)
For i = itemRect.Top To itemRect.Bottom - 1
red = Int(FillStartColor And &HFF) + Int((i - itemRect.Top) / (itemRect.Bottom - itemRect.Top + 1) * RedArea)
green = (Int(FillStartColor / &H100) And &HFF) + Int((i - itemRect.Top) / (itemRect.Bottom - itemRect.Top + 1) * GreenArea)
blue = Int(FillStartColor / &H10000) + Int((i - itemRect.Top) / (itemRect.Bottom - itemRect.Top + 1) * BlueArea)
hPen = CreatePen(PS_SOLID, 1, RGB(red, green, blue))
Call SelectObject(.hdc, hPen)
Call MoveToEx(.hdc, itemRect.Left, i, 0)
Call LineTo(.hdc, itemRect.Right, i)
Call DeleteObject(hPen)
Next i
Case ISFS_SOLIDCOLOR ' 實色填充
hPen = CreatePen(PS_SOLID, 0, FillStartColor)
hBrush = CreateSolidBrush(FillStartColor)
SelectObject .hdc, hPen
SelectObject .hdc, hBrush
Rectangle .hdc, itemRect.Left, itemRect.Top, itemRect.Right, itemRect.Bottom
DeleteObject hPen
DeleteObject hBrush
End Select
' 畫菜單項文字
SetTextColor .hdc, TextSelectColor
DrawText .hdc, MyItemInfo(.itemID).itemText, -1, textRect, DT_SINGLELINE Or DT_LEFT Or DT_VCENTER
' 畫菜單項圖標
If MyItemInfo(.itemID).itemType <> MIT_CHECKBOX Then
DrawIconEx .hdc, iconRect.Left + 2, iconRect.Top + (iconRect.Bottom - iconRect.Top + 1 - 16) / 2, MyItemInfo(.itemID).itemIcon, 16, 16, 0, 0, DI_NORMAL
Select Case IconStyle
Case IIS_NONE ' 無效果
Case IIS_SUNKEN ' 凹進
If MyItemInfo(.itemID).itemIcon <> 0 Then
DrawEdge .hdc, iconRect, BDR_SUNKENOUTER, BF_RECT
End If
Case IIS_RAISED ' 凸起
If MyItemInfo(.itemID).itemIcon <> 0 Then
DrawEdge .hdc, iconRect, BDR_RAISEDINNER, BF_RECT
End If
Case IIS_SHADOW ' 陰影
hBrush = CreateSolidBrush(RGB(128, 128, 128))
DrawState .hdc, hBrush, 0, MyItemInfo(.itemID).itemIcon, 0, iconRect.Left + 3, iconRect.Top + (iconRect.Bottom - iconRect.Top + 1 - 16) / 2 + 1, 0, 0, DST_ICON Or DSS_MONO
DeleteObject hBrush
DrawIconEx .hdc, iconRect.Left + 1, iconRect.Top + (iconRect.Bottom - iconRect.Top + 1 - 16) / 2 - 1, MyItemInfo(.itemID).itemIcon, 16, 16, 0, 0, DI_NORMAL
End Select
Else
' CHECKBOX型菜單項圖標效果
If MyItemInfo(.itemID).itemState And MIS_CHECKED Then
DrawIconEx .hdc, iconRect.Left + 2, iconRect.Top + (iconRect.Bottom - iconRect.Top + 1 - 16) / 2, MyItemInfo(.itemID).itemIcon, 16, 16, 0, 0, DI_NORMAL
End If
End If
Else ' 當鼠標移開菜單項時
' 畫菜單項邊框和背景(清除)
If BarStyle <> LBS_NONE Then
itemRect.Left = barRect.Right + 1
Else
itemRect.Left = 0
End If
hBrush = CreateSolidBrush(BkColor)
FillRect .hdc, itemRect, hBrush
DeleteObject hBrush
' 畫菜單項文字
SetTextColor .hdc, TextEnabledColor
DrawText .hdc, MyItemInfo(.itemID).itemText, -1, textRect, DT_SINGLELINE Or DT_LEFT Or DT_VCENTER
' 畫菜單項圖標
If MyItemInfo(.itemID).itemType <> MIT_CHECKBOX Then
DrawIconEx .hdc, iconRect.Left + 2, iconRect.Top + (iconRect.Bottom - iconRect.Top + 1 - 16) / 2, MyItemInfo(.itemID).itemIcon, 16, 16, 0, 0, DI_NORMAL
Else
If MyItemInfo(.itemID).itemState And MIS_CHECKED Then
DrawIconEx .hdc, iconRect.Left + 2, iconRect.Top + (iconRect.Bottom - iconRect.Top + 1 - 16) / 2, MyItemInfo(.itemID).itemIcon, 16, 16, 0, 0, DI_NORMAL
End If
End If
End If
Else ' 當菜單項不可用時
' 畫菜單項文字
SetTextColor .hdc, TextDisabledColor
DrawText .hdc, MyItemInfo(.itemID).itemText, -1, textRect, DT_SINGLELINE Or DT_LEFT Or DT_VCENTER
' 畫菜單項圖標
If MyItemInfo(.itemID).itemType <> MIT_CHECKBOX Then
DrawState .hdc, 0, 0, MyItemInfo(.itemID).itemIcon, 0, iconRect.Left + 2, iconRect.Top + (iconRect.Bottom - iconRect.Top + 1 - 16) / 2, 0, 0, DST_ICON Or DSS_DISABLED
Else
If MyItemInfo(.itemID).itemState And MIS_CHECKED Then
DrawState .hdc, 0, 0, MyItemInfo(.itemID).itemIcon, 0, iconRect.Left + 2, iconRect.Top + (iconRect.Bottom - iconRect.Top + 1 - 16) / 2, 0, 0, DST_ICON Or DSS_DISABLED
End If
End If
End If
End If
End With
End If
End Sub
' 菜單項事件響應(yīng)(單擊菜單項)
Private Sub MenuItemSelected(ByVal itemID As Long)
Debug.Print "鼠標單擊了:" & MyItemInfo(itemID).itemText
Select Case MyItemInfo(itemID).itemAlias
Case "exit"
Dim frm As Form
For Each frm In Forms
Unload frm
Next
End Select
End Sub
' 菜單項事件響應(yīng)(選擇菜單項)
Private Sub MenuItemSelecting(ByVal itemID As Long)
Debug.Print "鼠標移動到:" & MyItemInfo(itemID).itemText
End Sub
OK,到此為止,我們就徹底完成了菜單類的編寫,而且還包括一個測試窗體,F(xiàn)在,完整的工程里應(yīng)該包括兩個窗體:frmMain和frmMenu;一個標準模塊:mMenu;一個類模塊:cMenu。按F5編譯運行一下,在窗體空白處單擊鼠標右鍵。怎么樣,出現(xiàn)彈出式菜單了嗎?換個風格再試試。
在看完這個系列的文章后,我想你應(yīng)該已經(jīng)對采用物主繪圖技術(shù)的自繪菜單有一定的了解了,回過頭來再看看MS Office 2003的菜單,其實也沒什么難的嘛。以后,我們就可以在自己的任何程序中調(diào)用這個寫好的菜單類,為自己的程序添光加彩了。 :)
該程序在Windows XP、VB6下調(diào)試通過。
源代碼下載地址:http://y365.com/ses518/soft/samplecsdn.zip