BrewManNH Posted November 1, 2010 Posted November 1, 2010 I am in the process of writing a media player, and I have run into something that I'm not sure is a bug or not. In the script below, if you run it and delete an item from the listview and select any remaining item in the listing, you should be able to get to the next item in the list by pressing the Next button. Unfortunately that isn't what happens. I have included 2 different methods used to delete an item in a ListView tied to different buttons on the GUI. The first one marked LVM_DELETEITEM uses this command _SendMessage($hListView, $LVM_DELETEITEM, _GUICtrlListView_GetSelectedIndices($hListView, 0)) The second button, marked GUICtrlDelete uses this command Local $ctrlID = _GUICtrlListView_GetItemParam($ListView, _GUICtrlListView_GetSelectedIndices($ListView, 0)) If $ctrlID Then GUICtrlDelete($ctrlID) After selecting a row in the LV and clicking the first button, it will delete the item from the listview, and then runs the RebuildLV function that I created. After deleting an item with the first button, you can go from one item to the next item in the LV with the Next button without a problem. If you do the same thing with the GUICtrlDelete button, you can't do that. It will delete the item, the RebuildLV function gets run as before, but you can't use the Next button, the indexes are all screwed up. It won't work correctly unless you press the Rebuild button, so that the RebuildLV function gets run a second time. Some of you may recognize where these command lines came from in regards to deleting an item from a LV, and this is what led me to believe that there may be a problem with the GUICtrlDelete command. I couldn't for the life of me figure out why my media player wouldn't go to the Next and Previous songs in the song list after I deleted them. I was using check boxes to mark which items I wanted to delete, and running through a For...Next loop to delete them using _GUICtrlListView_DeleteItem. When I deleted one item from the LV I used the _GUICtrlListView_DeleteItemsSelected, and this worked perfectly, but not when deleting multiple items, one at a time. The ONLY time that _GUICtrlListView_DeleteItem worked was when I called the UDF using a Handle to the Listview, and not when using a ControlID even though the Helpfile says both can be used. The function is written to use 2 different procedures to delete an item from a listview depending upon whether you call it with a handle or a controlID and this causes problems. So, is there a bug in GUICtrlDelete, or is there something going on behind the scenes that I don't see? Please let me know what you think. Here's an example script to demonstrate the bug/feature. expandcollapse popup#include <GUIConstants.au3> #include <WindowsConstants.au3> #include <GUIConstantsEx.Au3> #include <GUIListView.Au3> #include <GUIMenu.Au3> Global $hOpenLVItem[30] Opt("GUIOnEventMode", 1) $hGUI = GUICreate("Test GUI", 400, 400, -1, -1) GUISetOnEvent($GUI_EVENT_CLOSE, "hGUIClose") Const $Next = GUICtrlCreateButton("Next", 10, 10) GUICtrlSetOnEvent(-1, "Next1") Const $Delete1 = GUICtrlCreateButton("LVM_DELETEITEM", 50, 10) GUICtrlSetOnEvent(-1, "Delete1") Const $Delete2 = GUICtrlCreateButton("GUICtrlDelete", 170, 10) GUICtrlSetOnEvent(-1, "Delete2") Const $Rebuild = GUICtrlCreateButton("Rebuild", 270, 10) GUICtrlSetOnEvent($Rebuild, "RebuildLV") Const $ListView = GUICtrlCreateListView("Column 1| Column 2| Column 3", 20, 60, 360, 300) Const $hListView = GUICtrlGetHandle($ListView) For $I = 1 To 12 $hOpenLVItem[$I] = GUICtrlCreateListViewItem("Section 1-" & $I & "|Section 2-" & $I & "|Section 3-" & $I, $ListView) Next $hOpenLVItem[0] = 12 RebuildLV() GUISetState() GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY") _GUICtrlListView_RegisterSortCallBack($ListView) While 1 Sleep(200) WEnd Func _WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam) #forceref $hWnd, $iMsg, $iwParam Local $I Global $hWndFrom, $iCode, $tNMHDR, $hWndListView, $lParam $hWndListView = $hListView If Not IsHWnd($ListView) Then $hWndListView = GUICtrlGetHandle($ListView) $tNMHDR = DllStructCreate($tagNMHDR, $ilParam) $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom")) $iCode = DllStructGetData($tNMHDR, "Code") Switch $hWndFrom Case $hWndListView Switch $iCode Case $LVN_COLUMNCLICK ; A column was clicked Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam) _GUICtrlListView_SortItems($hWndFrom, DllStructGetData($tInfo, "SubItem")) Case $LVN_ITEMACTIVATE Local $nmia = DllStructCreate($tagNMITEMACTIVATE, $lParam) $I = DllStructGetData($nmia, "Index") Play() EndSwitch EndSwitch Return $__LISTVIEWCONSTANT_GUI_RUNDEFMSG EndFunc ;==>_WM_NOTIFY Func Delete1() ConsoleWrite("Delete 1") _SendMessage($hListView, $LVM_DELETEITEM, _GUICtrlListView_GetSelectedIndices($hListView, 0)) RebuildLV() EndFunc ;==>Delete1 Func Delete2() ConsoleWrite("Delete 2") Local $ctrlID = _GUICtrlListView_GetItemParam($ListView, _GUICtrlListView_GetSelectedIndices($ListView, 0)) If $ctrlID Then GUICtrlDelete($ctrlID) RebuildLV() EndFunc ;==>Delete2 Func hGUIClose() Exit EndFunc ;==>hGUIClose Func Next1() $Current = GUICtrlRead($ListView) If $hOpenLVItem[0] <> "" Then $Skip = $Current - ($hOpenLVItem[1] - 1) EndIf If $Skip = _GUICtrlListView_GetItemCount($ListView) Then $Skip = 0 EndIf ConsoleWrite("$Skip = " & $Skip & @LF & @LF) _GUICtrlListView_SetItemSelected($ListView, $Skip) _GUICtrlListView_EnsureVisible($ListView, $Skip) EndFunc ;==>Next1 Func RebuildLV() ConsoleWrite("RebuildLV") Local $Read1, $LVItems[100] For $I = 1 To _GUICtrlListView_GetItemCount($ListView) _GUICtrlListView_SetItemState($ListView, $I - 1, $LVIS_selected, $LVIS_selected) $LVItems[$I] = GUICtrlRead(GUICtrlRead($ListView)) Next $LVItems[0] = $I - 1 Global $hOpenLVItem[$LVItems[0] + 1] _GUICtrlListView_DeleteAllItems($hListView) For $I = 1 To ($LVItems[0]) $hOpenLVItem[$I] = GUICtrlCreateListViewItem($LVItems[$I], $ListView) Next $hOpenLVItem[0] = $I - 1 EndFunc ;==>RebuildLV If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag GudeHow to ask questions the smart way! I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from. Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays. - ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script. - Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label. - _FileGetProperty - Retrieve the properties of a file - SciTE Toolbar - A toolbar demo for use with the SciTE editor - GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI. - Latin Square password generator
Moderators Melba23 Posted November 1, 2010 Moderators Posted November 1, 2010 BrewManNH,You are mixing native and UDF commands throughout that script - which usually ends in tears, so I am not surprised you are running into problems. My preferred way to do something like this is to keep the data in an array and act on the array for deletion, addition, moving etc of items. Rewriting the ListView from the array is then easy. This post has some code - taken incidentally from my own media player script - which shows how I go about it. M23 Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area
BrewManNH Posted November 1, 2010 Author Posted November 1, 2010 I've tried building a listview with an array and acting upon the array to delete, add etc. Unfortunately once you sort the listview you lose track of where the indexes end up. So I had to resort to deleting everything in the listview, and then rebuiding it. That was the only way that I could get the Next and Previous buttons to work correctly. Also unfortunately, using the GUICtrlDelete function doesn't work doing it that way. It causes the Next and Previous buttons to jump all over the listview once it's been destroyed and rebuilt, unless I delete everything and rebuild it twice. Have you run the example I posted? Is there a flaw in what I am doing that would say that GUICtrlDelete has an issue with LV controls or not? Because that one command is the only thing that is messing up the Listview next and previous functions in my media player. If the _GUICtrlListview_DeleteItem worked with control ids the same way it worked with handle's then I wouldn't have found the problem in the first place. Also, I'm aware that mixing the native commands and the UDF commands can cause issues, but I'm also aware that there are some things that just can't be done as easily with the built-in commands that have been done with a UDF. I have found workarounds or dropped some ideas to avoid using a UDF when a built-in would work just as well. But, if you look at what I'm doing in rebuilding the LV, then it should be obvious that all I'm doing is reading every entry in the LV and storing it in an array, deleting everything in the LV, and then rebuilding the LV with the array's elements. This SHOULD rebuild all of the indexes and control IDs, and allow me to use the Next and Previous buttons on my media player without issue. If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag GudeHow to ask questions the smart way! I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from. Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays. - ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script. - Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label. - _FileGetProperty - Retrieve the properties of a file - SciTE Toolbar - A toolbar demo for use with the SciTE editor - GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI. - Latin Square password generator
Moderators Melba23 Posted November 7, 2010 Moderators Posted November 7, 2010 BrewManNH,Does this help you see how you might do what you want? As I suggested, this script uses an array to hold the data and rewrites the ListView each time, so you get the ControlIDs in the correct order after sorting or deletion and the "Next" button works as expected:expandcollapse popup#include <GUIConstantsEx.Au3> #include <WindowsConstants.au3> #include <GUIListView.Au3> #include <Array.au3> Opt("GUIOnEventMode", 1) ; ListView content Global $aLV_Content[13][3] = [ _ ["", "", ""], _ ["Item 1", "SubItem Q", "SubItem J"], _ ["Item 2", "SubItem W", "SubItem H"], _ ["Item 3", "SubItem E", "SubItem G"], _ ["Item 4", "SubItem R", "SubItem K"], _ ["Item 5", "SubItem T", "SubItem L"], _ ["Item 6", "SubItem Y", "SubItem Z"], _ ["Item 7", "SubItem U", "SubItem X"], _ ["Item 8", "SubItem I", "SubItem C"], _ ["Item 9", "SubItem O", "SubItem V"], _ ["Item 10", "SubItem P", "SubItem B"], _ ["Item 11", "SubItem A", "SubItem N"], _ ["Item 12", "SubItem S", "SubItem M"]] ; ListView item handles Global $aLV_Items[13] = [12] ; Track sort order for the columns Global $aColOrder[3] = [1, 1, 1] ; Create GUI $hGUI = GUICreate("Test GUI", 400, 400, -1, -1) GUISetOnEvent($GUI_EVENT_CLOSE, "_GUIClose") ; Crete buttons $Next = GUICtrlCreateButton("Next", 10, 10) GUICtrlSetOnEvent(-1, "_Next") $Delete = GUICtrlCreateButton("Delete", 170, 10) GUICtrlSetOnEvent(-1, "_Delete") ; Create ListView $hListView = GUICtrlCreateListView("Column 1| Column 2| Column 3", 20, 60, 360, 300) $LV_Handle = GUICtrlGetHandle($hListView) ; And fill it _FillListView() GUISetState() GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY") ; If you do not need the arrow on the column header remove this _GUICtrlListView_RegisterSortCallBack($hListView) While 1 Sleep(200) WEnd Func _WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam) #forceref $hWnd, $iMsg, $iwParam Global $hWndFrom, $iCode, $tNMHDR, $hWndListView, $lParam $hWndListView = $LV_Handle If Not IsHWnd($hListView) Then $hWndListView = GUICtrlGetHandle($hListView) $tNMHDR = DllStructCreate($tagNMHDR, $ilParam) $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom")) $iCode = DllStructGetData($tNMHDR, "Code") Switch $hWndFrom Case $hWndListView Switch $iCode Case $LVN_COLUMNCLICK ; A column was clicked Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam) $iCol = DllStructGetData($tInfo, "SubItem") ; If you do not need the arrow on the column header remove this _GUICtrlListView_SortItems($hWndFrom, $iCol) ; Reverse sort order for the column $aColOrder[$iCol] = Not($aColOrder[$iCol]) ; Sort the array on the column _ArraySort($aLV_Content, $aColOrder[$iCol], 1, 0, $iCol) ; Refill the ListView _FillListView() Case $LVN_ITEMACTIVATE Local $nmia = DllStructCreate($tagNMITEMACTIVATE, $lParam) $I = DllStructGetData($nmia, "Index") ;Play() EndSwitch EndSwitch Return $__LISTVIEWCONSTANT_GUI_RUNDEFMSG EndFunc ;==>_WM_NOTIFY Func _GUIClose() Exit EndFunc ;==>hGUIClose Func _Next() ; Get current selected item Local $iCurr = GUICtrlRead($hListView) ; Convert to the index and reloop if required Local $iNext = _ArraySearch($aLV_Items, $iCurr, 1) If $iNext = $aLV_Items[0] Then $iNext = 0 ; Show we have the correct next item ConsoleWrite(_GUICtrlListView_GetItemText($hListView, $iNext) & @CRLF) ; Select it _GUICtrlListView_SetItemSelected($hListView, $iNext) _GUICtrlListView_EnsureVisible($hListView, $iNext) EndFunc ;==>Next1 Func _FillListView() _GUICtrlListView_DeleteAllItems($LV_Handle) For $i = 1 To $aLV_Items[0] Local $sItem = $aLV_Content[$i][0] & "|" & $aLV_Content[$i][1] & "|" & $aLV_Content[$i][2] $aLV_Items[$i] = GUICtrlCreateListViewItem($sItem, $hListView) Next EndFunc Func _Delete() ; Get current selection Local $iCurr = GUICtrlRead($hListView) ; Convert to index $iIndex = _ArraySearch($aLV_Items, $iCurr) ; Delete that index from data and ControlID arrays _ArrayDelete($aLV_Items, $iIndex) $aLV_Items[0] -= 1 _ArrayDelete($aLV_Content, $iIndex) ; Refill the ListView _FillListView() EndFuncM23 Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area
BrewManNH Posted November 7, 2010 Author Posted November 7, 2010 That works as it should. But, it still doesn't answer the question as to whether or not the GUICtrlDelete function is working incorrectly, mainly because you're not using it in your example. I will look at your code and see if it makes any difference in the media player I'm working on to see if it works better than what I'm doing now. It looks a lot cleaner than what I'm doing. If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag GudeHow to ask questions the smart way! I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from. Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays. - ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script. - Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label. - _FileGetProperty - Retrieve the properties of a file - SciTE Toolbar - A toolbar demo for use with the SciTE editor - GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI. - Latin Square password generator
Moderators Melba23 Posted November 8, 2010 Moderators Posted November 8, 2010 BrewManNH,whether or not the GUICtrlDelete function is working incorrectlyYou have a real bug about this (pun fully intended!). The GUICtrlDelete function works perfectly. The problem in your earlier script was caused by the sorting you were doing on the columns. Each "row" of the ListView is given a handle and a ControlID which Windows and AutoIt use to track them. When you sorted the rows, you mixed them up and so neither UDF (using the handles) nor AutoIt (using ControlIDs) could get a sensible order. As the example I posted above shows, the ONLY way to get the order re-established is to destroy and then recreate the ListView items so that the rows are in the correct order for that sorted state - deleting rows just further confused the issue. ListViews are complex beasts and my experience is that deletion and recreation of the data which is actually help in an array is the best way to go about any form of manipulation other than very simple "list and select" tasks. As soon as you get into insertion, deletion or (as in this case) sorting, everything goes to pot unless you use the array as a basis. So please do not jump into any more threads claiming there is a problem with GUICtrlDelete - it works just fine. M23 Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area
BrewManNH Posted November 8, 2010 Author Posted November 8, 2010 I would agree that the method you showed is much easier than the way I was doing it. Basically what I was doing, after deleting the row or sorting the listview, was reading every line in the listview into an array, deleting all items in the Listview with _GUICtrlListView_DeleteAllItems($Listviewhandle), and then recreating the Listview from the array that I created. Your method is much faster than the way I was doing it, considering I had to read every row one at a time and storing it in the array. This worked fine for every operation that changed the order of the listview items except for deleting the rows with GUICtrlDelete, then and only then did I have problems. I've come to the conclusion that doing it another way is better and faster, and we'll just have to agree to disagree on anything else. BTW, I am in the process of incorporating your array method into the media player I'm writing, mostly to see how to do it correctly. Although the sorting method used isn't giving the same results, as of right now, that using _GUICtrlListView_SortItems does, I am working with it to see if I can tweak the results. Thank you for posting it as it has greatly sped up the process for a very large listview. If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag GudeHow to ask questions the smart way! I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from. Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays. - ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script. - Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label. - _FileGetProperty - Retrieve the properties of a file - SciTE Toolbar - A toolbar demo for use with the SciTE editor - GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI. - Latin Square password generator
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