0

我正在尝试在自定义绘制(使用 GDI+)的(WinForms)UserControl 上使用 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;
        }
    }
}
4

3 回答 3

1

不是很优雅,但是您可以Timer在控件中使用 a 来跟踪鼠标何时空闲,并在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);
                    }
                }
            )
        );
    }
}
于 2013-10-13T07:45:23.400 回答
0

通过取消PopUp事件,您将明确阻止ToolTip显示 ,因为PopUp发生在实际显示ToolTip. 每次您的表单触发要显示的工具提示时都会e.Cancel = true受到打击。

我不确定您的意图e.Cancel,但我想您只想在文本为空或不在有效显示区域之一中时将其设置为 true。将另一个 else 添加到您的条件链中并e.Cancel作为包罗万象放置,它应该对应于您不想显示的所有区域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
}

这应该是最简单和最快的修复。

于 2013-10-08T15:57:13.730 回答
0

我认为您的方法比void OnTooltipPopup(object sender, PopupEventArgs e) 您缺少以下行

_tooltip.Show(text, _lp);

它应该强制工具提示显示。

此外,为了避免在此方法上计算位置,请尝试从 System.Drawning 的 Paint 中测试击中区域。它在上面链接的 MSDN 上描述:msdn

于 2013-10-12T12:20:58.167 回答