8

I have a dynamically filled ContextMenuStrip where each ToolStripMenuItem has a formatted text for the tooltip. And, in order for this text to make sense to the user, I must use a monospaced font, such as "Courier New". The default font is a regular, non Monospaced font. I couldn't find any getter for the ToolTip object nor a way to override its Draw event nor a way to set its style.

So, is it even possible to change ToolStripMenuItem's tooltip font?

Implementing CustomToolTip that inherits from ToolTip doesn't solve the issue, which is passing the new tooltip to ToolStripMenuItem.

ElyaSh
  • 502
  • 2
  • 4
  • 13

3 Answers3

16

OK, thanks to Tony Abrams and William Andrus, the solution is as follows:

  • A static instance of ToolTip which initialized.

    toolTip = new ToolTip();
    toolTip.OwnerDraw = true;
    toolTip.Draw += new DrawToolTipEventHandler(tooltip_Draw);
    toolTip.Popup += new PopupEventHandler(tooltip_Popup);    
    toolTip.UseAnimation = true;
    toolTip.AutoPopDelay = 500;
    toolTip.AutomaticDelay = 500;
    
  • ToolTip's Popup event to set its size.

    void tooltip_Popup(object sender, PopupEventArgs e)
    {
        e.ToolTipSize = TextRenderer.MeasureText(toolTipText, new Font("Courier New", 10.0f, FontStyle.Bold));
        e.ToolTipSize = new Size(e.ToolTipSize.Width + TOOLTIP_XOFFSET, e.ToolTipSize.Height + TOOLTIP_YOFFSET);
    }
    
  • ToolTip's Draw event for actual drawing.

    void tooltip_Draw(object sender, DrawToolTipEventArgs e)
    {
    Rectangle bounds = e.Bounds;
    bounds.Offset(TOOLTIP_XOFFSET, TOOLTIP_YOFFSET);
    DrawToolTipEventArgs newArgs = new DrawToolTipEventArgs(e.Graphics, e.AssociatedWindow, e.AssociatedControl, bounds, e.ToolTipText, toolTip.BackColor, toolTip.ForeColor, new Font("Courier New", 10.0f, FontStyle.Bold));
        newArgs.DrawBackground();
        newArgs.DrawBorder();
        newArgs.DrawText(TextFormatFlags.TextBoxControl);
    }
    
  • ToolStripMenuItem's MouseEnter event to show the tooltip.

    System.Windows.Forms.ToolStripMenuItem item = (sender as System.Windows.Forms.ToolStripMenuItem);
    toolTip.SetToolTip(item.Owner, "ToolTipText");
    
Mickael Bergeron Néron
  • 1,472
  • 1
  • 18
  • 31
ElyaSh
  • 502
  • 2
  • 4
  • 13
  • 1
    +1 Thanks for posting the final solution! That way if someone else arrives here with the same question, they'll know how you solved it. I also formatted the code for you. The trick to getting the formatting to work within bullets is indenting 8 spaces, rather than the normal 4. – Cody Gray - on strike Jan 12 '11 at 13:54
  • I was looking for a solution for a slightly-related problem: showing a tooltip with custom text on some buttons of a toolstrip, but not on all of them. Didn't need the custom drawing, but disabling the toolstrip's built-in tooltips, and handling the ToolStripMenuItem's MouseEnter and MouseLeave to show the item's tooltip text iff it wasn't null or empty, worked great. – neminem Jun 29 '12 at 15:33
  • Worked great for me, although in some situations I ended up with an additional (blank) tooltip, this seemed to be when my window redrew the button controls that used the tooltips). To resolve this I ensured that my MouseLeave disposed the tooltip and re-created the tooltip in the MouseHover. Obviously needed a reference outside of both listeners for that to work. – RobbiewOnline Jan 08 '14 at 11:44
  • Nice work. Upvoted. In practice, with default settings, sometimes the border is not drawn properly which I assume is just another gift from Windows :) In .NET 4.5, I found it necessary to force the ToolTip to Hide in the Hover event-handler if it was 'Active: if(customToolTip.Active) customToolTip.Hide(); ... in order to get the tooltip to vanish as desired. – BillW Jun 28 '14 at 10:23
  • As ElyaSh said, Tony Abrams's answer and William Andrus's solution is a good solution for creating custom tooltip. – Mohsen Oct 11 '17 at 18:37
3

You could create a custom ToolTip class (CustomToolTip) that inherits from ToolTip. Then you would have to handle the OnDraw event. Inside that event you can change the font.

Look here for an example (there is a vb and c# example).

EDIT

You would have to handle the rendering of the custom tooltip on your own (IE: OnMouseOver, OnMouseLeave events of the toolstripmenuitem). You might be able to create a customtoolstripmenuitem that uses a custom tooltip, but I'm not sure that toolstripmenuitem exposes a tooltip propety/object.

Tony Abrams
  • 4,505
  • 3
  • 25
  • 32
  • The problem isn't with inheriting from ToolTip, but with providing it to ToolStripMenuItem. – ElyaSh Jan 11 '11 at 12:15
  • You would have to handle the rendering of the custom tooltip on your own (IE: OnMouseOver, OnMouseLeave events of the toolstripmenuitem). You might be able to create a customtoolstripmenuitem that uses a custom tooltip, but I'm not sure that toolstripmenuitem exposes a tooltip propety/object. – Tony Abrams Jan 11 '11 at 12:32
  • toolstripmenuitem not exposing a tooltip propety/object is the main reason I decided to ask the question here. – ElyaSh Jan 11 '11 at 12:38
  • And that's why I provided my answer of creating a custom ToolTip (where you can change the font settings) and then the update about you having to handle the rendering of the custom tooltip. Also, just because a default control does not expose a property that does not mean that it does not contain a private/internal (aka not exposed) property. – Tony Abrams Jan 11 '11 at 12:43
  • Sorry, I misunderstood your previous comment. Now it actually did give me a new direction according to which I found the following http://andrusdevelopment.blogspot.com/2007/10/implementing-custom-tooltip-in-c.html . Hopefully it answers my question. – ElyaSh Jan 11 '11 at 13:02
1

I know I'm a little late to the party on this one but you can use reflection to set the instance of ToolTip that is used for rendering the tooltips. After doing that you can just use the Draw method as you normally would.

public void SetToolTipInstance(ToolStrip ts, ToolTip tt)
{
    Type type = ts.GetType.BaseType;
    int propToolTip = Convert.ToInt32(type.GetField("PropToolTip", BindingFlags.NonPublic | BindingFlags.Static).GetValue(ts));
    dynamic ps = type.BaseType.GetProperty("Properties", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(ts);
    ps.GetType.GetMethod("SetObject", BindingFlags.Instance | BindingFlags.Public).Invoke(ps, {propToolTip,tt});
}
idb
  • 11
  • 3