我想在WPF應用程序中使用圖像或圖標作爲自定義光標。什麼是最好的方式來做到這一點?WPF中的自定義光標?
回答
你有兩個基本的選擇:
當鼠標光標在你的控制,通過設置
this.Cursor = Cursors.None;
隱藏系統光標,並使用你喜歡的任何技術,繪製自己的光標。然後,通過響應鼠標事件來更新光標的位置和外觀。這裏有兩個例子:由一個或.CUR文件.ani的加載圖像創建一個新的光標對象。您可以在Visual Studio中創建和編輯這些類型的文件。還有一些免費的實用程序可以處理它們。基本上它們是圖像(或動畫圖像),它們指定一個「熱點」,指示光標位於圖像中的哪個點。
如果選擇從文件加載,請注意您需要一個絕對的文件系統路徑使用Cursor(string fileName)
構造。 Lamely,相對路徑或Pack URI將不起作用。如果您需要從相對路徑或與您的程序集一起打包的資源加載光標,則需要從文件中獲取流並將其傳遞給Cursor(Stream cursorStream)
構造函數。令人討厭但真實。
。另一方面,指定一個遊標的相對路徑使用XAML屬性不工作,你可以用它來得到加載到一個隱藏的控制光標,然後一個事實複製參考使用上加載時另一種控制。我沒有嘗試過,但它應該工作。
你可以試試這個
<Window Cursor=""C:\WINDOWS\Cursors\dinosaur.ani"" />
Xamlog鏈接是會員制:( – jschroedl 2009-09-08 13:57:13
還檢查了斯科特Hanselman的BabySmash(www.codeplex.com/babysmash)。他用隱藏窗口光標並顯示在畫布上他的新光標,然後將光標移動到了「真正的」光標將是一個更「蠻力」方法
在這裏閱讀更多: http://www.hanselman.com/blog/DeveloperDesigner.aspx
像Peter上面提到的那樣,如果您已經有了.cur文件,您可以通過在資源部分創建一個虛擬元素,然後在需要時引用虛擬光標,將其用作嵌入式資源。
例如,假設您想根據所選工具顯示非標準遊標。
添加到資源:
<Window.Resources>
<ResourceDictionary>
<TextBlock x:Key="CursorGrab" Cursor="Resources/Cursors/grab.cur"/>
<TextBlock x:Key="CursorMagnify" Cursor="Resources/Cursors/magnify.cur"/>
</ResourceDictionary>
</Window.Resources>
實施例代碼中引用嵌入光標的:
if (selectedTool == "Hand")
myCanvas.Cursor = ((TextBlock)this.Resources["CursorGrab"]).Cursor;
else if (selectedTool == "Magnify")
myCanvas.Cursor = ((TextBlock)this.Resources["CursorMagnify"]).Cursor;
else
myCanvas.Cursor = Cursor.Arrow;
-Ben
是否有任何理由爲什麼你已經使用TextBlock緩存Cursor引用超過FrameworkElement,第一次定義Cursor屬性? – PaulJ 2011-03-21 10:07:58
沒理由; FrameworkElement將是更好的選擇。謝謝! – 2011-03-22 08:18:26
有比管理光標顯示自己或使用Visual更簡單的方法Studio來構建大量的自定義遊標。
如果你有一個FrameworkElement的,你可以使用下面的代碼構建從它光標:
public Cursor ConvertToCursor(FrameworkElement visual, Point hotSpot)
{
int width = (int)visual.Width;
int height = (int)visual.Height;
// Render to a bitmap
var bitmapSource = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
bitmapSource.Render(visual);
// Convert to System.Drawing.Bitmap
var pixels = new int[width*height];
bitmapSource.CopyPixels(pixels, width, 0);
var bitmap = new System.Drawing.Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
for(int y=0; y<height; y++)
for(int x=0; x<width; x++)
bitmap.SetPixel(x, y, Color.FromArgb(pixels[y*width+x]));
// Save to .ico format
var stream = new MemoryStream();
System.Drawing.Icon.FromHandle(resultBitmap.GetHicon()).Save(stream);
// Convert saved file into .cur format
stream.Seek(2, SeekOrigin.Begin);
stream.WriteByte(2);
stream.Seek(10, SeekOrigin.Begin);
stream.WriteByte((byte)(int)(hotSpot.X * width));
stream.WriteByte((byte)(int)(hotSpot.Y * height));
stream.Seek(0, SeekOrigin.Begin);
// Construct Cursor
return new Cursor(stream);
}
請注意,您的FrameworkElement的的尺寸必須是標準的光標大小(例如16×16或32×32),例如:
<Grid x:Name="customCursor" Width="32" Height="32">
...
</Grid>
它會像這樣使用:
someControl.Cursor = ConvertToCursor(customCursor, new Point(0.5, 0.5));
顯然如果你有一個現有的圖像,你的FrameworkElement可能是一個<Image>
控件,或者你可以使用WPF的內置繪圖工具繪製任何你喜歡的東西。
請注意,.cur文件格式的詳細信息可在ICO (file format)找到。
嘿,我試圖用這個代碼片斷來定義一個用xaml定製的遊標。不幸的是,它只顯示任何東西,而不是我定義的「
我知道這個主題現在已經有幾年了,但是昨天我想從項目資源中加載一個自定義光標文件,並遇到類似的問題。我在網上搜索了一個解決方案,但沒有找到我需要的:在運行時將this.Cursor
設置爲存儲在我的項目資源文件夾中的自定義光標。 我試過本的xaml解決方案,但沒有發現它足夠優雅。 PeterAllen說:
Lamely,相對路徑或Pack URI將不起作用。如果需要從相對路徑或裝配到程序集的資源加載遊標,則需要從文件中獲取流並將其傳遞給Cursor(Stream cursorStream)構造函數。令人討厭但真實。
我無意中發現了一個很好的方式做到這一點,解決了我的問題:
System.Windows.Resources.StreamResourceInfo info = Application.GetResourceStream(new Uri("/MainApp;component/Resources/HandDown.cur", UriKind.Relative));
this.Cursor = new System.Windows.Input.Cursor(info.Stream);
「MainApp」應該替換爲應用程序的*名稱*。 「資源」應該替換爲項目內部的* .cur文件的相關文件夾路徑。 – 2016-07-26 03:43:39
一個非常簡單的方法是創建Visual Studio中的文件的.cur內的光標,然後添加到項目資源。
然後,只需添加以下代碼,當你要分配光標:
myCanvas.Cursor = new Cursor(new System.IO.MemoryStream(myNamespace.Properties.Resources.Cursor1));
確保,任何GDI資源(例如bmp.GetHIcon)得到處理。否則,最終會發生內存泄漏。下面的代碼(圖標的擴展方法)完美適用於WPF。它會在右下方創建一個帶有小圖標的箭頭光標。
備註:此代碼使用圖標來創建光標。它不使用當前的UI控件。
馬蒂亞斯
public static Cursor CreateCursor(this Icon icon, bool includeCrossHair, System.Drawing.Color crossHairColor)
{
if (icon == null)
return Cursors.Arrow;
// create an empty image
int width = icon.Width;
int height = icon.Height;
using (var cursor = new Bitmap(width * 2, height * 2))
{
// create a graphics context, so that we can draw our own cursor
using (var gr = System.Drawing.Graphics.FromImage(cursor))
{
// a cursor is usually 32x32 pixel so we need our icon in the lower right part of it
gr.DrawIcon(icon, new Rectangle(width, height, width, height));
if (includeCrossHair)
{
using (var pen = new System.Drawing.Pen(crossHairColor))
{
// draw the cross-hair
gr.DrawLine(pen, width - 3, height, width + 3, height);
gr.DrawLine(pen, width, height - 3, width, height + 3);
}
}
}
try
{
using (var stream = new MemoryStream())
{
// Save to .ico format
var ptr = cursor.GetHicon();
var tempIcon = Icon.FromHandle(ptr);
tempIcon.Save(stream);
int x = cursor.Width/2;
int y = cursor.Height/2;
#region Convert saved stream into .cur format
// set as .cur file format
stream.Seek(2, SeekOrigin.Begin);
stream.WriteByte(2);
// write the hotspot information
stream.Seek(10, SeekOrigin.Begin);
stream.WriteByte((byte)(width));
stream.Seek(12, SeekOrigin.Begin);
stream.WriteByte((byte)(height));
// reset to initial position
stream.Seek(0, SeekOrigin.Begin);
#endregion
DestroyIcon(tempIcon.Handle); // destroy GDI resource
return new Cursor(stream);
}
}
catch (Exception)
{
return Cursors.Arrow;
}
}
}
/// <summary>
/// Destroys the icon.
/// </summary>
/// <param name="handle">The handle.</param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public extern static Boolean DestroyIcon(IntPtr handle);
要使用XAML自定義光標我改變本麥金託什略提供的代碼:
<Window.Resources>
<Cursor x:Key="OpenHandCursor">Resources/openhand.cur</Cursor>
</Window.Resources>
使用遊標只是參考資源:
<StackPanel Cursor="{StaticResource OpenHandCursor}" />
如果您使用visual studio,您可以
- 新光標文件
- 複製/粘貼圖像
- 保存它的.cur文件。
還有一個解決方案有點類似雷人的,但不是緩慢和繁瑣像素複製,這種使用了一些Windows內部:
private struct IconInfo {
public bool fIcon;
public int xHotspot;
public int yHotspot;
public IntPtr hbmMask;
public IntPtr hbmColor;
}
[DllImport("user32.dll")]
private static extern IntPtr CreateIconIndirect(ref IconInfo icon);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);
public Cursor ConvertToCursor(FrameworkElement cursor, Point HotSpot) {
cursor.Arrange(new Rect(new Size(cursor.Width, cursor.Height)));
var bitmap = new RenderTargetBitmap((int)cursor.Width, (int)cursor.Height, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(cursor);
var info = new IconInfo();
GetIconInfo(bitmap.ToBitmap().GetHicon(), ref info);
info.fIcon = false;
info.xHotspot = (byte)(HotSpot.X * cursor.Width);
info.yHotspot = (byte)(HotSpot.Y * cursor.Height);
return CursorInteropHelper.Create(new SafeFileHandle(CreateIconIndirect(ref info), true));
}
有一個在中間的擴展方法,我更喜歡有一個擴展類爲這種情況下:
using DW = System.Drawing;
public static DW.Bitmap ToBitmap(this BitmapSource bitmapSource) {
var bitmap = new DW.Bitmap(bitmapSource.PixelWidth, bitmapSource.PixelHeight, DW.Imaging.PixelFormat.Format32bppPArgb);
var data = bitmap.LockBits(new DW.Rectangle(DW.Point.Empty, bitmap.Size), DW.Imaging.ImageLockMode.WriteOnly, DW.Imaging.PixelFormat.Format32bppPArgb);
bitmapSource.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
bitmap.UnlockBits(data);
return bitmap;
}
所有這一切,它是相當簡單和直接。
而且,如果你碰巧不是需要指定自己的熱點,你甚至可以減少這種短(你不需要的結構或P /調用,要麼):
public Cursor ConvertToCursor(FrameworkElement cursor, Point HotSpot) {
cursor.Arrange(new Rect(new Size(cursor.Width, cursor.Height)));
var bitmap = new RenderTargetBitmap((int)cursor.Width, (int)cursor.Height, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(cursor);
var icon = System.Drawing.Icon.FromHandle(bitmap.ToBitmap().GetHicon());
return CursorInteropHelper.Create(new SafeFileHandle(icon.Handle, true));
}
這裏有一個功能豐富,免費的實用程序,允許您從任何圖像創建曲線文件: http://www.rw-designer.com/cursor-maker
它被稱爲RealWorld光標編輯器。
而且這裏有一個如何嵌入光標在一個項目鏈接:
如果有人正在尋找的UIElement本身作爲一個光標,我結合的Ray和Arcturus的解決方案:
public Cursor ConvertToCursor(UIElement control, Point hotSpot)
{
// convert FrameworkElement to PNG stream
var pngStream = new MemoryStream();
control.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
Rect rect = new Rect(0, 0, control.DesiredSize.Width, control.DesiredSize.Height);
RenderTargetBitmap rtb = new RenderTargetBitmap((int)control.DesiredSize.Width, (int)control.DesiredSize.Height, 96, 96, PixelFormats.Pbgra32);
control.Arrange(rect);
rtb.Render(control);
PngBitmapEncoder png = new PngBitmapEncoder();
png.Frames.Add(BitmapFrame.Create(rtb));
png.Save(pngStream);
// write cursor header info
var cursorStream = new MemoryStream();
cursorStream.Write(new byte[2] { 0x00, 0x00 }, 0, 2); // ICONDIR: Reserved. Must always be 0.
cursorStream.Write(new byte[2] { 0x02, 0x00 }, 0, 2); // ICONDIR: Specifies image type: 1 for icon (.ICO) image, 2 for cursor (.CUR) image. Other values are invalid
cursorStream.Write(new byte[2] { 0x01, 0x00 }, 0, 2); // ICONDIR: Specifies number of images in the file.
cursorStream.Write(new byte[1] { (byte)control.DesiredSize.Width }, 0, 1); // ICONDIRENTRY: Specifies image width in pixels. Can be any number between 0 and 255. Value 0 means image width is 256 pixels.
cursorStream.Write(new byte[1] { (byte)control.DesiredSize.Height }, 0, 1); // ICONDIRENTRY: Specifies image height in pixels. Can be any number between 0 and 255. Value 0 means image height is 256 pixels.
cursorStream.Write(new byte[1] { 0x00 }, 0, 1); // ICONDIRENTRY: Specifies number of colors in the color palette. Should be 0 if the image does not use a color palette.
cursorStream.Write(new byte[1] { 0x00 }, 0, 1); // ICONDIRENTRY: Reserved. Should be 0.
cursorStream.Write(new byte[2] { (byte)hotSpot.X, 0x00 }, 0, 2); // ICONDIRENTRY: Specifies the horizontal coordinates of the hotspot in number of pixels from the left.
cursorStream.Write(new byte[2] { (byte)hotSpot.Y, 0x00 }, 0, 2); // ICONDIRENTRY: Specifies the vertical coordinates of the hotspot in number of pixels from the top.
cursorStream.Write(new byte[4] { // ICONDIRENTRY: Specifies the size of the image's data in bytes
(byte)((pngStream.Length & 0x000000FF)),
(byte)((pngStream.Length & 0x0000FF00) >> 0x08),
(byte)((pngStream.Length & 0x00FF0000) >> 0x10),
(byte)((pngStream.Length & 0xFF000000) >> 0x18)
}, 0, 4);
cursorStream.Write(new byte[4] { // ICONDIRENTRY: Specifies the offset of BMP or PNG data from the beginning of the ICO/CUR file
(byte)0x16,
(byte)0x00,
(byte)0x00,
(byte)0x00,
}, 0, 4);
// copy PNG stream to cursor stream
pngStream.Seek(0, SeekOrigin.Begin);
pngStream.CopyTo(cursorStream);
// return cursor stream
cursorStream.Seek(0, SeekOrigin.Begin);
return new Cursor(cursorStream);
}
您可以通過如下代碼
this.Cursor = new Cursor(@"<your address of icon>");
做到這一點
它可能已與Visual Studio 2017年改變,但我能夠引用的.cur文件作爲嵌入資源:
<Setter
Property="Cursor"
Value="/assembly-name;component/location-name/curser-name.cur" />
- 1. 圖像到光標/自定義光標
- 2. 在WPF中設置自定義光標圖像熱點
- 3. 在WPF彈出窗口中保留自定義光標
- 4. 在WPF應用程序中顯示自定義光標
- 5. 如何在wpf中正確使用自定義光標
- 6. QML:自定義光標
- 7. 自定義光標java
- 8. 自定義加載光標
- 9. 多個自定義光標
- 10. 自定義光標圖像
- 11. Kinect自定義光標
- 12. CSS3自定義光標
- 13. 用as3中的mouse_down自定義光標
- 14. Swing中的自定義光標JDialog
- 15. 整個WPF應用程序的自定義光標
- 16. 如何在NSSearchField中自定義光標?
- 17. 在C中使用自定義光標#
- 18. 在SearchView中自定義光標顏色
- 19. WPF中的自定義標題按鈕
- 20. WPF和自定義遊標
- 21. WPF GroupBox標題自定義
- 22. 自定義鼠標光標+ IE愁楚
- 23. 刪除tumblr上的自定義光標
- 24. 自定義光標在Adobe的邊緣
- 25. 如何用自定義圖像光標覆蓋鼠標光標?
- 26. 將默認光標樣式更改爲自定義光標
- 27. C#嵌入自定義光標
- 28. 自定義光標在XNA 4.0
- 29. HTML5畫布繪製自定義光標
- 30. 不能使用自定義光標
不幸的是,第一個例子確實不再工作未經授權。 – 2009-08-24 10:24:11
另請注意,您可以從任何WPF內容中隨時構建遊標。請參閱http://stackoverflow.com/questions/2835502/rotating-cursor-according-to-rotated-textbox/2836904#2836904,瞭解如何完成此操作的示例。 – 2010-05-14 19:42:40
我在前面的提交中發佈的鏈接處理旋轉現有的光標。我剛剛發佈了一個關於這個問題的新答案(見下文),它告訴我們如何將任意的Visual轉換爲Cursor。 – 2010-05-14 19:53:12