Click here to Skip to main content
Click here to Skip to main content

Listbox Control with Tooltip for Each Item

, 15 Sep 2012
Rate this:
Please Sign up or sign in to vote.
This article describes how to extend the Windows Forms ListBox control to display a tooltip for each item.

Introduction 

This article describes a way of displaying tooltips for items in a Windows Forms ListBox control. The built-in ToolTip control allows you to display a single tooltip for the entire listbox. However, if you want to display separate tooltips for each item in the listbox, you're out of luck. Fortunately, it's not too difficult to mimic the tooltip behavior yourself. Here, we will look at how to create and use a custom ListBox control called ToolTipListBox.

Description of Code

This article contains the complete code required to create a listbox with different tooltips for each item. We will go through the code in the following sections. The code consists of the following parts:  

  1. Adding ListBoxItem objects to the ToolTipListBox control
  2. ListBoxItem class
  3. IToolTipDisplayer interface
  4. ToolTipListBox class

Adding ListBoxItem Objects to the ToolTipListBox

// Create list of items
ListBoxItem[] items = new ListBoxItem[]
{
    new ListBoxItem("Apple",     "Malus pumila"),
    new ListBoxItem("Banana",    "Porcelia macrocarpa"),
    new ListBoxItem("Kiwi",      "Actinidia deliciosa"),
    new ListBoxItem("Papaya",    "Carica papaya"),
    new ListBoxItem("Mango",     "Mangifera indica"),
    new ListBoxItem("Tomato",    "Lycopersicon esculentum"),
    new ListBoxItem("Lychee",    "Litchi chinensis"),
    new ListBoxItem("Coconut",   "Cocos nucifera"),
    new ListBoxItem("Tangerine", "Citrus reticulata"),
    new ListBoxItem("Avocado",   "Persea americana"),
};
 
// Populate list box
toolTipListBox.Items.AddRange(items);

The code listed above creates an array of ListBoxItem objects and adds the items to the ToolTipListBox control. The constructor for each ListBoxItem takes in the text to display in the listbox and the tooltip text.

ListBoxItem Class

internal class ListBoxItem : IToolTipDisplayer
{
    public string DisplayText { get; private set; }
    public string ToolTipText { get; private set; }
 
    // Constructor
    public ListBoxItem(string displayText, string toolTipText)
    {
        DisplayText = displayText;
        ToolTipText = toolTipText;
    }
 
    // Returns the display text of this item.
    public override string ToString()
    {
        return DisplayText;
    }
    // Returns the tooltip text of this item.
    public string GetToolTipText()
    {
        return ToolTipText;
    }
}

ListBoxItem is a simple class that is used to represent each item in the listbox. The ToString() method is overridden from Object and it returns the text that is displayed in the listbox. The GetToolTipText() method returns the tooltip text that is displayed for the item. It implements the IToolTipDisplayer interface that is described below.

IToolTipDisplayer Interface

/// Interface used by listbox items in ToolTipListBox.
internal interface IToolTipDisplayer
{
    string GetToolTipText();
} 

The IToolTipDisplayer interface is used by ToolTipListBox to get the tooltip text for the listbox item. The interface has a single method that returns the tooltip text to display for the item. Any object that is added to the listbox should implement this interface to display tooltip text. As you have seen above, the ListBoxItem class implements IToolTipDisplayer.

ToolTipListBox Class

Now we will get to the meat of this article which describes the implementation of ToolTipListBox. First, let's declare the class and some member variables:

/// ListBox that displays item-specific tooltips.
internal partial class ToolTipListBox : ListBox
{
    // The item index that the mouse is currently over
    private int _currentItem;
 
    // A value indicating if the current item has been set
    private bool _currentItemSet;
 
    // A value indicating if a tooltip is currently being displayed
    private bool _toolTipDisplayed;
 
    // Timer that is used to wait for the mouse to hover over an item
    private Timer _toolTipDisplayTimer;
 
    // Tooltip control
    private ToolTip _toolTip;

Pretty straightforward so far. The class extends the built-in ListBox control and adds tooltip functionality. Now, let's define the constructor:

public ToolTipListBox()
{
    InitializeComponent();
 
    this.MouseMove += listBox_MouseMove;
    this.MouseLeave += listBox_MouseLeave;
            
    _currentItemSet = false;
    _toolTipDisplayed = false;
    _toolTipDisplayTimer = new Timer();
    _toolTip = new ToolTip();
 
    // Set the timer interval to the system time that it takes for a tooltip to appear
    _toolTipDisplayTimer.Interval = SystemInformation.MouseHoverTime;
    _toolTipDisplayTimer.Tick += _toolTipDisplayTimer_Tick;
} 

InitializeComponent() is automatically added by Visual Studio when you create a new User Control. We add handlers for the MouseMove and MouseLeave events of the listbox. Then we initialize the member variables. Then we set the timer to raise the Tick event after the standard system time for a tooltip (SystemInformation.MouseHoverTime). Now, let's define the MouseMove event handler for the listbox:

private void listBox_MouseMove(object sender, MouseEventArgs e)
{
    // Get the item that the mouse is currently over
    Point cursorPoint = Cursor.Position;
    cursorPoint = this.PointToClient(cursorPoint);
    int itemIndex = this.IndexFromPoint(cursorPoint);
 
    if (itemIndex == ListBox.NoMatches)
    {
        // Mouse is over empty space in the listbox so hide tooltip
        _toolTip.Hide(this);
        _currentItemSet = false;
        _toolTipDisplayed = false;
        _toolTipDisplayTimer.Stop();
    }
    else if (!_currentItemSet)
    {
        // Mouse is over a new item so start timer to display tooltip
        _currentItem = itemIndex;
        _currentItemSet = true;
        _toolTipDisplayTimer.Start();
    }
    else if (itemIndex != _currentItem)
    {
        // Mouse is over a different item so hide tooltip and restart timer
        _currentItem = itemIndex;
        _toolTipDisplayTimer.Stop();
        _toolTipDisplayTimer.Start();
        _toolTip.Hide(this);
        _toolTipDisplayed = false;
    }
}

This event is raised whenever the mouse is over the listbox (whether it's moving or not). First, we determine which item index the mouse is over. We can use the PointToClient() and IndexFromPoint() methods of the listbox to get this. Now, we have several cases depending on the index that the mouse is over:

itemIndex == ListBox.NoMatches

This condition is satisfied when the mouse is over empty space in the listbox. This means that we should hide the tooltip and stop the tooltip display timer.

!_currentItemSet

This condition is satisfied when the mouse has just began moving over a listbox item. In this case, we want to set the current item and start the timer to display the tooltip.

itemIndex != _currentItem

This condition is satisfied when the mouse has moved over a new item that is different from the currently set one. In this case, we should set the current item to the new item, hide the tooltip if it's currently being displayed and restart the tooltip display timer.

private void listBox_MouseLeave(object sender, EventArgs e)
{
    // Mouse has left listbox so stop timer (tooltip is automatically hidden)
    _currentItemSet = false;
    _toolTipDisplayed = false;
    _toolTipDisplayTimer.Stop();
} 

The MouseLeave event is raised when the mouse is no longer over the listbox. In this case, we want to reset the current item and stop the tooltip display timer.

void _toolTipDisplayTimer_Tick(object sender, EventArgs e)
{
    // Display tooltip text since the mouse has hovered over an item
    if (!_toolTipDisplayed && _currentItem != ListBox.NoMatches && 
				_currentItem < this.Items.Count)
    {
        IToolTipDisplayer toolTipDisplayer = this.Items[_currentItem] as IToolTipDisplayer;
        if (toolTipDisplayer != null)
        {
            _toolTip.SetToolTip(this, toolTipDisplayer.GetToolTipText());
            _toolTipDisplayed = true;
        }
    }
} 

The Tick event of the timer is raised after the standard mouse hover time has passed. When this happens, we know that the mouse has been on the same item for some time so we should display the tooltip for that item. The tooltip text for the item is obtained by calling the GetToolTipText() method of the current item. Of course, this will only work if the item has implemented the IToolTipDisplayer interface.

Conclusion

That's it! The complete code listed here is available in the attached .zip file. The project was created using Visual C# 2010 Express. There are several other ways of displaying tooltips, but I found that this way is clean since it hides the implementation details in a custom control. The ToolTipListBox control can be added to a form just like any built-in control and the IToolTipDisplayer interface can be added to any existing object that you add to the listbox.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Mehul Dhorda
Software Developer
United States United States
I have been developing software for several years, both personally and professionally. These days, I'm mostly coding in C++, C#, Objective-C and Python. In my spare time, I can usually be found playing video games, reading books, bicycling and hiking.
Follow on   Twitter   LinkedIn

Comments and Discussions

 
GeneralMy vote of 5 PinmemberBritteandy26-Jul-13 1:10 
GeneralMy vote of 5 PinmvpKanasz Robert27-Sep-12 11:04 
GeneralRe: My vote of 5 PinmemberMehul Dhorda29-Sep-12 12:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140827.1 | Last Updated 15 Sep 2012
Article Copyright 2012 by Mehul Dhorda
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid