C# 使用 ComboBox 显示工具提示(下拉菜单)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19687094/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 15:37:17  来源:igfitidea点击:

Show ToolTip with ComboBox (dropdownmenu)

c#winformstooltip

提问by searchforit

I am showing a little tooltip, but if I change the selecteditem/text in the dropdownmenu, tooltip shows the old text and the new text. I want it to show only the new text.

我正在显示一个小工具提示,但是如果我更改下拉菜单中的选定项/文本,工具提示将显示旧文本和新文本。我希望它只显示新文本。

private void optionsvalueComboBox_MouseHover(object sender, EventArgs e)
{
    ToolTip buttonToolTip = new ToolTip();
    buttonToolTip.ToolTipTitle = "Value";
    buttonToolTip.UseFading = true;
    buttonToolTip.UseAnimation = true;
    buttonToolTip.IsBalloon = true;
    buttonToolTip.ShowAlways = true;
    buttonToolTip.AutoPopDelay = 5000;
    buttonToolTip.InitialDelay = 1000;
    buttonToolTip.ReshowDelay = 0;

    buttonToolTip.SetToolTip(optionsvalueComboBox, optionsvalueComboBox.Text);
}

采纳答案by King King

I've tried digging in the MouseHoverevent of a ComboBoxand looks like it doesn't work normally as we expect. The MouseHoveris in fact firedonly when you move the mouse over the drop down buttonif your ComboBoxhas style of dropdown. The simplest solution for this is change your combobox style to dropdownlistlike this:

我试过在 a 的情况MouseHover下进行挖掘,ComboBox看起来它不像我们预期的那样正常工作。该MouseHover其实解雇,只有当你在移动鼠标drop down button,如果您ComboBox有风格dropdown。最简单的解决方案是将您的组合框样式更改为dropdownlist如下所示:

comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;

However that kind of style will make the ComboBoxreadonly. If that's not what you want, there is a work-around for you is to use the event MouseMovewith a Timerto mimic the MouseHover, here is the code for you:

然而,这种风格会使ComboBox只读。如果这不是您想要的,则有一种解决方法是使用MouseMove带有 a的事件Timer来模仿MouseHover,这是适合您的代码:

public partial class Form1 : Form {
  public Form1(){
    InitializeComponent();
     t.Interval = 600;
     t.Tick += (se, ev) => {
       buttonToolTip.SetToolTip(comboBox1, (string)comboBox1.SelectedItem);
       t.Stop();
     };
     //init the buttonToolTip
     buttonToolTip.ToolTipTitle = "Value";
     buttonToolTip.UseFading = true;
     buttonToolTip.UseAnimation = true;
     buttonToolTip.IsBalloon = true;
     buttonToolTip.ShowAlways = true;
     buttonToolTip.AutoPopDelay = 5000;
     buttonToolTip.InitialDelay = 1000;
     buttonToolTip.ReshowDelay = 0;
     //register MouseMove event handler for your comboBox1
     comboBox1.MouseMove += (se, ev) => {                    
       //Restart the timer every time the mouse is moving
       t.Stop();
       t.Start();
     };
  }
  Timer t = new Timer();
  ToolTip buttonToolTip = new ToolTip();
}

回答by gnarlybracket

Assuming what you don't like is the tooltip text changing from the old text to the new text...

假设您不喜欢的是工具提示文本从旧文本更改为新文本...

The reason it's doing that is because you are creating a new tooltip instance on every hover event. Every time the hover event is fired, the old tooltip instance is replaced with a new one which is why you see both. To fix this, put the declaration outside the event, like this:

这样做的原因是因为您在每个悬停事件上都创建了一个新的工具提示实例。每次触发悬停事件时,旧的工具提示实例都会替换为一个新的实例,这就是您看到两者的原因。要解决此问题,请将声明放在事件之外,如下所示:

ToolTip buttonToolTip = new ToolTip();

private void optionsvalueComboBox_MouseHover(object sender, EventArgs e)
{
    buttonToolTip.ToolTipTitle = "Value";
    buttonToolTip.UseFading = true;
    buttonToolTip.UseAnimation = true;
    buttonToolTip.IsBalloon = true;
    buttonToolTip.ShowAlways = true;
    buttonToolTip.AutoPopDelay = 5000;
    buttonToolTip.InitialDelay = 1000;
    buttonToolTip.ReshowDelay = 0;

    buttonToolTip.SetToolTip(optionsvalueComboBox, optionsvalueComboBox.Text);
  }

Now the same tooltip is being used with the wording simply being replaced. Let me know if this works for you!

现在正在使用相同的工具提示,只是替换了措辞。让我知道这是否适合您!

回答by Martin.Martinsson

A complete working example:

一个完整的工作示例:

[Serializable, StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public RECT(Rectangle rect)
    {
        Left = rect.Left;
        Top = rect.Top;
        Right = rect.Right;
        Bottom = rect.Bottom;
    }

    public Rectangle Rect
    {
        get
        {
            return new Rectangle(Left, Top, Right - Left, Bottom - Top);
        }
    }

    public Point Location
    {
        get
        {
            return new Point(Left, Top);
        }
    }

    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}

public class ToolTipComboBox: ComboBox
{
    #region Fields

    private ToolTip toolTip;
    private bool _tooltipVisible;
    private bool _dropDownOpen;
    #endregion

    #region Types

    [StructLayout(LayoutKind.Sequential)]
    // ReSharper disable once InconsistentNaming
    public struct COMBOBOXINFO
    {
        public Int32 cbSize;
        public RECT rcItem;
        public RECT rcButton;
        public ComboBoxButtonState buttonState;
        public IntPtr hwndCombo;
        public IntPtr hwndEdit;
        public IntPtr hwndList;
    }

    public enum ComboBoxButtonState
    {
        // ReSharper disable once UnusedMember.Global
        StateSystemNone = 0,
        // ReSharper disable once UnusedMember.Global
        StateSystemInvisible = 0x00008000,
        // ReSharper disable once UnusedMember.Global
        StateSystemPressed = 0x00000008
    }

    [DllImport("user32.dll")]
    public static extern bool GetComboBoxInfo(IntPtr hWnd, ref COMBOBOXINFO pcbi);
    [DllImport("user32.dll", SetLastError = true)]
    public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);

    #endregion

    #region Properties

    private IntPtr HwndCombo
    {
        get
        {
            COMBOBOXINFO pcbi = new COMBOBOXINFO();
            pcbi.cbSize = Marshal.SizeOf(pcbi);
            GetComboBoxInfo(Handle, ref pcbi);
            return pcbi.hwndCombo;
        }
    }

    private IntPtr HwndDropDown
    {
        get
        {
            COMBOBOXINFO pcbi = new COMBOBOXINFO();
            pcbi.cbSize = Marshal.SizeOf(pcbi);
            GetComboBoxInfo(Handle, ref pcbi);
            return pcbi.hwndList;
        }
    }

    [Browsable(false)]
    public new DrawMode DrawMode
    {
        get { return base.DrawMode; }
        set { base.DrawMode = value; }
    }

    #endregion

    #region ctor

    public ToolTipComboBox()
    {
        toolTip = new ToolTip
        {
            UseAnimation = false,
            UseFading = false
        };

        base.DrawMode = DrawMode.OwnerDrawFixed;
        DrawItem += OnDrawItem;
        DropDownClosed += OnDropDownClosed;
        DropDown += OnDropDown;
        MouseLeave += OnMouseLeave;
    }

    #endregion

    #region Methods

    private void OnDropDown(object sender, EventArgs e)
    {
        _dropDownOpen = true;
    }

    private void OnMouseLeave(object sender, EventArgs e)
    {
        ResetToolTip();
    }

    private void ShowToolTip(string text, int x, int y)
    {
        toolTip.Show(text, this, x, y);
        _tooltipVisible = true;
    }

    private void OnDrawItem(object sender, DrawItemEventArgs e)
    {
        ComboBox cbo = sender as ComboBox;
        if (e.Index == -1) return;

        // ReSharper disable once PossibleNullReferenceException
        string text = cbo.GetItemText(cbo.Items[e.Index]);
        e.DrawBackground();

        if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
        {
            TextRenderer.DrawText(e.Graphics, text, e.Font, e.Bounds.Location, SystemColors.Window);

            if (_dropDownOpen)
            {
                Size szText = TextRenderer.MeasureText(text, cbo.Font);
                if (szText.Width > cbo.Width - SystemInformation.VerticalScrollBarWidth && !_tooltipVisible)
                {
                    RECT rcDropDown;
                    GetWindowRect(HwndDropDown, out rcDropDown);

                    RECT rcCombo;
                    GetWindowRect(HwndCombo, out rcCombo);

                    if (rcCombo.Top > rcDropDown.Top)
                    {
                        ShowToolTip(text, e.Bounds.X, e.Bounds.Y - rcDropDown.Rect.Height - cbo.ItemHeight - 5);
                    }
                    else
                    {
                        ShowToolTip(text, e.Bounds.X, e.Bounds.Y + cbo.ItemHeight - cbo.ItemHeight);
                    }
                }
            }
        }
        else
        {
            ResetToolTip();
            TextRenderer.DrawText(e.Graphics, text, e.Font, e.Bounds.Location, cbo.ForeColor);
        }

        e.DrawFocusRectangle();
    }

    private void OnDropDownClosed(object sender, EventArgs e)
    {
        _dropDownOpen = false;
        ResetToolTip();
    }

    private void ResetToolTip()
    {
        if (_tooltipVisible)
        {
            // ReSharper disable once AssignNullToNotNullAttribute
            toolTip.SetToolTip(this, null);
            _tooltipVisible = false;
        }
    }

    #endregion
}