|
|
![]() |
|
||
|
|
|||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||
| Visual Basic Common Control API
Routines SendMessage: Simulate 'TopIndex' in ListViews |
||
| Posted: | Sunday January 25, 2004 | |
| Updated: | Monday December 26, 2011 | |
| Applies to: | VB4-32, VB5, VB6 | |
| Developed with: | VB4-32, Windows XP | |
| OS restrictions: | None | |
| Author: | VBnet - Randy Birch | |
| Prerequisites |
| None. |
|
|
![]() A listview control's EnsureVisible method provides a means to bring a referenced item into view. Ditto, the LVM_ENSUREVISIBLE message simply "ensures that a list-view item is either entirely or partially visible, scrolling the list-view control if necessary." If the item of interest is back up the list (its index is less than the index of the current top item) EnsureVisible dutifully scrolls the item into view and positions it at the top of the control. Similarly, if the index of interest is later in the listing calling EnsureVisible just brings the item into view as the bottom-most item. Ironically, amongst the plethora of Windows' listview messages there is one to allow programmers to determine the index of the item at the top of the control (LVM_GETTOPINDEX). But unlike a listbox, there is no message to set it. This code, using a combination of the LVM_GETTOPINDEX and LVM_GETCOUNTPERPAGE messages, along with the control's intrinsic behaviour when EnsureVisible is called, remedies that oversight! The EnsureVisible method's quirk of never doing more work than it needs to and always positioning the EnsureVisble'd item to the top or bottom of the control (when the item was outside the viewport) can be used to our advantage here. The demo uses the control's FindItem method to locate a particular string match in the main column, then calls ListView_SetTopIndex the item to the top. The label on the form simply reflects the new top index resulting from the call (not the selected item index). The demo also creates the listview columns, view and data, as well as labels all controls, so just toss the controls mentioned below onto a form and run. Illustration 1 shows the item at index at 100 set to the top. Illustration 2 shows how the top index command is handled when the control contains insufficient items to move the desired index to the top. Illustration 3 shows the effect of setting the top index to an item earlier in the list. |
| BAS Module Code |
| None. |
|
|
| Form Code |
|
|
| Add a listview (Listview1), a label (Label1) and three command buttons (Command1, Command2, Command3) to a form and add the following code: |
|
|
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Const LVM_FIRST = &H1000
Private Const LVM_GETTOPINDEX = (LVM_FIRST + 39)
Private Const LVM_GETCOUNTPERPAGE As Long = (LVM_FIRST + 40)
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
Private Sub Form_Load()
Dim itmx As ListItem
Dim cnt As Long
With ListView1
.ColumnHeaders.Add , , "main"
.ColumnHeaders.Add , , "sub 1"
.ColumnHeaders.Add , , "sub 2"
.ColumnHeaders.Add , , "sub 3"
For cnt = 1 To 200
Set itmx = .ListItems.Add(, , "main item" & CStr(cnt))
itmx.SubItems(1) = "subitem 1," & CStr(cnt)
itmx.SubItems(2) = "subitem 3," & CStr(cnt)
itmx.SubItems(3) = "subitem 4," & CStr(cnt)
Next
.SortKey = 0
.Sorted = False
.View = lvwReport
.FullRowSelect = True
.LabelEdit = lvwManual
End With
Command1.Caption = "mid-way"
Command2.Caption = "item 197"
Command3.Caption = "item 2"
End Sub
Private Sub Command1_Click()
Dim itmx As ListItem
Dim topIndex As Long
Set itmx = ListView1.FindItem("main item100", lvwText, 1, lvwPartial)
If Not itmx Is Nothing Then
topIndex = ListView_SetTopIndex(ListView1, itmx.Index)
itmx.Selected = True
End If
Label1.Caption = topIndex
End Sub
Private Sub Command2_Click()
Dim itmx As ListItem
Dim topIndex As Long
Set itmx = ListView1.FindItem("main item197", lvwText, 1, lvwPartial)
If Not itmx Is Nothing Then
topIndex = ListView_SetTopIndex(ListView1, itmx.Index)
itmx.Selected = True
End If
Label1.Caption = topIndex
End Sub
Private Sub Command3_Click()
Dim itmx As ListItem
Dim topIndex As Long
Set itmx = ListView1.FindItem("main item2", lvwText, 1, lvwPartial)
If Not itmx Is Nothing Then
topIndex = ListView_SetTopIndex(ListView1, itmx.Index)
itmx.Selected = True
End If
Label1.Caption = topIndex
End Sub
Private Sub ListView1_ColumnClick(ByVal ColumnHeader As ColumnHeader)
'sort the items
ListView1.SortKey = ColumnHeader.Index - 1
ListView1.SortOrder = Abs(Not ListView1.SortOrder = 1)
ListView1.Sorted = True
End Sub
Private Function ListView_GetTopIndex(hwndlv As Long) As Long
ListView_GetTopIndex = SendMessage(hwndlv, _
LVM_GETTOPINDEX, _
0&, _
ByVal 0&)
End Function
Private Function ListView_GetVisibleCount(ByVal hwndlv As Long) As Long
ListView_GetVisibleCount = SendMessage(hwndlv, _
LVM_GETCOUNTPERPAGE, _
0&, _
ByVal 0&)
End Function
Private Function ListView_SetTopIndex(lv As ListView, ByVal itemToTop As Long) As Long
Dim lvItemsPerPage As Long
Dim lvNeededItems As Long
Dim lvCurrentTopIndex As Long
'determine if desired index + number
'of items in view will exceed total
'items in the control
lvCurrentTopIndex = ListView_GetTopIndex(lv.hwnd) + 1 '0-based!
lvItemsPerPage = ListView_GetVisibleCount(lv.hwnd)
lvNeededItems = (itemToTop - lvItemsPerPage)
'is current index above or below
'desired index?
If lvCurrentTopIndex > itemToTop Then
'it is above the desired index, so
'scroll up. The item will automatically
'be positioned at the top
lv.ListItems((itemToTop)).EnsureVisible
ElseIf (itemToTop - lvCurrentTopIndex) >= lvItemsPerPage Then
'it's below, so based on whether there
'are sufficient items to set to the topindex ...
If (itemToTop + lvItemsPerPage) > lv.ListItems.Count Then
'it is below but it can't be set to
'the top as the control has insufficient
'items, so just scroll to the end of listview
lv.ListItems(lv.ListItems.Count).EnsureVisible
Else
'it is below, and since a listview
'always moves the item just into view,
'have it instead move to the top by
'faking item we want to 'EnsureVisible'
'the item lvItemsPerPage -1 below the actual
'index of interest.
lv.ListItems((itemToTop + lvItemsPerPage) - 1).EnsureVisible
End If
End If
'return the 1-based top index
'as sign of success.
ListView_SetTopIndex = ListView_GetTopIndex(lv.hwnd) + 1
End Function
|
| Comments |
|
|
|
|
|
|||||
|
|||||
|
|
|||||
|
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |
![]() |