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

7

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

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事件中绘制所有信息,也许与此有关?如果是的话,我该如何防止提示框闪烁呢?


它如何“闪烁”?你是指当你移动鼠标时它会消失和重新出现吗?如果是这样的话,那是预期的行为。 - Cody Gray
好的,当我移动鼠标并出现工具提示时,如果我保持鼠标不动,那么工具提示会闪烁一下。 - Martijn
6个回答

11

记住鼠标的最后位置,仅在鼠标位置发生变化时设置工具提示。

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

    }

2
这个解决了我闪烁的工具提示问题。谢谢! - BoltBait

6
当你在鼠标光标位置显示工具提示时,就会发生这种情况。一旦提示窗口出现,Windows会注意到鼠标位于该窗口中,并发送MouseMove消息,导致提示框消失。这样,Windows会向你的控件发送MouseMove消息,运行OnMouseMove()方法,从而使提示框再次出现。等等,你会看到提示框快速闪烁。
通过以下任何方法解决此问题:
  • 将工具提示显示在鼠标位置远离的地方,以免重叠
  • 仅在需要更改/显示工具提示时执行操作
  • 将控件的Capture属性设置为true,以便工具提示不会收到MouseMove消息

我尝试了建议1和3,但工具提示仍然闪烁。对于选项1,我有以下代码:_tooltip.Show(plannedItem.Description, this, e.X + 20, e.Y + 20); - Martijn
请注意,即使您将工具提示设置远离鼠标,由于工具提示太靠近屏幕边缘并被“推”到左侧或向上覆盖在鼠标光标上,这种情况仍可能发生。请注意屏幕底部/右侧显示的长工具提示。 - Tom West

1

由于这是一个绘制的自定义控件,我认为最好只需使用一个变量来保存上次显示的提示,而不是总是“设置”工具提示,只需显示即可。

以下是一个简单的示例(仅使用一个窗体):

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

1

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
}

您的答案可以通过提供更多支持信息来改进。请[编辑]以添加进一步的细节,例如引用或文档,以便他人可以确认您的答案是否正确。您可以在帮助中心找到有关如何撰写良好答案的更多信息。 - Community

0
对于这个帖子的访问者,以下是我根据上面的建议所做的事情(使用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

它停止了闪烁。


0

我想象你的鼠标在你认为它静止时确实会移动一点。我建议你在这里进行某种缓存 - 只有在 plannedItem 发生变化时才调用 _tooltip.SetToolTip。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接