7

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?

Martijn
  • 24,441
  • 60
  • 174
  • 261

6 Answers6

10

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;
        }

    }
Petr Havlicek
  • 2,051
  • 1
  • 19
  • 25
6

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
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Passent I Have tried suggestion 1 and three and the tooltip still flickers. For option one I've this code: `_tooltip.Show(plannedItem.Description, this, e.X + 20, e.Y + 20);` – Martijn Jan 08 '12 at 17:04
  • Note, even if you set the tooltip away from the mouse, you can have this happen because the tooltip is too close to the edge of the screen and is "shoved" left or up over top of the mouse cursor again. Watch out for long tooltips displayed near the bottom/right of the screen. – Tom West Nov 14 '17 at 17:10
1

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;
  }
}
LarsTech
  • 80,625
  • 14
  • 153
  • 225
0

For the visitors of this thread, here is what I did, following suggestions above (VB.NET):

Dim LastToolTip As String
Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
    Dim NewToolTip = CalculateTooltipText(e.X, e.Y)
    If LastToolTip <> NewToolTip Then
        ToolTip1.SetToolTip(PictureBox1, NewToolTip)
        LastToolTip = NewToolTip
    End If
End Sub

It stopped the flickering.

Oak_3260548
  • 1,882
  • 3
  • 23
  • 41
0

c# (works on tooltip chart):

Point mem = new Point();
private void xxx_MouseMove(MouseEventArgs e){
    // start
    Point pos = e.Location;
    if (pos == mem) { return; }

    // your code here

    // end
    mem = pos
}
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 06 '22 at 03:07
0

I imagine your mouse does move a little when you think it is still. I suggest you do some kind of caching here - only call _tooltip.SetToolTip if the plannedItem has changed.

Asaf
  • 4,317
  • 28
  • 48