Jump to content

Help with a Treeview Context Menu


benners
 Share

Go to solution Solved by Nine,

Recommended Posts

I have a GUI that contains a treeview and what I am trying to do is to get the context menu to only show when an item is right clicked. Currently, as it's assigned to the treeview, the context menu activates whenever the treeview is clicked. Rather than keep enabling\disabling the menu items I am in need of a way limit the menus popup.

One of the options on the menu will open another GUI and disable the parent, for this reason, I cannot do much in the WM_NOTIFY portion as it hangs the program and I don't want to hang around blocking the messages.

The other option is to create a menu for each treeview item when the are added to the list. This will fix the issue but there maybe 100+ items and I don't want to have that many menus all of which have the same 2/3 options.

I am currently looking at using an Adlib function as mentioned here by Melba. I could create and destroy the menu each time and unregister the adlib when the function closes.

Anyway, a producer code is below if there are any other ideas, or I've missed the obvious. Cheers

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <TreeViewConstants.au3>
#include <GuiTreeView.au3>
#include <ButtonConstants.au3>
#include <GUIListBox.au3>

Opt('MustDeclareVars', 1)

_Main()

Func _Main()
    Local $hGUI = GUICreate("TreeView", 400, 300)
    Global $cTreeView = GUICtrlCreateTreeView(10, 10, 380, 280)
    Local $cParent = GUICtrlCreateTreeViewItem('List', $cTreeView)

    For $i = 1 To 5
        GUICtrlCreateTreeViewItem('Item ' & $i, $cParent)
    Next

    Local $cCMenu = GUICtrlCreateContextMenu($cTreeView)
    Global $cCMenuEdit = GUICtrlCreateMenuItem("Edit", $cCMenu)
    GUICtrlSetState(-1, $GUI_DISABLE)

    _GUICtrlTreeView_Expand($cTreeView)

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
    GUISetState(@SW_SHOW)

    Local $nMsg

    While 1
        $nMsg = GUIGetMsg()

        Switch $nMsg
            Case $GUI_EVENT_CLOSE
                Exit
            Case $cCMenuEdit

        EndSwitch
    WEnd

EndFunc   ;==>_Main

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

    Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    Local $hWndFrom = DllStructGetData($tNMHDR, "hWndFrom")
    Local $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    Local $iCode = DllStructGetData($tNMHDR, "Code")

    Switch $iIDFrom
        Case $cTreeView
            Switch $iCode
                Case $NM_RCLICK
                    Local $tPoint = _WinAPI_GetMousePos(True, $hWndFrom)
                    Local $tHitTest = _GUICtrlTreeView_HitTestEx($hWndFrom, DllStructGetData($tPoint, 1), DllStructGetData($tPoint, 2))

                    If BitAND(DllStructGetData($tHitTest, "Flags"), $TVHT_ONITEM) Then
                        If _GUICtrlTreeView_Level($cTreeView, DllStructGetData($tHitTest, 'Item')) > 0 Then
                            GUICtrlSetState($cCMenuEdit, $GUI_ENABLE)
                        Else
                            GUICtrlSetState($cCMenuEdit, $GUI_DISABLE)
                        EndIf

                        _GUICtrlTreeView_SelectItem($hWndFrom, DllStructGetData($tHitTest, 'Item'))
                    Else
                        GUICtrlSetState($cCMenuEdit, $GUI_DISABLE)
                    EndIf
            EndSwitch
    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

 

Link to comment
Share on other sites

Well i managed to get it working how I wanted after a bit of trial and error.

#include <GuiMenu.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <TreeViewConstants.au3>
#include <GuiTreeView.au3>
#include <ButtonConstants.au3>
#include <GUIListBox.au3>

Opt('MustDeclareVars', 1)

Global $bShowMenu = False

_Main()

Func _Main()
    Global $hGUI = GUICreate("TreeView", 400, 300)
    Global $cTreeView = GUICtrlCreateTreeView(10, 10, 380, 280)
    Local $cParent = GUICtrlCreateTreeViewItem('List', $cTreeView)

    For $i = 1 To 5
        GUICtrlCreateTreeViewItem('Item ' & $i, $cParent)
    Next

    Global Enum $idOpen = 1000, $idSave

    Global $hMenu = _GUICtrlMenu_CreatePopup()
    _GUICtrlMenu_InsertMenuItem($hMenu, 0, "Open", $idOpen)
    _GUICtrlMenu_InsertMenuItem($hMenu, 1, "Save", $idSave)

    _GUICtrlTreeView_Expand($cTreeView)

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
    GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
    GUISetState(@SW_SHOW)

    Local $nMsg

    While 1
        $nMsg = GUIGetMsg()

        Switch $nMsg
            Case $GUI_EVENT_CLOSE
                Exit
        EndSwitch

        If $bShowMenu Then showmenu()
    WEnd

EndFunc   ;==>_Main

Func showmenu()
    $bShowMenu = False
    _GUICtrlMenu_TrackPopupMenu($hMenu, $hGUI)
EndFunc   ;==>showmenu

Func creategui()
    Local $hGUI2 = GUICreate("Dialog", 368, 216, 834, 271)
    Local $Button1 = GUICtrlCreateButton("&OK", 272, 16, 75, 25)
    Local $Button2 = GUICtrlCreateButton("&Cancel", 272, 48, 75, 25)

    GUISetState(@SW_SHOW)
    GUISwitch($hGUI2)
    GUISetState(@SW_DISABLE, $hGUI)

    Local $nMsg

    While 1
        $nMsg = GUIGetMsg()

        Switch $nMsg
            Case $GUI_EVENT_CLOSE, $Button2
                ExitLoop
        EndSwitch
    WEnd

    GUISwitch($hGUI)
    GUISetState(@SW_ENABLE, $hGUI)
    GUIDelete($hGUI2)
EndFunc   ;==>creategui

Func WM_COMMAND($hWnd, $iMsg, $iwParam, $ilParam)
    Switch $iwParam
        Case $idOpen
            creategui()
        Case $idSave
            _WinAPI_ShowMsg("Save")
    EndSwitch
EndFunc   ;==>WM_COMMAND

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

    Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    Local $hWndFrom = DllStructGetData($tNMHDR, "hWndFrom")
    Local $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    Local $iCode = DllStructGetData($tNMHDR, "Code")

    Switch $iIDFrom
        Case $cTreeView
            Switch $iCode
                Case $NM_RCLICK
                    Local $tPoint = _WinAPI_GetMousePos(True, $hWndFrom)
                    Local $tHitTest = _GUICtrlTreeView_HitTestEx($hWndFrom, DllStructGetData($tPoint, 1), DllStructGetData($tPoint, 2))

                    If BitAND(DllStructGetData($tHitTest, "Flags"), $TVHT_ONITEM) Then
                        If _GUICtrlTreeView_Level($cTreeView, DllStructGetData($tHitTest, 'Item')) > 0 Then
                            _GUICtrlTreeView_SelectItem($hWndFrom, DllStructGetData($tHitTest, 'Item'))
                            $bShowMenu = True
                        EndIf
                    EndIf
            EndSwitch
    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

 

Link to comment
Share on other sites

  • Solution

Wouldn't be easier just to cancel the right click whenever it is not on an item ?

How about this notify proc ?

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

  Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
  Local $hWndFrom = DllStructGetData($tNMHDR, "hWndFrom")
  Local $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
  Local $iCode = DllStructGetData($tNMHDR, "Code")

  Switch $iIDFrom
    Case $cTreeView
      Switch $iCode
        Case $NM_RCLICK
          Local $tPoint = _WinAPI_GetMousePos(True, $hWndFrom)
          Local $tHitTest = _GUICtrlTreeView_HitTestEx($hWndFrom, $tPoint.X, $tPoint.Y)
          If BitAND($tHitTest.Flags, $TVHT_ONITEM) And _GUICtrlTreeView_Level($cTreeView, $tHitTest.Item) > 0 Then Return $GUI_RUNDEFMSG
          Return 1
      EndSwitch
  EndSwitch

  Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

 

Link to comment
Share on other sites

No. It would be much easier with loads more lines of code and and faffing about.:D:> at least that's what I'll now tell myself after you showed me how easy things are if you understand them. Every day is a school day.

It makes me understand the help file line a bit more now. I had read it but didn't get that it would only ignore the message that was activated, i.e. right clicking.

Quote

However, if Return is used with any other value (including no value at all) the AutoIt internal message handler will NOT be actioned.

I have tested your new WM_Notify on an old copy of the main script and it works. It works better than the new code as the new one seems to fire the function associated with the selection of the treeview item. Maybe due to the hit test?

Thanks for the help

Edited by benners
Manners
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...