Sign in to follow this  
Followers 0
CMJ

Context Menu and TreeView

6 posts in this topic

Why doesn't right clicking on an item in a tree view set that item as selected. The item appears to be selected but then when you act on the selected item the selection switches to the first item in the treeview.

Here is a script that shows what I mean. In this example expand a parent, for example Parent 4, and right click on the child, Child 4-2. You will see the context menu but when you select delete it will delete Parent 1 and all of its children. However if you left click Child 4-1 before you right click on it, the delete function works as expected.

Thanks in advance for any help.

cj

#include <GuiConstantsEx.au3>
#include <GuiTreeView.au3>
#include <WindowsConstants.au3>

Opt("GUIOnEventMode", 1)
Global $MenuParent, $gui, $contextmenu, $i, $n, $textitem, $Tree, $Child

Main()

While 1
    Sleep(100)
WEnd

Func Main()
    $gui = GUICreate("Treeview Demo", 300, 500, -1, -1)

    $Tree = GUICtrlCreateTreeView(-1, -1, 300, 500)

    For $n = 1 to 9
        $Parent = GUICtrlCreateTreeViewItem("Parent " & $n,$Tree)
        For $i = 1 to 3
            $Child = GUICtrlCreateTreeViewItem("Child " & $n & "-" & $i,$Parent)
            contextMenu($Child)
        Next
    Next
    GUISetOnEvent($GUI_EVENT_CLOSE, 'Close')
    GUISetState(@SW_SHOW)
EndFunc

Func contextMenu($MenuParent)
    $contextmenu = GUICtrlCreateContextMenu($MenuParent)
    $textitem = GUICtrlCreateMenuItem("Delete", $contextmenu)
        GUICtrlSetOnEvent ( $textitem, "Delete" )
EndFunc

Func Delete()
    _GUICtrlTreeView_Delete($Tree, _GUICtrlTreeView_GetSelection ($Tree))
EndFunc

Func Close()
    Exit
EndFunc

Share this post


Link to post
Share on other sites



I am going to bump this topic because I keep encountering this "bug".

Anyone know if there is a work around? It is definitely only an issue with the treeview. List controls work as expected. If not is there a place that I can officially report this bug so that it can be fixed in the next release.

Thanks in advance for any help.

cj

Share this post


Link to post
Share on other sites

This is the default behaviour of a treeview, no bug

Right click notifications from the treeview must be hit tested for the item under the mouse

so the item can be selected.

#include <GuiConstantsEx.au3>
#include <GuiTreeView.au3>
#include <WindowsConstants.au3>
Opt("GUIOnEventMode", 1)
Global $MenuParent, $gui, $contextmenu, $i, $n, $textitem, $Tree, $Child
Global $Tree, $tNMHDR, $hWndFrom, $iIDFrom, $iCode, $fOnItem = False
Main()
While 1
    Sleep(100)
WEnd
Func Main()
    $gui = GUICreate("Treeview Demo", 300, 500, -1, -1)
    $Tree = GUICtrlCreateTreeView(-1, -1, 300, 500)
    For $n = 1 to 9
        $Parent = GUICtrlCreateTreeViewItem("Parent " & $n,$Tree)
        For $i = 1 to 3
            $Child = GUICtrlCreateTreeViewItem("Child " & $n & "-" & $i,$Parent)
            contextMenu($Child)
        Next
    Next
    GUISetOnEvent($GUI_EVENT_CLOSE, 'Close')
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
    GUISetState(@SW_SHOW)
EndFunc
Func contextMenu($MenuParent)
$contextmenu = GUICtrlCreateContextMenu($MenuParent)
$textitem = GUICtrlCreateMenuItem("Delete", $contextmenu)
GUICtrlSetOnEvent ( $textitem, "Delete" )
EndFunc
Func Delete()
;If $fOnItem Then ;optionally block menu return from right click over non-item area
  ;$fOnItem = False
  _GUICtrlTreeView_Delete($Tree, _GUICtrlTreeView_GetSelection ($Tree))
;EndIf
EndFunc
Func Close()
    Exit
EndFunc

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
#forceref $hWnd, $iMsg, $wParam
$tNMHDR = DllStructCreate($tagNMHDR, $lParam)
$hWndFrom = DllStructGetData($tNMHDR, "hWndFrom")
$iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
$iCode = DllStructGetData($tNMHDR, "Code")
Switch $iIDFrom
  Case $Tree
   Switch $iCode
    Case $NM_RCLICK
     Local $tPoint = _WinAPI_GetMousePos(True, $hWndFrom), $tHitTest
     $tHitTest = _GUICtrlTreeView_HitTestEx($hWndFrom, DllStructGetData($tPoint, 1), DllStructGetData($tPoint, 2))
     ;If BitAND(DllStructGetData($tHitTest, "Flags"), $TVHT_ONITEM) Then ;optionally block menu return from right click over non-item area
      ;$fOnItem = True
      Local $hItem = DllStructGetData($tHitTest, 'Item')
      If IsPtr($hItem) Then
       _GUICtrlTreeView_SelectItem($hWndFrom, $hItem)
      EndIf
     ;EndIf
   EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY
2 people like this

I see fascists...

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Thanks for the reply Rover. Seems to work perfectly. Though I am not sure I understand hittesting. I guess I have more studying to do.

cj

Edit: Implemented and working great. Thanks again. As a followup question: Is there ever a time when you would want a right click not to select the item you right click on? Seems as if this could be "built in" to the functionality of the TreeView control. The ListView functions this way so it seem logical that the TreeView would follow suit. No?

Edited by CMJ

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Thanks for the reply Rover. Seems to work perfectly. Though I am not sure I understand hittesting. I guess I have more studying to do.

cj

Edit: Implemented and working great. Thanks again. As a followup question: Is there ever a time when you would want a right click not to select the item you right click on? Seems as if this could be "built in" to the functionality of the TreeView control. The ListView functions this way so it seem logical that the TreeView would follow suit. No?

Hit testing determines if there is a treeview/listview item under the mouse, and, if the mouse is over an allowable area of the item.

(over checkbox, icon, text, or if over a non item element such as the header or blank areas)

Very useful for limiting a contextmenu to treeview/listview items.

Read the Wiki for an explanation of message handling with GUIRegisterMsg (NM_RCLICK)

http://www.autoitscript.com/wiki/GUIRegisterMsg

If you want the default treeview behaviour, this example bounces back to the previously selected/focused item after deleting a right clicked item.

I've added _GUICtrlTreeView_SetFocused($Tree, $hItemSel, True) to the code, and it should be added to the other example as well.

It seems there is an issue under some circumstances if the right clicked item is not given focus (mentioned on an MSDN forum)

though I don't see any problem here.

Is there ever a time when you would want a right click not to select the item you right click on?

I can only point to Explorer as an example.

Selecting a contextmenu action on a drive/folder other than the currently selected drive/folder

doesn't change the currently selected drive/folder in the right pane listview.

I'll hazard a guess that this is the reason for this treeview design feature.

Seems as if this could be "built in" to the functionality of the TreeView control.

The ListView functions this way so it seem logical that the TreeView would follow suit. No?

This is a user preference change of a Microsoft Common Controls default behaviour.

The AutoIt devs will reject a user preference change request for a common controls default behaviour.

Requested changes that can be easily implemented by a UDF and are of minimal utility

to the broader community of AutoIt users are always rejected.

A read of the Closed Requests list in TRAC will give you some idea of what gets rejected.

#include <GuiConstantsEx.au3>
#include <GuiTreeView.au3>
#include <WindowsConstants.au3>
Opt('MustDeclareVars', 1)
Opt("GUIOnEventMode", 1)
Global $MenuParent, $Parent, $gui, $contextmenu, $i, $n, $textitem, $Tree, $Child
Global $Tree, $tNMHDR, $hWndFrom, $iIDFrom, $iCode, $fOnItem = False
Global $hItemSel
Main()
While 1
    Sleep(100)
WEnd
Func Main()
    $gui = GUICreate("Treeview Demo", 300, 500, -1, -1)
    $Tree = GUICtrlCreateTreeView(-1, -1, 300, 500)
    For $n = 1 to 9
        $Parent = GUICtrlCreateTreeViewItem("Parent " & $n,$Tree)
        For $i = 1 to 3
            $Child = GUICtrlCreateTreeViewItem("Child " & $n & "-" & $i,$Parent)
            contextMenu($Child)
        Next
    Next
    GUISetOnEvent($GUI_EVENT_CLOSE, 'Close')
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
    GUISetState(@SW_SHOW)
EndFunc
Func contextMenu($MenuParent)
$contextmenu = GUICtrlCreateContextMenu($MenuParent)
$textitem = GUICtrlCreateMenuItem("Delete", $contextmenu)
GUICtrlSetOnEvent ( $textitem, "Delete" )
EndFunc
Func Delete()
;If $fOnItem Then ;optionally block menu return from right click over non-item area
  ;$fOnItem = False
  If IsPtr($hItemSel) Then
   _GUICtrlTreeView_SetFocused($Tree, $hItemSel, True)
   _GUICtrlTreeView_Delete($Tree, $hItemSel)
   $hItemSel = 0
  EndIf
  ;_GUICtrlTreeView_Delete($Tree, _GUICtrlTreeView_GetSelection ($Tree))
;EndIf
EndFunc
Func Close()
    Exit
EndFunc
 
Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
#forceref $hWnd, $iMsg, $wParam
$tNMHDR = DllStructCreate($tagNMHDR, $lParam)
$hWndFrom = DllStructGetData($tNMHDR, "hWndFrom")
$iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
$iCode = DllStructGetData($tNMHDR, "Code")
Switch $iIDFrom
  Case $Tree
   Switch $iCode
    Case $NM_RCLICK
     Local $tPoint = _WinAPI_GetMousePos(True, $hWndFrom), $tHitTest
     $tHitTest = _GUICtrlTreeView_HitTestEx($hWndFrom, DllStructGetData($tPoint, 1), DllStructGetData($tPoint, 2))
     ;If BitAND(DllStructGetData($tHitTest, "Flags"), $TVHT_ONITEM) Then ;optionally block menu return from right click over non-item area
      ;$fOnItem = True
      $hItemSel = DllStructGetData($tHitTest, 'Item')
      ;Local $hItem = DllStructGetData($tHitTest, 'Item')
;~     If IsPtr($hItem) Then
;~      _GUICtrlTreeView_SelectItem($hWndFrom, $hItem)
;~      _GUICtrlTreeView_SetFocused($hWndFrom, $hItem, True)
;~     EndIf
     ;EndIf
   EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY
Edited by rover

I see fascists...

Share this post


Link to post
Share on other sites

Thanks for the info. I see your point about the tree view selection. I had not considered the explorer behavior. Seems obvious now.

Thanks again.

cj

Share this post


Link to post
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
Sign in to follow this  
Followers 0