首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用ToolStripDropDown模拟工具提示功能

使用ToolStripDropDown模拟工具提示功能
EN

Stack Overflow用户
提问于 2012-03-03 00:03:57
回答 1查看 1.5K关注 0票数 1

我创建了一个在ToolStripDropDown中显示自身的自定义UserControl,以模拟ToolTip功能。当我订阅他们的MouseEnter和MouseLeave事件时,它对任何控件都很好用。

我还想将它用于自定义对象(而不是控件)。我已经创建了一个定义MouseEnter和MouseLeave事件的接口,这样我就可以向这个工具提示订阅任何对象(比如自定义绘制的基元)。这些类自行决定何时触发MouseEnter和MouseLeave。

我的问题是,当工具提示显示时,包含自定义对象的UserControls不会接收MouseMove事件,即使工具提示显示在旁边,而不是在鼠标下方。如果鼠标不再停留在有问题的对象上,我将基于签入MouseMove生成我自己的MouseLeave事件。但很明显,如果没有MouseMove事件,MouseLeave永远不会触发。

当我在控件上显示工具提示时,除了MouseLeave仍然触发之外,同样的事情也发生了(没有MouseMove事件)。

1)如何模拟此MouseLeave功能?我必须使用p/ SetCapture来调用鼠标移动吗?或者有人知道更简单的方法吗?

2)当工具提示显示时,即使其中的ToolStripDropDown或我的UserControl都没有触发"GotFocus“事件,只要工具提示被显示,我仍然会失去键盘焦点,这也不是理想的工具提示行为。我能避免这种情况吗?

基本上,我希望它是一个完全无焦点、无干扰的工具提示。我看过一个名为SuperTooltip的示例项目,但它也有同样的功能缺陷。我尝试将ControlStyles.Selectable设置为false,但没有注意到任何变化。

下面是我创建工具提示UserControl的代码:

代码语言:javascript
复制
public CustomTooltip()
{
    this.SetStyle(ControlStyles.Selectable, false);

    dropDown = new ToolStripDropDown();
    dropDown.AutoSize = false;
    dropDown.Margin = Padding.Empty;
    dropDown.Padding = Padding.Empty;

    host = new ToolStripControlHost(this);
    host.AutoSize = false;
    host.Margin = Padding.Empty;
    host.Padding = Padding.Empty;

    this.Location = new Point(0, 0);
    dropDown.Items.Add(host);
}

我用以下命令来展示它:

代码语言:javascript
复制
dropDown.Show(
    new Point(Cursor.Position.X, Cursor.Position.Y + Cursor.Current.Size.Height),
    ToolStripDropDownDirection.BelowRight
);
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-03-03 05:09:51

我发现我能够通过从Form派生而不使用ToolStripDropDown来实现这一点。这个类模拟工具提示的功能,并允许自定义淡入/淡出参数。您可以订阅一个控件或任何定义和实现MouseEnter和MouseLeave的ITooltipTarget的类。

代码语言:javascript
复制
public abstract class CustomTooltip : Form
{
    #region Static
    protected static readonly int FadeInterval = 25;
    protected static readonly IntPtr HWND_TOPMOST = (IntPtr)(-1);
    private const int SWP_NOSIZE = 0x0001;
    private const int SWP_NOMOVE = 0x0002;
    private const int SWP_NOACTIVATE = 0x0010;
    private const int WS_POPUP = unchecked((int)0x80000000);
    private const int WS_EX_TOPMOST = 0x00000008;
    private const int WS_EX_NOACTIVATE = 0x08000000;

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
    #endregion

    protected Dictionary<object, object> subscriptions;
    protected Timer popupTimer;
    protected Timer fadeTimer;
    protected bool isFading = false;
    protected int fadeDirection = 1;

    [DefaultValue(500)]
    /// <summary>
    /// Delay in milliseconds before the tooltip is shown.  0 means no delay.
    /// </summary>
    public int PopupDelay
    {
        get
        {
            return _popupDelay;
        }
        set
        {
            _popupDelay = value;

            if (value > 0)
                popupTimer.Interval = value;
            else
                popupTimer.Interval = 1;
        }
    }
    private int _popupDelay = 500;

    [DefaultValue(0)]
    /// <summary>
    /// How long to spend fading in and out in milliseconds.  0 means no fade.
    /// </summary>
    public int FadeTime
    {
        get
        {
            return _fadeTime;
        }
        set
        {
            _fadeTime = value;
        }
    }
    private int _fadeTime = 0;

    public virtual new object Tag
    {
        get
        {
            return base.Tag;
        }
        set
        {
            base.Tag = value;

            OnTagChanged(EventArgs.Empty);
        }
    }

    public CustomTooltip()
    {
        this.SetStyle(ControlStyles.Selectable, false);

        subscriptions = new Dictionary<object, object>();

        popupTimer = new Timer();
        popupTimer.Interval = PopupDelay;
        popupTimer.Tick += new EventHandler(popupTimer_Tick);

        fadeTimer = new Timer();
        fadeTimer.Interval = FadeInterval;
        fadeTimer.Tick += new EventHandler(fadeTimer_Tick);

        this.Visible = false;
        this.ShowInTaskbar = false;
        this.FormBorderStyle = FormBorderStyle.None;
        this.ControlBox = false;
        this.StartPosition = FormStartPosition.Manual;
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;

            cp.Style |= WS_POPUP;
            cp.ExStyle |= WS_EX_TOPMOST | WS_EX_NOACTIVATE;

            return cp;
        }
    }

    protected override bool ShowWithoutActivation
    {
        get
        {
            return true;
        }
    }

    protected virtual void Subscribe(Control control, object tag)
    {
        subscriptions.Add(control, tag);
        control.MouseEnter += new EventHandler(Item_MouseEnter);
        control.MouseLeave += new EventHandler(Item_MouseLeave);
    }

    protected virtual void Subscribe(ITooltipTarget item, object tag)
    {
        subscriptions.Add(item, tag);
        item.MouseEnter += new EventHandler(Item_MouseEnter);
        item.MouseLeave += new EventHandler(Item_MouseLeave);
    }

    public virtual void Unsubscribe(Control control)
    {
        control.MouseEnter -= new EventHandler(Item_MouseEnter);
        control.MouseLeave -= new EventHandler(Item_MouseLeave);
        subscriptions.Remove(control);
    }

    public virtual void Unsubcribe(ITooltipTarget item)
    {
        item.MouseEnter -= new EventHandler(Item_MouseEnter);
        item.MouseLeave -= new EventHandler(Item_MouseLeave);
        subscriptions.Remove(item);
    }

    public void ClearSubscriptions()
    {
        foreach (object o in subscriptions.Keys)
        {
            if (o is Control)
                Unsubscribe((Control)o);
            else if (o is ITooltipTarget)
                Unsubscribe((ITooltipTarget)o);
        }
    }

    protected virtual void OnTagChanged(EventArgs e)
    {
    }

    protected override void OnSizeChanged(EventArgs e)
    {
        base.OnSizeChanged(e);
    }

    protected override void OnMouseEnter(EventArgs e)
    {
        base.OnMouseEnter(e);

        Item_MouseLeave(null, EventArgs.Empty);
    }

    private void Item_MouseEnter(object sender, EventArgs e)
    {
        Tag = subscriptions[sender];
        popupTimer.Start();
    }

    private void Item_MouseLeave(object sender, EventArgs e)
    {
        if (FadeTime > 0)
            FadeOut();
        else
            this.Hide();

        popupTimer.Stop();
    }

    protected virtual void FadeIn()
    {
        isFading = true;
        Opacity = 0;
        fadeDirection = 1;
        fadeTimer.Start();
    }

    protected virtual void FadeOut()
    {
        isFading = true;
        Opacity = 1;
        fadeDirection = -1;
        fadeTimer.Start();
    }

    private void popupTimer_Tick(object sender, EventArgs e)
    {
        if (isFading)
            this.Hide();

        if (FadeTime > 0)
            FadeIn();

        Location = new Point(Cursor.Position.X, Cursor.Position.Y + Cursor.Size.Height);
        SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
        Show();

        popupTimer.Stop();
    }

    private void fadeTimer_Tick(object sender, EventArgs e)
    {
        if (Opacity == 0 && fadeDirection == -1)
        {
            isFading = false;
            fadeTimer.Stop();
            this.Hide();
        }
        else if (Opacity == 1 && fadeDirection == 1)
        {
            fadeTimer.Stop();
            isFading = false;
        }
        else
        {
            double change = ((double)fadeTimer.Interval / (double)FadeTime) * (double)fadeDirection;
            Opacity += change;
        }
    }
}

public interface ITooltipTarget
{
    event EventHandler MouseEnter;
    event EventHandler MouseLeave;
}

要使用上面的类,你只需要从CustomTooltip派生出你自己的自定义绘制工具提示即可。派生类将使用Tag属性来确定显示的内容。例如,如果我想要一个工具提示将一个图像与一个对象相关联并绘制该图像,我会这样做:

代码语言:javascript
复制
public class CustomImageTooltip : CustomTooltip
{
     public Image Image
     {
        get
        {
            if (Tag is Image)
                return Tag as Image;
            else
                return null;
        }
     }

    public CustomImageTooltip()
    {
        InitializeComponent();

        this.SetStyle(ControlStyles.DoubleBuffer |
                      ControlStyles.AllPaintingInWmPaint |
                      ControlStyles.UserPaint, true);
    }

    public void Subscribe(Control control, Image image)
    {
        base.Subscribe(control, image);
    }

    public void Subscribe(ITooltipTarget item, Image image)
    {
        base.Subscribe(item, image);
    }

    protected override void OnTagChanged(EventArgs e)
    {
        base.OnTagChanged(e);
        if (Image != null)
            this.Size = Image.Size;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        Graphics g = e.Graphics;

        g.Clear(Color.White);

        if (Image != null)
            g.DrawImage(
                Image,
                new RectangleF(0, 0, ClientSize.Width, ClientSize.Height),
                new RectangleF(0, 0, Image.Size.Width, Image.Size.Height),
                GraphicsUnit.Pixel
            );

        g.DrawRectangle(Pens.Black, 0, 0, ClientRectangle.Width - 1, ClientRectangle.Height - 1);
    }
}

为了在您的应用程序中使用这个CustomImageTooltip类,您只需要订阅和取消订阅该类的一个实例:

代码语言:javascript
复制
// Constructor
customImageTooltip = new CustomImageTooltip();

foreach (CustomObject o in myCustomObjects)
{
    customImageTooltip.Subscribe(o, o.Image);
}

// Destructor
foreach (CustomObject o in myCustomObjects)
{
    customImageTooltip.Unsubscribe(o);
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9536454

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档