0

我试图通过调用“ToolTip.Show(String, IWin32Window, Point)”来显示工具提示,但我想像 Windows 资源管理器那样做——在光标的左下角显示工具提示。

我可以通过“MousePosition”获得鼠标位置,但我怎样才能获得它的左下角位置呢?

谢谢,

4

3 回答 3

2

如果没有人想出更好的答案,你可以试试这个:

    toolTip1.Show("Am I where you want me to be?", this, this.PointToClient(MousePosition).X,
                                                         this.PointToClient(MousePosition).Y + Cursor.Size.Height * 2);

通过使用 x/y 参数调整文本位置。它适用于我的机器,但我不确定它在不同设置下的外观。

ToolTip 有趣的提示:将这一行放在 Form 的 MouseMove 事件中。

于 2009-11-17T02:09:58.840 回答
1

唯一的方法是扫描光标 MASK 并找到光标掩码中最后设置的像素与光标 Y 热点之间的距离,我今天必须这样做,所以这里是代码:

#define useUnsafe

using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System;
using System.Windows.Forms;

namespace Utils
{
    /// <summary>
    /// Provides extension methods for the Cursor class
    /// </summary>
    /// <remarks>By Aaron Murgatroyd</remarks>
    public static class CursorExtensionMethods
    {
        #region API Functions

        /// <summary>
        /// Contains the icon information for a Windows API icon
        /// </summary>
        private struct IconInfo
        {
            public bool fIcon;
            public int xHotspot;
            public int yHotspot;
            public IntPtr hbmMask;
            public IntPtr hbmColor;
        }

        /// <summary>
        /// Gets the icon information for a Windows API icon
        /// </summary>
        /// <param name="hIcon">The icon to get the info for</param>
        /// <param name="pIconInfo">The object to receive the info</param>
        /// <returns>True on success, false on failure</returns>
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);

        [DllImport("gdi32.dll")]
        static extern bool DeleteObject(IntPtr hObject);

        #endregion

        #region Private Static Methods

        /// <summary>
        /// Scans bits in bitmap data for a set or unset bit
        /// </summary>
        /// <param name="byteData">The pointer to the first byte of the first scanline</param>
        /// <param name="start">The vertical position to start the scan</param>
        /// <param name="lineInc">The number of bytes to move per line</param>
        /// <param name="maxLines">The number of lines to scan</param>
        /// <param name="set">True to scan for set bits, false to scan for unset bits</param>
        /// <param name="fromBottom">True to scan from the bottom of the bitmap, false to scan from the top</param>
        /// <returns>The number of lines scanned before a bit was found, or -1 if none found before reaching max lines</returns>
#if useUnsafe
        private static unsafe int ScanBits(IntPtr byteData, int start, int lineInc, int maxLines, bool set, bool fromBottom)
#else
        private static int ScanBits(IntPtr byteData, int start, int lineInc, int maxLines, bool set, bool fromBottom)
#endif
        {
            // Calculate the starting byte of the first scanline
#if useUnsafe
            byte* lbLine = ((byte*)byteData) + (start * lineInc);
#else
            int lbLine = ((int)(byteData) + (start * lineInc));
#endif

            int liLine = 0;

            // Use lineInc to determines bytes per line
            int liBytesPerLine = (lineInc < 0 ? -lineInc : lineInc);

            // If we want to search in reverse order
            if (fromBottom)
            {
                // Move to the START of the line
                lbLine += lineInc * (maxLines - 1);

                // Negate the line increment
                lineInc = -lineInc;
            }

            while (maxLines > 0)
            {
                // Setup the line scan
#if useUnsafe
                byte* lbData = lbLine;
#else
                int lbData = lbLine;
#endif
                int liByte = liBytesPerLine;

                // For each byte in the line
                while (liByte > 0)
                {
#if !useUnsafe
                    byte lbByte = Marshal.ReadByte((IntPtr)lbData);
#endif

                    // If we want set bits, and a bit is set
#if useUnsafe
                    if (set && *lbData != 0)
#else
                    if (set && lbByte != 0)
#endif
                        // Return the line number
                        return liLine;
                    else
                        // If we want unset bits and any bits arent set
#if useUnsafe
                        if (!set && *lbData != byte.MaxValue)
#else
                        if (!set && lbByte != byte.MaxValue)
#endif
                            // Return the line number
                            return liLine;

                    // Next byte for scan line
                    liByte--;
                    lbData++;
                }

                // Next scan line
                liLine++;
                maxLines--;
                lbLine += lineInc;
            }

            // If all lines were scanned, return -1
            if (maxLines == 0)
                return -1;
            else
                // Return number of lines scanned
                return liLine;
        }

        #endregion

        #region Public Static Methods

        /// <summary>
        /// Gets the number of pixels between the Y hotspot 
        /// and the last physical line of a cursor
        /// </summary>
        /// <param name="cursor">The cursor to scan</param>
        /// <returns>
        /// The number of lines between the Y hotspot
        /// and the last physical line of the cursor
        /// </returns>
        public static int GetBaseLineHeight(this Cursor cursor)
        {
            return GetBaseLine(cursor) - cursor.HotSpot.Y;
        }

        /// <summary>
        /// Gets the physical base line of the cursor, that is,
        /// the distance between the top of the virtual cursor
        /// and the physical base line of the cursor
        /// </summary>
        /// <param name="cursor">The cursor to scan</param>
        /// <returns>The number of lines between the top of the virtual cursor 
        /// and the physical base line of the curosr</returns>
        public static int GetBaseLine(this Cursor cursor)
        {
            IconInfo liiInfo = new IconInfo();

            if (!GetIconInfo(cursor.Handle, ref liiInfo))
                return cursor.Size.Height;

            Bitmap lbmpBitmap = Bitmap.FromHbitmap(liiInfo.hbmMask);

            try
            {
                BitmapData lbdData = lbmpBitmap.LockBits(
                    new Rectangle(0, 0, lbmpBitmap.Width, lbmpBitmap.Height),
                    ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed);

                try
                {
                    // Calculate number of lines in AND scan before any found
                    int liLine = ScanBits(lbdData.Scan0, 0, lbdData.Stride, cursor.Size.Height, false, true);

                    // If no AND scan bits found then scan for XOR bits
                    if (liLine == -1 && lbdData.Height == cursor.Size.Height * 2)
                        liLine = ScanBits(lbdData.Scan0, cursor.Size.Height, lbdData.Stride, cursor.Size.Height, true, true);

                    return cursor.Size.Height-liLine;
                }
                finally
                {
                    lbmpBitmap.UnlockBits(lbdData);
                }
            }
            finally
            {
                DeleteObject(liiInfo.hbmMask);
                DeleteObject(liiInfo.hbmColor);
                lbmpBitmap.Dispose();
            }
        }

        #endregion
    }
}

您可以取消定义顶部的条件定义“useUnsafe”,这样您就不必根据需要启用不安全代码,但请注意它在此模式下运行速度会变慢。

所以这使用了扩展方法,所以你所要做的就是将 Cursor.Current.GetBaseLineHeight() 添加到你的 Cursor.Position.Y 中,这将是光标下的第一个空白行。

IE。

Point lptBlankLineUnderCursor = new Point(Cursor.Position.X, Cursor.Position.Y + Cursor.Current.GetBaseLineHeight())
于 2011-03-15T02:55:10.590 回答
1

我认为资源管理器将工具提示放在光标的热点下方,因此您不必更正 X 位置。这看起来不错:

private void panel1_MouseClick(object sender, MouseEventArgs e) {
  int x = e.X;
  int y = e.Y + Cursor.Current.Size.Height - Cursor.Current.HotSpot.Y;
  toolTip1.Show("test", panel1, x, y);
}
于 2009-11-17T03:57:25.903 回答