2008-09-05 2 views

ответ

28

у вас есть два основных варианта:

  1. Когда курсор мыши находится над вашим контролем, скрыть системный курсор, установив this.Cursor = Cursors.None; и рисовать свой собственный курсор, используя любой метод вы хотите. Затем обновите положение и внешний вид вашего курсора, отвечая на события мыши. Вот два примера:

  2. Создать новый объект Cursor путем загрузки изображения из .CUR или .ANI файла. Вы можете создавать и редактировать эти файлы в Visual Studio. Есть также некоторые бесплатные утилиты, плавающие вокруг для борьбы с ними. В основном это изображения (или анимированные изображения), которые указывают «горячую точку», указывающую, на какой точке изображения находится курсор.

Если вы выбрали загрузку из файла, обратите внимание, что вам нужно абсолютный путь файловой системы, чтобы использовать Cursor(string fileName) конструктор. А именно, относительный путь или URI пакета не будет работать. Если вам нужно загрузить курсор из относительного пути или из ресурса, собранного вместе с вашей сборкой, вам нужно будет получить поток из файла и передать его в конструктор Cursor(Stream cursorStream). Досадно, но верно.

С другой стороны, указав курсор как относительный путь при его загрузке с использованием атрибута XAML , выполните, что может привести к тому, что курсор загрузится на скрытый элемент управления, а затем скопируйте ссылку для использования на другой контроль. Я не пробовал, но он должен работать.

+7

, к сожалению, первый пример не делает, больше не работает без разрешения. – 2009-08-24 10:24:11

+0

Также обратите внимание, что вы можете построить курсор на лету из любого содержимого WPF. См. Http://stackoverflow.com/questions/2835502/rotating-cursor-according-to-rotated-textbox/2836904#2836904 для примера того, как это делается. – 2010-05-14 19:42:40

+0

Ссылка, которую я опубликовал в предыдущей статье, касается вращения существующего курсора.Я только что опубликовал новый ответ на этот вопрос (см. Ниже), в котором рассказывается, как преобразовать произвольный Visual в Cursor. – 2010-05-14 19:53:12

2

Вы могли бы попробовать это

<Window Cursor=""C:\WINDOWS\Cursors\dinosaur.ani"" /> 
+0

Xamlog ссылка для членов только :( – jschroedl 2009-09-08 13:57:13

1

проверить Также из BabySmash Скотта Хансельман в (www.codeplex.com/babysmash). Он использовал больше метод «грубой силы» сокрытия окна курсор и показывая его новый курсор на холсте, а затем переместив курсор были «реальные» курсор был бы

Подробнее здесь: http://www.hanselman.com/blog/DeveloperDesigner.aspx

26

Как упоминалось выше, Питер, если у вас уже есть .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; 

-Бен

+2

Есть ли причина, по которой вы использовали TextBlock для кэширования ссылок курсора над FrameworkElement, где сначала определено свойство Cursor? – PaulJ 2011-03-21 10:07:58

+2

Отсутствие причины; FrameworkElement будет лучшим выбором. Благодаря! – 2011-03-22 08:18:26

14

Существует более простой способ, чем управление курсором отображения самостоятельно или с помощью видео 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 «s должен быть стандартный размер курсора (например, 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).

+3

Эй, я попытался использовать этот фрагмент кода для определения пользовательского курсора с помощью xaml. К сожалению, он просто ничего не отображает вместо `` -элемент, который я определил. Отлаживая код, я понял, что `var pixels`-array просто содержит 0 для каждого пикселя после запуска` CopyPixels() `-method. Я получил ошибку для параметра `stride` для метода` CopyPixels() `, поэтому я немного изменил код в соответствии с некоторыми другими фрагментами, которые я нашел: ` int stride = width * ((bitmapSource.Format.BitsPerPixel + 7)/8); `За исключением того, что код выглядит так же, как и выше. «Визуальным» является: `` – andineupert 2013-10-30 19:06:00

8

Я знаю, что эта тема уже несколько лет, но вчера я захотел загрузить пользовательский файл курсора из ресурсов проекта и столкнулся с подобными проблемами. Я искал в Интернете решение и не нашел то, что мне нужно: установить this.Cursor в пользовательский курсор, хранящийся в моей папке ресурсов в моем проекте во время выполнения. Я пробовал решение xaml от Ben, но не нашел его достаточно элегантным. PeterAllen заявлено:

А именно, относительный путь или 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); 
+0

«MainApp» следует заменить на * имя * вашего приложения. «Ресурсы» следует заменить на относительный путь к папкам * .cur внутри вашего проекта. – 2016-07-26 03:43:39

8

очень простой способ заключается в создании курсора внутри Visual Studio в виде файла .CUR, а затем добавить, что проекты Ресурсы.

Затем просто добавьте следующий код, если вы хотите назначить курсор:

myCanvas.Cursor = new Cursor(new System.IO.MemoryStream(myNamespace.Properties.Resources.Cursor1)); 
1

Убедитесь, что любой ресурс GDI (например bmp.GetHIcon) получает удален. В противном случае вы получите утечку памяти. Следующий код (метод расширения для значка) отлично работает для WPF. Он создает стрелочный указатель с маленьким значком, расположенным ниже справа.

Примечание. Этот код использует значок для создания курсора. Он не использует текущий контроль пользовательского интерфейса.

Matthias

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); 
8

Чтобы использовать пользовательский курсор в XAML я изменил код Ben McIntosh при условии немного:

<Window.Resources>  
<Cursor x:Key="OpenHandCursor">Resources/openhand.cur</Cursor> 
</Window.Resources> 

Чтобы использовать курсор просто ссылку на ресурс:

<StackPanel Cursor="{StaticResource OpenHandCursor}" /> 
1

Если вы используете визуальную студию, вы можете

  1. Новый курсор файл
  2. Копировать/Вставить изображение
  3. Сохранить его .CUR файл.
4

еще одно решение, несколько похож на Рэя, но вместо медленной и громоздкой пиксельной копирования, это использует некоторые внутренние 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)); 
} 
8

В случае, если кто ищет 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); 
    } 
0

вы можете сделать это кодекс, как

this.Cursor = new Cursor(@"<your address of icon>"); 
0

Это может быть изменен с Visual Studio 2017, но я был в состоянии сделать ссылку на файл .CUR в качестве внедренного ресурса:

<Setter 
    Property="Cursor" 
    Value="/assembly-name;component/location-name/curser-name.cur" />