如何防止工具提示在自定义控件中闪烁

本文关键字:闪烁 自定义控件 何防止 工具提示 | 更新日期: 2023-09-27 18:19:54

我制作了一个自定义控件,当满足条件时,我想显示一个工具提示:

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

此代码运行良好,但工具提示闪烁的面除外。

这个自定义控件绘制了OnPaint事件中的所有信息,也许这与它有关?如果是,我该如何防止工具提示闪烁?

如何防止工具提示在自定义控件中闪烁

记住最后一个鼠标位置,并仅在鼠标位置更改时设置工具提示。

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

当您在鼠标光标位置显示工具提示时,会发生这种情况。提示窗口一出现,Windows就会注意到鼠标位于该窗口中,并发布MouseMove消息。这会使工具提示消失。这使得Windows通过运行OnMouseMove()方法向您的控件发送MouseMove消息。这将使工具提示再次出现。等等,你会看到工具提示快速闪烁。

通过以下任一方法解决此问题:

  • 显示远离鼠标位置的工具提示,使其不会与鼠标光标重叠
  • 仅在需要更改时更新/显示工具提示
  • 将控件的Capture属性设置为true,这样工具提示就不会得到MouseMove消息

由于这是一个绘制的自定义控件,我认为让一个变量保存最后显示的提示可能会更容易,而不是总是"设置"工具提示,只显示它。

简单示例(仅使用一个表单):

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

这是我创建的TipRect类,用于模拟PlannedItem类:

public class TipRect {
  public Rectangle Rect;
  public string Text;
  public TipRect(Rectangle r, string text) {
    Rect = r;
    Text = text;
  }
}

我想当你认为鼠标静止时,它确实会移动一点。我建议你在这里进行某种缓存——如果plannedItem已经更改,只调用_toltip.SetToolTip。

对于这个线程的访问者,以下是我所做的,遵循上面的建议(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

它停止了闪烁。

c#(适用于工具提示图表):

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
}