No announcement yet.

Owner Drawn Menus

  • Filter
  • Time
  • Show
Clear All
new posts

  • Owner Drawn Menus


    Has anyone got some example code for owner drawn menus?

    I need to be able to display: Icons, Mnemonics and Accelerator keys, I have an MSDN Example which seems to use a structure that looks like this:

    // Structure associated with menu items 
    typedef struct tagMYITEM 
        HFONT hfont; 
        int   cchItemText; 
        char  szItemText[1]; 
    } MYITEM; 
    #define CCH_MAXITEMTEXT 256
    Is this the correct translation though?

     Type MENUINFO
         hFont       As Long
         cchItemText As Long
         szItemText  As Asciiz * 256  
     End Type
    I tried the above TYPE, but I managed to get a GPF, so no go

    Any help on this would be most appreciated,


    Kev G Peel
    KGP Software, Bridgwater, UK. | Slam DBMS | PrpT Control | Other Downloads | Contact Me

  • #2
    I seem to remember that the PETZOLD.ZIP archive in the FILES section contains a translated PB example of using ODM's...

    Worth checking out anyway...

    PowerBASIC Support
    mailto:[email protected][email protected]</A>
    mailto:[email protected]


    • #3
      Kev --
      some monthes ago I took MSDN and wrote following training code.

      When I used it in real app, I found that Windows adds some (depends of OS) no. of pixels to a value in %WM_MEASUREITEM.

         #Compile Exe
         #Register None
         #Dim All
         #Include "WIN32API.INC"
         Type MYITEM
            hfont As Long
            psz   As Asciiz * 255
         End Type
         Function GetAFont(fnFont As Long) As Long
            Local lf As LOGFONT
            Local sFontName As String
            GetObject GetStockObject(%ANSI_VAR_FONT), SizeOf(lf), ByVal VarPtr(lf)
            If (fnFont = 1) Then
               lf.lfHeight = -14
               lf.lfWeight = %FW_BOLD
               lf.lfFaceName = "Times New Roman"
               lf.lfWeight = %FW_NORMAL
            End If
            lf.lfItalic = (fnFont = 3)
            lf.lfUnderline = (fnFont = 4)
            lf.lfCharset = %RUSSIAN_CHARSET
            Function = CreateFontIndirect(lf)
         End Function
         Function MainWndProc(ByVal hWnd As Dword, ByVal wMsg As Dword, ByVal wParam  As Dword, ByVal lParam  As Dword) Export As Long
            Dim hMenuPopup As Long
            Dim pMyItem As MYITEM Ptr
            Dim MyItem(0 To 3) As Static MYITEM
            Static hmenu As Long
            Local lpmis As MEASUREITEMSTRUCT Ptr
            Local lpdis As DRAWITEMSTRUCT Ptr
            Local hdc As Long
            Local SizeA As SizeL
            Local i As Long
            Local hfontOld As Long
            Select Case wMsg
               Case %WM_CREATE
                  hMenu = CreateMenu: hMenuPopup  = CreateMenu
                  For i = 0 To 3: InsertMenu hMenuPopup, %MF_BYCOMMAND, %MF_STRING, 100 + i, "":  Next
                  AppendMenu hMenu, %MF_STRING Or %MF_POPUP, hMenuPopup, "File": SetMenu hWnd, hMenu
                  For i = 0 To 3
                     ModifyMenu hmenu, 100 + i, %MF_BYCOMMAND Or %MF_OWNERDRAW, i, ByVal VarPtr(myitem(i))
                     MyItem(i).hfont = GetAFont(i)
                     MyItem(i).psz = Trim$(Mid$("Ñåìåí Þðà   Ìàðèíà Ìàøà  ", 6 * i + 1, 6))
               Case %WM_DESTROY
                  For i = 0 To 3: DeleteObject MyItem(i).hfont:Next
                  PostQuitMessage 0
                  Exit Function
              Case %WM_MEASUREITEM
                  hdc = GetDC(hwnd)
                  lpmis = lParam
                  pmyitem = @lpmis.itemData
                  hfontOld = SelectObject(hdc, @pmyitem.hfont)
                  GetTextExtentPoint32 hdc, @pmyitem.psz, Len(@pmyitem.psz), SizeA
                  @lpmis.itemWidth = 8 +
                  @lpmis.itemHeight =
                  SelectObject hdc, hfontOld
                  ReleaseDC hwnd, hdc
                  Function = %TRUE: Exit Function
              Case %WM_DRAWITEM
                  lpdis = lParam
                  pmyitem = @lpdis.itemData
                  If (@lpdis.itemState And %ODS_SELECTED) Then
                     SetTextColor @lpdis.hDC, GetSysColor(%COLOR_HIGHLIGHTTEXT)
                     SetBkColor @lpdis.hDC, GetSysColor(%COLOR_HIGHLIGHT)
                     SetTextColor @lpdis.hDC, GetSysColor(%COLOR_MENUTEXT)
                     SetBkColor @lpdis.hDC, GetSysColor(%COLOR_MENU)
                  End If
                  hfontOld = SelectObject(@lpdis.hDC, @pmyitem.hfont)
                  ExtTextOut @lpdis.hDC, 8 + @lpdis.rcItem.nleft, @lpdis.rcItem.nTop, %ETO_OPAQUE, _
                      @lpdis.rcItem, @pmyitem.psz, Len(@pmyitem.psz), ByVal 0
                  SelectObject @lpdis.hDC, hfontOld
                  Function = %TRUE: Exit Function
            End Select
            Function = DefWindowProc(hwnd, wMsg, wParam, lParam)
         End Function
         Function PbMain
            Local Msg         As tagMsg
            Local wndclass    As WndClassEx
            Local szClassName As Asciiz * 80
            Local hWnd        As Long
            szClassName            = "LtrGUITop"
            wndclass.cbSize        = SizeOf(WndClass)
            wndclass.lpfnWndProc   = CodePtr(MainWndProc)
            wndclass.hInstance     = GetModuleHandle (ByVal 0&)
            wndclass.hbrBackground = GetStockObject(%LTGRAY_BRUSH )
            wndclass.hCursor       = LoadCursor(%NULL, ByVal %IDC_ARROW )
            wndclass.lpszMenuName  = %NULL
            wndclass.lpszClassName = VarPtr(szClassName)
            RegisterClassEx wndclass
            hWnd = CreateWindow(szClassName, "", 0, 100, 100, 200, 200, 0, ByVal %Null, wndclass.hInstance, ByVal %NULL)
            ShowWindow hWnd, %SW_SHOW
            UpdateWindow hWnd
            While GetMessage(Msg, %NULL, 0, 0)
               TranslateMessage Msg
               DispatchMessage Msg
            Function = msg.wParam
         End Function
      E-MAIL: [email protected]


      • #4
        Hm, I have code for including icons in a menu here, but it's part
        of a huge app so I must extract and rewrite it before it can be of
        any use. One has to make the menu ownerdrawn with for example the
        ModifyMenu API, trap %WM_MEASUREITEM and %WM_DRAWITEM to draw all
        aspects (text, selections, icons, etc.) of the menu on the fly,
        by hand.

        A bit messy, but I'll see if I can come up with a working sample
        in a day or two (as soon as I can find time to do it..

        BTW, Semen, don't know if this can be of any help there, but this
        how I do it in %WM_MEASUREITEM and it seems to give a fairly correct
        value, at least for the height..
            CASE %WM_MEASUREITEM    'Get menu item size
                IF wParam = 0 THEN  'a menu is calling
                   LOCAL lpmis AS MEASUREITEMSTRUCT PTR
                   lpmis = lParam         'Copy the pointer into our structure
                   @lpmis.itemWidth = 120 'This is arbitrary in this case
                   IF @lpmis.itemID THEN @lpmis.ItemHeight = GetSystemMetrics(%SM_CYMENU) + 1 'a menu item
                   lParam = lpmis 'return the info to Windows
                   FUNCTION = %TRUE : EXIT FUNCTION
               END IF


        • #5
          Originally posted by Kev Peel:

          // Structure associated with menu items 
          typedef struct tagMYITEM 
              HFONT hfont; 
              int   cchItemText; 
              char  szItemText[1]; 
          } MYITEM; 
          #define CCH_MAXITEMTEXT 256

          The structure you refer to above is a global app data struct, not
          to be confused with the MENUITEMINFO struct.

          Review the API function InsertMenuItem on MSDN, I believe the
          clue will be apparent there.




          • #6
            Okay - I have just uploaded a file called DrawMenu - a sample of
            how to include bitmaps in ownerdrawn menus to my PB page at

            From the header:
            ' *******************************************************************
            ' DrawMenu - a sample of how to include bitmaps in ownerdrawn menus.
            ' Public Domain by Borje Hagsten, October 25, 2000
            ' Files: DrawMenu.exe, DrawMenu.bas, DrawMenu.pbr, DrawMenu.rc and Toolbar.bmp
            ' The bmp contains some 16x16 bitmaps for the menu items.
            ' All these files are available in for free download from
            ' Included both File and Edit menu just to show how to disable/enable
            ' menu items, plus some code for trapping keyboard shortcuts like
            ' Ctrl + N for New, etc. Comments are added to most of the code - this
            ' one belongs to the category "advanced programming", so I hope
            ' you will be able to follow and understand at least some of it..
            ' I'm not 100% sure about this one since it has been extracted from
            ' a larger app', but it seems to work fine, without any memory leaks.
            ' Use at own responsibility and risk, in other words..
            ' *******************************************************************



            • #7
              Thanks Borje, Semen and Others,

              Borje, I did use part of Semen's code but with DrawText to draw the underscores (ampersands) properly.

              One trick with menu separators is when specifying 'MF_OWNERDRAW' make sure the item's text isn't a line ('-') and windows will handle it for you, the only problem now is correctly aligning the text for the accelerator keys, which comes after the '\t' sequence, i.e: '&Open\tCtrl+O'

              I will test your sample as well, to see if it covers that one last problemo


              Kev G Peel
              KGP Software, Bridgwater, UK.
     | Slam DBMS | PrpT Control | Other Downloads | Contact Me


              • #8

                Reporting Back...

                Cheers Borje! That's the right way to do it, I'll use your code.

                One more thing though, I need the top menu items (the menu bar, ie.: File, Help, etc.) in a different font as well, any ideas?

                Thanks Again,

                Kev G Peel
                KGP Software, Bridgwater, UK.
       | Slam DBMS | PrpT Control | Other Downloads | Contact Me


                • #9

                  Great example! Thanks much.

                  However, the icons don't display in Windows 2000.


                  Home of the BASIC Gurus
                  Home of the BASIC Gurus


                  • #10
                    Kev --
                    In Petzold's translation ( )
                    Chapter 10 - Grafmenu.Bas

                    E-MAIL: [email protected]


                    • #11
                      Dave, sorry to hear it doesn't work with Win2000. I have no idea
                      why and since I don't have Win2000 here, I can't do much about
                      it either. Hm..

                      Does everything else work? I mean, text, selections and the drawing
                      of the 3D-"buttons" around what should be the bitmaps? In that case,
                      the fault could be in the SetMenuBitmap() function. Could you check
                      to see if SetMenuBitmap() returns anything at all, when called from
                      the DrawMenuItem() function?

                      If you want to, you can contact me by mail: [email protected]