ListBox: Delete Selected Rows as fast as I can

Hi all,

while I was watching news on the TV, I was also coding a “Delete All Selected Rows” method.

Here the final code:

[code] Dim ListCnt As Integer // Number of Rows in LB
Dim LoopIdx As Integer // Loop Indice
Dim DelCnt As Integer // Number of Deleted Rows
Dim SelCnt As Integer // Number of Selected Rows

// Get the number of Selected Rows
SelCnt = LB.SelCount

// Exit if no Row is Selected
If SelCnt < 1 Then Exit // This can be tested earlier

// Flag a change occured (Changes have to be saved)
If SelCnt > 0 Then
isChanged = True
End If

// Get the number of Rows in LB
ListCnt = LB.ListCount

// Loop thru the Rows from the last to the first and delete any selected row
For LoopIdx = ListCnt DownTo 0
// Delete the row if it is Selected
If LB.Selected(LoopIdx) Then
// Delete the selected Row
LB.RemoveRow LoopIdx

  // Inc the number of Selected Rows
  DelCnt = DelCnt + 1
End If

// Check if I Deleted all Selected Rows…
If DelCnt = SelCnt Then Exit // No more Rows to Delete ? Exit !

// To avoid 1, Infinite Loop
If UserCancelled Then Exit

Next[/code]

I set it in the window that use it instead in a Module (so no passed parameter, more saved time).

Questions:

a. Is it possible to speed up the shared code ?

b. Am I right to place the code in the only place (a Window) that use it ?
(Instead of in a Method with the ListBox reference - LB - as parameter)

c. Am I right to use an If line to exit if I found all Selected Rows ?
Related code:

If DelCnt = SelCnt Then Exit

That line makes the code to exits instead of letting it go down until LoopIdx = 0.

If the Selected Rows are not located at the beginning of the ListBox, I will avoid some loop iterations. This will make a gain of some seconds to far more, depending on the ListBox contents (hundred to thousand Rows) and the lowest Selected Row number.

Note: I used DownTo, like in a method to delete files on disk, to run the loop.

Looks good IMO

Probably little to be done to improve on the speed, except possibly in the case where there are more selected than not, in which case MAYBE it might be faster to deleteallrows and repopulate.

A while back when I first started with Xojo I came up with this snippet, and surprised even Norman that it worked so efficiently. It was easy to come up with because I was still reading the documentation for every method I used.

while myListBox.SelCount > 0 myListBox.RemoveRow(myListBox.ListIndex) wend

Personally, I think you went a little overboard.

Documentation…interesting, what’s that? :slight_smile:

Or maybe even this?

// DELETE ALL SELECTED LISTBOX ROWS for i as integer = listbox1.listcount -1 downto 0 if listbox1.selected(i) then listbox1.removeRow(i) end if next

Something everyone knows exists but always wonders “Whats in there?” :stuck_out_tongue:

Hi Norman,

I understand the joke, but I do not do that.

In fact, very long time ago, I get a Nakamishi K7 recorder and a day where py pure hazard, my hands falled into its manual, I started to read it and found a feature I do not even think it can be there.

Since then, I always read the docs, I translated some into French and even wrote some in French !

Of course, I checked everything that was in the manuals I translate or wrote.

[quote=139928:@Richard Summers]Or maybe even this?

// DELETE ALL SELECTED LISTBOX ROWS for i as integer = listbox1.listcount -1 downto 0 if listbox1.selected(i) then listbox1.removeRow(i) end if next[/quote]
I would take that one step further and keep track of the highest and lowest positions selected in the list and then only count down from there to the lowest selected row rather than stepping through the entire listbox. Of course, if there are only 100 or so rows, this won’t help much in speeding things up, but if there are 1,000’s of rows, the change can be noticeable.

What was wrong with @Tim Parnell 's solution? That seems like it would be the fastest.

@Kem Tekinay - How would it take into account extended and skipped-entry selections?

See it work it in Answers.

ListIndex returns one selected item (the lowest one according to docs), and the while loop goes until there’s nothing selected.

Well that’s as clear as mud and a great little discovery - even for us old dogs who thought that we knew better.

I’ve added it to my CodeVue snips.

Its definitely not obvious from the docs or the listbox code that listindex would walk through all the selected indexes like that.

The only gotcha I can think of is if selections are required. In that case, would that method end up deleting every row?

Thank you for your answers.

Norman:
It was so few obvious that I really inderstnad when I read your answer !

Ken:
Before calling the delete part, you check if ListIndex > -1

I finally got a chance to test and my fears were unfounded. Even if RequiresSelection is true, deleting the last selected row leaves no row selected.

Wouldn’t it be better to *not have to remove so many rows and utilize some sort of “paging” when adding rows? It seems like you’d benefit from speeds boosts in both adding, displaying and removing rows doing it that way.

Setting the listbox’s visibility to false while in the loop also speeds up the process. Flickers on Windows though. Use the “FreezeUpdate” method of the windows functionality suite to deal with the flicker.