如果ComboBox宽度不够,需要鼠标经过时显示完整提示,就添加鼠标经过事件。
如果希望点击下拉时也显示提示,重写ComboBox添加鼠标经过提示。
private void comboBoxEx1_MouseHover(
object sender, EventArgs e)
{
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;
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: