alexkwok
asked on
Listview "Selection" event that is raised when Items are being selected?
What I'm looking for is a way to know when a selection occurs, much like how in Windows Explorer, the filesize in the status bar is update as you select files.
There isn't an event built-in that I know of, and the Mouse(up/down/move) events do not work as it should. Anyone know how to do this?
There isn't an event built-in that I know of, and the Mouse(up/down/move) events do not work as it should. Anyone know how to do this?
There is a method called OnSelectedIndexChanged for listview controls
ASKER
Which version of common controls is it on? The one I am using does not have it.
Private Sub Form_Load()
With ListView1
Call .ListItems.Add(, , "1")
Call .ListItems.Add(, , "2")
Call .ListItems.Add(, , "3")
Call .ListItems.Add(, , "4")
End With
End Sub
Private Sub ListView1_ItemClick(ByVal Item As MSComctlLib.ListItem)
Me.Caption = "Selected: " & Item.Text
End Sub
With ListView1
Call .ListItems.Add(, , "1")
Call .ListItems.Add(, , "2")
Call .ListItems.Add(, , "3")
Call .ListItems.Add(, , "4")
End With
End Sub
Private Sub ListView1_ItemClick(ByVal Item As MSComctlLib.ListItem)
Me.Caption = "Selected: " & Item.Text
End Sub
I do it in a separate helper class - I call CheckSelChange (sub which checks selected count) in KeyUp event and in MouseUp, and also in MouseMove if flag buttonisdown was set in MouseDown.
To check count I use:
SelCount = SendMessage(ListView.hWnd, LVM_GETSELECTEDCOUNT, 0&, ByVal 0&)
To check count I use:
SelCount = SendMessage(ListView.hWnd,
What you want is a Hittest.
With LV as the ListView control:
Private Sub LV_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)
Dim li As ListItem
Set li = LV.HitTest(x, y)
Select Case Button
Case 1 ' Left Click
If Not li Is Nothing Then
' An Item was clicked with the Left Button
Case 2
If li Is Nothing Then ' Whitespace was clicked with Right Button
Else
' An Item was clicked with the Right Button
End Select
I hope this helps.
RichW
With LV as the ListView control:
Private Sub LV_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)
Dim li As ListItem
Set li = LV.HitTest(x, y)
Select Case Button
Case 1 ' Left Click
If Not li Is Nothing Then
' An Item was clicked with the Left Button
Case 2
If li Is Nothing Then ' Whitespace was clicked with Right Button
Else
' An Item was clicked with the Right Button
End Select
I hope this helps.
RichW
Ooops, forgot the End If in the Case 2.
ASKER
I actually want a solution where if you drag the selection rectangle and start selecting things, the status bar will update. Using MouseMove will not work because it just doesn't raise events when you select like that. Mouseup/mousedown/itemclic k only occurs when you click.
I know that this is possible by subclassing, but I would like a more elegant solution.
(If you don't understand about the selection thing, open Windows Explorer and drag the selection rectangle. _As_ you select multiple files, the status bar will update the sum size of the files everytime the selection changes).
I know that this is possible by subclassing, but I would like a more elegant solution.
(If you don't understand about the selection thing, open Windows Explorer and drag the selection rectangle. _As_ you select multiple files, the status bar will update the sum size of the files everytime the selection changes).
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
MouseMove isn't raised, true, but I have a code there, it is executed once after selection is finished.
Here is a small sample which shows selection while user is dragging selection rectangle and selecting items.
It doesn't show selection if user is dragging and DEselecting items, but it might be partial solution until you make something with timer, as zzzzzoc suggested.
(to simplify code, I removed CheckSelChange, it requires module variables oldNumItems and oldSelItem, I simply raise SelChange event instead)
' caList class -------------------------- -------
Option Explicit
Event SelChange()
Public WithEvents ListView As ListView
Private idx As Long
Private buttonisdown As Boolean
' APIs
Private Const LVM_FIRST = &H1000
Private Const LVM_GETSELECTEDCOUNT = (LVM_FIRST + 50)
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal _
hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
' returns collection of selected items
Public Property Get HilitedItems() As Collection
Dim i As Long, cnt As Long, selcnt As Long
On Error Resume Next
selcnt = SelCount
Set HilitedItems = New Collection
For i = 1 To ListView.ListItems.Count
If ListView.ListItems(i).Sele cted = True Then
HilitedItems.Add ListView.ListItems(i)
cnt = cnt + 1
If cnt = selcnt Then Exit Property
End If
Next
End Property
Public Property Get SelCount() As Long
SelCount = SendMessage(ListView.hwnd, LVM_GETSELECTEDCOUNT, 0&, ByVal 0&)
End Property
Private Sub ListView_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
buttonisdown = True
If ListView.HitTest(x, y) Is Nothing Then
If Not ListView.SelectedItem Is Nothing Then
idx = ListView.SelectedItem.Inde x
Set ListView.SelectedItem = Nothing
ListView.ListItems(idx).Se lected = False
End If
End If
End Sub
Private Sub ListView_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
If buttonisdown Then
If Button = 0 Then
buttonisdown = False
RaiseEvent SelChange
End If
End If
End Sub
Private Sub ListView_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)
buttonisdown = False
RaiseEvent SelChange
End Sub
Private Sub ListView_KeyUp(KeyCode As Integer, Shift As Integer)
RaiseEvent SelChange
End Sub
Private Sub ListView_ItemClick(ByVal Item As MSComctlLib.ListItem)
RaiseEvent SelChange
End Sub
' Form1, add listview ------------------------
Option Explicit
Private WithEvents aList As caList
Private Sub aList_SelChange()
Dim sum As Long, i As Long, itm As ListItem
Beep
For Each itm In aList.HilitedItems
sum = sum + CLng(itm.SubItems(1))
Next
Caption = aList.SelCount & " items, sum=" & sum
End Sub
Private Sub Form_Load()
With ListView1
With .ColumnHeaders
.Add 1, , "Name", 1555, 0
.Add 2, , "Count", 1485, 0
End With
.View = lvwReport
.MultiSelect = True
.ListItems.Add(, , "item 1").SubItems(1) = 10
.ListItems.Add(, , "item 2").SubItems(1) = 20
.ListItems.Add(, , "item 3").SubItems(1) = 30
.ListItems.Add(, , "item 4").SubItems(1) = 40
End With
Set aList = New caList
Set aList.ListView = Me.ListView1
End Sub
Private Sub Form_Unload(Cancel As Integer)
Set aList = Nothing ' cleanup
End Sub
Here is a small sample which shows selection while user is dragging selection rectangle and selecting items.
It doesn't show selection if user is dragging and DEselecting items, but it might be partial solution until you make something with timer, as zzzzzoc suggested.
(to simplify code, I removed CheckSelChange, it requires module variables oldNumItems and oldSelItem, I simply raise SelChange event instead)
' caList class --------------------------
Option Explicit
Event SelChange()
Public WithEvents ListView As ListView
Private idx As Long
Private buttonisdown As Boolean
' APIs
Private Const LVM_FIRST = &H1000
Private Const LVM_GETSELECTEDCOUNT = (LVM_FIRST + 50)
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal _
hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
' returns collection of selected items
Public Property Get HilitedItems() As Collection
Dim i As Long, cnt As Long, selcnt As Long
On Error Resume Next
selcnt = SelCount
Set HilitedItems = New Collection
For i = 1 To ListView.ListItems.Count
If ListView.ListItems(i).Sele
HilitedItems.Add ListView.ListItems(i)
cnt = cnt + 1
If cnt = selcnt Then Exit Property
End If
Next
End Property
Public Property Get SelCount() As Long
SelCount = SendMessage(ListView.hwnd,
End Property
Private Sub ListView_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
buttonisdown = True
If ListView.HitTest(x, y) Is Nothing Then
If Not ListView.SelectedItem Is Nothing Then
idx = ListView.SelectedItem.Inde
Set ListView.SelectedItem = Nothing
ListView.ListItems(idx).Se
End If
End If
End Sub
Private Sub ListView_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
If buttonisdown Then
If Button = 0 Then
buttonisdown = False
RaiseEvent SelChange
End If
End If
End Sub
Private Sub ListView_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)
buttonisdown = False
RaiseEvent SelChange
End Sub
Private Sub ListView_KeyUp(KeyCode As Integer, Shift As Integer)
RaiseEvent SelChange
End Sub
Private Sub ListView_ItemClick(ByVal Item As MSComctlLib.ListItem)
RaiseEvent SelChange
End Sub
' Form1, add listview ------------------------
Option Explicit
Private WithEvents aList As caList
Private Sub aList_SelChange()
Dim sum As Long, i As Long, itm As ListItem
Beep
For Each itm In aList.HilitedItems
sum = sum + CLng(itm.SubItems(1))
Next
Caption = aList.SelCount & " items, sum=" & sum
End Sub
Private Sub Form_Load()
With ListView1
With .ColumnHeaders
.Add 1, , "Name", 1555, 0
.Add 2, , "Count", 1485, 0
End With
.View = lvwReport
.MultiSelect = True
.ListItems.Add(, , "item 1").SubItems(1) = 10
.ListItems.Add(, , "item 2").SubItems(1) = 20
.ListItems.Add(, , "item 3").SubItems(1) = 30
.ListItems.Add(, , "item 4").SubItems(1) = 40
End With
Set aList = New caList
Set aList.ListView = Me.ListView1
End Sub
Private Sub Form_Unload(Cancel As Integer)
Set aList = Nothing ' cleanup
End Sub
ASKER
zzzz's code works well enough... I guess it'll have to do until I decide to subclass.