代码之家  ›  专栏  ›  技术社区  ›  Daren Thomas

如何在windows.forms中创建浮动(工具提示)控件?

  •  3
  • Daren Thomas  · 技术社区  · 15 年前

    场景: 托管用户控件的(小)窗体。

    情节: 每当用户控件引发悬停事件时,以工具提示的方式显示一些(图形)信息。当用户移动鼠标时,再次将其淡出。

    笔记: 我想显示不止一个“工具提示”,每个工具提示都是以图形方式显示信息的用户控件。不仅仅是黄色框里的文字!另外,我正在使用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一起工作。这主要是因为我试图在用户绘制的控件中显示“热点”的工具提示(考虑功能点的绘图,显示点的其他项)。工具提示控件只希望在用户首次输入控件时显示-手动显示似乎不起作用。我试过了。又长又硬。

    所以,这个 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 事件。首先检查,如果你在一个“热点”之上,并显示工具提示。在 鼠标移动 ,如果不在“热点”上方,则隐藏工具提示。此外,在关闭窗口时,请确保同时关闭所有工具提示窗口!

    注: 这个 莫希尔 事件只在鼠标第一次进入控件时显示。如果希望它重复出现(如检测到“热点”时),应向包含“热点”的控件添加如下代码:

        #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 回复  |  直到 15 年前
        1
  •  5
  •   Hans Passant    15 年前

    您的代码有一个严重的问题,它会在每次鼠标悬停时向用户控件添加一个控件,但从不删除它们。

    首先,确保内置的工具提示组件没有解决您的问题。它应该,它的行为方式你的描述。注意,它有ownerDraw属性,允许您自定义其外观。

    创建自己的是很棘手的。工具提示是一个相当不寻常的窗口,它不像所有其他wf控件那样是子控件。它是一个顶级窗口,允许它与其他窗口重叠并扩展到容器窗口的工作区之外。windows窗体中唯一这样做的类是form类。使用无边界表单实现自定义工具提示是可能的。

    最棘手的部分是确保它在用户控件的父窗体移动时移动。在找到表单之前,必须迭代UC的父属性,然后订阅LocationChanged、VisibleChanged和FormClosing事件。你还应该联系UC的父母变更和处理失职事件。