Visual Basic Common Control API Routines
SendMessage: Indent ListView ListItems
     
Posted:   Thursday January 20, 2000
Updated:   Monday December 26, 2011
     
Applies to:   VB4-32, VB5, VB6
Developed with:   VB4-32, Windows 95
OS restrictions:   None
Author:   VBnet - Randy Birch
     
 Prerequisites
This method is intended for Visual Basic 5 or Visual Basic 6 where the Common Control library used is the MSComCtl 5 version (comctl32.ocx). Because the VB6-specific mscomctl.ocx (Common Controls 6) is an implementation of the comctl32.dll control and not reliant on the version of comctl32.dll installed, this routine may not work when applied to a ListView created from the VB6-specific mscomctl.ocx.

This enhanced Comctl32 functionality is only available to users with comctl32.dll version 4.72 or greater installed, typically installed with IE4.x or greater, or with Win98.


Many people erroneously believe that the 'control' used in displaying hierarchical data such as Outlook Express' news reader view is a treeview control with columns. Actually, the control is a ListView taking advantage of the comctl version 4-specific Indent member of the LV_ITEM structure. This page shows how to add this functionality to a comctl32-based ListView (see Prerequisites above).

In addition, it demonstrates how to adjust the column indent for a selected item either programmatically or under a user's control. Not demonstrated is the 'other' side of the news reader feature set - expanding and collapsing the items subordinate to the thread.

Note: this method requires that an imagelist be assigned to the control, even if its images are not used.

 BAS Module Code
Place the following code into the general declarations area of a bas module:

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.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Const LVIF_INDENT As Long = &H10
Public Const LVIF_TEXT As Long = &H1
Public Const LVS_EX_FULLROWSELECT As Long = &H20
Public Const LVM_FIRST As Long = &H1000
Public Const LVM_GETITEM As Long = (LVM_FIRST + 5)
Public Const LVM_SETITEM As Long = (LVM_FIRST + 6)
Public Const LVM_DELETEALLITEMS As Long = (LVM_FIRST + 9)
Public Const LVM_SETEXTENDEDLISTVIEWSTYLE As Long = (LVM_FIRST + 54)
Public Const LVM_GETEXTENDEDLISTVIEWSTYLE As Long = (LVM_FIRST + 55)
Public Const ICC_LISTVIEW_CLASSES As Long = &H1

Public Type LV_ITEM
    mask As Long
    iItem As Long
    iSubItem As Long
    state As Long
    stateMask As Long
    pszText As String
    cchTextMax As Long
    iImage As Long
    lParam As Long
    iIndent As Long
End Type
 
Public Type tagINITCOMMONCONTROLSEX
    dwSize As Long
    dwICC As Long
End Type

Public Declare Sub InitCommonControls Lib "comctl32" ()

Public Declare Function InitCommonControlsEx Lib "comctl32" _
   (lpInitCtrls As tagINITCOMMONCONTROLSEX) As Boolean

Public Declare Function SendMessage Lib "user32" _
   Alias "SendMessageA" _
  (ByVal hWnd As Long, _
   ByVal wMsg As Long, _
   ByVal wParam As Long, _
   lParam As Any) As Long
       
Public Declare Function LockWindowUpdate Lib "user32" _
   (ByVal hwndLock As Long) As Long
       
Public Declare Function UpdateWindow Lib "user32" _
   (ByVal hWnd As Long) As Long


Public Function InitComctl32(dwFlags As Long) As Boolean

  Dim icc As tagINITCOMMONCONTROLSEX
  On Error GoTo Err_OldVersion
  
  icc.dwSize = Len(icc)
  icc.dwICC = dwFlags
  
 'VB will generate error 453 "Specified
 'DLL function not found" here if the new
 'version isn't installed and it can't find
 'the function's name. We'll hopefully be
 'able to load the old version below.
  InitComctl32 = InitCommonControlsEx(icc)
  Exit Function

Err_OldVersion:
  InitCommonControls

End Function
 Form Code
Create a new project, adding a VB5 ListView (ListView1), two command buttons (Command1/Command2) and an UpDown control (UpDown1). Add an ImageList populated with at least a single 16x16 icon, and assign it to the SmallIcon property of the ListView. Finally, add a single column header to the ListView, and add the following code to the form:

Option Explicit

Private Sub Form_Load()

   With ListView1
      .SortKey = 0
      .SmallIcons = ImageList1
      .ColumnHeaders(1).Width = .Width - 600
      .View = lvwReport
   End With
   
   Call InitComctl32(ICC_LISTVIEW_CLASSES)
   Call SendMessage(ListView1.hWnd, _
                    LVM_SETEXTENDEDLISTVIEWSTYLE, _
                    LVS_EX_FULLROWSELECT, ByVal True)
   
End Sub


Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)

   Call LockWindowUpdate(ListView1.hWnd)
   Call SendMessage(ListView1.hWnd, LVM_DELETEALLITEMS, 0&, ByVal 0&)
   Call LockWindowUpdate(0&)
   
End Sub


Private Sub Command1_Click()

  'be sure to change the imgKey value to the 
  'key you've assigned to your list image(s)
   LVLoadIndentDemo imgKey:="windows", Indent:=0
   LVLoadIndentDemo imgKey:="page", Indent:=1
   LVLoadIndentDemo imgKey:="pagecyan", Indent:=2
   LVLoadIndentDemo imgKey:="pagecyan", Indent:=2
   LVLoadIndentDemo imgKey:="page", Indent:=1
   LVLoadIndentDemo imgKey:="pagecyan", Indent:=2
   LVLoadIndentDemo imgKey:="cyanclip", Indent:=3
   LVLoadIndentDemo imgKey:="yellowclip", Indent:=4
   LVLoadIndentDemo imgKey:="yellowclip", Indent:=5
   LVLoadIndentDemo imgKey:="yellowclip", Indent:=6

   Exit Sub
   
  'a different arrangement
   LVLoadIndentDemo imgKey:="page", Indent:=0
   LVLoadIndentDemo imgKey:="yellowclip", Indent:=1
   LVLoadIndentDemo imgKey:="cyanclip", Indent:=2
   LVLoadIndentDemo imgKey:="windows", Indent:=3
   LVLoadIndentDemo imgKey:="yellowclip", Indent:=1
   LVLoadIndentDemo imgKey:="cyanclip", Indent:=2
   LVLoadIndentDemo imgKey:="windows", Indent:=3
   LVLoadIndentDemo imgKey:="yellowclip", Indent:=4
   LVLoadIndentDemo imgKey:="cyanclip", Indent:=5
   LVLoadIndentDemo imgKey:="windows", Indent:=6
   LVLoadIndentDemo imgKey:="page", Indent:=7
   LVLoadIndentDemo imgKey:="yellowclip", Indent:=8

End Sub


Private Sub Command2_Click()
   
   Unload Me
   
End Sub


Private Sub UpDown1_DownClick()

   MoveListItem CLng(ListView1.SelectedItem.Index), -1
   
End Sub


Private Sub UpDown1_UpClick()

   MoveListItem CLng(ListView1.SelectedItem.Index), 1
   
End Sub


Private Sub MoveListItem(hIndex As Long, direction As Long)

   Dim newIndent As Long
   Dim LV As LV_ITEM
   
  'set the LV_ITEM mask and item index
   LV.mask = LVIF_INDENT
   LV.iItem = hIndex - 1 'subtract 1 as control is 0-based
   
  'retrieve the current settings
   Call SendMessage(ListView1.hWnd, LVM_GETITEM, 0&, LV)
   
  'just add the direction passed to calculate
  'the new indent position. Adding a negative
  'number is the same as subtracting.
   newIndent = LV.iIndent + direction
   
  'if the new position is not less than the edge..
   If newIndent >= 0 Then
   
     'assign the new indent
      LV.iIndent = newIndent
      
     'set the new item indent
      Call SendMessage(ListView1.hWnd, LVM_SETITEM, 0&, LV)
      
     'change the item caption to reflect the new indent
      ListView1.SelectedItem.Text = _
      "This string is indented " & LV.iIndent & " level(s)"
      
   End If
   
End Sub


Private Sub LVLoadIndentDemo(imgKey As String, Indent As Long)

   Dim itmX As ListItem
   Dim imgX As ListImage
   Dim LV As LV_ITEM
   Dim nItem As Long
   Dim sItem As String
   
  'add the item
   sItem = "This string is indented " & Indent & " level(s)"
   Set itmX = ListView1.ListItems.Add(, , Trim$(sItem))
    
  'add the icon
   If Len(imgKey) > 0 Then
      itmX.SmallIcon = ImageList1.ListImages(imgKey).Key
   End If
      
  'if indentation is indicated
   If Indent Then
      
     'this is the item to indent (in this
     'routine, the newly-added item)
      nItem = CLng(itmX.Index)
      
     'set up the structure
      With LV
        .mask = LVIF_INDENT
        .iItem = nItem - 1 '0-based, so have to subtract 1
        .iIndent = Indent
      End With
      
     'indent the item
      Call SendMessage(ListView1.hWnd, LVM_SETITEM, 0&, LV)
      
   End If
  
End Sub
 Comments

 
 

PayPal Link
Make payments with PayPal - it's fast, free and secure!

 
 
 
 

Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy

 

Hit Counter