争怎路由网/网站教程/内容

VB打造超酷个性化菜单(6)

网站教程2024-06-20 阅读
接上篇)

 

' 拦截菜单消息 (frmMenu 窗口入口函数)
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                                            ' 退出菜单消息循环(保留)
           
        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
       
        ' 设置菜单附加条矩形
        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
       
        ' 设置图标矩形, 文字矩形
        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                         ' 当鼠标移动到菜单项时
                   
                        ' 设置菜单项高亮范围
                        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

' 菜单项事件响应(单击菜单项)
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

' 菜单项事件响应(选择菜单项)
Private Sub MenuItemSelecting(ByVal itemID As Long)
    Debug.Print "鼠标移动到:" & MyItemInfo(itemID).itemText
End Sub

 

    到此为止,我们就完成了菜单类的编写,且还包括一个测试窗体。现在,完整的工程里应该包括两个窗体:frmMain和frmMenu;一个标准模块:mMenu;一个类模块:cMenu。按F5编译运行一下,在窗体空白处单击鼠标右键。怎么样,出现弹出式菜单了吗?换个风格再试试。
    看完这个系列的文章后,我想你应该已经对采用物主绘图技术的自绘菜单有了一定的了解,再看看MS Office 2003的菜单,其实也没什么难的嘛。
    该程序在Windows XP、VB6下调试通过。
   




……

相关阅读