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