Announcement

Collapse
No announcement yet.

Checkbox inside menu?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Checkbox inside menu?

    I don't like visible checkboxes in a well-designed GUI (transparent dialog with photograph as a background, for instance). They spoil the effect. Instead, I can use a menu with options that have either the %MF_CHECKED or the %MF_UNCHECKED state. It works, but for the user it may not be very clear what happens, because the checkmarks disappear/reappear "under water", so to speak.

    Now I want to try to create a menu with checkboxes inside, replacing the normal checked/unchecked options. I guess that I should create an owner drawn menu. Unfort., I have not the slightest idea, where to start. Are there samples around here? A search for "checkbox menu" did not deliver anything usable, nor did a search for "owner drawn menu".

    Thanks for any hint, help or code sample.

    Egbert Zijlema, journalist and programmer (zijlema at basicguru dot eu)
    http://zijlema.basicguru.eu
    *** Opinions expressed here are not necessarily untrue ***

  • #2
    Check out MENUITEMINFO in the Win32 API help

    Comment


    • #3
      Or, you could make a dialog/window with which just looks like a menu and show it when the user would expect it.

      Seems to me someone did an owner-drawn menu demo here just in the last couple of weeks, except it was NOT in the Source Code forum. Try a full text search on "%MF_OWNERDRAW" since that would have had to appear in the code. WM_MEASUREITEM would also have had to appear.
      Michael Mattias
      Tal Systems (retired)
      Port Washington WI USA
      [email protected]
      http://www.talsystems.com

      Comment


      • #4
        The SetMenuItemBitmaps API function allows you to replace the standard checkmark images with your own custom bitmaps. You can do this by either drawing your own Bitmaps and use them, or by creating a blank bitmap in memory and drawing the checkbox images using the DrawFrameControl API function to draw your images.

        DrawFrameControl is a very useful function, since it can draw any of the common window elements used by most controls.

        The GetSystemMetrics API function is useful to determine the actual size a number of window elements should be. The SM_CXMENUCHECK and SM_CYMENUCHECK flags should be used to find the proper size for a check image for menus. Then use DrawFrameControl to draw it the correct size in a blank bitmap and then use that bitmap in SetMenuItemBitmap.
        Chris Boss
        Computer Workshop
        Developer of "EZGUI"
        http://cwsof.com
        http://twitter.com/EZGUIProGuy

        Comment


        • #5
          MENUITEMINFO is not the solution

          When using SetMenuItemInfo (API) a coder can change the standard checkmark of a menu item into a bullet. Although defined as MFT_RADIOCHECK, it is not really a radio-button but a normal bullet, which is only displayed when the state of the menu-item is MF_CHECKED (MFS_CHECKED). It disappears when the state of the item becomes unchecked. In fact, same behaviour as standard checkmark. In other words: lots of fuss to create no change.

          What I want to achieve is a real checkbox that can be checked/unchecked by the user. So I'm going to try Michael's suggestion now: a second dialog that pops up instead of the menu. This means that the original menu should be disabled (it never opens) but should nevertheless receive a notification message in order to launch the replacing dialog. How?

          Thanks, guys, for all your help, so far.

          Egbert Zijlema, journalist and programmer (zijlema at basicguru dot eu)
          http://zijlema.basicguru.eu
          *** Opinions expressed here are not necessarily untrue ***

          Comment


          • #6
            Afaik a menu does not support checkboxes behaviour.
            The radio it does and is a bullet.
            You can 'uncheck' when the item is clicked and therefore make it work as a checkbox.

            Other option is already suggested, ownerdrawn.
            hellobasic

            Comment


            • #7
              This code does not create the bitmaps

              Well, I've made this pseudo code, but I don't see the checkbox appear.
              I think something is wrong in respect with the memory device context stuff. Normally hDC = CreateCompatibleDC(0) should be followed by SelectObject hDC, hObject, but which handle of which object must we select, since the bitmap handles will be set later by DrawFrameControl API function?

              Code:
              #COMPILE EXE
              #DIM ALL
              
              #INCLUDE "WIN32API.INC"
              
              %IDM_OPT1 = 1002
              
              FUNCTION AttachMenu(BYVAL hDlg AS DWORD) AS DWORD
                LOCAL cxMnu AS LONG, cyMnu AS LONG
                LOCAL hDC AS DWORD, hBmp1 AS DWORD, hBmp2 AS DWORD, rt AS RECT
                LOCAL hMenu  AS DWORD
                LOCAL hPopUp AS DWORD
              
                MENU NEW BAR TO hMenu
                MENU NEW POPUP TO hPopUp
                MENU ADD POPUP, hMenu, "&Edit", hPopUp, %MF_ENABLED
                MENU ADD STRING, hPopUp, "Option1", %IDM_OPT1, %MF_ENABLED
                MENU ATTACH hMenu, hDlg
              
                hDC = CreateCompatibleDC(0)
                cxMnu = GetSystemMetrics(%SM_CXMENUCHECK)
                cyMnu = GetSystemMetrics(%SM_CYMENUCHECK)
              
                rt.nLeft = 0
                rt.nTop = 0
                rt.nRight = cxMnu - 1
                rt.nBottom = cyMnu - 1
              
                hBmp1 = DrawFrameControl(hDC, rt, %DFC_BUTTON, %DFCS_BUTTONCHECK OR %DFCS_CHECKED)
                hBmp2 = DrawFrameControl(hDC, rt, %DFC_BUTTON, %DFCS_BUTTONCHECK)
              
                SetMenuItemBitmaps hMenu, %IDM_OPT1, %MF_BYCOMMAND, hBmp2, hBmp1
                FUNCTION = hMenu
              END FUNCTION
              
              CALLBACK FUNCTION ShowDlgProc()
                SELECT CASE AS LONG CBMSG
                  CASE %WM_COMMAND
                    SELECT CASE AS LONG CBCTL
                      CASE %IDM_OPT1
                        MSGBOX "%IDM_OPT1 = " & FORMAT$(%IDM_OPT1), 64 OR %MB_TASKMODAL, " Bmp demo.."
                    END SELECT
                END SELECT
              END FUNCTION
              
              FUNCTION PBMAIN()
                LOCAL hDlg AS DWORD, dwRet AS DWORD
                DIALOG NEW %HWND_DESKTOP, " Menu bitmap demo..", 70, 70, 201, 133, %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU TO hDlg
                dwRet = AttachMenu(hDlg)
                DIALOG SHOW MODAL hDlg, CALL ShowDlgProc
              END FUNCTION

              Egbert Zijlema, journalist and programmer (zijlema at basicguru dot eu)
              http://zijlema.basicguru.eu
              *** Opinions expressed here are not necessarily untrue ***

              Comment


              • #8
                DrawFrameControl() is used at drawing time, not at menu creation time.

                If the menu is MF_OWNERDRAW style, that would be on the WM_DRAWITEM notification, and you have to process the WM_MEASUREITEM notification, too.
                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]
                http://www.talsystems.com

                Comment


                • #9
                  This is an old one, but it works!

                  Code:
                  '-------------------------------------------------------------------------------------------------------
                  ' INCLUDE FILES
                  '-------------------------------------------------------------------------------------------------------
                  #If Not %Def(%WINAPI)
                      #INCLUDE "WIN32API.INC"
                  #ENDIF
                  
                  '-------------------------------------------------------------------------------------------------------
                  ' FUNCTION DECLARATIONS
                  '-------------------------------------------------------------------------------------------------------
                  Declare Sub SwitchMenuItemCheck(sMenuString As String)
                  Declare Sub SetMenuItemCheck(sMenuString As String, lCheckState As long)
                  Declare Function GetMenuItemCheck(sMenuString As String) As long
                  Declare Function VCIsCurrentWorldValid Lib "VCMAIN32.DLL" Alias "VCIsCurrentWorldValid" () As Integer
                  Declare Function VCGethWndFrame Lib "VCMAIN32.DLL" Alias "VCGethWndFrame" () As Long
                  Declare Sub SetMenuChecksByDrawingSettings()
                  
                  '-------------------------------------------------------------------------------------------------------
                  '  SUB GetMenuItemCheck
                  '-------------------------------------------------------------------------------------------------------
                  Function GetMenuItemCheck(sMenuString As String) As Long
                  	Local hWnd As Long
                  	Local hMenu As Long
                  	Local lMenuCount As Long
                  	Local lSubMenuCount As Long
                  	Local hSubMenu As Long
                  	Local ItemID As Long
                  	Local lRes As Long
                  	Local szMenuString As Asciiz * 64
                  	Local MainMenuIndex As Long
                  	Local SubMenuIndex As Long
                  	Local iState As Integer
                  	Function = %MF_UNCHECKED
                  	If VCIsCurrentWorldValid() = 0 Then Exit Function
                  	hWnd = VCGetHwndFrame() 'Mcadd frame handle
                  '	hMenu = GetSystemMenu(hWnd, 0) 'prüfen, ob Systemmenü aktiv
                  '	lSysMenuCount = GetMenuItemCount(hMenu) 'Anzahl der aktiven Systemmenü-Items
                  	hMenu = GetMenu(hWnd)	'Handle des Mcadd Hauptmenüs
                  	lMenuCount = GetMenuItemCount(hMenu) 'Anzahl der Untermenüs im Hauptmenü = 14 ohne Systemmenü, 18 mit Systemmenü
                  	For MainMenuIndex = 0 To lMenuCount -1
                  		hSubMenu = GetSubMenu(hMenu, MainMenuindex) 'Handle des Untermenüs mit Menütitel "Layer"
                  		lSubMenuCount = GetMenuItemCount(hSubMenu)
                  		For SubMenuIndex = 0 To lSubMenuCount - 1
                  			ItemID = GetMenuItemID(hSubMenu, SubMenuIndex)	'ID des ersten Menüeintrags im Untermenü 4
                  			lRes = GetMenuString(hSubMenu, ItemID, szMenuString, 0, %MF_BYCOMMAND) 'zuerst mit Parameter 0 nur die Länge ermitteln
                  			lRes = GetMenuString(hSubMenu, ItemID, szMenuString, lRes, %MF_BYCOMMAND) 'jetzt über die Länge den String ermitteln
                  			If InStr(szMenuString, sMenuString) Then
                  				iState = GetMenuState(hMenu, ItemID, %MF_BYCOMMAND Or %MF_CHECKED)
                  				Function = iState
                  				Exit For
                  			End If
                  		Next SubMenuIndex
                  	Next MainMenuIndex
                  End Function
                  
                  '-------------------------------------------------------------------------------------------------------
                  '  SUB SetMenuItemCheck
                  '-------------------------------------------------------------------------------------------------------
                  Sub SetMenuItemCheck(sMenuString As String, iCheckVal As Long)
                  	'INPUT: iCheckVal = %MF_CHECKED oder iCheckVal = %MF_UNCHECKED
                  	'INPUT alternativ: iCheckVal = 1 oder iCheckVal = 0
                  	Local hWnd As Long
                  	Local hMenu As Long
                  	Local lMenuCount As Long
                  	Local lSubMenuCount As Long
                  	Local hSubMenu As Long
                  	Local ItemID As Long
                  	Local lRes As Long
                  	Local MainMenuIndex As Long
                  	Local SubMenuIndex As Long 
                  	Local szMenuString As Asciiz * 64
                  	If VCIsCurrentWorldValid() = 0 Then Exit Sub
                  	If iCheckVal = 0 Then 
                  		iCheckVal = %MF_UNCHECKED
                  	ElseIf iCheckVal = 1 Then
                  		iCheckVal = %MF_CHECKED
                  	End If
                  	hWnd = VCGetHwndFrame() 'Mcadd frame handle
                  '	hMenu = GetSystemMenu(hWnd, 0) 'prüfen, ob Systemmenü aktiv
                  '	lSysMenuCount = GetMenuItemCount(hMenu) 'Anzahl der aktiven Systemmenü-Items
                  	hMenu = GetMenu(hWnd)	'Handle des Mcadd Hauptmenüs
                  	lMenuCount = GetMenuItemCount(hMenu) 'Anzahl der Untermenüs im Hauptmenü = 14 ohne Systemmenü, 18 mit Systemmenü
                  	For MainMenuIndex = 0 To lMenuCount -1
                  		hSubMenu = GetSubMenu(hMenu, MainMenuindex) 'Handle des Untermenüs per MainMenuindex
                  		lSubMenuCount = GetMenuItemCount(hSubMenu)
                  		For SubMenuIndex = 0 To lSubMenuCount - 1
                  			ItemID = GetMenuItemID(hSubMenu, SubMenuIndex)	'ID des ersten Menüeintrags im Untermenü per SubMenuIndex
                  			lRes = GetMenuString(hSubMenu, ItemID, szMenuString, 0, %MF_BYCOMMAND) 'zuerst mit Parameter 0 nur die Länge ermitteln
                  			lRes = GetMenuString(hSubMenu, ItemID, szMenuString, lRes, %MF_BYCOMMAND) 'jetzt über die Länge den String ermitteln
                  			If InStr(szMenuString, sMenuString) Then
                  				lRes = CheckMenuItem(hSubMenu, ItemID, %MF_BYCOMMAND Or iCheckVal)
                  				Exit For
                  			End If
                  		Next SubMenuIndex
                  	Next MainMenuIndex
                  End Sub
                  Norbert Doerre

                  Comment

                  Working...
                  X