为ListBox的每一项添加提示

原文:http://www.codeproject.com/Articles/457444/List-box-control-with-tooltip-for-each-item

Introduction 简介

This article describes a way of displaying tooltips for items in a Windows Forms ListBox control. The built-in ToolTipcontrol 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.

本文描述了给WinForm的ListBox控件每项添加显示提示信息的一种方式。自带的ToolTipControl允许你为整个listbox显示一个单个的信息。然而,要是想单独为listbox每项显示提示就没这么幸运了。所幸的是,你自己来模拟下这个提示方式并不太难。这里我们将看下如何创建使用一个叫ToolTipListBox的自定义的ListBox控件。

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 sectinos. The code consists of the following parts:  

文章包含用于创建一个每项带不同提示的listbox所需的完整的代码。随后章节我们深入了解这个代码。这个代码有下面几部分组成:

  1. Adding ListBoxItem objects to the ToolTipListBox control. 给ToolTipListBox添加ListBoxItem项
  2. ListBoxItem class.ListBoxItem类
  3. IToolTipDisplayer interface. IToolTipDisplayer接口
  4. ToolTipListBox class. ToolTipListBox类

Adding ListBoxItem objects to the ToolTipListBox 

 1 // Create list of items 创建项目的列表
 2 ListBoxItem[] items = new ListBoxItem[]
 3 {
 4     new ListBoxItem("Apple",     "Malus pumila"),
 5     new ListBoxItem("Banana",    "Porcelia macrocarpa"),
 6     new ListBoxItem("Kiwi",      "Actinidia deliciosa"),
 7     new ListBoxItem("Papaya",    "Carica papaya"),
 8     new ListBoxItem("Mango",     "Mangifera indica"),
 9     new ListBoxItem("Tomato",    "Lycopersicon esculentum"),
10     new ListBoxItem("Lychee",    "Litchi chinensis"),
11     new ListBoxItem("Coconut",   "Cocos nucifera"),
12     new ListBoxItem("Tangerine", "Citrus reticulata"),
13     new ListBoxItem("Avocado",   "Persea americana"),
14 };
15  
16 // Populate list box 填充ListBox的数据
17 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对象并把它们添加到ToolTipListBox控件。每个ListBoxItem的构造方法都携带listbox里显示的文本和提示文本2个参数。

ListBoxItem class

 1 internal class ListBoxItem : IToolTipDisplayer
 2 {
 3     public string DisplayText { get; private set; }
 4     public string ToolTipText { get; private set; }
 5  
 6     // Constructor 构造方法
 7     public ListBoxItem(string displayText, string toolTipText)
 8     {
 9         DisplayText = displayText;
10         ToolTipText = toolTipText;
11     }
12  
13     // Returns the display text of this item. 重写ToString()返回项目的显示文本
14     public override string ToString()
15     {
16         return DisplayText;
17     }
18     // Returns the tooltip text of this item. 返回该项目的提示信息
19     public string GetToolTipText()
20     {
21         return ToolTipText;
22     }
23 }

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.ListBoxItem这个类比较简单用来表示listbox里的每一项。重写了Object的ToString()方法返回的文本用于在listbox里显示。而GetToolTipText()方法返回每一项显示的提示文本。它实现了IToolTipDisplayer接口,这个接口我们下面再描述。

IToolTipDisplayer interface 

1 /// Interface used by listbox items in ToolTipListBox. 
2 internal interface IToolTipDisplayer
3 {
4     string GetToolTipText();
5 }

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 implementsIToolTipDisplayer.IToolTipDisplayer接口由ToolTipListBox用来获取每项都提示文本。这个接口就有一个方法,用来返回显示的提示文本。任何要添加到该listbox的对象都要实现这个接口来显示提示文本。正如上面所示,这个ListBoxItem类实现了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:

好了现在我们进入今天文章的主题,实现ToolTipListBox.首先我们声明这个类和一些成员变量:

 1 /// ListBox that displays item-specific tooltips.
 2 internal partial class ToolTipListBox : ListBox
 3 {
 4     // The item index that the mouse is currently over鼠标当前停留的项目的索引
 5     private int _currentItem;
 6  
 7     // A value indicating if the current item has been set一个值指示当前项是否设置
 8     private bool _currentItemSet;
 9  
10     // A value indicating if a tooltip is currently being displayed指示当前是否显示了提示
11     private bool _toolTipDisplayed;
12  
13     // Timer that is used to wait for the mouse to hover over an item一个Timer用来等待鼠标滑过一个项目
14     private Timer _toolTipDisplayTimer;
15  
16     // Tooltip control
17     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:
目前为止都很顺利。该类扩展了内置的ListBox控件添加了提示功能。现在让我们来定义下构造方法:

 1 public ToolTipListBox()
 2 {
 3     InitializeComponent();
 4  
 5     this.MouseMove += listBox_MouseMove;
 6     this.MouseLeave += listBox_MouseLeave;
 7             
 8     _currentItemSet = false;
 9     _toolTipDisplayed = false;
10     _toolTipDisplayTimer = new Timer();
11     _toolTip = new ToolTip();
12  
13     // Set the timer interval to the system time that it takes for a tooltip to appear
14     _toolTipDisplayTimer.Interval = SystemInformation.MouseHoverTime;
15     _toolTipDisplayTimer.Tick += _toolTipDisplayTimer_Tick;
16 }

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:

 1 private void listBox_MouseMove(object sender, MouseEventArgs e)
 2 {
 3     // Get the item that the mouse is currently over 得到鼠标当前悬停的列表项
 4     Point cursorPoint = Cursor.Position;//这里得到的是屏幕坐标
 5     cursorPoint = this.PointToClient(cursorPoint);//需要把屏幕坐标转成客户坐标
 6     int itemIndex = this.IndexFromPoint(cursorPoint);//根据坐标位置获取列表项索引号
 7  
 8     if (itemIndex == ListBox.NoMatches)
 9     {
10         // Mouse is over empty space in the listbox so hide tooltip 如果鼠标在listbox的空白区域的话,则隐藏提示框
11         _toolTip.Hide(this);
12         _currentItemSet = false;
13         _toolTipDisplayed = false;
14         _toolTipDisplayTimer.Stop();
15     }
16     else if (!_currentItemSet)
17     {
      //_currentItemSet==false
18 // Mouse is over a new item so start timer to display tooltip 鼠标移到一个新的项目上,所以启动定时器来显示提示框 19 _currentItem = itemIndex; 20 _currentItemSet = true; 21 _toolTipDisplayTimer.Start(); 22 } 23 else if (itemIndex != _currentItem) 24 { 25 // Mouse is over a different item so hide tooltip and restart timer 如果鼠标移到另一个项目时隐藏当前提示框,并重启定时器 26 _currentItem = itemIndex; 27 _toolTipDisplayTimer.Stop(); 28 _toolTipDisplayTimer.Start(); 29 _toolTip.Hide(this); 30 _toolTipDisplayed = false; 31 } 32 }

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.

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

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.

 1 void _toolTipDisplayTimer_Tick(object sender, EventArgs e)
 2 {
 3     // Display tooltip text since the mouse has hovered over an item
 4     if (!_toolTipDisplayed && _currentItem != ListBox.NoMatches && _currentItem < this.Items.Count)
 5     {
 6         IToolTipDisplayer toolTipDisplayer = this.Items[_currentItem] as IToolTipDisplayer;
 7         if (toolTipDisplayer != null)
 8         {
 9             _toolTip.SetToolTip(this, toolTipDisplayer.GetToolTipText());
10             _toolTipDisplayed = true;
11         }
12     }
13 }

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.

 

 

 

 

 

 

 

posted @ 2012-11-23 13:50  xcf007  阅读(670)  评论(0编辑  收藏  举报