ComboBox的ToolTip显示


ComboBox的ToolTip显示
2010年06月17日
  在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 comboBoxApp
  ...{
  /**//// 
  /// 可带ToolTip的组合框控件
  /// 
  public class ComboBoxEx : ComboBox
  ...{
  /**//// 
  /// 这个子类窗口用来存放下拉列表窗口,通过它来操作下拉列表
  /// 
  private SubWindow m_SubWindow;
  /**//// 
  /// 通常的构造函数
  /// 
  public ComboBoxEx()
  ...{
  }
  /**//// 
  /// 处理Windows的消息
  /// 
  /// 
  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);
  }
  /**//// 
  /// 重写以释放子类
  /// 
  /// 
  protected override void Dispose(bool disposing)
  ...{
  if (disposing && this.m_SubWindow != null)
  ...{
  this.m_SubWindow.DestroyHandle();
  }
  base.Dispose(disposing);
  }
  }
  /**//// 
  /// 子类化窗口的类
  /// 
  internal class SubWindow : NativeWindow
  ...{
  /**//// 
  /// 为了得到列表上的鼠标坐标而使用Api函数及其所用到的数据结构
  /// 
  [StructLayout(LayoutKind.Sequential)]
  public class POINT
  ...{
  public int x;
  public int y;
  public POINT(int x, int y)
  ...{
  this.x = x;
  this.y = y;
  }
  }
  /**//// 
  /// 映射窗体的坐标
  /// 
  /// 源窗口句柄
  /// 要影射到的窗口句柄
  /// 转换前后的坐标数据
  /// 
  /// 
  [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
  public static extern int MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, [In, Out] POINT pt, int cPoints);
  /**//// 
  /// 为了得到指定坐标下的项而需要向列表发送消息
  /// 
  /// 
  /// 
  /// 
  /// 
  /// 
  [DllImport("user32.dll", CharSet = CharSet.Auto)]
  public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
  /**//// 
  /// 为了得到指定索引的列表的内容而需要向列表发送消息,因为列表文本可能被格式化,所以这是合理的。
  /// 
  /// 
  /// 
  /// 
  /// 
  /// 
  [DllImport("user32.dll", CharSet = CharSet.Auto)]
  public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, StringBuilder lParam);
  /**//// 
  /// 上一索引值
  /// 
  private int m_Index;
  /**//// 
  /// 用来显示信息ToolTip
  /// 
  private ToolTip toolTip;
  /**//// 
  /// 所属性的ComboBox
  /// 
  private Control m_Owner;
  /**//// 
  /// 构造函数
  /// 
  public SubWindow()
  ...{
  this.m_Index = -1;
  this.toolTip = new ToolTip();
  }
  /**//// 
  /// 所属的控件
  /// 
  public Control Owner
  ...{
  get ...{ return m_Owner; }
  set ...{ m_Owner = value; }
  }
  /**//// 
  /// 处理鼠标的消息以显示ToolTip信息
  /// 
  /// 
  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) & 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);
  }
  }
  }

猜你喜欢

转载自tze49tze.iteye.com/blog/1361156
今日推荐