Why are balloon tips not showing correct control?

I use the ToolTip element in my form, but found that although my cursor is on one control, a tooltip shows somewhere else. I would like to show this inside the control where my cursor is located.

alt text

As shown in the image above, when my cursor is over Textbox3 , a tooltip is displayed on Textbox4 . I would like it to display, pointing to Textbox3 .

I am currently using the following code to display a tooltip in three different events:

  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); } 

Edit

  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); } 

This works fine, but when the mouse is first on the control, it displays normal, if I have a second time, it displays correctly

Look at the following images

alt text

alt text

+6
c # winforms tooltip textbox
source share
5 answers

The problem you are seeing is that your ToolTip IsBalloon set to True. Using this set of properties, ToolTip does not change its relative location, with the result that the arrow of the balloon indicates improper control.

Here is a side-by-side comparison demonstrating this phenomenon:

itScl.pngFPNsG.png

A simple fix, obviously, is to disable the IsBalloon property by setting it to "False". The control will revert to displaying a standard rectangular tooltip that will look right.

If this is not acceptable to you, you will need to specify the exact location where you want to display the tooltip. Unfortunately, it looks like there is an error in the ToolTip control due to which it does not appear properly the first time you connect to the control. This can usually be fixed by calling the Show method with an empty string once. For example, using the following code:

 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); } 

produces this result:

Of course, your luck may change along this route. I usually don’t use the built-in ToolTip control for editing controls (like text boxes and comboboxes). I find it more reliable for P / Invoke SendMessage by specifying the EM_SHOWBALLOONTIP and EDITBALLOONTIP structure containing the tooltip information I want to show. I will leave the search for suitable definitions and write the shell code as an exercise for the reader, as this answer is too long.

+22
source share

After much troubleshooting, I found the code below to be clean, superior to the built-in tooltip. Make sure Visual Styles is enabled by uncommenting the dependency in the manifest file.

Create a BalloonTip over a TextBox as follows:

 new BalloonTip("Title", "Message", textBox1, BalloonTip.ICON.INFO, 5000); 

and implement BalloonTip as follows:

 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); } } 

Here's what it looks like:

enter image description here

+5
source share

You tried to use only the SetToolTip method (without calling the show method) in the MouseOver event

ttpTemp.SetToolTip (txtTemp, "Ex: 01 (must be numeric)");

This works fine for me (I use Managed C ++, but I think it is the same).

+2
source share

With Chris credit response , I host the VB.NET port here:

 Imports System.Collections.Generic Imports System Imports System.Linq Imports System.Text Imports System.Windows.Forms Imports System.Runtime.InteropServices Namespace [Lib].Windows Class BalloonTip Private timer As New System.Timers.Timer() Private semaphore As New System.Threading.SemaphoreSlim(1) Private hWnd As IntPtr Public Sub New(text As String, control As Control) Show("", text, control) End Sub Public Sub New(title As String, text As String, control As Control, Optional icon As ICON = 0, Optional timeOut As Double = 0, Optional focus As Boolean = False) Show(title, text, control, icon, timeOut, focus) End Sub Private Sub Show(title As String, text As String, control As Control, Optional icon As ICON = 0, Optional timeout As Double = 0, Optional focus As Boolean = False) Dim x As UShort = CType(control.RectangleToScreen(control.ClientRectangle).Left + control.Width / 2, UShort) Dim y As UShort = CType(control.RectangleToScreen(control.ClientRectangle).Top + control.Height / 2, UShort) Dim toolInfo As New TOOLINFO() toolInfo.cbSize = CType(Marshal.SizeOf(toolInfo), UInteger) toolInfo.uFlags = &H20 ' TTF_TRACK toolInfo.lpszText = text Dim pToolInfo As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(toolInfo)) Marshal.StructureToPtr(toolInfo, pToolInfo, False) Dim buffer As Byte() = Encoding.UTF8.GetBytes(title) buffer = buffer.Concat(New Byte() {0}).ToArray() Dim pszTitle As IntPtr = Marshal.AllocCoTaskMem(buffer.Length) Marshal.Copy(buffer, 0, pszTitle, buffer.Length) hWnd = User32.CreateWindowEx(&H8, "tooltips_class32", "", &HC3, 0, 0, _ 0, 0, control.Parent.Handle, CType(0, IntPtr), CType(0, IntPtr), CType(0, IntPtr)) User32.SendMessage(hWnd, 1028, CType(0, IntPtr), pToolInfo) ' TTM_ADDTOOL 'User32.SendMessage(hWnd, 1043, CType(0, IntPtr), CType(0, IntPtr); ' TTM_SETTIPBKCOLOR 'User32.SendMessage(hWnd, 1044, CType(&HFFFF, IntPtr), CType(0, IntPtr); ' TTM_SETTIPTEXTCOLOR User32.SendMessage(hWnd, 1056, CType(icon, IntPtr), pszTitle) ' TTM_SETTITLE 0:None, 1:Info, 2:Warning, 3:Error, >3:assumed to be an hIcon. ; 1057 for Unicode User32.SendMessage(hWnd, 1048, CType(0, IntPtr), CType(500, IntPtr)) ' TTM_SETMAXTIPWIDTH User32.SendMessage(hWnd, &H40C, CType(0, IntPtr), pToolInfo) ' TTM_UPDATETIPTEXT; 0x439 for Unicode User32.SendMessage(hWnd, 1042, CType(0, IntPtr), CType(x Or (CUInt(y) << 16), IntPtr)) ' TTM_TRACKPOSITION User32.SendMessage(hWnd, 1041, CType(1, IntPtr), pToolInfo) ' TTM_TRACKACTIVATE Marshal.FreeCoTaskMem(pszTitle) Marshal.DestroyStructure(pToolInfo, GetType(TOOLINFO)) Marshal.FreeCoTaskMem(pToolInfo) If focus Then control.Focus() End If ' uncomment below 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 'AddHandler control.Click, AddressOf control_Event 'AddHandler control.Leave, AddressOf control_Event 'AddHandler control.TextChanged, AddressOf control_Event 'AddHandler control.LocationChanged, AddressOf control_Event 'AddHandler control.SizeChanged, AddressOf control_Event 'AddHandler control.VisibleChanged, AddressOf control_Event 'Dim parent As Control = control.Parent 'While Not (parent Is Nothing) ' AddHandler parent.VisibleChanged, AddressOf control_Event ' parent = parent.Parent 'End While 'AddHandler control.TopLevelControl.LocationChanged, AddressOf control_Event 'AddHandler DirectCast(control.TopLevelControl, Form).Deactivate, AddressOf control_Event timer.AutoReset = False RemoveHandler timer.Elapsed, AddressOf timer_Elapsed If timeout > 0 Then timer.Interval = timeout timer.Start() End If End Sub Private Sub timer_Elapsed(sender As Object, e As System.Timers.ElapsedEventArgs) Close() End Sub Private Sub control_Event(sender As Object, e As EventArgs) Close() End Sub Sub Close() If Not semaphore.Wait(0) Then ' ensures one time only execution Return End If RemoveHandler timer.Elapsed, AddressOf timer_Elapsed timer.Close() User32.SendMessage(hWnd, &H10, CType(0, IntPtr), CType(0, IntPtr)) ' WM_CLOSE 'User32.SendMessage(hWnd, &H0002, CType(0, IntPtr), CType(0, IntPtr)); ' WM_DESTROY 'User32.SendMessage(hWnd, &H0082, CType(0, IntPtr), CType(0, IntPtr)); ' WM_NCDESTROY End Sub <StructLayout(LayoutKind.Sequential)> _ Private Structure TOOLINFO Public cbSize As UInteger Public uFlags As UInteger Public hwnd As IntPtr Public uId As IntPtr Public rect As RECT Public hinst As IntPtr <MarshalAs(UnmanagedType.LPStr)> _ Public lpszText As String Public lParam As IntPtr End Structure <StructLayout(LayoutKind.Sequential)> _ Private Structure RECT Public Left As Integer Public Top As Integer Public Right As Integer Public Bottom As Integer End Structure Public Enum ICON NONE INFO WARNING [ERROR] End Enum End Class NotInheritable Class User32 Private Sub New() End Sub <DllImportAttribute("user32.dll")> _ Public Shared Function SendMessage(hWnd As IntPtr, Msg As UInt32, wParam As IntPtr, lParam As IntPtr) As Integer End Function <DllImportAttribute("user32.dll")> _ Public Shared Function CreateWindowEx(dwExStyle As UInteger, lpClassName As String, lpWindowName As String, dwStyle As UInteger, x As Integer, y As Integer, _ nWidth As Integer, nHeight As Integer, hWndParent As IntPtr, hMenu As IntPtr, hInstance As IntPtr, LPVOIDlpParam As IntPtr) As IntPtr End Function End Class End Namespace 
+1
source share

Hi i finally got this code

When MouseLeave

  public class MouseLeave { public void mouseLeave(TextBox txtTemp, ToolTip ttpTemp) { ttpTemp.Hide(txtTemp); } } 

When the mouse is over

  public class MouseOver { public void mouseOver(TextBox txtTemp, ToolTip ttpTemp) { switch (txtTemp.Name) { case "textBox1": { ttpTemp.AutoPopDelay = 2000; ttpTemp.InitialDelay = 1000; ttpTemp.ReshowDelay = 500; ttpTemp.IsBalloon = true; ttpTemp.SetToolTip(txtTemp, "Ex:01(Should be Numeric)"); ttpTemp.Show("Ex : 01(Should Be Numeric)", txtTemp, txtTemp.Width, txtTemp.Height / 10, 5000); } break; case "txtDetail": { ttpTemp.AutoPopDelay = 2000; ttpTemp.InitialDelay = 1000; ttpTemp.ReshowDelay = 500; ttpTemp.IsBalloon = true; ttpTemp.SetToolTip(txtTemp, "Ex:01(Should be Numeric)"); ttpTemp.Show("Ex : 01(Should Be Numeric)", txtTemp, txtTemp.Width, txtTemp.Height / 10, 5000); } break; } } } 
0
source share

All Articles