Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent tooltip from flickering in custom control?

Tags:

c#

winforms

I have made a custom control and when a condition is met, I want to show a tooltip:

protected override void OnMouseMove(MouseEventArgs e)
{
    base.OnMouseMove(e);

    var plannedItem = GetPlannedItemByPosition(e.Location);

    if (plannedItem != null)
        _tooltip.SetToolTip(this, plannedItem.Description);
    else
        _tooltip.RemoveAll();
}

This code works fine, excepts for the face that the tooltip flickers.

This custom control, paints all the information in the OnPaint event, maybe this has something to do with it? And if it does, how can I prevent the tooltip from flickering?

like image 913
Martijn Avatar asked Jan 08 '12 12:01

Martijn


3 Answers

Remember last mouse position and set the tooltip only when the mouse position changes.

public partial class Form1 : Form
{
    private int lastX;
    private int lastY;

    private void button1_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.X != this.lastX || e.Y != this.lastY)
        {
            toolTip1.SetToolTip(button1, "test");

            this.lastX = e.X;
            this.lastY = e.Y;
        }

    }
like image 140
Petr Havlicek Avatar answered Oct 18 '22 23:10

Petr Havlicek


This will happen when you display the tooltip at the mouse cursor position. As soon as the tip window shows up, Windows notices that the mouse is located in that window and posts a MouseMove message. Which makes the tooltip disappear. Which makes Windows send a MouseMove message to your control, running your OnMouseMove() method. Which makes the tooltip appear again. Etcetera, you'll see the tooltip rapidly flickering.

Solve this by any of the following methods:

  • show the tooltip well away from the mouse position so it won't overlap the mouse cursor
  • only update/show the tooltip when it needs to be changed
  • set the control's Capture property to true so the tooltip won't get a MouseMove message
like image 6
Hans Passant Avatar answered Oct 19 '22 01:10

Hans Passant


Since this is a painted custom control, I think it might be easier to just have a variable hold the last shown tip, and instead of always "setting" the tooltip, just show it.

Simple example (using just a form):

public partial class Form1 : Form {
  private List<TipRect> _Tips = new List<TipRect>();
  private TipRect _LastTip;
  private ToolTip _tooltip = new ToolTip();

  public Form1() {
    InitializeComponent();
    _Tips.Add(new TipRect(new Rectangle(32, 32, 32, 32), "Tip #1"));
    _Tips.Add(new TipRect(new Rectangle(100, 100, 32, 32), "Tip #2"));
  }

  private void Form1_Paint(object sender, PaintEventArgs e) {
    foreach (TipRect tr in _Tips)
      e.Graphics.FillRectangle(Brushes.Red, tr.Rect);
  }

  private void Form1_MouseMove(object sender, MouseEventArgs e) {
    TipRect checkTip = GetTip(e.Location);
    if (checkTip == null) {
      _LastTip = null;
      _tooltip.Hide(this);
    } else {
      if (checkTip != _LastTip) {
        _LastTip = checkTip;
        _tooltip.Show(checkTip.Text, this, e.Location.X + 10, e.Location.Y + 10, 1000);
      }
    }
  }

  private TipRect GetTip(Point p) {
    TipRect value = null;
    foreach (TipRect tr in _Tips) {
      if (tr.Rect.Contains(p))
        value = tr;
    }
    return value;
  }
}

Here is the TipRect class I created to simulate whatever your PlannedItem class is:

public class TipRect {
  public Rectangle Rect;
  public string Text;

  public TipRect(Rectangle r, string text) {
    Rect = r;
    Text = text;
  }
}
like image 1
LarsTech Avatar answered Oct 18 '22 23:10

LarsTech