2009-11-17 34 views

回答

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參數打調整文字的定位。它適用於我的機器,但我不確定它在不同設置下的外觀。

工具提示有趣的提示:把這一行放在你的Form的MouseMove事件中。

+0

感謝, 其實我剛剛發現Cursor.Size.Height都可以使用。但是爲什麼多加2呢? 它會隨自定義光標縮放嗎? – user124858 2009-11-17 02:20:14

+0

我不知道爲什麼要兩個作品多重。我檢查了Cursor.Size屬性到底是什麼(以及它如何與用戶的本地設置相關),並且當我的第一次嘗試沒有出現答案時就放棄了。這就是爲什麼我加了我的警告,說明代碼可能不適用於所有機器! – 2009-11-17 02:25:00

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

做到這一點的唯一方法是掃描光標MASK並找到光標面具的最後一組像素和光標ÿ熱點之間的距離,我今天不得不做的這件事,因此繼承人代碼:

#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()) 
相關問題