PowerBASIC之系统菜单的自绘方法

本文介绍了一种通过修改背景颜色和使用自定义图标来美化系统菜单的方法,并提供了详细的代码实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言:

当你在单击窗口标题栏图标或点击鼠标右键时,系统会弹出一个默认菜单,如果在我们自己的程序中需要统一界面风格,则需要对这个弹出菜单进行些美化处理。

先上效果图,下面再演示实现方法:

二、实现方法:

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 

 

 三、自此一个具有个性化的标题菜单就绘制完成了。由于水平有限代码未必严谨,仅供大家交流学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值