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パラメータを操作して、テキストの位置を調整します。私のマシンでは動作しますが、さまざまな設定でどのように表示されるかわかりません。

ツールチップの楽しいヒント:この行をフォームの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に追加するだけで、カーソルの下の最初の空白行になります。

すなわち。

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 に答える