CMJ Posted August 27, 2012 Share Posted August 27, 2012 (edited) I have a treeview. Each Parent item in the tree has an GuiCtrlOnEvent set. If an item in the tree is selected and I delete all items in the treeview the OnEvent for the each parent item below the selected item will fire. See the code below for an example of this. To prove it. Run the script and select Delete All. Items are Deleted and all is well. Then select one item in the tree. Now press Delete all. You will see a message box display for each parent item in the tree below your selection (Assuming you did not select an item under the last parent item). I can think of two ways to resolve this. Either I need to stop the Event from firing in the first place which I would prefer or I need to be able to unselect the item. Neither of these statements work: _GUICtrlTreeView_SetSelected(<tree>, <hWnd of slected item>, False) GUICtrlSetState(<hWnd of slected item>, $GUI_NOFOCUS) Thanks in advance for any help. cj EDIT: With the help of rover I have updated this script so that it should work...There are some messages and console logs you will want to remove if you are going to re-use this. expandcollapse popup#include <GUIConstantsEx.au3> #include <GuiTreeView.au3> #include <GuiImageList.au3> #include <WindowsConstants.au3> $Debug_TV = False ; Check ClassName being passed to functions, set to True and use a handle to another control to see it work Opt("GUIOnEventMode", 1) Global $hTreeView, $cTreeview Global $message = "You clicked a parent" _Main() Func _Main() Local $hItem Local $iStyle = BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS) GUICreate("TreeView Delete All", 400, 300) $cTreeview = GUICtrlCreateTreeView(2, 2, 396, 225, $iStyle, $WS_EX_CLIENTEDGE) $hTreeView = GUICtrlGetHandle(-1) GUISetState() GUICtrlCreateButton("Delete All", 2, 250, 75, 25) GUICtrlSetOnEvent(-1, "DeleteAll") GUICtrlCreateButton("Rebuild Tree", 79, 250, 75, 25) GUICtrlSetOnEvent(-1, "BuildTree") BuildTree() ; Loop until user exits GUISetOnEvent($GUI_EVENT_CLOSE, 'Close') While 1 Sleep(10) WEnd EndFunc ;==>_Main Func DeleteAll() $message = "You did not click a parent." & @CRLF & "Why is this showing?" Local $hParentItem = _GUICtrlTreeView_GetFirstItem($hTreeView), $hChildItem, $cItem, $iCnt, $Selected = 0 Do $cItem = _GUICtrlTreeView_GetItemParam($hTreeView, $hParentItem) ConsoleWrite('! Item Param Data (0 for items added with UDF) = ' & $cItem & @crlf) $hParentItem = _GUICtrlTreeView_GetNextSibling($hTreeView, $hParentItem) GUICtrlSetOnEvent($cItem, "") ;unregister event Until $hParentItem = 0 GUICtrlSendMsg($cTreeView, $TVM_DELETEITEM, $TVI_ROOT, 0) EndFunc ;==>DeleteAll Func What() Local $test = GUICtrlGetHandle(@GUI_CtrlId) MsgBox(0, "Warning", $message & @CRLF & @GUI_CtrlId &@CRLF& $test) EndFunc ;==>What Func BuildTree() For $x = 1 To 5 $hItem = GUICtrlCreateTreeViewItem("Parent - " & $x, $cTreeView) GUICtrlSetOnEvent(-1, "What") ConsoleWrite('+ Item added ControlID = ' & $hItem & @crlf ) For $y = 1 To 5 GUICtrlCreateTreeViewItem("Child - " & $y, $hItem) Next Next EndFunc ;==>BuildTree Func Close() GUIDelete($hTreeView) Exit EndFunc ;==>Close Edited August 29, 2012 by CMJ Link to comment Share on other sites More sharing options...
Zedna Posted August 27, 2012 Share Posted August 27, 2012 I tried dirty workaound but it doesn't work :-( expandcollapse popup#include <GUIConstantsEx.au3> #include <GuiTreeView.au3> #include <GuiImageList.au3> #include <WindowsConstants.au3> $Debug_TV = False ; Check ClassName being passed to functions, set to True and use a handle to another control to see it work Opt("GUIOnEventMode", 1) Global $hTreeView Global $message = "You clicked a parent" Global $b_deleting = False _Main() Func _Main() Local $hItem Local $iStyle = BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS) GUICreate("TreeView Delete All", 400, 300) $hTreeView = GUICtrlCreateTreeView(2, 2, 396, 225, $iStyle, $WS_EX_CLIENTEDGE) GUISetState() GUICtrlCreateButton("Delete All", 2, 250, 75, 25) GUICtrlSetOnEvent(-1, "DeleteAll") GUICtrlCreateButton("Rebuild Tree", 79, 250, 75, 25) GUICtrlSetOnEvent(-1, "BuildTree") BuildTree() ; Loop until user exits GUISetOnEvent($GUI_EVENT_CLOSE, 'Close') While 1 Sleep(10) WEnd EndFunc ;==>_Main Func DeleteAll() $b_deleting = True $message = "You did not click a parent." & @CRLF & "Why is this showing?" GUICtrlSendMsg($hTreeView, $TVM_DELETEITEM, $TVI_ROOT, 0) ;~ _GUICtrlTreeView_DeleteAll($hTreeView) $b_deleting = False EndFunc ;==>DeleteAll Func What() If $b_deleting = True Then Return MsgBox(0, "Warning", $message) EndFunc ;==>What Func BuildTree() $message = "You clicked a parent" For $x = 1 To 5 $hItem = GUICtrlCreateTreeViewItem("Parent - " & $x, $hTreeView) GUICtrlSetOnEvent(-1, "What") For $y = 1 To 5 GUICtrlCreateTreeViewItem("Child - " & $y, $hItem) Next Next EndFunc ;==>BuildTree Func Close() GUIDelete($hTreeView) Exit EndFunc ;==>Close Resources UDF Â ResourcesEx UDF Â AutoIt Forum Search Link to comment Share on other sites More sharing options...
CMJ Posted August 28, 2012 Author Share Posted August 28, 2012 I had tried that too. Crazy that it does not work. The bad thing is that I figured this out because the What() function in this script represents a Delete item from my database function in my live application so there are times when data just starts disappearing... Thanks for trying to help. Link to comment Share on other sites More sharing options...
rover Posted August 28, 2012 Share Posted August 28, 2012 (edited) You also have a GUICtrlCreateTreeViewItem memory leak as well as the event message queue misfiring.The misfire event is common with message loop mode as well.The solution is to call GuiGetMsg() in a Do Until GuiGetMsg() = 0 loop to clear out any events.or switch between event/loop/event mode.There are the message queue APIs that might have a clear queue function.An event function is disabled with GUICtrlSetOnEvent($cItem, "")but in a modified version of your script below, the misfire is still occurring when the event is unregistered, and the parent item deleted in the same loop the child items are deleted in.Only by running a second loop to destroy the parent items did the event misfiring stop.Memory leak:If you look at the consolewrite in BuildTree() the control IDs returned should be the samefor each build/delete cycle, instead there is an incremental increase of new control IDs * added because the previous ones are not deleted.You will also see a growing memory leak in taskmgr or process explorer.* With the original TVM_DELETEITEM messageThis is the same issue as a listview with GUICtrlCreateListViewItem and _GUICtrlListView_DeleteAllItemsAutoIt uses the item param data to store a control ID so the GUICtrlCreateTreeViewItem items have to be deleted with GUICtrlDelete().These control IDs are never deleted, so they increase with each delete/build cycle.For some reason the treeview delete functions were not coded the same as the listview delete functions (delete items differently by handle or control ID).To get around using a more complex delete all items function instead of TVM_DELETEITEM, you coulduse the _GUICtrlTreeView_Add*** and _GUICtrlTreeView_InsertItem functionswith a WM_NOTIFY message handler for the parent clicks.Edit: rewording on-the-fly error, missing includesexpandcollapse popup#include <GUIConstantsEx.au3> #include <GuiTreeView.au3> #include <GuiImageList.au3> #include <WindowsConstants.au3> $Debug_TV = False ; Check ClassName being passed to functions, set to True and use a handle to another control to see it work Opt("GUIOnEventMode", 1) Global $hTreeView, $cTreeview Global $message = "You clicked a parent" _Main() Func _Main() Local $hItem Local $iStyle = BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS) GUICreate("TreeView Delete All", 400, 300) $cTreeview = GUICtrlCreateTreeView(2, 2, 396, 225, $iStyle, $WS_EX_CLIENTEDGE) $hTreeView = GUICtrlGetHandle(-1) GUISetState() GUICtrlCreateButton("Delete All", 2, 250, 75, 25) GUICtrlSetOnEvent(-1, "DeleteAll") GUICtrlCreateButton("Rebuild Tree", 79, 250, 75, 25) GUICtrlSetOnEvent(-1, "BuildTree") BuildTree() ; Loop until user exits GUISetOnEvent($GUI_EVENT_CLOSE, 'Close') While 1 Sleep(10) WEnd EndFunc ;==>_Main Func DeleteAll() $message = "You did not click a parent." & @CRLF & "Why is this showing?" ;GUICtrlSendMsg($cTreeView, $TVM_DELETEITEM, $TVI_ROOT, 0) Local $hParentItem = _GUICtrlTreeView_GetFirstItem($hTreeView), $cItem = 0, $hChildItem, $iCnt Do $hChildItem = _GUICtrlTreeView_GetFirstChild($hTreeView, $hParentItem) $iCnt = _GUICtrlTreeView_GetChildCount($hTreeView, $hParentItem) For $i = 1 To $iCnt $cItem = _GUICtrlTreeView_GetItemParam($hTreeView, $hChildItem) $hChildItem = _GUICtrlTreeView_GetNextChild($hTreeView, $hChildItem) GUICtrlDelete($cItem) ;delete child Next $cItem = _GUICtrlTreeView_GetItemParam($hTreeView, $hParentItem) ConsoleWrite('! Item Param Data (0 for items added with UDF) = ' & $cItem & @crlf) $hParentItem = _GUICtrlTreeView_GetNextSibling($hTreeView, $hParentItem) GUICtrlSetOnEvent($cItem, "") ;unregister event ;GUICtrlDelete($cItem) ;delete parent Until $hParentItem = 0 $hParentItem = _GUICtrlTreeView_GetFirstItem($hTreeView) Do $cItem = _GUICtrlTreeView_GetItemParam($hTreeView, $hParentItem) $hParentItem = _GUICtrlTreeView_GetNextSibling($hTreeView, $hParentItem) GUICtrlDelete($cItem) ;delete parent Until $hParentItem = 0 $message = "You clicked a parent" EndFunc ;==>DeleteAll Func What() MsgBox(0, "Warning", $message) EndFunc ;==>What Func BuildTree() For $x = 1 To 5 $hItem = GUICtrlCreateTreeViewItem("Parent - " & $x, $cTreeView) GUICtrlSetOnEvent(-1, "What") ConsoleWrite('+ Item added ControlID = ' & $hItem & @crlf ) For $y = 1 To 5 GUICtrlCreateTreeViewItem("Child - " & $y, $hItem) Next Next EndFunc ;==>BuildTree Func Close() GUIDelete($hTreeView) Exit EndFunc ;==>Close Edited August 28, 2012 by rover I see fascists... Link to comment Share on other sites More sharing options...
CMJ Posted August 28, 2012 Author Share Posted August 28, 2012 (edited) Thanks rover.Great info. Only one problem. Your code still triggers the What function...but only one time, so that is definitely progress! After more investigation it appears that this happens because if a child item in the tree is selected and you delete it, the parent item gets the selection and the event for that parent item is run. You can see a modified version of your code below that seems to prove this.so I guess that means that the best answer is to find a way to deselect an item. This seems simple at first, but none of these functions work:_GUICtrlTreeView_SetState($hTreeView,$hChildItem,$TVIS_SELECTED,False)_GUICtrlTreeView_SetSelected($hTreeView,$hChildItem, False)GUICtrlSetState($$hChildItem, $GUI_NOFOCUS)Any ideas as to how to either stop the selection from falling back to the parent or to simply de-select the item?Thanks again for all the help.ChrisP.S. I had been aware of the memory leak and just could not find an answer for that. Thanks for that too! And I have tried using the _GUICtrlTreeView_Add*** and _GUICtrlTreeView_InsertItem functions but cannot in this case because of some other limitations I have found with those functions. I try to stick with native autoit functions over the treeview UDF in all cases and most of the time it proves to be a good philosophy. expandcollapse popup#include #include #include #include $Debug_TV = False ; Check ClassName being passed to functions, set to True and use a handle to another control to see it work Opt("GUIOnEventMode", 1) Global $hTreeView, $cTreeview Global $message = "You clicked a parent" _Main() Func _Main() Local $hItem Local $iStyle = BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS) GUICreate("TreeView Delete All", 400, 300) $cTreeview = GUICtrlCreateTreeView(2, 2, 396, 225, $iStyle, $WS_EX_CLIENTEDGE) $hTreeView = GUICtrlGetHandle(-1) GUISetState() GUICtrlCreateButton("Delete All", 2, 250, 75, 25) GUICtrlSetOnEvent(-1, "DeleteAll") GUICtrlCreateButton("Rebuild Tree", 79, 250, 75, 25) GUICtrlSetOnEvent(-1, "BuildTree") BuildTree() ; Loop until user exits GUISetOnEvent($GUI_EVENT_CLOSE, 'Close') While 1 Sleep(10) WEnd EndFunc ;==>_Main Func DeleteAll() $message = "You did not click a parent." & @CRLF & "Why is this showing?" ;GUICtrlSendMsg($cTreeView, $TVM_DELETEITEM, $TVI_ROOT, 0) Local $hParentItem = _GUICtrlTreeView_GetFirstItem($hTreeView), $hChildItem, $cItem, $iCnt, $Selected = 0 Do $hChildItem = _GUICtrlTreeView_GetFirstChild($hTreeView, $hParentItem) $iCnt = _GUICtrlTreeView_GetChildCount($hTreeView, $hParentItem) For $i = 1 To $iCnt $cItem = _GUICtrlTreeView_GetItemParam($hTreeView, $hChildItem) $hChildItem = _GUICtrlTreeView_GetNextChild($hTreeView, $hChildItem) If _GUICtrlTreeView_GetSelected($hTreeView, $hChildItem) Then $Selected = 1 EndIf GUICtrlDelete($cItem) ;delete child Next $cItem = _GUICtrlTreeView_GetItemParam($hTreeView, $hParentItem) ConsoleWrite('! Item Param Data (0 for items added with UDF) = ' & $cItem & @crlf) $hParentItem = _GUICtrlTreeView_GetNextSibling($hTreeView, $hParentItem) GUICtrlSetOnEvent($cItem, "") ;unregister event MsgBox(0,0,$cItem) ;GUICtrlDelete($cItem) ;delete parent Until $hParentItem = 0 or $Selected = 1 If $Selected = 1 Then Return $hParentItem = _GUICtrlTreeView_GetFirstItem($hTreeView) Do $cItem = _GUICtrlTreeView_GetItemParam($hTreeView, $hParentItem) $hParentItem = _GUICtrlTreeView_GetNextSibling($hTreeView, $hParentItem) ConsoleWrite('--Delete Parent Item = ' & $cItem & @crlf) GUICtrlDelete($cItem) ;delete parent Until $hParentItem = 0 ;$message = "You clicked a parent" EndFunc ;==>DeleteAll Func What() MsgBox(0, "Warning", $message & @CRLF & @GUI_CtrlId) EndFunc ;==>What Func BuildTree() For $x = 1 To 5 $hItem = GUICtrlCreateTreeViewItem("Parent - " & $x, $cTreeView) GUICtrlSetOnEvent(-1, "What") ConsoleWrite('+ Item added ControlID = ' & $hItem & @crlf ) For $y = 1 To 5 GUICtrlCreateTreeViewItem("Child - " & $y, $hItem) Next Next EndFunc ;==>BuildTree Func Close() GUIDelete($hTreeView) Exit EndFunc ;==>Close Edited August 28, 2012 by CMJ Link to comment Share on other sites More sharing options...
CMJ Posted August 28, 2012 Author Share Posted August 28, 2012 Here is an interesting bit of information. If you add a ContinueLoop step after $Selected = 1 at Line 50 in my previous code you do not get the problem. I am not sure why that would solve it but it does seem to be a work around for now...Still testing. I would still love to know how to de-select the item but this may at least let me move on. Link to comment Share on other sites More sharing options...
CMJ Posted August 29, 2012 Author Share Posted August 29, 2012 I did end up finding a solution here and it is a little simpler than the original code. Just use this function in place of the DeleteAll() function in either Rover's or my last post. Thanks again for all the help. Func DeleteAll() Local $hParentItem = _GUICtrlTreeView_GetFirstItem($hTreeView), $hChildItem, $cItem, $iCnt, $Selected = 0 Do $cItem = _GUICtrlTreeView_GetItemParam($hTreeView, $hParentItem) $hParentItem = _GUICtrlTreeView_GetNextSibling($hTreeView, $hParentItem) GUICtrlSetOnEvent($cItem, "") ;unregister event Until $hParentItem = 0 GUICtrlSendMsg($cTreeView, $TVM_DELETEITEM, $TVI_ROOT, 0) EndFunc ;==>DeleteAll Link to comment Share on other sites More sharing options...
rover Posted August 30, 2012 Share Posted August 30, 2012 (edited) I did end up finding a solution here and it is a little simpler than the original code. Just use this function in place of the DeleteAll() function in either Rover's or my last post. Thanks again for all the help. Func DeleteAll() Local $hParentItem = _GUICtrlTreeView_GetFirstItem($hTreeView), $hChildItem, $cItem, $iCnt, $Selected = 0 Do $cItem = _GUICtrlTreeView_GetItemParam($hTreeView, $hParentItem) $hParentItem = _GUICtrlTreeView_GetNextSibling($hTreeView, $hParentItem) GUICtrlSetOnEvent($cItem, "") ;unregister event Until $hParentItem = 0 GUICtrlSendMsg($cTreeView, $TVM_DELETEITEM, $TVI_ROOT, 0) EndFunc ;==>DeleteAll You still have the memory leak from undeleted child item control ids if you use TVM_DELETEITEM. Might I suggest purging the message queue after all delete item events. Your code still triggers the What function...but only one timeIn my DeleteAll function there were no misfires (only tested on my XP box - 7x64 box being rebuilt) Setting events for items of a Treeview as if they are controls obviously has issues with false events when items are unregistered/deleted. Treeview/Listview Item notifications should be processed in a WM_NOTIFY message handler... Consider the added complication of having to code delete functions to loop through and unregister (item set to run an event mode function) and delete every root and child item. and then clear the message queue, as opposed to using the existing udf single line delete all or delete all children functions with WM_NOTIFY for event handling. And I have tried using the _GUICtrlTreeView_Add*** and _GUICtrlTreeView_InsertItem functions but cannot in this case because of some other limitations I have found with those functions. What problems are you having using the udf functions? I forgot that _GUICtrlTreeView_GetItemParam returns False instead of 0 when there is no item data (the combobox and listview param functions return 0 for no data). Try this message queue purge example, no memory leaks and no event misfires. Edit: clarification. expandcollapse popup#include <GUIConstantsEx.au3> #include <GuiTreeView.au3> #include <GuiImageList.au3> #include <WindowsConstants.au3> $Debug_TV = False ; Check ClassName being passed to functions, set to True and use a handle to another control to see it work Opt("GUIOnEventMode", 1) Global $hTreeView, $cTreeview Global $message = "You clicked a parent" _Main() Func _Main() Local $hItem Local $iStyle = BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS) GUICreate("TreeView Delete All", 400, 300) $cTreeview = GUICtrlCreateTreeView(2, 2, 396, 225, $iStyle, $WS_EX_CLIENTEDGE) $hTreeView = GUICtrlGetHandle(-1) GUISetState() GUICtrlCreateButton("Delete All", 2, 250, 75, 25) GUICtrlSetOnEvent(-1, "DeleteAll") GUICtrlCreateButton("Rebuild Tree", 79, 250, 75, 25) GUICtrlSetOnEvent(-1, "BuildTree") BuildTree() ; Loop until user exits GUISetOnEvent($GUI_EVENT_CLOSE, 'Close') While 1 Sleep(10) WEnd EndFunc ;==>_Main Func DeleteAll() $message = "You did not click a parent." & @CRLF & "Why is this showing?" Local $hParentItem = _GUICtrlTreeView_GetFirstItem($hTreeView), $cItem = 0, $hChildItem Do $hChildItem = _GUICtrlTreeView_GetFirstChild($hTreeView, $hParentItem) Do $cItem = _GUICtrlTreeView_GetItemParam($hTreeView, $hChildItem) $hChildItem = _GUICtrlTreeView_GetNextChild($hTreeView, $hChildItem) ;GUICtrlSetOnEvent($cItem, "") ;unregister event GUICtrlDelete($cItem) ;delete child Until $hChildItem = 0 $cItem = _GUICtrlTreeView_GetItemParam($hTreeView, $hParentItem) ConsoleWrite('! Item Param Data (False for items added with UDF) = ' & $cItem & @crlf) $hParentItem = _GUICtrlTreeView_GetNextSibling($hTreeView, $hParentItem) GUICtrlSetOnEvent($cItem, "") ;unregister event GUICtrlDelete($cItem) ;delete parent Until $hParentItem = 0 ;purge message queue Opt("GUIOnEventMode", 0) ;switch to PeekMessage API (loop mode) Do Until GUIGetMsg() = 0 ;clear message queue Opt("GUIOnEventMode", 1) ;switch back to GetMessage API (event mode) $message = "You clicked a parent" EndFunc ;==>DeleteAll Func What() MsgBox(0, "Warning", $message) EndFunc ;==>What Func BuildTree() For $x = 1 To 5 $hItem = GUICtrlCreateTreeViewItem("Parent - " & $x, $cTreeView) GUICtrlSetOnEvent(-1, "What") ConsoleWrite('+ Item added ControlID = ' & $hItem & @crlf ) For $y = 1 To 5 GUICtrlCreateTreeViewItem("Child - " & $y, $hItem) Next _GUICtrlTreeView_SetChildren($cTreeView, $hItem) ;using control id for native items Next EndFunc ;==>BuildTree Func Close() GUIDelete($hTreeView) Exit EndFunc ;==>Close Edited August 30, 2012 by rover I see fascists... Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now