The new vbAccelerator Site - more VB and .NET Code and Controls
Source Code
2 Common Controls Library &nbsp
 

Adding InfoTips to Microsoft's ListView control

 
 

Provide Individual Multi-line tooltips for any item within a ListView

 
 


InfoTip Demonstration


Download Code
Download the InfoTip Demonstration (32kb)

&nbsp Before you Begin &nbsp
&nbsp This project requires the SSubTmr.DLL component. Make sure you have loaded and registered this before trying the project. &nbsp
 


An InfoTip is the name Microsoft give to a tooltip which has multiple lines. If you run IE4.01 or higher, or have Win98 or 2000 then you will see InfoTips in effect whenever you point your mouse at 'My Computer' or 'Internet Explorer' on the desktop.

You can add this facility to a Microsoft ListView control by setting an extended style and then subclassing to respond to LVN_GETINFOTIP notifications passed via the WM_NOTIFY message.

The Endlessly Flexible WM_NOTIFY Message
Most Common Controls use the WM_NOTIFY message to notify the container window of a condition the application might want to respond to.

MS have designed an interface for the WM_NOTIFY message so it can cover large numbers of different notifications. The first part of this scheme is that whenever you receive a WM_NOTIFY message, the lParam of the message is a long pointer to an area of memory, and this area of memory will always contain at least an NMHDR structure:

Private Const WM_NOTIFY = &H4E

Private Type NMHDR
   hWndFrom As Long
   idFrom As Long
   code As Long
End Type

This structure allows the control to identify itself to the container window using the hWndFrom and idFrom members, and also allows a huge number of submessages to be packed in by setting different values for the code member.

In the commmon control's header file, Microsoft have indicated that ListViews use code values between -100 and -199, although currently a limited number of these are actually used.

The extensibility of the WM_NOTIFY message to handling any sort of notification is achieved by creating structures which contain the mandatory NMHDR structure fields as the first three elements, but then contain further fields. Each notification code defines its own unique structure.

In the case of a WM_NOTIFY message with the LVS_INFOTIP code value, the required structure is as follows:

Private Type NMLVGETINFOTIP
   hdr As NMHDR
   dwFlags As Long
   pszText As String
   cchTextMax As Long
   iItem As Long
   iSubItem As Long
   lParam As Long
End Type

InfoTips In Action
To enable InfoTips in a ListView, you just need to tell the ListView it should support InfoTips. This is done by setting the LVS_EX_INFOTIP extended style:

Private Const LVM_FIRST = &H1000& '' ListView messages
Private Const LVN_FIRST = -100 '' listview

Private Const LVS_EX_INFOTIP = &H400 ' listview does InfoTips for you
Private Const LVM_SETEXTENDEDLISTVIEWSTYLE = (LVM_FIRST + 54) ' optional wParam == mask
Private Const LVM_GETEXTENDEDLISTVIEWSTYLE = (LVM_FIRST + 55)


pSetExStyle lvw.hWnd, 0, LVS_EX_INFOTIP


Private Sub pSetExStyle(ByVal hWnd As Long, ByVal lStyle As Long, ByVal lStyleNot As Long)

   Dim lS As Long

   lS = SendMessageLong(hWnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0)
   lS = lS And Not lStyleNot
   lS = lS Or lStyle
   SendMessageLong hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, lS

End Sub

Once you have done this, the ListView will start sending WM_NOTIFY messages with the LVN_GETINFOTIP code to the container window of the ListView control. You can then subclass for the WM_NOTIFY message and return the string for the ListView to show in the InfoTip using code like this:

Private Const LVN_GETINFOTIP = (LVN_FIRST - 57)
      ' Module level variable to ensure pointer is valid.
      ' String pointed to should be an ANSI string.
Private msInfoTipBuffer As String

m_hWnd = GetParent(lvw.hWnd)
AttachMessage Me, m_hWnd, WM_NOTIFY


Private Function ISubclass_WindowProc(ByVal hWnd As Long, ByVal iMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
   Dim tNMH As NMHDR

   Select Case iMsg
   Case WM_NOTIFY
      CopyMemory tNMH, ByVal lParam, Len(tNMH)
      Select Case tNMH.code
      Case LVN_GETINFOTIP
         Dim tLVIT As NMLVGETINFOTIP_NOSTRING
         Dim sTip As String

         CopyMemory tLVIT, ByVal lParam, Len(tLVIT)
         sTip = m_lvw.ListItems(tLVIT.iItem + 1).Tag
         If sTip <> "" Then
            sTip = sTip & vbNullChar
            tLVIT.cchTextMax = Len(sTip)
            msInfoTipBuffer = StrConv(sTip, vbFromUnicode)
            tLVIT.pszText = StrPtr(msInfoTipBuffer)
            CopyMemory ByVal lParam, tLVIT, Len(tLVIT)
         End If

      End Select

   End Select

End Function

Wrapping It Up
The sample code includes a class (cListViewInfoTip) which can be used to simply add InfoTips support to a ListView. This class makes it particularly simple to use because it simply refers to the ListItem's Tag property, which it uses as the InfoTip. If you are already using the Tag property for something else, you will want to write some more sophisticated code. (A good method for doing this would be to store an Object Pointer in each of the Tags, and use the IUnknown AddRef and Release mechanism described in the article Store Objects against a Control's Tag or ItemData property.

To use the Class as is, just reference SSubTmr.DLL (it appears in the Project->References list as "Subclassing and Timer Assistant (with Multi-Control Support and Timer bug-fix)". Then add this code:

' Info tip support:
Private m_cLVTip As cListViewInfoTip


   Set m_cLVTip = New cListViewInfoTip
   m_cLVTip.Attach lvwFiles




TopBack to top
Source Code - What We're About!Back to Source Code

&nbsp &nbsp
 

About  Contribute  Send Feedback  Privacy

Copyright © 1998-1999, Steve McMahon ( steve@vbaccelerator.com). All Rights Reserved.
Last updated: 15 November 1999