本文重构了ToolTip组件,只为可以在上面显示图片所作,具体参考如下代码:
重写ToolTip
using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; using System; using System.Diagnostics; using System.ComponentModel; namespace CustomToolTipDemo { /// /// CustomizedToolTip to create tooltips with Image. /// internal class CustomizedToolTip : ToolTip { #region Constants /// /// 边框的粗细度 /// private const int BORDER_THICKNESS = 2; #endregion #region Fields private static Color myBorderColor = Color.Red; private static Font myFont = new Font("Arial", 8); private StringFormat myTextFormat = new StringFormat(); private Rectangle myImageRectangle = new Rectangle(); private Rectangle myToolTipRectangle = new Rectangle(); private Brush myBackColorBrush = new SolidBrush(Color.LightYellow); private Brush myTextBrush = new SolidBrush(Color.Black); private Brush myBorderBrush = new SolidBrush(myBorderColor); private Size mySize = new Size(500, 500); #endregion #region Properties /// /// 获取或设置一个值,该值指示工具提示是由操作系统绘制还是由您提供的代码绘制。若是true,表示ToolTipIcon和ToolTipTitle这两个属性值将被设为默认值并且工具提示将显示图片,否则将只显示文本提示信息 /// public new bool OwnerDraw { get { return base.OwnerDraw; } set { if (value) { this.ToolTipIcon = ToolTipIcon.None; this.ToolTipTitle = string.Empty; } base.OwnerDraw = value; } } /// /// 获取或设置一个值,该值定义要在工具提示文本旁显示的图标的类型。当OwnerDraw属性值为true时,无法设置该属性 /// public new ToolTipIcon ToolTipIcon { get { return base.ToolTipIcon; } set { if (!OwnerDraw) { base.ToolTipIcon = value; } } } /// /// 获取或设置工具提示窗口的标题。当OwnerDraw属性值为true时,无法设置该属性 /// public new string ToolTipTitle { get { return base.ToolTipTitle; } set { if (!OwnerDraw) { base.ToolTipTitle = value; } } } /// /// 获取或设置工具提示的背景色 /// public new Color BackColor { get { return base.BackColor; } set { base.BackColor = value; Brush temp = myBackColorBrush; myBackColorBrush = new SolidBrush(value); temp.Dispose(); } } /// /// 获取或设置工具提示的前景色 /// public new Color ForeColor { get { return base.ForeColor; } set { base.ForeColor = value; Brush temp = myTextBrush; myTextBrush = new SolidBrush(value); temp.Dispose(); } } /// /// 获取或设置工具提示窗口的大小 /// public Size Size { get { return mySize; } set { mySize = value; myToolTipRectangle.Size = mySize; } } /// /// 获取或设置工具提示窗口边框的颜色 /// public Color BorderColor { get { return myBorderColor; } set { myBorderColor = value; Brush temp = myBorderBrush; myBorderBrush = new SolidBrush(value); temp.Dispose(); } } #endregion #region Constructor /// /// 构造一个可以显示图片的ToolTip类实例 /// public CustomizedToolTip() { try { this.OwnerDraw = true; myTextFormat.FormatFlags = StringFormatFlags.LineLimit; myTextFormat.Alignment = StringAlignment.Near; myTextFormat.LineAlignment = StringAlignment.Center; myTextFormat.Trimming = StringTrimming.None; this.Popup += new PopupEventHandler(CustomizedToolTip_Popup); this.Draw += new DrawToolTipEventHandler(CustomizedToolTip_Draw); } catch (Exception ex) { string logMessage = "Exception in CustomizedToolTip.CustomizedToolTip () " + ex.ToString(); Trace.TraceError(logMessage); throw; } } #endregion #region Methods /// /// 释放组件 /// protected override void Dispose(bool disposing) { try { try { if (disposing) { if (myFont != null) { myFont.Dispose(); } if (myTextBrush != null) { myTextBrush.Dispose(); } if (myBackColorBrush != null) { myBackColorBrush.Dispose(); } if (myBorderBrush != null) { myBorderBrush.Dispose(); } if (myTextFormat != null) { myTextFormat.Dispose(); } } } finally { base.Dispose(disposing); } } catch (Exception ex) { string logMessage = "Exception in CustomizedToolTip.Dispose (bool) " + ex.ToString(); Trace.TraceError(logMessage); throw; } } /// /// 当绘制工具提示提示并且OwnerDraw属性设置为true时发生 /// void CustomizedToolTip_Draw(object sender, DrawToolTipEventArgs e) { try { e.Graphics.CompositingQuality = CompositingQuality.HighQuality; myToolTipRectangle.Size = e.Bounds.Size; //this condition add @2010-11-23 if (myToolTipRectangle.Width == 540) //抑制listview项的自带提示信息覆盖图片 { e.Graphics.FillRectangle(myBorderBrush, myToolTipRectangle); myImageRectangle = Rectangle.Inflate(myToolTipRectangle, -BORDER_THICKNESS, -BORDER_THICKNESS); e.Graphics.FillRectangle(myBackColorBrush, myImageRectangle); Control parent = e.AssociatedControl; Image toolTipImage = parent.Tag as Image; if (toolTipImage != null) { e.Graphics.DrawImage(toolTipImage, myImageRectangle); } else { e.Graphics.DrawString(e.ToolTipText, myFont, myTextBrush, myImageRectangle, myTextFormat); } } } catch (Exception ex) { string logMessage = "Exception in CustomizedToolTip.BlindHeaderToolTip_Draw (object, DrawToolTipEventArgs) " + ex.ToString(); Trace.TraceError(logMessage); throw; } } /// /// 在工具提示最初显示之前发生 /// void CustomizedToolTip_Popup(object sender, PopupEventArgs e) { try { if (OwnerDraw) { e.ToolTipSize = mySize; } } catch (Exception ex) { string logMessage = "Exception in CustomizedToolTip.CustomizedToolTip_Popup (object, PopupEventArgs) " + ex.ToString(); Trace.TraceError(logMessage); throw; } } #endregion } }
实例:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using CustomToolTipDemo.Properties; namespace CustomToolTipDemo { public partial class Form1 : Form { /// /// 构造一个可以显示图片的ToolTip类实例 /// CustomizedToolTip myToolTip = new CustomizedToolTip(); public Form1() { InitializeComponent(); // 设定工具提示窗口的大小 myToolTip.Size = new Size(600, 300); } /// /// 当鼠标悬停于某项上时,给出带有图片的提示信息 /// private void listView1_ItemMouseHover(object sender, ListViewItemMouseHoverEventArgs e) { switch (e.Item.Text) //根据项的文本值提示相应信息 { case "item1": myToolTip.SetToolTip(listView1, "Title"); listView1.Tag = Resources.Image1; //设定要提示的图片 break; case "item2": myToolTip.SetToolTip(listView1, "Title"); listView1.Tag = Resources.Image2; break; default: break; } } /// /// 当鼠标处于“无项区域”时,立即“隐藏”提示信息窗口 /// private void listView1_MouseMove(object sender, MouseEventArgs e) { ListViewHitTestInfo info = listView1.HitTest(e.Location); if (info.Item == null) //是否处于“无项区域” { myToolTip.SetToolTip(listView1, ""); listView1.Tag = null; } } } }
最后,会有一个问题:比如listView上有项item1、item2、…如本例给出的参考代码,当鼠标悬停于某项(如item1)上时,第一次可以正常显示带有图片的提示信息,然后我们在这个时候把鼠标移到“无项区域”,然后再把鼠标悬停于item1,此时我们会发现没有提示信息出现,只有先移到其他项(如item2)后再悬停于item1时,才会使提示信息重现。本人愚昧,这个问题还不得而解,还请各位不吝赐教。。
///ADD @2010-11-15
昨日的问题终于得到解决,无需ItemMouseHover事件,只需MouseMove外加一个全局变量tooltipOn用来保存当前提示信息项 即可。具体参考如下代码:
/// /// 当前提示信息项 /// ListViewItem tooltipOn; /// /// 根据项文本内容显示带有图片的提示信息 /// private void listView1_MouseMove(object sender, MouseEventArgs e) { ListViewItem item = listView1.HitTest(e.Location).Item; if (item != null) { //如果不是当前提示信息项,更新提示信息及提示信息项 if (item != tooltipOn) { switch (item.Text) //根据项的文本值提示相应信息 { case "item1": //设定要提示的图片 listView1.Tag = Resources.Image1; break; case "item2": listView1.Tag = Resources.Image2; break; default: break; } showToolTip(Cursor.Position, e.Location); tooltipOn = item; } } else //若鼠标处于“无项区域”,则清空提示信息相关的信息 { myToolTip.Hide(listView1); listView1.Tag = null; tooltipOn = null; } } #region 根据所在位置显示tooltip /// /// 根据所在位置显示tooltip /// /// 当前屏幕坐标点 /// 当前ListView坐标点 private void showToolTip(Point screenPos, Point listViewPos) { if (screenPos.X + 540 > Screen.AllScreens[0].WorkingArea.Width) //越过工作区右边界 { int X = listViewPos.X - (540 + 5); //定位提示信息的左边界 if (X < listViewPos.X - screenPos.X + 5) //越过左边界 { X = listViewPos.X - screenPos.X + 5; //定位左边界位于工作区左边界offset=5 } if (screenPos.Y + 235 > Screen.AllScreens[0].WorkingArea.Height) //越过工作区下边界 { //鼠标左上区域显示tooltip myToolTip.Show("Caption", listView1, X, listViewPos.Y - (235 + 5)); } else { //鼠标左下区域显示tooltip myToolTip.Show("Caption", listView1, X, listViewPos.Y + 5); } } else if (screenPos.X - 540 < 0) //越过工作区左边界 { if (screenPos.Y + 235 > Screen.AllScreens[0].WorkingArea.Height) //越过工作区下边界 { //鼠标右上区域显示tooltip myToolTip.Show("Caption", listView1, listViewPos.X + 5, listViewPos.Y - (235 + 5)); } else { //鼠标右下区域显示tooltip myToolTip.Show("Caption", listView1, listViewPos.X + 5, listViewPos.Y + 5); } } else //默认都是在鼠标右下区域显示tooltip { myToolTip.Show("Caption", listView1, listViewPos.X + 5, listViewPos.Y + 5); } } #endregion //说明上面的540和235是提示信息中图片的宽和高
注: 如果不用一个全局变量来保存当前提示信息项,也就是把if (item != tooltipOn) 这个判断逻辑拿掉,提示信息则会一直不停的闪烁。。