Solved

Listview "Selection" event that is raised when Items are being selected?

Posted on 2004-07-31
10
1,149 Views
Last Modified: 2008-01-16
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?
0
Comment
Question by:alexkwok
  • 3
  • 2
  • 2
  • +2
10 Comments
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 11686312
There is a method called OnSelectedIndexChanged for listview controls
0
 

Author Comment

by:alexkwok
ID: 11686360
Which version of common controls is it on?  The one I am using does not have it.
0
 
LVL 17

Expert Comment

by:zzzzzooc
ID: 11686413
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
0
 
LVL 15

Expert Comment

by:ameba
ID: 11687283
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&)
0
 
LVL 4

Expert Comment

by:RichW
ID: 11688332
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
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 4

Expert Comment

by:RichW
ID: 11688343
Ooops,  forgot the End If in the Case 2.

0
 

Author Comment

by:alexkwok
ID: 11688748
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/itemclick  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).
0
 
LVL 17

Accepted Solution

by:
zzzzzooc earned 500 total points
ID: 11689130
Due to the limitations you mentioned (with events not raising), you may be left with either subclassing the control or using a timer. If you're already subclassing a window, you can reuse the WindowProc and it'd be more appropriate. If you aren't subclassing anything already, adding the procedures to do such may not be desired.

Using a timer that's constantly active seems appropriate. With an interval of 1000ms, there's not processing going on. The ListView itself causes over 90% CPU usage during selection for me (does this occur for anybody else?).

Form1:
---------------
Option Explicit
Private Sub Form_Load()
    With ListView1
        Call .ListItems.Add(, , "1")
        Call .ListItems.Add(, , "2")
        Call .ListItems.Add(, , "3")
        Call .ListItems.Add(, , "4")
    End With
    Timer1.Interval = 1000
    Timer1.Enabled = True
End Sub
Private Sub Timer1_Timer()
    Dim objItem As ListItem, intCnt As Integer
    For Each objItem In ListView1.ListItems
        If objItem.Selected = True Then
            'You can access this specific item now through
            'objItem to get extra information.. if you wish
            'to just get the count, use LVM_GETSELECTEDCOUNT
            intCnt = intCnt + 1
        End If
    Next objItem
    Me.Caption = intCnt & " item(s) selected."
End Sub
0
 
LVL 15

Expert Comment

by:ameba
ID: 11689386
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).Selected = 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.Index
            Set ListView.SelectedItem = Nothing
            ListView.ListItems(idx).Selected = 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
0
 

Author Comment

by:alexkwok
ID: 11696742
zzzz's code works well enough... I guess it'll have to do until I decide to subclass.
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

Suggested Solutions

The debugging module of the VB 6 IDE can be accessed by way of the Debug menu item. That menu item can normally be found in the IDE's main menu line as shown in this picture.   There is also a companion Debug Toolbar that looks like the followin…
Enums (shorthand for ‘enumerations’) are not often used by programmers but they can be quite valuable when they are.  What are they? An Enum is just a type of variable like a string or an Integer, but in this case one that you create that contains…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now