1. Trang chủ
  2. » Công Nghệ Thông Tin

Tài liệu lập trình - WPF Tutorial - Sử dụng Custom Cursor pdf

5 621 1

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 5
Dung lượng 67,5 KB

Nội dung

Con trỏ là một thành phần quan trọng trong Window nó cần cho tất cả các ứng dụng, hỗ trợ người dùng thao tác với Hệ điều hành, những lợi ích mà nó mang lại là điều không thể chối cãi, nh

Trang 1

Collaborators

Tham gia ngày: Jun 2010

Bài gửi: 23 Cấp độ: 6 Điểm: 299

WPF Tutorial - Sử dụng Custom Cursor

WPF Tutorial - Sử dụng Custom Cursor

Các bạn có thể xem bài viết về sử dụng Custom Cursor trong WinForm ở đây Bài hướng dẫn này cũng có nhiều vấn đề tương tự, cho nên mình nghĩ là bạn nên xem qua nó trước

Thật sự là tạo và sử dụng một con trỏ trong WPF khó khăn hơn rất nhiều so với trong

WinForm Điều này là do một vấn đề duy nhất - đó là WPF không dùng GDI, nhưng con trỏ thì

lại dùng Con trỏ là một thành phần quan trọng trong Window (nó cần cho tất cả các ứng dụng,

hỗ trợ người dùng thao tác với Hệ điều hành), những lợi ích mà nó mang lại là điều không thể chối cãi, nhưng nó vẫn là đối tượng GDI Cho nên ta cần phải vượt qua ranh giới này để có thể

làm gì đó đặc biệt với con trỏ trong WPF.

WPF vẫn hỗ trợ những cursor chuẩn, nhưng khi bạn muốn tạo một hình vẽ gì đấy cho cursor,

phải làm nhiều việc đấy

Đầu tiên, bạn nhớ rằng, nếu muốn tạo một con trỏ trong WinForm, bạn phải dùng một số code

như sau:

PHP Code:

IntPtr curPtr;

/* CurPtr gets set to

a pointer to an icon */

Cursor myCur = new Cursor(curPtr);

Nhưng trong WPF, nó rất khác Trong WinForm, đối tượng Cursor là

System.Windows.Forms.Cursor, còn trong WPF, nó là System.Windows.Input.Cursor, và

Constructor của class này ko hỗ trợ đối số nào là IntPtr cả Nhưng cũng có một cách tương tự

như trên:

PHP Code:

IntPtr ptr;

/* CurPtr gets set to

a pointer to an icon */

SafeFileHandle handle = new SafeFileHandle(ptr, true);

Cursor myCur = System.Windows.Interop.CursorInteropHelper.Create(handle);

Chúng ta sẽ convert một đối tượng IntPtr sang một đối tượng SafeHandle (SafeFileHandle kế thừa từ SafeHandle - bạn không thể tạo một đối tượng SafeHandle, vì nó là một abstract class)

Sau đó bạn khởi tạo Cursor từ phương thức

System.Windows.Interop.CursorInteropHelper.Create với đối số là đối tượng SafeHandle đó Chúng ta liên kết code các phần trên, sẽ có một lớp như sau:

Trang 2

PHP Code:

using System;

using System.Windows.Interop;

using Microsoft.Win32.SafeHandles;

using System.Runtime.InteropServices;

using System.Windows.Input;

namespace WPFCursorTest

{

public class CursorHelper

{

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 static Cursor CreateCursor(System.Drawing.Bitmap bmp, int xHotSpot,

int yHotSpot)

{

IconInfo tmp = new IconInfo();

GetIconInfo(bmp.GetHicon(), ref tmp);

tmp.xHotspot = xHotSpot;

tmp.yHotspot = yHotSpot;

tmp.fIcon = false;

IntPtr ptr = CreateIconIndirect(ref tmp);

SafeFileHandle handle = new SafeFileHandle(ptr, true);

return CursorInteropHelper.Create(handle);

}

}

}

Bạn cần lưu ý rằng chúng ta đang sử dụng một đối tượng System.Drawing.Bitmap ở đây (bạn

nên Add Reference thư viện System.Drawing để có thể sử dụng nó) Đây là một đối tượng

Bitmap dạng GDI cũ - một khái niệm nằm ngoài các lớp WPF Mặc định WPF không sử dụng

thư viện System.Drawing cho nên bạn cần phải Add chúng vào (Project/ Add Reference ).

Mình đã thử, khá khó, để tìm ra một cách tạo một con trỏ trong WPF mà không cần phải dựa vào

System.Drawing.Bitmap Mình cần phải nhận được một con trỏ (Pointer chứ không phải

Cursor) Icon trỏ ra ngoài bitmap (như hàm GetHicon), nhưng đối tượng bitmap trong WPF lại

không thể tạo ra một Pointer nào cả

Trang 3

Nhưng ko phải đã hết hi vọng! Hãy thử với một overload của phương thức CreateCursor dưới đây xem:

PHP Code:

public static Cursor CreateCursor(UIElement element, int xHotSpot, int yHotSpot)

{

element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

element.Arrange(new Rect(0 0 element.DesiredSize.Width,

element.DesiredSize.Height));

RenderTargetBitmap rtb = new RenderTargetBitmap((int)element.DesiredSize.Width,

(int)element.DesiredSize.Height, 96, 96, PixelFormats.Pbgra32);

rtb.Render(element);

PngBitmapEncoder encoder = new PngBitmapEncoder();

encoder.Frames.Add(BitmapFrame.Create(rtb));

MemoryStream ms = new MemoryStream();

encoder.Save(ms);

System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(ms);

ms.Close();

ms.Dispose();

Cursor cur = InternalCreateCursor(bmp, xHotSpot, yHotSpot);

bmp.Dispose();

return cur;

}

Ở đây, mình dùng một UIElement - cốt lõi của cấu trúc WPF Mình đo đạc và sắp xếp nó để

chắc chắn nó được trả về những giá trị đúng, và sau đó mình "tạo một bức ảnh từ nó" Mình thực hiện bằng cách tạo một đối tượng RenderTargetBitmap Đây là một lớp đối tượng trong WPF

cho phép bạn lấy một đối tượng UIElement và vẽ nó lên một bitmap - nhưng nhớ là, đây là

bitmap của WPF (chính xác là một đối tượng

System.Windows.Media.Imaging.RenderTargetBitmap) Nó không giống như đối tượng

System.Drawing.Bitmap Mình hiệu chỉnh kích thước cho nó, sau đó render UIElement trên bitmap đó

Bây giờ mình có một đối tượng RenderTargetBitmap trong tay, mình muốn tạo một đối tượng System.Drawing.Bitmap Microsoft hoàn toàn có khả năng làm điều này dễ dàng hơn (nhưng họ không làm), và mình thực sự khó chịu về nó Có một vài phương pháp cho phép bạn chuyển từ đối tượng System.Drawing.Bitmap sang đối tượng bitmap của WPF, nhưng ngược lại thì hoàn toàn không Ít nhất là mình chưa thể tìm ra Nếu có bạn nào biết những phương thức tương tự như vậy (hoặc tốt hơn cách mình đã miêu tả), hãy chia sẻ^_^

Mình dùng một Encoder, và mã hóa bitmap (RenderTargetBitmap) như một đối tượng PNG

(bạn có thể mã hóa như thế nào tùy thích) Sau đó, mình tạo một MemoryStream và lưu mã của bitmap (đã được mã hóa) vào trong stream đó Tiếp theo mình tạo một đối tượng

System.Drawing.Bitmap với Contructor có tham số là một MemoryStream Nên nhớ phải giải phóng các đối tượng không dùng đến nữa

Toàn bộ code chúng ta cần ở đây:

PHP Code:

using System;

using System.Windows.Interop;

using Microsoft.Win32.SafeHandles;

using System.Runtime.InteropServices;

using System.Windows.Input;

using System.Windows.Media;

Trang 4

using System.Windows.Media.Imaging;

using System.IO;

using System.Windows;

namespace WPFCursorTest

{

public class CursorHelper

{

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

private static Cursor InternalCreateCursor(System.Drawing.Bitmap bmp,

int xHotSpot, int yHotSpot)

{

IconInfo tmp = new IconInfo();

GetIconInfo(bmp.GetHicon(), ref tmp);

tmp.xHotspot = xHotSpot;

tmp.yHotspot = yHotSpot;

tmp.fIcon = false;

IntPtr ptr = CreateIconIndirect(ref tmp);

SafeFileHandle handle = new SafeFileHandle(ptr, true);

return CursorInteropHelper.Create(handle);

}

public static Cursor CreateCursor(UIElement element, int xHotSpot, int yHotSpot) {

element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

element.Arrange(new Rect(0 0 element.DesiredSize.Width,

element.DesiredSize.Height));

RenderTargetBitmap rtb = new RenderTargetBitmap((int)element.DesiredSize.Width, (int)element.DesiredSize.Height, 96, 96, PixelFormats.Pbgra32);

rtb.Render(element);

PngBitmapEncoder encoder = new PngBitmapEncoder();

encoder.Frames.Add(BitmapFrame.Create(rtb));

MemoryStream ms = new MemoryStream();

encoder.Save(ms);

Trang 5

System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(ms);

ms.Close();

ms.Dispose();

Cursor cur = InternalCreateCursor(bmp, xHotSpot, yHotSpot);

bmp.Dispose();

return cur;

}

}

}

Bây giờ là cách sử dụng class:

PHP Code:

public partial class CursorTest : Window

{

public CursorTest()

{

InitializeComponent();

TextBlock tb = new TextBlock();

tb.Text = "{ } Switch On The Code" ;

tb.FontSize = 10;

tb.Foreground = Brushes.Green;

this.Cursor = CursorHelper.CreateCursor(tb, , );

}

}

Và kết quả là:

Translate from http://www.switchonthecode.com

Try my best

Ngày đăng: 11/07/2014, 12:20

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w