当ComboBox项超出可见限制时显示工具提示?

时间:2013-07-01 10:06:45

标签: .net vb.net tooltip balloon-tip

在我的应用程序中,这是一个WF项目,我有一个带有目录的组合框:

enter image description here

如果目录太大,用户将无法看到整个目录名称。

现在,在大多数应用程序中,我看到如果组合框或文本框的项目超出可见限制,则会显示/扩展完整字符串的项目/鼠标位置处显示一种小工具提示/ ballontip(完整目录名称我的意思是)

我的问题是如何做同样的事情,我不知道如何使用默认的工具提示。

  

更新:

我有这个用户控件,但打开下拉列表时变得非常慢,而当组合物项目过度移动时,项目之间的“导航”非常慢,就像我说的那样打开下拉列表也很慢单击以展开列表后单击列表。

我想像默认的组合框一样提高速度:

PS:我对C#

一无所知
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class ComboBoxTooltip : ComboBox
{
    private DropdownWindow mDropdown;
    public delegate void DropdownItemSelectedEventHandler(object sender, DropdownItemSelectedEventArgs e);
    public event DropdownItemSelectedEventHandler DropdownItemSelected;

    protected override void OnDropDown(EventArgs e)
    {
        // Install wrapper
        base.OnDropDown(e);
        // Retrieve handle to dropdown list
        COMBOBOXINFO info = new COMBOBOXINFO();
        info.cbSize = Marshal.SizeOf(info);
        SendMessageCb(this.Handle, 0x164, IntPtr.Zero, out info);
        mDropdown = new DropdownWindow(this);
        mDropdown.AssignHandle(info.hwndList);
    }
    protected override void OnDropDownClosed(EventArgs e)
    {
        // Remove wrapper
        mDropdown.ReleaseHandle();
        mDropdown = null;
        base.OnDropDownClosed(e);
        OnSelect(-1, Rectangle.Empty, true);
    }
    internal void OnSelect(int item, Rectangle pos, bool scroll)
    {
        if (this.DropdownItemSelected != null)
        {
            pos = this.RectangleToClient(pos);
            DropdownItemSelected(this, new DropdownItemSelectedEventArgs(item, pos, scroll));
        }
    }
    // Event handler arguments
    public class DropdownItemSelectedEventArgs : EventArgs
    {
        private int mItem;
        private Rectangle mPos;
        private bool mScroll;
        public DropdownItemSelectedEventArgs(int item, Rectangle pos, bool scroll) { mItem = item; mPos = pos; mScroll = scroll; }
        public int SelectedItem { get { return mItem; } }
        public Rectangle Bounds { get { return mPos; } }
        public bool Scrolled { get { return mScroll; } }
    }

    // Wrapper for combobox dropdown list
    private class DropdownWindow : NativeWindow
    {
        private ComboBoxTooltip mParent;
        private int mItem;
        public DropdownWindow(ComboBoxTooltip parent)
        {
            mParent = parent;
            mItem = -1;
        }
        protected override void WndProc(ref Message m)
        {
            // All we're getting here is WM_MOUSEMOVE, ask list for current selection for LB_GETCURSEL
            Console.WriteLine(m.ToString());
            base.WndProc(ref m);
            if (m.Msg == 0x200)
            {
                int item = (int)SendMessage(this.Handle, 0x188, IntPtr.Zero, IntPtr.Zero);
                if (item != mItem)
                {
                    mItem = item;
                    OnSelect(false);
                }
            }
            if (m.Msg == 0x115)
            {
                // List scrolled, item position would change
                OnSelect(true);
            }
        }
        private void OnSelect(bool scroll)
        {
            RECT rc = new RECT();
            SendMessageRc(this.Handle, 0x198, (IntPtr)mItem, out rc);
            MapWindowPoints(this.Handle, IntPtr.Zero, ref rc, 2);
            mParent.OnSelect(mItem, Rectangle.FromLTRB(rc.Left, rc.Top, rc.Right, rc.Bottom), scroll);
        }
    }
    // P/Invoke declarations
    private struct COMBOBOXINFO
    {
        public Int32 cbSize;
        public RECT rcItem;
        public RECT rcButton;
        public int buttonState;
        public IntPtr hwndCombo;
        public IntPtr hwndEdit;
        public IntPtr hwndList;
    }
    [StructLayout(LayoutKind.Sequential)]
    private struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }
    [DllImport("user32.dll", EntryPoint = "SendMessageW", CharSet = CharSet.Unicode)]
    private static extern IntPtr SendMessageCb(IntPtr hWnd, int msg, IntPtr wp, out COMBOBOXINFO lp);
    [DllImport("user32.dll", EntryPoint = "SendMessageW", CharSet = CharSet.Unicode)]
    private static extern IntPtr SendMessageRc(IntPtr hWnd, int msg, IntPtr wp, out RECT lp);
    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
    [DllImport("user32.dll")]
    private static extern int MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, [In, Out] ref RECT rc, int points);
}

2 个答案:

答案 0 :(得分:1)

试试这个:

' Get the longest element
For Each elem As String In CBox1.Items
    If elem.Length > auxCad.Length Then auxCad = elem
Next

' Get the size
iSize = CInt(CBox1.CreateGraphics.MeasureString(auxCad, CBox1.Font).Width) + 20

If iSize > CBox1.Width Then
    'Show tooltip
End If

答案 1 :(得分:1)

嗯,你可以试试这个:

    Dim LastSelectedItem As Int32 = -1

Private Sub ComboBoxTooltip_DropdownItemSelected(sender As Object, e As ComboBoxTooltip.DropdownItemSelectedEventArgs) _
Handles ComboBoxTooltip1.DropdownItemSelected

    Dim SelectedItem As Int32 = e.SelectedItem

    If SelectedItem <> LastSelectedItem Then
        ToolTip1.Hide(sender)
        LastSelectedItem = -1
    End If

    If SelectedItem < 0 OrElse e.Scrolled Then
        ToolTip1.Hide(sender)
        LastSelectedItem = -1
    Else
        If sender.Items(e.SelectedItem).Length > CInt(sender.CreateGraphics.MeasureString(0, sender.Font).Width) + 8 Then
            LastSelectedItem = SelectedItem
            ToolTip1.Show(sender.Items(SelectedItem).ToString(), sender, e.Bounds.Location)
        End If
    End If

End Sub

用户控制代码:

    using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class ComboBoxTooltip : ComboBox
{
    private DropdownWindow mDropdown;
    public delegate void DropdownItemSelectedEventHandler(object sender, DropdownItemSelectedEventArgs e);
    public event DropdownItemSelectedEventHandler DropdownItemSelected;

    protected override void OnDropDown(EventArgs e)
    {
        // Install wrapper
        base.OnDropDown(e);
        // Retrieve handle to dropdown list
        COMBOBOXINFO info = new COMBOBOXINFO();
        info.cbSize = Marshal.SizeOf(info);
        SendMessageCb(this.Handle, 0x164, IntPtr.Zero, out info);
        mDropdown = new DropdownWindow(this);
        mDropdown.AssignHandle(info.hwndList);
    }
    protected override void OnDropDownClosed(EventArgs e)
    {
        // Remove wrapper
        mDropdown.ReleaseHandle();
        mDropdown = null;
        base.OnDropDownClosed(e);
        OnSelect(-1, Rectangle.Empty, true);
    }
    internal void OnSelect(int item, Rectangle pos, bool scroll)
    {
        if (this.DropdownItemSelected != null)
        {
            pos = this.RectangleToClient(pos);
            DropdownItemSelected(this, new DropdownItemSelectedEventArgs(item, pos, scroll));
        }
    }
    // Event handler arguments
    public class DropdownItemSelectedEventArgs : EventArgs
    {
        private int mItem;
        private Rectangle mPos;
        private bool mScroll;
        public DropdownItemSelectedEventArgs(int item, Rectangle pos, bool scroll) { mItem = item; mPos = pos; mScroll = scroll; }
        public int SelectedItem { get { return mItem; } }
        public Rectangle Bounds { get { return mPos; } }
        public bool Scrolled { get { return mScroll; } }
    }

    // Wrapper for combobox dropdown list
    private class DropdownWindow : NativeWindow
    {
        private ComboBoxTooltip mParent;
        private int mItem;
        public DropdownWindow(ComboBoxTooltip parent)
        {
            mParent = parent;
            mItem = -1;
        }
        protected override void WndProc(ref Message m)
        {
            // All we're getting here is WM_MOUSEMOVE, ask list for current selection for LB_GETCURSEL
            Console.WriteLine(m.ToString());
            base.WndProc(ref m);
            if (m.Msg == 0x200)
            {
                int item = (int)SendMessage(this.Handle, 0x188, IntPtr.Zero, IntPtr.Zero);
                if (item != mItem)
                {
                    mItem = item;
                    OnSelect(false);
                }
            }
            if (m.Msg == 0x115)
            {
                // List scrolled, item position would change
                OnSelect(true);
            }
        }
        private void OnSelect(bool scroll)
        {
            RECT rc = new RECT();
            SendMessageRc(this.Handle, 0x198, (IntPtr)mItem, out rc);
            MapWindowPoints(this.Handle, IntPtr.Zero, ref rc, 2);
            mParent.OnSelect(mItem, Rectangle.FromLTRB(rc.Left, rc.Top, rc.Right, rc.Bottom), scroll);
        }
    }
    // P/Invoke declarations
    private struct COMBOBOXINFO
    {
        public Int32 cbSize;
        public RECT rcItem;
        public RECT rcButton;
        public int buttonState;
        public IntPtr hwndCombo;
        public IntPtr hwndEdit;
        public IntPtr hwndList;
    }
    [StructLayout(LayoutKind.Sequential)]
    private struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }
    [DllImport("user32.dll", EntryPoint = "SendMessageW", CharSet = CharSet.Unicode)]
    private static extern IntPtr SendMessageCb(IntPtr hWnd, int msg, IntPtr wp, out COMBOBOXINFO lp);
    [DllImport("user32.dll", EntryPoint = "SendMessageW", CharSet = CharSet.Unicode)]
    private static extern IntPtr SendMessageRc(IntPtr hWnd, int msg, IntPtr wp, out RECT lp);
    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
    [DllImport("user32.dll")]
    private static extern int MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, [In, Out] ref RECT rc, int points);
}