Visual Basic Common Control API Routines
SendMessage: Add Images to a ListView Header
     
Posted:   Saturday March 1, 1997
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 a complete implementation of comctl32.dll 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. The VB6 control supports an imagelist specifically for the ColumnHeaders.

Enhanced Comctl32 functionality is only available to users with comctl32.dll version 4.70 or greater installed. This dll is typically installed with IE3.x or greater.


In most Windows applications, a visual indication of the sorting direction of the currently active listview column header is indicated by an up or down arrow. This functionality has previously been unavailable to the Visual Basic developer. The method detailed here demonstrates the steps to add your own image to a listview header, to respond to the user interaction with a given column header, and to display the appropriate image to provide feedback.

Some of this functionality may be unavailable if you are using a version of comctl32.dll earlier than version 4.70, the version first provided with Internet Explorer 3.01.

The Windows API provides for placing images loaded into an imagelist control onto any or all headers through the HD_ITEM structure, and its related style and format messages HDI_IMAGE, HDI_FORMAT, HDF_LEFT, HDF_STRING, HDF_BITMAP and HDF_BITMAP_ON_RIGHT. By setting specific combinations of these messages, the image can be added left or right of the header caption, or removed altogether.

This example contains all the code required to construct the illustration shown. The concepts demonstrated here can then be transplanted into an existing project utilizing a VB5 ListView control with subitems.

 BAS Module Code
None.

 Form Code
To a form add a listview  (ListView1), ImageList (Imagelist1), and a command button (Command1).

To the imagelist, add at least two images (bitmaps, icons or gifs). I used Paint to create the two images using grey, white and dark grey. The image size should not be larger than 16x16, and more desirably around 12x12 or 13x13 pixels. The routine below uses the ListView1.SortOrder to determine the image to display - a sort order of 0 (ascending) displays the first image, and a SortOrder of 1 (descending) the second image. Therefore I put the "down" arrow as image 1, and the "up" arrow as image 2.  Important: if you followed the above instructions, set the imagelist MaskColor and backcolour values to Button Face form the Colours property page.  If the images appear with a white of black background, these settings are the problem.


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_GETHEADER = (LVM_FIRST + 31)

Private Const HDI_BITMAP = &H10
Private Const HDI_IMAGE = &H20
Private Const HDI_FORMAT = &H4
Private Const HDI_TEXT = &H2

Private Const HDF_BITMAP_ON_RIGHT = &H1000
Private Const HDF_BITMAP = &H2000
Private Const HDF_IMAGE = &H800
Private Const HDF_STRING = &H4000

Private Const HDM_FIRST = &H1200
Private Const HDM_SETITEM = (HDM_FIRST + 4)
Private Const HDM_SETIMAGELIST = (HDM_FIRST + 8)
Private Const HDM_GETIMAGELIST = (HDM_FIRST + 9)

Private Type HD_ITEM
   mask As Long
   cxy As Long
   pszText As String
   hbm As Long
   cchTextMax As Long
   fmt As Long
   lParam As Long
   iImage As Long
   iOrder As Long
End Type

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 i As Integer
   Dim itmX As ListItem
   
  'Create and populate the listview
   With ListView1
      
      .SmallIcons = ImageList1
      
      For i = 1 To 3
         .ColumnHeaders.Add , "x" & i, "Column " & i 
         .ColumnHeaders.Item(i).Width = 1520
      Next i
      
      For i = 1 To 9
         Set itmX = .ListItems.Add(, "key" & i, "Item " & i)
         itmX.SubItems(1) = "Subitem " & i
         itmX.SubItems(2) = "Subitem " & i
      Next i
      
   End With
   
  'ShowHeaderIcon colNo, imgIndex, showFlag
   ShowHeaderIcon 0, 0, True
   
End Sub


Private Sub Command1_Click()

   Unload Me
      
End Sub


Public Sub ShowHeaderIcon(colNo As Long, _
                          imgIconNo As Long, _
                          showImage As Long)

   Dim hHeader As Long
   Dim HD As HD_ITEM
   
  'get a handle to the listview header component
   hHeader = SendMessage(ListView1.hwnd, LVM_GETHEADER, 0, ByVal 0)
   
  'set up the required structure members
   With HD
      .mask = HDI_IMAGE Or HDI_FORMAT
      .pszText = ListView1.ColumnHeaders(colNo + 1).Text
      
       If showImage Then
         .fmt = HDF_STRING Or HDF_IMAGE Or HDF_BITMAP_ON_RIGHT
         .iImage = imgIconNo
       Else
         .fmt = HDF_STRING
      End If


   End With
   
  'modify the header
   Call SendMessage(hHeader, HDM_SETITEM, colNo, HD)
   
End Sub


Private Sub ListView1_ColumnClick(ByVal ColumnHeader As ComctlLib.ColumnHeader)

   Dim i As Long
   Static sOrder
   
   sOrder = Not sOrder
   
  'Use default sorting to sort the items in the list
   ListView1.SortKey = ColumnHeader.Index - 1
   ListView1.SortOrder = Abs(sOrder)
   ListView1.Sorted = True
   
  'clear the image from the headers not
  'currently selected, and update the
  'header clicked
   For i = 0 To 2
      
     'if this is the index of the header clicked
      If i = ListView1.SortKey Then
      
        'ShowHeaderIcon colNo, imgIndex, showFlag
         ShowHeaderIcon ListView1.SortKey, _
                        ListView1.SortOrder, _
                        True
                           
      Else
         ShowHeaderIcon i, 0, False
      End If
   
   Next
   
End Sub
 Comments
Sorting the columns by clicking any ColumnHeader will cause the image to appear on the selected header, and its display orientation will follow that of the sort order of the listview.

 
 

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