2010年2月22日 星期一

在WPF中自訂Cursor

如果要使用WPF內建的游標符號(Cursor)可以直接透過

void SetCursor()
{
Cursor = Cursors.ArrowCD;
}

內建的游標符號種類可以參考Cursors 類別
但是有時候我們會希望要把游標設成一張圖或是一個UI元件的樣子
這時候就要透過Win32的幾個函式了

struct IconInfo
{
public bool fIcon;
public int xHotspot;
public int yHotspot;
public IntPtr hbmMask;
public IntPtr hbmColor;
}

[DllImport("user32.dll")]
static extern IntPtr CreateIconIndirect(
ref IconInfo piconinfo);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetIconInfo(
IntPtr hIcon,
ref IconInfo piconinfo);

然後將一張圖檔(System.Drawing.Bitmap)轉成WPF的Cursor

Cursor CreatCursor(Bitmap b, int x, int y)
{
/// get icon from input bitmap
IconInfo ico = new IconInfo();
GetIconInfo(b.GetHicon(), ref ico);

/// set the hotspot
ico.xHotspot = x;
ico.yHotspot = y;
ico.fIcon = false;

/// create a cursor from iconinfo
IntPtr cursor = CreateIconIndirect(ref ico);
return CursorInteropHelper.Create(
new SafeFileHandle(cursor, true));
}

這裡hotspot是指真正的游標在這張圖的哪個位置
如果是(0,0),整張圖會在游標的右下方
如果是圖的寬高的一半的話,那就會像是抓到整張圖的中心在動

另外,有時候會希望要把游標設成一個UIElement的樣子
那就先做一個轉換

Cursor CreatCursor(UIElement u, Point p)
{
Cursor c;

/// move to the orignal point of parent
u.Measure(new Size(double.PositiveInfinity,
double.PositiveInfinity));
u.Arrange(new Rect(0, 0,
u.DesiredSize.Width,
u.DesiredSize.Height));

/// render the source to a bitmap image
RenderTargetBitmap r =
new RenderTargetBitmap(
(int)u.DesiredSize.Width,
(int)u.DesiredSize.Height,
96, 96, PixelFormats.Pbgra32);
r.Render(u);

/// reset back to the orignal position
u.Measure(new Size(0, 0));

using (MemoryStream m = new MemoryStream())
{
/// use an encoder to transform to Bitmap
PngBitmapEncoder e = new PngBitmapEncoder();
e.Frames.Add(BitmapFrame.Create(r));
e.Save(m);
System.Drawing.Bitmap b =
new System.Drawing.Bitmap(m);

/// create cursor from Bitmap
c = CreatCursor(b,
(int)p.X, (int)p.Y);
}

return c;
}

有關measure及arrange可以參考在WPF中的畫面重排(Measure & Arrange)在WPF中存圖檔的問題(RenderTargetBitmap)

--
參考資料
FrameworkElement.Cursor 屬性
WPF Tutorial - How To Use Custom Cursors
ICONINFO Structure
CreateIconIndirect Function
GetIconInfo Function
SafeFileHandle 類別

沒有留言:

張貼留言