Doubleclick multiple selection in Listbox

How to handle a Doubleclick on a listbox with multiple selection?
Since the MouseDown event fires before the DoubleClick event, I loose my multiple selection on DoubleClick event.

[quote=173238:@Massimo Valle]How to handle a Doubleclick on a listbox with multiple selection?
Since the MouseDown event fires before the DoubleClick event, I loose my multiple selection on DoubleClick event.[/quote]

There was the same question not long ago about WebListBox and contextual click.

Maybe you could keep track of the selection and restore it in double click, or even in mouseDown ?

[quote=173243:@Michel Bujardet]There was the same question not long ago about WebListBox and contextual click.

Maybe you could keep track of the selection and restore it in double click, or even in mouseDown ?[/quote]

To do so, I have to block mouseDown, and the doubleclick will not fire.
Or, if I store the selection and return false, the second mouseDown will get again a single selection. :frowning:

[quote=173252:@Massimo Valle]To do so, I have to block mouseDown, and the doubleclick will not fire.
Or, if I store the selection and return false, the second mouseDown will get again a single selection. :([/quote]

I just tested the same kind of solution as in Weblistbox :
1 - Store the selected state in an array. I have done that in MouseEnter, it could go in MouseMove as well
2 - In Double click, restore the selected state

Since the selection is changed immediately when mouseDown occurs, there seem to be no way to prevent the selection to change upon it, but as soon as the second click happens, DoubleClick fires and the selection is back to what it was.

It is not perfect, but it works.

Actually, the proper place to save the selected state is in MouseMove. Otherwise a single click selection cannot stick.

It’s little bit lame, but it works, thanks.
I added a refresh in the Doubleclick event to force redrawing the selection.

[quote=173368:@Massimo Valle]It’s little bit lame, but it works, thanks.
I added a refresh in the Doubleclick event to force redrawing the selection.[/quote]

I agree, it is not quite perfect.

To prevent selection in Keydown, I though about using an overlaid canvas that would present a mockup drawinto of the listbox in MouseEnter and make the actual Listbox invisible, so keyboard events be first managed by the canvas. Then from what happens in the canvas, you can display again the listbox itself, and for instance set the new selection if it is actually a single click, or simply remove the canvas in case of mousewheel, and so on. That would be a ton of extra work, but the result would be much less crude.

Unfortunately this trick is very weak and fails most of the time on Windows.
I guess the mouse tends to move more on Windows, so what happens is between the two mouse clicks, the MouseMove fires and reset the selection:

Multiple selection
MouseMove (store the selection)
FirstClick (MouseDown change the selection to 1 row)
MouseMove (store the selection - 1 row only) <------------ This is the problem
SecondClick (MouseDown change the selection to 1 row)
DoubleClick

Since updating in mousedown will override the last data then store the last two

[code]Private oldSelsA() As Integer
Private oldSelsB() As Integer

Private Sub pushSelection()

oldSelsB = oldSelsA

dim newSels() As integer
for i As integer = 0 to lb.ListCount - 1
if lb.Selected(i) then newSels.Append i
next
oldSelsA = newSels

End Sub

Function MouseDown(x As Integer, y As Integer) As Boolean
pushSelection
End Function

Sub DoubleClick()
//oldSelsB contains the pre-doubleclick selections
End Sub[/code]

Something clumsy about this is that a double click acts on the multiple selection but a single click will still clear it. A single click shouldn’t clear it, at least not until the double click time has passed.

This appears to be how apple does it. Setting Double-click speed to the slowest and clicking in a multiplie selected finder window, there’s a five second delay until it changes to the single clicked row.

You can get the double click time with a simple declare, but replicating the OSes behavior may be challenging. I only know Mac where the double click is measured from mouse up to up which means you’d have to handle all the mousing selection logic. ick. But doable.

Have you tried the cellclick handler ? I use it to create context menus without loosing the multiple selection. Maybe you can catch and handle a double click there by storing mouse.x and .y ?

I can’t try myself right now, sorry.

[quote=173391:@Oliver Osswald]Have you tried the cellclick handler ? I use it to create context menus without loosing the multiple selection. Maybe you can catch and handle a double click there by storing mouse.x and .y ?

I can’t try myself right now, sorry.[/quote]

Well thanks, but CellClick fires after MouseDown, so when I get the click, the selection is already gone…

[quote=173390:@Will Shank]Since updating in mousedown will override the last data then store the last two

[code]Private oldSelsA() As Integer
Private oldSelsB() As Integer

Private Sub pushSelection()

oldSelsB = oldSelsA

dim newSels() As integer
for i As integer = 0 to lb.ListCount - 1
if lb.Selected(i) then newSels.Append i
next
oldSelsA = newSels

End Sub

Function MouseDown(x As Integer, y As Integer) As Boolean
pushSelection
End Function

Sub DoubleClick()
//oldSelsB contains the pre-doubleclick selections
End Sub[/code]

Something clumsy about this is that a double click acts on the multiple selection but a single click will still clear it. A single click shouldn’t clear it, at least not until the double click time has passed.

This appears to be how apple does it. Setting Double-click speed to the slowest and clicking in a multiplie selected finder window, there’s a five second delay until it changes to the single clicked row.

You can get the double click time with a simple declare, but replicating the OSes behavior may be challenging. I only know Mac where the double click is measured from mouse up to up which means you’d have to handle all the mousing selection logic. ick. But doable.[/quote]

Will, this solution works better than the MouseMove, and it also works on Windows, thanks.
One problem still remains, when the user want to select a single row. If there is already a selected row (say row 0) and the user directly doubleclick on row 10, it will get both 0 and 10.
Clearly the user intention here is to only select row 10…

Mousemove appeared as a simple solution which it is not.

You could store the state of selection each time you create or modify the multiple selection.

Right. I believe this will only happen when clicking on a non-selected row so that will have to be trapped and specially handled. Change and add this…

[code]Function MouseDown(x As Integer, y As Integer) As Boolean

dim row As integer = me.RowFromXY(x, y)

if me.Selected(row) then
pushSelection
else
pushSpecialSel(row) //store the selection that ‘will be’ for this click
end

End Function

Private Sub pushSpecialSel(row As integer)

oldSelsB = oldSelsA

oldSelsA = Array(row)

End Sub[/code]

Thanks Will, this solved the issue.

I understand that you found already a solution. So just for the records: you can get the indexes of multiselected rows from the CellClick event, and then you can workaround a doubleclick. Maybe not the most elegant solution but it works

Testproject here

The code in the cell click event handler would be something like this:

[code]Function CellClick(row as Integer, column as Integer, x as Integer, y as Integer) As Boolean
Dim ar(-1) As String
If not Me.Selected(row) Then
ar.Append(Str(row))
End If
For i As Integer = 0 To Me.ListCount-1
If me.Selected(i) Then
ar.Append(Str(i))
End If
Next

If LastX = x And LastY = y Then
For j As Integer = 0 To Ubound(SelectedRowID)
me.Selected(Integer.FromText(SelectedRowID(j).ToText)) = True
Next
MsgBox(Join(SelectedRowID,","))
Else
Self.SelectedRowID = ar
End If

Self.LastX = x
Self.LastY = y
End Function
[/code]

One more time the testproject download

Thank you Oliver.
It’s nice when you ask for a solution and you get three! :slight_smile: