
如果ComboBox寬度不夠,需要鼠標經過時顯示完整提示,就添加鼠標經過事件。
如果希望點擊下拉時也顯示提示,重寫ComboBox添加鼠標經過提示。
{
toolTip1.SetToolTip(comboBoxEx1, comboBoxEx1.Text);
}
在Windows應用程序中使用ToolTip控件給ComboBox控件顯示提示的信息,往往要求的不是直接給控件一個固定的ToolTip提示,可能更多的時候要給ComboBox的下拉列表的項添加提示。可是默認的Combobox控件並不提供這個功能。見到網上有了這方面的做法,但是總覺得“不太可靠”。。。
我們知道對於ComboBox來說,其實他不像TextBox或Button一樣有一個句柄,它有多於一個句柄,一個是ComboBox本身,一個是處理編輯狀態的編輯框的文本的句柄,一個是下拉出來的“列表”的句柄。其實確實是這樣的。一個ComboBox是一個“復合”控件,由文本框和下拉列表組成。就是這個下拉列表有着非常吸引人的地方,可在程序里通過一般的方法又很難訪問到它,所以ComboBox控件變得好像是Windows控件中“最神秘”的控件之一。
因為我們確實需要給ComboBox的下拉列表項添加ToolTip。既然我們知道了這個下拉列表是一個“ListBox”那么我們就有了訪問它的方法:使用Listbox的相關方法(API)來操作就可以了。比如我們可以通過在ListBox上的坐標得到坐標下的項所在的Items的索引,由這個索引就可以得到Items中的第幾個元素的內容。因為ToolTip都是通過鼠標在其上的時候顯示出來的,所以我們可通過這個方法得到當前鼠標下的ListBox的元素的索引,有了這個“難得”的索引就可以動態的顯示出項的ToolTip了。代碼參考如下:
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Threading;
namespace WinLib
{
/// <summary>
/// 可帶ToolTip的組合框控件
/// </summary>
public class ComboBoxEx : ComboBox
{
/// <summary>
/// 這個子類窗口用來存放下拉列表窗口,通過它來操作下拉列表
/// </summary>
private SubWindow m_SubWindow;
/// <summary>
/// 通常的構造函數
/// </summary>
public ComboBoxEx()
{
}
/// <summary>
/// 處理Windows的消息
/// </summary>
/// <param name="m"></param>
protected override void WndProc( ref Message m)
{
// 通過這個消息可以得到下拉列表的窗口名柄
if (m.Msg == 0x210 && ( int)m.WParam == 0x3e80001)
{
// 構建子類化窗口
SubWindow sw = new SubWindow();
// 把當前ComboBox實例做為屬性傳入方便處理
sw.Owner = this;
// 把得到的列表句柄關聯到子類窗口類上。
sw.AssignHandle(m.LParam);
// 這里的做用是保證子類窗口和ComboBoxEx生存期同步
this.m_SubWindow = sw;
}
base.WndProc( ref m);
}
/// <summary>
/// 重寫以釋放子類
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose( bool disposing)
{
if (disposing && this.m_SubWindow != null)
{
this.m_SubWindow.DestroyHandle();
}
base.Dispose(disposing);
}
}
/// <summary>
/// 子類化窗口的類
/// </summary>
internal class SubWindow : NativeWindow
{
/// <summary>
/// 為了得到列表上的鼠標坐標而使用Api函數及其所用到的數據結構
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public class POINT
{
public int x;
public int y;
public POINT( int x, int y)
{
this.x = x;
this.y = y;
}
}
/// <summary>
/// 映射窗體的坐標
/// </summary>
/// <param name="hWndFrom"> 源窗口句柄 </param>
/// <param name="hWndTo"> 要影射到的窗口句柄 </param>
/// <param name="pt"> 轉換前后的坐標數據 </param>
/// <param name="cPoints"></param>
/// <returns></returns>
[DllImport( " user32.dll ", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern int MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, [In, Out] POINT pt, int cPoints);
/// <summary>
/// 為了得到指定坐標下的項而需要向列表發送消息
/// </summary>
/// <param name="hWnd"></param>
/// <param name="msg"></param>
/// <param name="wParam"></param>
/// <param name="lParam"></param>
/// <returns></returns>
[DllImport( " user32.dll ", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
/// <summary>
/// 為了得到指定索引的列表的內容而需要向列表發送消息,因為列表文本可能被格式化,所以這是合理的。
/// </summary>
/// <param name="hWnd"></param>
/// <param name="msg"></param>
/// <param name="wParam"></param>
/// <param name="lParam"></param>
/// <returns></returns>
[DllImport( " user32.dll ", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, StringBuilder lParam);
/// <summary>
/// 上一索引值
/// </summary>
private int m_Index;
/// <summary>
/// 用來顯示信息ToolTip
/// </summary>
private ToolTip toolTip;
/// <summary>
/// 所屬性的ComboBox
/// </summary>
private Control m_Owner;
/// <summary>
/// 構造函數
/// </summary>
public SubWindow()
{
this.m_Index = - 1;
this.toolTip = new ToolTip();
}
/// <summary>
/// 所屬的控件
/// </summary>
public Control Owner
{
get { return m_Owner; }
set { m_Owner = value; }
}
/// <summary>
/// 處理鼠標的消息以顯示ToolTip信息
/// </summary>
/// <param name="m"></param>
protected override void WndProc( ref Message m)
{
if (m.Msg == 0x200)
{
// 獲取鼠標坐標
Point msPoint = Cursor.Position;
POINT pt = new POINT(msPoint.X, msPoint.Y);
// 影射到列表上的坐標
MapWindowPoints(IntPtr.Zero, this.Handle, pt, 1);
// 獲取鼠標下的項的索引
int index = SendMessage(m.HWnd, 0x1a9, 0, (pt.y << 0x10) | (pt.x & 0xffff));
if (((index >> 0x10) & 0xffff) == 0)
{
index = (index & 0xffff);
if (m_Index != index)
{
// 獲取項的字符串的長度
int num = SendMessage( this.Handle, 0x18a, index, 0);
StringBuilder lParam = new StringBuilder(num + 1);
// 獲取項的字符串內容
SendMessage( this.Handle, 0x189, index, lParam);
// 獲取鼠標在所屬的控件的坐標信息
Point owPoint = this.Owner.PointToClient(msPoint);
// 設置ToolTip信息並顯示
this.toolTip.RemoveAll();
this.toolTip.Show(lParam.ToString(), this.Owner, owPoint.X + 10, owPoint.Y + 10, 1000);
m_Index = index;
}
}
}
base.WndProc( ref m);
}
}
}
url: http://greatverve.cnblogs.com/archive/2012/06/27/combobox-tooltip.html