C# 为什么不';t气球提示是否指向正确的控件?
我正在表单上使用C# 为什么不';t气球提示是否指向正确的控件?,c#,.net,winforms,textbox,tooltip,C#,.net,Winforms,Textbox,Tooltip,我正在表单上使用工具提示控件,但发现即使光标位于一个控件上,工具提示也会显示在其他地方。我想在我的光标所在的控件中显示它 如上图所示,当我的光标位于Textbox3上时,工具提示将显示在Textbox4上。我希望它能够指向Textbox3显示 我目前正在使用以下代码在3个不同的事件中显示工具提示: private void txtImmediateddest_Enter(object sender, EventArgs e) { ttpDetail.Show("Ex:111000
工具提示
控件,但发现即使光标位于一个控件上,工具提示也会显示在其他地方。我想在我的光标所在的控件中显示它
如上图所示,当我的光标位于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);
}
编辑
这很好,但当鼠标最初放在控件上时,如果我第二次正确显示,它将显示正常
请看以下图片
您看到的问题是因为您的
工具提示
控件设置为“True”。设置此属性后,工具提示不会更改其相对位置,从而导致引出序号的箭头指向错误的控件
下面是一个并排比较,展示了这种现象:
显然,简单的修复方法是通过将IsBalloon
属性设置为“False”来禁用它。控件将恢复为显示标准的矩形工具提示窗口,该窗口看起来将正确对齐
如果您不能接受,则必须指定工具提示引出序号显示的确切位置。不幸的是,工具提示
控件中似乎有一个bug,导致它在第一次附加到控件时无法正确显示。这通常可以通过使用空字符串调用一次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);
}
产生以下结果:
当然,沿着这条路线你的运气也会有所不同。我通常不使用内置的工具提示控件来编辑控件(如文本框和组合框)。我发现P/Invoke更可靠,它指定并包含我想要显示的工具提示的信息。我将把查找适当的定义和编写包装器代码作为读者的一个练习,因为这个答案已经太长了。嘿,我终于得到了这段代码
当老鼠离开
public class MouseLeave
{
public void mouseLeave(TextBox txtTemp, ToolTip ttpTemp)
{
ttpTemp.Hide(txtTemp);
}
}
当鼠标滑过
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;
}
}
}
您是否尝试在鼠标悬停事件中仅使用设置工具提示方法(不调用显示方法)
ttpTemp.SetToolTip(txtTemp,“Ex:01(应为数字)”强>
这对我来说很好(我使用的是管理C++,但我认为是一样的)。
< P>经过大量的故障排除,我发现代码BoLet比内置的气球工具提示更优秀。确保通过取消对清单文件中的依赖项的注释来启用视觉样式
在文本框上创建一个气球提示,如下所示:
new BalloonTip("Title", "Message", textBox1, BalloonTip.ICON.INFO, 5000);
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);
}
}
并实现如下balloottip
:
new BalloonTip("Title", "Message", textBox1, BalloonTip.ICON.INFO, 5000);
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);
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Windows.Forms;
使用System.Runtime.InteropServices;
名称空间库.Windows
{
类气球头
{
private System.Timers.Timer Timer=新的System.Timers.Timer();
私有信号量slim信号量=新信号量slim(1);
私人IntPtr hWnd;
公共气球提示(字符串文本、控件)
{
显示(“”,文本,控件);
}
公共气球提示(字符串标题、字符串文本、控件、图标图标=0、双超时=0、布尔焦点=false)
{
显示(标题、文本、控件、图标、超时、焦点);
}
无效显示(字符串标题、字符串文本、控件、图标图标=0、双超时=0、布尔焦点=false、短x=0、短y=0)
{
如果(x==0&&y==0)
{
x=(短)(control.RectangleToScreen(control.ClientRectangle.Left+control.Width/2);
y=(短)(control.RectangleToScreen(control.ClientRectangle.Top+control.Height/2);
}
TOOLINFO TOOLINFO=新的TOOLINFO();
toolInfo.cbSize=(uint)Marshal.SizeOf(toolInfo);
toolInfo.uFlags=0x20;//TTF\u轨迹
toolInfo.lpszText=文本;
IntPtr pToolInfo=Marshal.alloctaskmem(Marshal.SizeOf(toolInfo));
Marshal.StructureToPtr(toolInfo,pToolInfo,false);
byte[]buffer=Encoding.UTF8.GetBytes(title);
buffer=buffer.Concat(新字节[]{0}).ToArray();
IntPtr pszTitle=Marshal.alloctaskmem(buffer.Length);
Marshal.Copy(buffer,0,pszTitle,buffer.Length);
hWnd=User32.CreateWindowEx(0x8,“工具提示”\u class32“,”,0xC3,0,0,0,0,control.Parent.Handle,(IntPtr)0,(IntPtr)0,(IntPtr)0);
User32.SendMessage(hWnd,1028,(IntPtr)0,pToolInfo);//TTM_ADDTOOL
发送消息(hWnd,1042,(IntPtr)0,(IntPtr)((ushort)x |)((ushort)y 3:假定为一个hIcon;1057表示Unicode
User32.SendMessage(hWnd,1048,(IntPtr)0,(IntPtr)500);//TTM_SETMAXTIPWIDTH
User32.SendMessage(hWnd,0x40c,(IntPtr)0,pToolInfo);//TTM_UPDATETIPTEXT;0x439表示Unicode
User32.SendMessage(hWnd,1041,(IntPtr)1,pToolInfo);//TTM_TRACKACTIVATE
FreeCoTaskMem元帅(pszTitle);
结构(pToolInfo,typeof(toolnfo));
弗里科塔斯克梅姆元帅(托洛林福);
如果(焦点)
control.Focus();
//在用户更改焦点时,取消下面的注释以关闭引出序号,
//开始键入、调整/移动父窗口、最小化父窗口等
//根据显示引出序号提示的控件,调整要订阅的控件事件
/*控件。单击+=控件\事件;
控制。离开+=控制事件;
control.TextChanged+=control\u偶数