Как сделать плавающий (всплывающая подсказка) элемент управления в Windows.Forms? - PullRequest
3 голосов
/ 17 марта 2010

Сцена: A (маленькая) форма, в которой размещен UserControl.

График: Всякий раз, когда UserControl вызывает событие при наведении, отображать некоторую (графическую) информацию в виде всплывающей подсказки. Когда пользователь перемещает мышь, снова исчезает.

Примечания: Я хотел бы отобразить более одной «всплывающей подсказки», где каждая подсказка представляет собой UserControl, отображающий информацию в графической форме. Не просто текст в желтом поле! Также я использую библиотеку Windows.Forms.

Это то, что я имею до сих пор:

private void myControl_Hovered(object sender, MyEventArgs e)
{            
    var tooltip = new MyToolTip();
    Controls.Add(tooltip);
    tooltip.UpdateDisplay(e.Data);
    tooltip.Show();
}

Но он появляется на заднем плане (я могу справиться с этим) и, к сожалению, ограничивается окном ...


РЕДАКТИРОВАТЬ: Вот что я закончил делать ...

Я не смог заставить работать ToolTip элемент управления, поставляемый с .NET. Это происходит главным образом потому, что я пытаюсь показать всплывающие подсказки для «горячих точек» в нарисованном пользователем элементе управления (подумайте о графике функциональных точек, покажите дополнительные элементы для точек). Элемент управления ToolTip действительно хотел бы показывать только тогда, когда пользователь впервые вводит элемент управления - показ вручную, что он не работает. Я старался. Долго и трудно.

Итак, этот класс ToolTipWindow можно использовать для отображения элемента управления в безрамном окне. Я добавил свойство Offset, чтобы оно могло отображаться со смещением относительно текущей позиции мыши.

/// <summary>
/// A tooltip class to display some information from a control.
/// </summary>
internal class ToolTipWindow: Form
{
    /// <summary>
    /// The offset from the mouse pointer to show the window at.
    /// </summary>
    public Point Offset { get; set;}

    internal ToolTipWindow(Control controlToDisplay)
    {
        FormBorderStyle = FormBorderStyle.None;
        TopMost = true;
        ShowInTaskbar = false;
        Opacity = 0.9;
        Width = controlToDisplay.Width;
        Height = controlToDisplay.Height;
        Controls.Add(controlToDisplay);
        controlToDisplay.Show();
    }

    /// <summary>
    /// Move the window to an offset of mouse pointer.
    /// </summary>
    protected override void OnShown(EventArgs e)
    {
        base.OnShown(e);
        Location = new Point(MousePosition.X + Offset.X, MousePosition.Y + Offset.Y);
    }

    /// <summary>
    /// Move the window to an offset of mouse pointer.
    /// </summary>
    protected override void OnVisibleChanged(EventArgs e)
    {
        base.OnVisibleChanged(e);
        if (Visible)
        {
            Location = new Point(MousePosition.X + Offset.X, MousePosition.Y +     Offset.Y);    
        }
    }
}

Чтобы показать подсказку, вы можете перехватить события MouseHover и MouseMove. Сначала проверьте, если вы находитесь выше «горячей точки» и покажите всплывающую подсказку. В MouseMove скрывайте всплывающие подсказки, если вы не находитесь над «горячей точкой». Кроме того, при закрытии окна обязательно закройте все окна всплывающих подсказок!

Примечание: Событие MouseHover будет отображаться только при первом входе мыши в элемент управления. Если вы хотите, чтобы он появлялся повторно (как в случае обнаружения «горячих точек»), вам необходимо добавить код, подобный следующему, в элемент управления, содержащий «горячие точки»:

    #region AddReHoverExperience
    // ReSharper disable InconsistentNaming
    // found this code here: http://www.pinvoke.net/default.aspx/user32.TrackMouseEvent

    [DllImport("user32.dll")]
    static extern int TrackMouseEvent(ref TRACKMOUSEEVENT lpEventTrack);
    [StructLayout(LayoutKind.Sequential)]

    public struct TRACKMOUSEEVENT

    {
        public UInt32 cbSize;
        public UInt32 dwFlags;
        public IntPtr hwndTrack;
        public UInt32 dwHoverTime;
    }

    TRACKMOUSEEVENT tme;
    private const uint TME_HOVER = 0x1;

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

    protected override void OnMouseEnter(EventArgs e)
    {
        base.OnMouseEnter(e);
        tme = new TRACKMOUSEEVENT
                  {
                      hwndTrack = Handle, 
                      dwFlags = TME_HOVER, 
                      dwHoverTime = 500
                  };
        tme.cbSize = (uint)Marshal.SizeOf(tme);
        TrackMouseEvent(ref tme);
    }
    // ReSharper restore InconsistentNaming
    #endregion AddReHoverExperience

1 Ответ

5 голосов
/ 17 марта 2010

Ваш код имеет серьезную проблему, он добавляет элемент управления в пользовательский элемент управления каждый раз, когда мышь наводит курсор, но никогда не удаляет их.

Во-первых, убедитесь, что встроенный компонент ToolTip уже не решает вашу проблему. Должен, ведет себя так, как вы описываете. Обратите внимание, что у него есть свойство OwnerDraw, оно позволяет настроить его внешний вид.

Создание собственного сложно. Всплывающая подсказка - это довольно необычное окно, оно не является дочерним элементом управления, как все другие элементы управления WF. Это окно верхнего уровня, которое позволяет ему перекрывать другие окна и выходить за пределы клиентской области окна контейнера. Единственный класс в Windows Forms, который ведет себя таким образом, это класс Form. Возможно использование формы без полей для реализации настраиваемой подсказки.

Самая хитрая часть - обеспечить его перемещение при перемещении родительской формы вашего пользовательского элемента управления. Вам нужно будет перебирать свойство Parent UC, пока вы не найдете Form, а затем подписаться на события LocationChanged, VisibleChanged и FormClosing. Вам также следует связать события UC ParentChanged и HandleDestroyed.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...