为什么没有显示指向正确控件的气球提示?

Dor*_*eka 7 .net c# textbox tooltip winforms

ToolTip在我的表单上使用了一个控件,但是发现即使我的光标在一个控件上,工具提示也显示在其他地方.我想在我的光标所在的控件内显示这个.

替代文字

如上图所示,当我的光标结束时Textbox3,工具提示正在显示Textbox4.我希望它显示指向Textbox3.

我目前正在使用以下代码在3个不同的事件中显示工具提示:

 private void txtImmediateddest_Enter(object sender, EventArgs e)
 {
     ttpDetail.Show("Ex:111000025", txtImmediateddest);
 }

 private void txtImmediateddest_MouseHover(object sender, EventArgs e)
 {
     ttpDetail.Show("Ex:111000025", txtImmediateddest);
 }

  private void txtImmediateddest_MouseUp(object sender, MouseEventArgs e)
  {
      ttpDetail.Show("Ex:111000025", txtImmediateddest, e.Location);
      //toolTipimmeddest.Show("Required & Must be 9 Digits", txtImmediateddest);
  }
Run Code Online (Sandbox Code Playgroud)

编辑

 private void textBox1_MouseHover(object sender, EventArgs e)
    {
        ttpDetail.AutoPopDelay = 2000;
        ttpDetail.InitialDelay = 1000;
        ttpDetail.ReshowDelay = 500;
        ttpDetail.IsBalloon = true;
        //ttpDetail.SetToolTip(textBox1, "Ex:01(Should be Numeric)");
        ttpDetail.Show("Ex : 01(Should Be Numeric)", textBox1,textBox1.Width, textBox1.Height/10,5000);
    }
Run Code Online (Sandbox Code Playgroud)

这工作正常,但当鼠标初始到控件时它显示正常,如果我有第二次它正确显示

请看下面的图片

替代文字

替代文字

Cod*_*ray 23

您看到的问题是因为您的ToolTip控件的IsBalloon属性设置为"True".设置此属性后,ToolTip不会更改其相对位置,导致气球的箭头指向错误的控件.

这是一个并排比较,展示了这种现象:

        

显然,简单的解决方法是通过将IsBalloon属性设置为"False" 来禁用该属性.控件将恢复显示标准的矩形工具提示窗口,该窗口将正确对齐.

如果您无法接受,则必须指定工具提示气球显示的确切位置.不幸的是,看起来ToolTip控件中存在一个错误,导致它在第一次连接到控件时不能正确显示.通常可以通过Show使用空字符串调用方法一次来修复此问题.例如,使用以下代码:

private void txtImmediateddest_Enter(object sender, EventArgs e)
{
    ttpDetail.Show(string.Empty, textBox3, 0);
    ttpDetail.Show("Ex:111000025", textBox3, textBox3.Width / 2, textBox3.Height, 5000);
}
Run Code Online (Sandbox Code Playgroud)

产生这个结果:

  

当然,你的运气也可能因这条路线而异.我通常不使用内置ToolTip控件进行编辑控件(例如文本框和组合框).我发现P/Invoke更可靠SendMessage,指定EM_SHOWBALLOONTIP和包含我想要显示的工具提示信息的EDITBALLOONTIP结构.我将留下查找适当的定义并将包装器代码编写为读者的练习,因为这个答案已经太久了.


Chr*_*ris 5

经过大量的故障排除后,我发现下面的代码比内置气球工具提示优于网络.通过取消注释清单文件中的依赖项,确保启用了Visual Styles.

在TextBox上创建一个BalloonTip,如下所示:

new BalloonTip("Title", "Message", textBox1, BalloonTip.ICON.INFO, 5000);
Run Code Online (Sandbox Code Playgroud)

并实现BalloonTip如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace Lib.Windows
{
    class BalloonTip
    {
        private System.Timers.Timer timer = new System.Timers.Timer();
        private SemaphoreSlim semaphore = new SemaphoreSlim(1);
        private IntPtr hWnd;

        public BalloonTip(string text, Control control)
        {
            Show("", text, control);
        }

        public BalloonTip(string title, string text, Control control, ICON icon = 0, double timeOut = 0, bool focus = false)
        {
            Show(title, text, control, icon, timeOut, focus);
        }

        void Show(string title, string text, Control control, ICON icon = 0, double timeOut = 0, bool focus = false, short x = 0, short y = 0)
        {
            if (x == 0 && y == 0)
            {
                x = (short)(control.RectangleToScreen(control.ClientRectangle).Left + control.Width / 2);
                y = (short)(control.RectangleToScreen(control.ClientRectangle).Top + control.Height / 2);
            }
            TOOLINFO toolInfo = new TOOLINFO();
            toolInfo.cbSize = (uint)Marshal.SizeOf(toolInfo);
            toolInfo.uFlags = 0x20; // TTF_TRACK
            toolInfo.lpszText = text;
            IntPtr pToolInfo = Marshal.AllocCoTaskMem(Marshal.SizeOf(toolInfo));
            Marshal.StructureToPtr(toolInfo, pToolInfo, false);
            byte[] buffer = Encoding.UTF8.GetBytes(title);
            buffer = buffer.Concat(new byte[] { 0 }).ToArray();
            IntPtr pszTitle = Marshal.AllocCoTaskMem(buffer.Length);
            Marshal.Copy(buffer, 0, pszTitle, buffer.Length);
            hWnd = User32.CreateWindowEx(0x8, "tooltips_class32", "", 0xC3, 0, 0, 0, 0, control.Parent.Handle, (IntPtr)0, (IntPtr)0, (IntPtr)0);
            User32.SendMessage(hWnd, 1028, (IntPtr)0, pToolInfo); // TTM_ADDTOOL
            User32.SendMessage(hWnd, 1042, (IntPtr)0, (IntPtr)((ushort)x | ((ushort)y << 16))); // TTM_TRACKPOSITION
            //User32.SendMessage(hWnd, 1043, (IntPtr)0, (IntPtr)0); // TTM_SETTIPBKCOLOR
            //User32.SendMessage(hWnd, 1044, (IntPtr)0xffff, (IntPtr)0); // TTM_SETTIPTEXTCOLOR
            User32.SendMessage(hWnd, 1056, (IntPtr)icon, pszTitle); // TTM_SETTITLE 0:None, 1:Info, 2:Warning, 3:Error, >3:assumed to be an hIcon. ; 1057 for Unicode
            User32.SendMessage(hWnd, 1048, (IntPtr)0, (IntPtr)500); // TTM_SETMAXTIPWIDTH
            User32.SendMessage(hWnd, 0x40c, (IntPtr)0, pToolInfo); // TTM_UPDATETIPTEXT; 0x439 for Unicode
            User32.SendMessage(hWnd, 1041, (IntPtr)1, pToolInfo); // TTM_TRACKACTIVATE
            Marshal.FreeCoTaskMem(pszTitle);
            Marshal.DestroyStructure(pToolInfo, typeof(TOOLINFO));
            Marshal.FreeCoTaskMem(pToolInfo);
            if (focus)
                control.Focus();
            // uncomment bellow to make balloon close when user changes focus,
            // starts typing, resizes/moves parent window, minimizes parent window, etc
            // adjust which control events to subscribe to depending on the control over which the balloon tip is shown

            /*control.Click += control_Event;
            control.Leave += control_Event;
            control.TextChanged += control_Event;
            control.LocationChanged += control_Event;
            control.SizeChanged += control_Event;
            control.VisibleChanged += control_Event;
            Control parent = control.Parent;
            while(parent != null)
            {
                parent.VisibleChanged += control_Event;
                parent = parent.Parent;
            }
            control.TopLevelControl.LocationChanged += control_Event;
            ((Form)control.TopLevelControl).Deactivate += control_Event;*/

            timer.AutoReset = false;
            timer.Elapsed += timer_Elapsed;
            if (timeOut > 0)
            {
                timer.Interval = timeOut;
                timer.Start();
            }
        }

        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            Close();
        }

        void control_Event(object sender, EventArgs e)
        {
            Close();
        }

        void Close()
        {
            if (!semaphore.Wait(0)) // ensures one time only execution
                return;
            timer.Elapsed -= timer_Elapsed;
            timer.Close();
            User32.SendMessage(hWnd, 0x0010, (IntPtr)0, (IntPtr)0); // WM_CLOSE
            //User32.SendMessage(hWnd, 0x0002, (IntPtr)0, (IntPtr)0); // WM_DESTROY
            //User32.SendMessage(hWnd, 0x0082, (IntPtr)0, (IntPtr)0); // WM_NCDESTROY
        }

        [StructLayout(LayoutKind.Sequential)]
        struct TOOLINFO
        {
            public uint cbSize;
            public uint uFlags;
            public IntPtr hwnd;
            public IntPtr uId;
            public RECT rect;
            public IntPtr hinst;
            [MarshalAs(UnmanagedType.LPStr)]
            public string lpszText;
            public IntPtr lParam;
        }
        [StructLayout(LayoutKind.Sequential)]
        struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        public enum ICON
        {
            NONE,
            INFO,
            WARNING,
            ERROR
        }
    }

    static class User32
    {
        [DllImportAttribute("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
        [DllImportAttribute("user32.dll")]
        public static extern IntPtr CreateWindowEx(uint dwExStyle, string lpClassName, string lpWindowName, uint dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr LPVOIDlpParam);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是它的样子:

在此输入图像描述