Jump to content

Dynamic Context Menu


Recommended Posts

Hi all,

I'm working on a toolbar that has a user-customizable number of buttons that each need to have their own context menu so I got help from people here and this is what I've come up with. It works totally fine except when a normal context menu pops up over a button that has a context menu it'll pop up the button's context menu when you click the menuitem.

It seems to be registering a right click over the menuitem that i select - which triggers the custom context menu... any help would be outstanding :o

is there way to query whether or not a context menu is popped up? could I disable the custom context menu? I'm at a loss :D

try this test code and you'll see what I mean. Try right clicking on the title label and click on a menuitem that pops up ontop of a button

Test:

#include <GUIConstantsEx.au3>
#include <ButtonConstants.au3>
#include <WindowsConstants.au3>

Opt("GUIResizeMode", $GUI_DOCKALL)

;try and change buttons to activate on buttonUP so that dragging and releasing ontop of a button will work
;what about using static ctrls for buttons?...regular buttons are a lot simpler


Global $Buttonid[4]
$Buttonid[0] = 3;num buttons


_Main()
Func _Main()
    
    Local $ExitID, $GUIMenu, $GUIMenu_About, $GUIMenu_Exit
    Local $ButtonMenu, $ButtonMenu_Dummy, $ButtonMenu_Test1, $ButtonMenu_Test2
    
;create main ui
    $hGUI = GUICreate("Test GUI", 160, 80, -1, -1, $WS_POPUP + $WS_SIZEBOX, $GUI_WS_EX_PARENTDRAG)
        $GUIMenu = GUICtrlCreateContextMenu(-1)
            $GUIMenu_About = GUICtrlCreateMenuItem("About", $GUIMenu)
            $GUIMenu_Exit = GUICtrlCreateMenuItem("Exit", $GUIMenu)
    
    $toolbarTitle = GUICtrlCreateLabel("Test GUI", 5, 5, 180, 20, -1, $GUI_WS_EX_PARENTDRAG)
         $GUIMenuTB = GUICtrlCreateContextMenu($toolbarTitle)
            $GUIMenuTB_About = GUICtrlCreateMenuItem("About", $GUIMenuTB)
            $GUIMenuTB_Exit = GUICtrlCreateMenuItem("Exit", $GUIMenuTB)
        
;three buttons...
    $Buttonid[1] = GUICtrlCreateButton( "Test1", 10, 20, 40, 40)
    $Buttonid[2] = GUICtrlCreateButton( "Test2", 60, 20, 40, 40)
    $Buttonid[3] = GUICtrlCreateButton( "Test3", 110, 20, 40, 40)
    
    GUICtrlSetResizing ( $toolbarTitle, $GUI_DOCKLEFT + $GUI_DOCKRIGHT + $GUI_DOCKTOP + $GUI_DOCKHEIGHT )

;dummy to store index of button
    $ButtonMenu_Dummy = GUICtrlCreateDummy()
    $ButtonMenu = GUICtrlCreateContextMenu($ButtonMenu_Dummy)
        $ButtonMenu_Test1 = GUICtrlCreateMenuItem("ButtonMenu test1", $ButtonMenu)
        $ButtonMenu_Test2 = GUICtrlCreateMenuItem("ButtonMenu test2", $ButtonMenu) 
        
        
    GUISetState(@SW_SHOW)


    While 1
    ;start the message loop!!!!
        $msg = GUIGetMsg()
        
        local $i=1
            
        While UBound($Buttonid) > $i
            If $msg == $Buttonid[$i] Then
                MsgBox(0, "button pressed", "You've pressed button #" & $i, 2)
                ExitLoop
            EndIf
            $i += 1
        WEnd
        
        If $msg == $GUI_EVENT_CLOSE Or $msg == $GUIMenu_Exit Or $msg == $GUIMenuTB_Exit Or $msg == $ExitID Then
            GUIDelete($hGUI)
            Exit
        ElseIf $msg == $GUIMenu_About Or $msg == $GUIMenuTB_About Then
            Msgbox(64, "About", "blah blah blah")

        ElseIf $msg == $ButtonMenu_Test1 Then
            $index = GUICtrlRead($ButtonMenu_Dummy)
            MsgBox(0, "Context menu pressed", "test1 pressed from button #" &$index, 2)
        ElseIf $msg == $ButtonMenu_Test2 Then
            $index = GUICtrlRead($ButtonMenu_Dummy)
            MsgBox(0, "Context menu pressed", "test2 pressed from button #" &$index, 2)
        ElseIf $msg == $GUI_EVENT_SECONDARYUP Then
            ShowMenu($hGUI, $ButtonMenu, $ButtonMenu_Dummy, $ButtonMenu_Test1, $ButtonMenu_Test2)
        EndIf
    WEnd
EndFunc  ;==>_Main


;---------------Button Ctx menu functions---------------
Func ShowMenu($hGUI, $ButtonMenu, $ButtonMenu_Dummy, $ButtonMenu_Test1, $ButtonMenu_Test2)
    $hover = GUIGetCursorInfo($hGUI);get what control the mouse is over at this point and relative position for popup placement
    $hitX = $hover[0]
    $hitY = $hover[1]
    For $i=1 to (UBound($Buttonid)-1)
        If $hover[4] == $Buttonid[$i] And $hover[2] == 0 Then
                GUICtrlSendToDummy ($ButtonMenu_Dummy, $i); send index of hit item to dummy for reading later
                
            ;set new text
                GUICtrlSetData($ButtonMenu_Test1, "ButtonMenu #" & $i & " test1")
                GUICtrlSetData($ButtonMenu_Test2, "ButtonMenu #" & $i & " test2")
                
                Local $hMenu = GUICtrlGetHandle($ButtonMenu)
                ClientToScreen($hGUI, $hitX, $hitY)
                TrackPopupMenu($hGUI, $hMenu, $hitX, $hitY)
                Return
        EndIf
    Next 
EndFunc ;==>ShowMenu


; Convert the client (GUI) coordinates to screen (desktop) coordinates
Func ClientToScreen($hGUI, ByRef $x, ByRef $y)
    Local $stPoint = DllStructCreate("int;int")

    DllStructSetData($stPoint, 1, $x)
    DllStructSetData($stPoint, 2, $y)

    DllCall("user32.dll", "int", "ClientToScreen", "hwnd", $hGUI, "ptr", DllStructGetPtr($stPoint))
    
    $x = DllStructGetData($stPoint, 1)
    $y = DllStructGetData($stPoint, 2)
; release Struct not really needed as it is a local
    $stPoint = 0
EndFunc  

; Show at the given coordinates (x, y) the popup menu (hMenu) which belongs to a given GUI window (hWnd)
Func TrackPopupMenu($hGUI, $hMenu, $x, $y)
    DllCall("user32.dll", "int", "TrackPopupMenuEx", "hwnd", $hMenu, "int", 0, "int", $x, "int", $y, "hwnd", $hGUI, "ptr", 0)
EndFunc
Edited by FunkyBunnies
Link to comment
Share on other sites

Hi all,

I'm working on a toolbar that has a user-customizable number of buttons that each need to have their own context menu so I got help from people here and this is what I've come up with. It works totally fine except when a normal context menu pops up over a button that has a context menu it'll pop up the button's context menu when you click the menuitem.

It seems to be registering a right click over the menuitem that i select - which triggers the custom context menu... any help would be outstanding :o

is there way to query whether or not a context menu is popped up? could I disable the custom context menu? I'm at a loss :D

try this test code and you'll see what I mean. Try right clicking on the title label and click on a menuitem that pops up ontop of a button

Test:

#include <GUIConstantsEx.au3>
#include <ButtonConstants.au3>
#include <WindowsConstants.au3>

Opt("GUIResizeMode", $GUI_DOCKALL)

;try and change buttons to activate on buttonUP so that dragging and releasing ontop of a button will work
;what about using static ctrls for buttons?...regular buttons are a lot simpler


Global $Buttonid[4]
$Buttonid[0] = 3;num buttons


_Main()
Func _Main()
    
    Local $ExitID, $GUIMenu, $GUIMenu_About, $GUIMenu_Exit
    Local $ButtonMenu, $ButtonMenu_Dummy, $ButtonMenu_Test1, $ButtonMenu_Test2
    
;create main ui
    $hGUI = GUICreate("Test GUI", 160, 80, -1, -1, $WS_POPUP + $WS_SIZEBOX, $GUI_WS_EX_PARENTDRAG)
        $GUIMenu = GUICtrlCreateContextMenu(-1)
            $GUIMenu_About = GUICtrlCreateMenuItem("About", $GUIMenu)
            $GUIMenu_Exit = GUICtrlCreateMenuItem("Exit", $GUIMenu)
    
    $toolbarTitle = GUICtrlCreateLabel("Test GUI", 5, 5, 180, 20, -1, $GUI_WS_EX_PARENTDRAG)
         $GUIMenuTB = GUICtrlCreateContextMenu($toolbarTitle)
            $GUIMenuTB_About = GUICtrlCreateMenuItem("About", $GUIMenuTB)
            $GUIMenuTB_Exit = GUICtrlCreateMenuItem("Exit", $GUIMenuTB)
        
;three buttons...
    $Buttonid[1] = GUICtrlCreateButton( "Test1", 10, 20, 40, 40)
    $Buttonid[2] = GUICtrlCreateButton( "Test2", 60, 20, 40, 40)
    $Buttonid[3] = GUICtrlCreateButton( "Test3", 110, 20, 40, 40)
    
    GUICtrlSetResizing ( $toolbarTitle, $GUI_DOCKLEFT + $GUI_DOCKRIGHT + $GUI_DOCKTOP + $GUI_DOCKHEIGHT )

;dummy to store index of button
    $ButtonMenu_Dummy = GUICtrlCreateDummy()
    $ButtonMenu = GUICtrlCreateContextMenu($ButtonMenu_Dummy)
        $ButtonMenu_Test1 = GUICtrlCreateMenuItem("ButtonMenu test1", $ButtonMenu)
        $ButtonMenu_Test2 = GUICtrlCreateMenuItem("ButtonMenu test2", $ButtonMenu) 
        
        
    GUISetState(@SW_SHOW)


    While 1
    ;start the message loop!!!!
        $msg = GUIGetMsg()
        
        local $i=1
            
        While UBound($Buttonid) > $i
            If $msg == $Buttonid[$i] Then
                MsgBox(0, "button pressed", "You've pressed button #" & $i, 2)
                ExitLoop
            EndIf
            $i += 1
        WEnd
        
        If $msg == $GUI_EVENT_CLOSE Or $msg == $GUIMenu_Exit Or $msg == $GUIMenuTB_Exit Or $msg == $ExitID Then
            GUIDelete($hGUI)
            Exit
        ElseIf $msg == $GUIMenu_About Or $msg == $GUIMenuTB_About Then
            Msgbox(64, "About", "blah blah blah")

        ElseIf $msg == $ButtonMenu_Test1 Then
            $index = GUICtrlRead($ButtonMenu_Dummy)
            MsgBox(0, "Context menu pressed", "test1 pressed from button #" &$index, 2)
        ElseIf $msg == $ButtonMenu_Test2 Then
            $index = GUICtrlRead($ButtonMenu_Dummy)
            MsgBox(0, "Context menu pressed", "test2 pressed from button #" &$index, 2)
        ElseIf $msg == $GUI_EVENT_SECONDARYUP Then
            ShowMenu($hGUI, $ButtonMenu, $ButtonMenu_Dummy, $ButtonMenu_Test1, $ButtonMenu_Test2)
        EndIf
    WEnd
EndFunc  ;==>_Main


;---------------Button Ctx menu functions---------------
Func ShowMenu($hGUI, $ButtonMenu, $ButtonMenu_Dummy, $ButtonMenu_Test1, $ButtonMenu_Test2)
    $hover = GUIGetCursorInfo($hGUI);get what control the mouse is over at this point and relative position for popup placement
    $hitX = $hover[0]
    $hitY = $hover[1]
    For $i=1 to (UBound($Buttonid)-1)
        If $hover[4] == $Buttonid[$i] And $hover[2] == 0 Then
                GUICtrlSendToDummy ($ButtonMenu_Dummy, $i); send index of hit item to dummy for reading later
                
            ;set new text
                GUICtrlSetData($ButtonMenu_Test1, "ButtonMenu #" & $i & " test1")
                GUICtrlSetData($ButtonMenu_Test2, "ButtonMenu #" & $i & " test2")
                
                Local $hMenu = GUICtrlGetHandle($ButtonMenu)
                ClientToScreen($hGUI, $hitX, $hitY)
                TrackPopupMenu($hGUI, $hMenu, $hitX, $hitY)
                Return
        EndIf
    Next 
EndFunc ;==>ShowMenu


; Convert the client (GUI) coordinates to screen (desktop) coordinates
Func ClientToScreen($hGUI, ByRef $x, ByRef $y)
    Local $stPoint = DllStructCreate("int;int")

    DllStructSetData($stPoint, 1, $x)
    DllStructSetData($stPoint, 2, $y)

    DllCall("user32.dll", "int", "ClientToScreen", "hwnd", $hGUI, "ptr", DllStructGetPtr($stPoint))
    
    $x = DllStructGetData($stPoint, 1)
    $y = DllStructGetData($stPoint, 2)
; release Struct not really needed as it is a local
    $stPoint = 0
EndFunc  

; Show at the given coordinates (x, y) the popup menu (hMenu) which belongs to a given GUI window (hWnd)
Func TrackPopupMenu($hGUI, $hMenu, $x, $y)
    DllCall("user32.dll", "int", "TrackPopupMenuEx", "hwnd", $hMenu, "int", 0, "int", $x, "int", $y, "hwnd", $hGUI, "ptr", 0)
EndFunc
When the secondary mouse button is pressed and the mouse is not over a button the context menu for the gui is shown. Then the secondary button is released but this event is queued until the gui context menu is closed which happens when you left click. I think that's what happens at least.

So if you use $GUI_EVENT_SECONDARYDOWN instead of $GUI_EVENT_SECONDARYUP it might work.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

You're making it more troubles attraction than it is:

#include <GuiConstants.au3>

Dim $hGUI = GUICreate('Test', 240, 140)
Dim $GUIMenu = GUICtrlCreateContextMenu()
    Dim $About_Menu = GUICtrlCreateMenuItem('About', $GUIMenu)
    Dim $Exit_Menu  = GUICtrlCreateMenuItem('Exit', $GUIMenu)

Dim $Buttons[4] = [3], $Menus[4][3] = [[3,2,0]]
For $i = 1 To $Buttons[0]
    $Buttons[$i] = GUICtrlCreateButton('#' & $i, 20+($i-1)*70, 40, 50, 50)
    Local $Button_Menu = GUICtrlCreateContextMenu($Buttons[$i])
    
    For $j = 0 To $Menus[0][1]
        $Menus[$i][$j] = GUICtrlCreateMenuItem('B' & $i & '->#' & $j+1, $Button_Menu)
    Next
Next

GUISetState()

While 1
    Local $Msg = GUIGetMsg()
    
    Switch $Msg
        Case $About_Menu
            MsgBox(0x40, 'Title', '(\/)' & @LF & '(oO)' & @LF & '(")(")')
            
        Case $Exit_Menu, $GUI_EVENT_CLOSE
            ExitLoop
            
        Case Else
            _WhoCalls($Msg, $Buttons, $Menus)
    EndSwitch
    
    Sleep(20)
WEnd

GUIDelete()

Func _WhoCalls($iIDFrom, ByRef $Btns, ByRef $Mns)
    For $i = 1 To $Btns[0]
        If $iIDFrom = $Btns[$i] Then
            MsgBox(0x40, 'Button Message!', 'From button: #' & $i)
            ExitLoop
        EndIf
        
        For $j = 0 To $Mns[0][1]
            If $iIDFrom = $Mns[$i][$j] Then
                MsgBox(0x40, 'Menu Message!', 'From button: #' & $i & @LF & 'From menu: #' & $j+1)
                ExitLoop(2)
            EndIf
        Next
    Next
EndFunc

';]

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...