|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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. |