【问题标题】:make WinForms Tooltip show multiple times on one control?使 WinForms Tooltip 在一个控件上显示多次?
【发布时间】:2013-10-06 03:44:07
【问题描述】:

我正在尝试在自定义绘制(使用 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;
        }
    }
}

【问题讨论】:

    标签: c# .net winforms tooltip


    【解决方案1】:

    不是很优雅,但是您可以使用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);
                        }
                    }
                )
            );
        }
    }
    

    【讨论】:

    • 感谢您发布一些实际有效的代码。好吧,我的意思是“几乎”。如果您在角落之间快速移动,它实际上会发布错误的文本。然而,它更接近。
    【解决方案2】:

    通过取消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
    }
    

    这应该是最简单、最快的修复方法。

    【讨论】:

    • 不幸的是,您的示例代码并不比我的原始代码更好。你会注意到我的并不总是设置e.Cancel,因为return在它上面几行。 (SetToolTip 方法实际上触发了Popup 处理程序。)
    • @Brannon 你是对的,它不会总是点击取消;仅当 ToolTip 文本未更改时。无论表单上的位置如何,您的代码也会加载一个工具提示。我加载了您的代码并验证了行为。如果您将鼠标悬停在角落上,则不会显示任何工具提示,除非您在同一角落再次触发 PopUp 事件。 SetToolTip 不会触发 PopUp 事件,它只是更改指定控件的 ToolTip 内容。触发 PopUp 事件的唯一方法是调用 Show() 或隐式触发。
    • 如果您注意到,您的 OnTooltipPopup 事件会在您的鼠标每次停留在表单上时触发。如果我发布的解决方案不起作用,则可能是您的代码的另一部分导致了您的问题。
    • 我没有比我上面发布的更多的示例代码。我希望每次鼠标停止时触发 Popup 事件。那很完美。我显示工具提示的真实计算成本太高,无法在鼠标移动事件中运行。
    【解决方案3】:

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

    _tooltip.Show(text, _lp);
    

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

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

    【讨论】:

    • 很抱歉,将 SetToolTip 替换为 Show 似乎对最终行为没有任何影响。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-26
    • 2018-06-03
    • 2011-03-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多