Jump to content

_GUICtrlTreeView_Create and WM_CONTEXTMENU WM_COMMAND won't work together


Recommended Posts

#include <GUIConstantsEx.au3>
#include <GuiTreeView.au3>
#include <WindowsConstants.au3>
#include <GuiMenu.au3>

Global $g_hTreeView
Global Enum $e_idOpen = 1000, $e_idSave, $e_idInfo

Example()

Func Example()
    Local $hGUI, $hItem
    Local $iStyle = BitOR($TVS_EDITLABELS, $TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS, $TVS_CHECKBOXES)
    $hGUI = GUICreate("(UDF Created) TreeView Create", 400, 300)

    $g_hTreeView = _GUICtrlTreeView_Create($hGUI, 2, 2, 396, 268, $iStyle, $WS_EX_CLIENTEDGE)
    GUISetState(@SW_SHOW)

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
    GUIRegisterMsg($WM_CONTEXTMENU, "WM_CONTEXTMENU")
    GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")

    _GUICtrlTreeView_BeginUpdate($g_hTreeView)
    For $x = 1 To Random(2, 10, 1)
        $hItem = _GUICtrlTreeView_Add($g_hTreeView, 0, StringFormat("[%02d] New Item", $x))
        For $y = 1 To Random(2, 10, 1)
            _GUICtrlTreeView_AddChild($g_hTreeView, $hItem, StringFormat("[%02d] New Child", $y))
        Next
    Next
    _GUICtrlTreeView_EndUpdate($g_hTreeView)

    ; Loop until the user exits.
    Do
    Until GUIGetMsg() = $GUI_EVENT_CLOSE
    GUIDelete()
EndFunc   ;==>Example

Func WM_CONTEXTMENU($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $lParam

    ;ConsoleWrite($GUI_RUNDEFMSG & @CRLF)
    ;Switch $wParam

    ;   Case $hTreeView

            Local $hMenu

            $hMenu = _GUICtrlMenu_CreatePopup()
            _GUICtrlMenu_InsertMenuItem($hMenu, 0, "Open", $e_idOpen)
            _GUICtrlMenu_InsertMenuItem($hMenu, 1, "Save", $e_idSave)
            _GUICtrlMenu_InsertMenuItem($hMenu, 3, "", 0)
            _GUICtrlMenu_InsertMenuItem($hMenu, 3, "Info", $e_idInfo)
            _GUICtrlMenu_TrackPopupMenu($hMenu, $wParam)
            _GUICtrlMenu_DestroyMenu($hMenu)
            Return True

    ;EndSwitch

    Return $GUI_RUNDEFMSG

EndFunc   ;==>WM_CONTEXTMENU

Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $lParam
    Switch $wParam
        Case $e_idOpen
             _DebugPrint("WM_COMMAND " & $wParam & " Open")
        Case $e_idSave
             _DebugPrint("WM_COMMAND " & $wParam & " Save")
        Case $e_idInfo
             _DebugPrint("WM_COMMAND " & $wParam & " Info")
    EndSwitch

    Return $GUI_RUNDEFMSG

EndFunc   ;==>WM_COMMAND


Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndTreeview
    $hWndTreeview = $g_hTreeView
    If Not IsHWnd($g_hTreeView) Then $hWndTreeview = GUICtrlGetHandle($g_hTreeView)

    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hWndTreeview
            Switch $iCode
                Case $NM_CLICK ; The user has clicked the left mouse button within the control
                    _DebugPrint("$NM_CLICK" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; Return 1 ; nonzero to not allow the default processing
                    Return 0 ; zero to allow the default processing
                Case $NM_DBLCLK ; The user has double-clicked the left mouse button within the control
                    _DebugPrint("$NM_DBLCLK" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; Return 1 ; nonzero to not allow the default processing
                    Return 0 ; zero to allow the default processing
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Func _DebugPrint($s_Text, $sLine = @ScriptLineNumber)
    ConsoleWrite( _
            "!===========================================================" & @CRLF & _
            "+======================================================" & @CRLF & _
            "-->Line(" & StringFormat("%04d", $sLine) & "):" & @TAB & $s_Text & @CRLF & _
            "+======================================================" & @CRLF)
EndFunc   ;==>_DebugPrint

In the example code I have a treeview and a context/popup menu, I can't use a conventional context menu because I need to use the treeview UDF functions.

The WM_COMMAND never fires from the context/popup menu selection while there is a treeview using  _GuiCtrlTreeview_Create

If you comment out _GuiCtrlTreeview_Create line you will then see the right click selection works as expected and the debug is written to the console on selection.

Autoit Ver 3.3.14.2

Any ideas why this combination won't work together?

Thanks

 

Link to comment
Share on other sites

You may have noticed that WM_COMMAND messages are still handled correctly when you right-click in the small empty area below the TreeView. Only when you right-click in the TreeView area the messages are not handled correctly.

When you right-click in a window WM_COMMAND messages are always send to the same window. If you right-click in the GUI WM_COMMAND messages are send to the GUI. If you right-click in the TreeView WM_COMMAND messages are to send to the TreeView.

But GUIRegisterMsg is only able to catch messages which are send to the GUI. GUIRegisterMsg cannot catch messages which are send to the TreeView.

The solution is to subclass the TreeView. Details in the codebox. I've added 10 code lines.

#include <GUIConstantsEx.au3>
#include <GuiTreeView.au3>
#include <WindowsConstants.au3>
#include <GuiMenu.au3>

#include <WinAPIShellEx.au3>

Global $g_hTreeView
Global Enum $e_idOpen = 1000, $e_idSave, $e_idInfo

Example()

Func Example()
    Local $hGUI, $hItem
    Local $iStyle = BitOR($TVS_EDITLABELS, $TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS, $TVS_CHECKBOXES)
    $hGUI = GUICreate("(UDF Created) TreeView Create", 400, 300)

    $g_hTreeView = _GUICtrlTreeView_Create($hGUI, 2, 2, 396, 268, $iStyle, $WS_EX_CLIENTEDGE)
    GUISetState(@SW_SHOW)

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
    GUIRegisterMsg($WM_CONTEXTMENU, "WM_CONTEXTMENU")
    GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")

    Local $pTreeViewMsgHandler = DllCallbackGetPtr( DllCallbackRegister( "TreeViewMsgHandler", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr" ) )
    _WinAPI_SetWindowSubclass( $g_hTreeView, $pTreeViewMsgHandler, 0, 0 ) ; $iSubclassId = 0, $pData = 0

    _GUICtrlTreeView_BeginUpdate($g_hTreeView)
    For $x = 1 To Random(2, 10, 1)
        $hItem = _GUICtrlTreeView_Add($g_hTreeView, 0, StringFormat("[%02d] New Item", $x))
        For $y = 1 To Random(2, 10, 1)
            _GUICtrlTreeView_AddChild($g_hTreeView, $hItem, StringFormat("[%02d] New Child", $y))
        Next
    Next
    _GUICtrlTreeView_EndUpdate($g_hTreeView)

    ; Loop until the user exits.
    Do
    Until GUIGetMsg() = $GUI_EVENT_CLOSE
    _WinAPI_RemoveWindowSubclass( $g_hTreeView, $pTreeViewMsgHandler, 0 )
    GUIDelete()
EndFunc   ;==>Example

Func TreeViewMsgHandler( $hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $pData )
  Switch $iMsg
    Case $WM_COMMAND
      Switch $wParam
          Case $e_idOpen
               _DebugPrint("WM_COMMAND " & $wParam & " Open")
          Case $e_idSave
               _DebugPrint("WM_COMMAND " & $wParam & " Save")
          Case $e_idInfo
               _DebugPrint("WM_COMMAND " & $wParam & " Info")
      EndSwitch
  EndSwitch
  ; Call next function in subclass chain (this forwards Windows messages to main GUI)
  Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0]
EndFunc

Func WM_CONTEXTMENU($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $lParam

    ;ConsoleWrite($GUI_RUNDEFMSG & @CRLF)
    ;Switch $wParam

    ;   Case $hTreeView

            Local $hMenu

            $hMenu = _GUICtrlMenu_CreatePopup()
            _GUICtrlMenu_InsertMenuItem($hMenu, 0, "Open", $e_idOpen)
            _GUICtrlMenu_InsertMenuItem($hMenu, 1, "Save", $e_idSave)
            _GUICtrlMenu_InsertMenuItem($hMenu, 3, "", 0)
            _GUICtrlMenu_InsertMenuItem($hMenu, 3, "Info", $e_idInfo)
            _GUICtrlMenu_TrackPopupMenu($hMenu, $wParam)
            _GUICtrlMenu_DestroyMenu($hMenu)
            Return True

    ;EndSwitch

    Return $GUI_RUNDEFMSG

EndFunc   ;==>WM_CONTEXTMENU

Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $lParam
    Switch $wParam
        Case $e_idOpen
             _DebugPrint("WM_COMMAND " & $wParam & " Open")
        Case $e_idSave
             _DebugPrint("WM_COMMAND " & $wParam & " Save")
        Case $e_idInfo
             _DebugPrint("WM_COMMAND " & $wParam & " Info")
    EndSwitch

    Return $GUI_RUNDEFMSG

EndFunc   ;==>WM_COMMAND


Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndTreeview
    $hWndTreeview = $g_hTreeView
    If Not IsHWnd($g_hTreeView) Then $hWndTreeview = GUICtrlGetHandle($g_hTreeView)

    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hWndTreeview
            Switch $iCode
                Case $NM_CLICK ; The user has clicked the left mouse button within the control
                    _DebugPrint("$NM_CLICK" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; Return 1 ; nonzero to not allow the default processing
                    Return 0 ; zero to allow the default processing
                Case $NM_DBLCLK ; The user has double-clicked the left mouse button within the control
                    _DebugPrint("$NM_DBLCLK" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; Return 1 ; nonzero to not allow the default processing
                    Return 0 ; zero to allow the default processing
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Func _DebugPrint($s_Text, $sLine = @ScriptLineNumber)
    ConsoleWrite( _
            "!===========================================================" & @CRLF & _
            "+======================================================" & @CRLF & _
            "-->Line(" & StringFormat("%04d", $sLine) & "):" & @TAB & $s_Text & @CRLF & _
            "+======================================================" & @CRLF)
EndFunc   ;==>_DebugPrint

 

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

×
×
  • Create New...