在未聚焦的ToolStripItem上显示工具提示

8
ToolStripItems在鼠标悬停时显示活动高亮,即使它们所在的窗体没有焦点。但是,除非窗体获得焦点,否则它们不会显示工具提示。我看过ToolStrip 'click-though' hack。有人知道如何使ToolStripButton在其父窗体没有焦点时显示其工具提示吗?
谢谢!

你为什么想要这样做?当表单没有焦点时,错误会被激活跟踪。 - OregonGhost
@OregonGhost - 我创建了一个浮动/始终置顶的工具栏,我希望当其他应用程序处于活动状态时,鼠标悬停时仍然显示工具提示。 - foson
4个回答

6
问题在于ToolStrip中的"控件",如ToolStripButton或ToolStripDropDownButton不继承自Control。目前,我通过在用户悬停在按钮上时聚焦ToolStrip来解决了这个问题。按钮的MouseHover事件太晚触发--在运行"显示工具提示"代码之后,因此我扩展了ToolStripDropDownButton类并使用了我的新按钮。这种方法对于从ToolStripItem继承的其他类的任何类似按钮的类都应该有效。
public class ToolStripDropDownEx : ToolStripDropDownButton
{
    public ToolStripDropDownEx(string text)
    {
    }

    protected override void OnMouseHover(EventArgs e)
    {
        if (this.Parent != null)
            Parent.Focus();
        base.OnMouseHover(e);
    } 
}

3
也许这段代码中的两种方法之一能够帮助你朝着正确的方向前进...
public Form1()
{
    InitializeComponent();

    tooltip = new ToolTip();
    tooltip.ShowAlways = true;
}

private ToolTip tooltip;
private void toolStripButton_MouseHover(object sender, EventArgs e)
{
    if (!this.Focused)
    {
        ToolStripItem tsi = (ToolStripItem)sender;
        tooltip.SetToolTip(toolStrip1, tsi.AutoToolTip ? tsi.ToolTipText : tsi.Text);
        /*tooltip.Show(tsi.AutoToolTip ? tsi.ToolTipText : tsi.Text, this, 
            new Point(toolStrip1.Left, toolStrip1.Bottom));*/
    }
}

private void toolStripButton_MouseLeave(object sender, EventArgs e)
{
    tooltip.RemoveAll();
}

第一个问题是你不能直接将它设置为按钮,因为它不继承自控件,除非鼠标悬停在带状区域而不是按钮上,否则工具提示不会显示。
第二个问题(注释方式)是根本不显示。不太确定原因,但也许你可以调试一下。

2
我尝试了几种方法,发现这是最简单的方法。
当我创建ToolStripButton项目时,我在其悬停事件中添加了一个事件处理程序:
private sub SomeCodeSnippet()

    Me.tooltipMain.ShowAlways = True

    Dim tsi As New ToolStripButton(String.Empty, myImage)
    tsi.ToolTipText = "my tool tip text"
    toolstripMain.Add(tsi)

    AddHandler tsi.MouseHover, AddressOf ToolStripItem_MouseHover

end sub

然后是事件处理程序:

Private Sub ToolStripItem_MouseHover(ByVal sender As Object, ByVal e As System.EventArgs)

    If TypeOf sender Is ToolStripButton Then
        Me.tooltipMain.SetToolTip(Me.toolstripMain, CType(sender, ToolStripButton).ToolTipText)
    End If

End Sub

这个功能工作得非常好,尽管我在第一次悬停在工具栏上时注意到了一个很小的初始延迟。

1

我曾试图做同样的事情,并确定这将是相当具有挑战性且不值得的。原因是在内部,.NET代码专门设计为仅在窗口处于活动状态时显示工具提示 - 它们在Win32级别进行检查,因此很难欺骗代码。

这是ToolTip.cs中检查“GetActiveWindow()”并返回false的代码片段。您可以在代码中看到注释“工具提示应仅在活动窗口上显示。”

顺便说一下,您可以使用Visual Studio 2008查看.NET BCL的所有源代码,以下是我使用的说明:

http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code.aspx

// refer VsWhidbey 498263: ToolTips should be shown only on active Windows.
private bool IsWindowActive(IWin32Window window)
{ 
    Control windowControl = window as Control;
    // We want to enter in the IF block only if ShowParams does not return SW_SHOWNOACTIVATE. 
    // for ToolStripDropDown ShowParams returns SW_SHOWNOACTIVATE, in which case we DONT want to check IsWindowActive and hence return true. 
    if ((windowControl.ShowParams & 0xF) != NativeMethods.SW_SHOWNOACTIVATE)
    { 
        IntPtr hWnd = UnsafeNativeMethods.GetActiveWindow();
        IntPtr rootHwnd =UnsafeNativeMethods.GetAncestor(new HandleRef(window, window.Handle), NativeMethods.GA_ROOT);
        if (hWnd != rootHwnd)
        { 
            TipInfo tt = (TipInfo)tools[windowControl];
            if (tt != null && (tt.TipType & TipInfo.Type.SemiAbsolute) != 0) 
            { 
                tools.Remove(windowControl);
                DestroyRegion(windowControl); 
            }
            return false;
        }
    } 
    return true;
} 

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