使 WinForms 工具提示在一个控件上多次显示
本文关键字:控件 一个 显示 工具提示 WinForms | 更新日期: 2023-09-27 18:34:08
我正在尝试在自定义绘制(使用 GDI+)的 (WinForms) 用户控件上使用 WinForms Tooltip 类。这是遗留代码,但我需要再维护几年。我希望当光标在各个位置暂停时显示工具提示。我不想进行计算以了解是否应该在光标暂停之前显示工具提示,这有助于确定 Popup 事件中的信息。在下面的非工作示例代码中,我希望我可以将光标移动到窗体上的任何角落并看到工具提示。似乎如果我单击以删除工具提示,则从此看不到工具提示。要显示的第一个工具提示并不像我期望的那样直接。我该如何完成这项工作?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace TestToolTip
{
public partial class Form1 : Form
{
private readonly ToolTip _tooltip = new ToolTip();
public Form1()
{
InitializeComponent();
_tooltip.AutoPopDelay = 10000;
_tooltip.InitialDelay = 1000;
_tooltip.ReshowDelay = 200;
_tooltip.Popup += OnTooltipPopup;
_tooltip.SetToolTip(this, "you should never see this"); // we need something or it won't ever trigger Popup
}
private Point _lp;
protected override void OnMouseMove(MouseEventArgs e)
{
_lp = e.Location;
base.OnMouseMove(e);
}
void OnTooltipPopup(object sender, PopupEventArgs e)
{
string text = null;
if (_lp.X < 100 && _lp.Y < 100)
text = "Top Left";
else if (_lp.X < 100 && _lp.Y > Height - 100)
text = "Bottom Left";
else if (_lp.X > Width - 100 && _lp.Y < 100)
text = "Top Right";
else if (_lp.X > Width - 100 && _lp.Y > Height - 100)
text = "Bottom Right";
var existing = _tooltip.GetToolTip(this);
if (existing == text)
return;
if (text != null)
_tooltip.SetToolTip(this, text); // calls into this method
e.Cancel = true;
}
}
}
不是很优雅,但您可以使用Timer
来跟踪鼠标在控件中的空闲时间,并在 Elapsed
事件中更新工具提示。
例:
public partial class Form1 : Form
{
private readonly ToolTip _tooltip = new ToolTip();
private readonly System.Timers.Timer _mouseIdleTimer = new System.Timers.Timer();
public Form1()
{
InitializeComponent();
MouseLeave += Form1_MouseLeave;
MouseMove += Form1_MouseMove;
_mouseIdleTimer.AutoReset = false;
_mouseIdleTimer.Interval = 900;
_mouseIdleTimer.Elapsed += _mouseIdleTimer_Elapsed;
_tooltip.AutoPopDelay = 10000;
_tooltip.InitialDelay = 1000;
_tooltip.ReshowDelay = 200;
}
void Form1_MouseLeave(object sender, EventArgs e)
{
_mouseIdleTimer.Stop();
}
private Point _lp;
void Form1_MouseMove(object sender, MouseEventArgs e)
{
_lp = e.Location;
// Mouse still moving, restart the countdown
_mouseIdleTimer.Stop();
_mouseIdleTimer.Start();
}
void _mouseIdleTimer_Elapsed(object sender, EventArgs e)
{
string text = null;
if (_lp.X < 100 && _lp.Y < 100)
text = "Top Left";
else if (_lp.X < 100 && _lp.Y > Height - 100)
text = "Bottom Left";
else if (_lp.X > Width - 100 && _lp.Y < 100)
text = "Top Right";
else if (_lp.X > Width - 100 && _lp.Y > Height - 100)
text = "Bottom Right";
BeginInvoke(
(Action)(
() =>
{
string currentText = _tooltip.GetToolTip(this);
if (currentText != text)
{
_tooltip.SetToolTip(this, text);
}
}
)
);
}
}
通过取消PopUp
事件,您可以显式阻止显示ToolTip
,因为PopUp
发生在实际显示ToolTip
之前。 每次窗体触发显示工具提示时,e.Cancel = true
都会受到点击。
我不确定您对e.Cancel
的意图,但我想您只想在文本为 null 或不在其中一个有效显示区域中时将其设置为 true。将另一个其他添加到您的条件链中,并将e.Cancel
作为 catch-all,它应该对应于您不想在其中显示ToolTip
的所有区域:
void OnTooltipPopup(object sender, PopupEventArgs e)
{
string text = null;
if (_lp.X < 100 && _lp.Y < 100)
text = "Top Left";
else if (_lp.X < 100 && _lp.Y > Height - 100)
text = "Bottom Left";
else if (_lp.X > Width - 100 && _lp.Y < 100)
text = "Top Right";
else if (_lp.X > Width - 100 && _lp.Y > Height - 100)
text = "Bottom Right";
else
e.Cancel = true;
var existing = _tooltip.GetToolTip(this);
if (existing == text)
{
return;
}
if (text != null)
_tooltip.SetToolTip(this, text); // calls into this method
}
这应该是最简单和最快的修复。
我认为
比你的方法void OnTooltipPopup(object sender, PopupEventArgs e)
您缺少以下行
_tooltip.Show(text, _lp);
它应该强制工具提示无论如何显示。
此外,为了避免在此方法上计数位置,请尝试从System.Drawning的"画图"中测试击中该区域。它在上面的链接中描述了MSDN:msdn