In Depth Banner
Skip Navigation Links

Select your preferred language

The NWTip class

using System;

using System.Collections;

using System.ComponentModel;

using System.Drawing;

using System.Windows.Forms;

using System.Runtime.InteropServices;

 

namespace WellFormed

{

  /// <summary>

  /// this extender-provider component also implements the custom interface

  /// IWndProcProvider so that it can interact with the ExtNativeWindow class. 

  /// </summary>

  [

  ProvideProperty("TipText","System.Windows.Forms.Control"),

  ProvideProperty("TipColor","System.Windows.Forms.Control"),

  ProvideProperty("TipTextColor","System.Windows.Forms.Control"),

  ProvideProperty("TipFont","System.Windows.Forms.Control"),

  ProvideProperty("TipBorderColor","System.Windows.Forms.Control")

  ]

  public class NWTip : Component, IExtenderProvider, IWndProcProvider

  {

 

    #region Interop

 

    [DllImport("User32.dll")]

    public extern static int ShowWindow( System.IntPtr hWnd, short cmdShow);

 

    [DllImport("User32.dll")]

    public extern static int ValidateRect( System.IntPtr hWnd, System.IntPtr rect);

 

    #endregion

 

    #region Fields

    //The NativeWindow member

    ExtNativeWindow _nw;

    //hash table that associates controls with tool tip data

    Hashtable _items=new Hashtable();

    //a reference to the current control. this is the control in which the cursor is hovering 

    Control _currentControl;

    //timer, used to remove the tool tip after a short interval. 

    Timer _killTimer;

    //A rectangle calculated from the size of the text. 

    Rectangle _tipRect;

    #endregion

 

    #region tooltip data container

 

    /// <summary>

    /// This class maintains all the properties associated with each control. 

    /// The hash table associates this class with the control using a reference as a key. 

    /// </summary>

    protected class tipData

    {

      string _text;

      public string Text

      {

        get{return _text;}

        set{_text=value;}

      }

 

      Color _tipColor=Color.Yellow;

      public Color TipColor

      {

        get{return _tipColor;}

        set{_tipColor=value;}

      }

 

      Color _textColor=Color.Black;

      public Color TextColor

      {

        get{return _textColor;}

        set{_textColor=value;}

      }

 

      Font _font=SystemInformation.MenuFont;

      public Font Font

      {

        get{return _font;}

        set{_font=value;}

      }

 

      Color _borderColor=Color.Black;

      public Color BorderColor

      {

        get{return _borderColor;}

        set{_borderColor=value;}

      }

 

    }

    #endregion

 

    #region Construction - disposal

 

    //when constructed, the class creates a new ExtNativeWindow

    public NWTip()

    {

      _nw=new ExtNativeWindow(this);

    }

 

    //The dispose method has to ensure that all the event handlers are removed from

    //the components that were extended.  

    protected override void Dispose(bool disposing)

    {

      if(disposing)

      {

        foreach(Control c in _items.Keys)

        {

          c.MouseHover-=new EventHandler(this.c_MouseHover);

          c.MouseLeave-=new EventHandler(this.c_MouseLeave);

        }

 

        this._items.Clear();

      }

      base.Dispose (disposing);

    }

    #endregion

 

    #region IExtenderProvider Members

 

    //This component can extend control. 

    public bool CanExtend(object extendee)

    {

      return extendee is Control;

    }

 

    //A utility routing to extract tipData from the hash table using the

    //Control  reference as a key. 

    protected tipData GetItem(Control c)

    {

      if(this._items.Contains(c))

        return (tipData)_items[c];

      tipData td=new tipData();

      _items[c]=td;

      c.MouseHover+=new EventHandler(c_MouseHover);

      c.MouseLeave+=new EventHandler(c_MouseLeave);

      return td;

    }

 

    /*

     * The following ten methods implement the set and get methods for each of the extended

     * properties that we provide to control based classes. 

     *

     */

 

    public void SetTipText(Control c, string value)

    {

      tipData td=GetItem(c);

      td.Text=value;

    }

 

    public void SetTipColor(Control c, Color value)

    {

      tipData td=GetItem(c);

      td.TipColor=value;

    }

    

    public void SetTipTextColor(Control c, Color value)

    {

      tipData td=GetItem(c);

      td.TextColor=value;

    }

 

    public void SetTipFont(Control c, Font value)

    {

      tipData td=GetItem(c);

      td.Font=value;

    }

 

    public void SetTipBorderColor(Control c, Color value)

    {

      tipData td=GetItem(c);

      td.BorderColor=value;

    }

 

    public string GetTipText(Control c)

    {

      tipData td=GetItem(c);

      return td.Text;

    }

 

    public Color GetTipColor(Control c)

    {

      tipData td=GetItem(c);

      return td.TipColor;

    }

    

    public Color GetTipTextColor(Control c)

    {

      tipData td=GetItem(c);

      return td.TextColor;

    }

 

    public Font GetTipFont(Control c)

    {

      tipData td=GetItem(c);

      return td.Font;

    }

 

    public Color GetTipBorderColor(Control c)

    {

      tipData td=GetItem(c);

      return td.BorderColor;

    }

 

    #endregion

 

    #region IWndProcProvider Members

 

    //Implements the IWndProcProvider interface which enables any class to host an ExtNativeWindow

    //Note. It is important to call the default WndProc for any messages not processed by this method. 

    void WellFormed.IWndProcProvider.WndProc(ref Message m, ExtNativeWindow defWndProcProvider)

    {

      switch(m.Msg)

      {

        case (int)WmDefs.WM_PAINT:

          PaintTooltip(ref m);

          break;

        default:

          defWndProcProvider.DefWndProc(ref m);

          break;

      }

    }

 

    #endregion

 

    #region Extended control mouse handlers

 

    //Handles the MouseHover event from the control been extended. 

    //this enables the extender-provider to know when the mouse cursor is in a control. 

    private void c_MouseHover(object sender, EventArgs e)

    {

      _currentControl=(Control)sender;

      if(_killTimer!=null)

      {

        _killTimer.Enabled=false;

        _killTimer.Dispose();

        _killTimer=null;

        _nw.DestroyHandle();

      }

      ShowTip();

    }

 

    //Handles the MouseLeave event from the control be extended.

    //This enables the extender-provider to know when the mouse cursor has left the

    //control and hence, when to destroy the tool tip window. 

    private void c_MouseLeave(object sender, EventArgs e)

    {

      if(sender == _currentControl)

      {

        _killTimer=new Timer();

        _killTimer.Interval=100;

        _killTimer.Tick+=new EventHandler(_killTimer_Tick);

        _killTimer.Enabled=true;

      }

    }

    #endregion

 

    #region Painting

 

    //A simple paint routine.  This fills the window with the background color,

    //paints the border, the text and finally validates the rectangle of the window. 

    protected void PaintTooltip(ref Message m)

    {

      tipData td=this.GetItem(this._currentControl);

      Graphics g=Graphics.FromHwnd(_nw.Handle);

      g.Clear(td.TipColor);

      Pen p=new Pen(td.BorderColor,_tipRect.Height/100);

      g.DrawRectangle(p,0,0,_tipRect.Width-1,_tipRect.Height-1);

      p.Dispose();

      SolidBrush sb=new SolidBrush(td.TextColor);

      g.DrawString(td.Text,td.Font,sb,_tipRect.Width/20,_tipRect.Height/20,StringFormat.GenericTypographic);

      sb.Dispose();

      g.Dispose();

      m.Result=IntPtr.Zero;

      ValidateRect(m.HWnd,IntPtr.Zero);

    }

    #endregion

 

    #region low-level window management

 

    //The windows creation parameters. 

    protected CreateParams CreateParams

    {

      get

      {

        System.Windows.Forms.CreateParams cp=new System.Windows.Forms.CreateParams();

        unchecked

        {

          cp.Style = (int)WindowStyles.WS_POPUP;

        }

        cp.ClassStyle=(int)ClassStyles.CS_OWNDC | (int)ClassStyles.CS_HREDRAW | (int)ClassStyles.CS_VREDRAW;

        cp.ExStyle=(int)WindowStyles.WS_EX_TOPMOST;

        cp.ClassName="tooltips_class32";

        cp.X=0;

        cp.Y=0;

        cp.Height=0;

        cp.Width=0;

        cp.Parent=System.IntPtr.Zero;

 

        cp.Caption=null;

        return cp;

      }

    }

 

    //This handles the time out from the timer which is set whenever the cursor leaves a control.

    //It destroys the tool tip window. 

    private void _killTimer_Tick(object sender, EventArgs e)

    {

      ((Timer)sender).Enabled=false;

      _nw.DestroyHandle();

    }

 

    //Called by the mouse hover Handler to display the tool tip window.

    private void ShowTip()

    {

      CreateParams cp=this.CreateParams;

      Graphics g = Graphics.FromHwnd(IntPtr.Zero);

      tipData td = (tipData)_items[this._currentControl];

      SizeF sf=g.MeasureString(td.Text,td.Font,1024,StringFormat.GenericTypographic);

      Point position =Control.MousePosition;

      Rectangle rc=new Rectangle(position.X,(int)(position.Y+SystemInformation.CursorSize.Height),(int)sf.Width,(int)sf.Height);

      rc.Inflate(rc.Width/10,rc.Height/10);

      _tipRect=rc;

      if(rc.Right>SystemInformation.VirtualScreen.Right)

        rc.Offset(-(rc.Right-SystemInformation.VirtualScreen.Right),0);

      if(rc.Bottom>SystemInformation.VirtualScreen.Bottom)

        rc.Offset(0,-((rc.Bottom-SystemInformation.VirtualScreen.Bottom)+rc.Height+SystemInformation.CursorSize.Height));

      if(rc.Left<10)

        rc.X=10;

      cp.X=rc.X;

      cp.Y=rc.Y;

      cp.Width=rc.Width;

      cp.Height=rc.Height;

      _nw.CreateHandle(cp);

      ShowWindow(_nw.Handle,(short)WellFormed.ShowWindow.SW_SHOWNOACTIVATE);

    }

    #endregion

 

  }

}

 

Use the Back button to return to the article.

Copyright © Bob Powell 2003-2009. All rights reserved