سفارشی کردن cursor در پروژه های NET.
  نحوه ی ساخت یک اشاره گر موس (cursor) سفارشی شده، در پروژه های تحت ویندوز و استفاده از آن به جای cursor های استاندارد...
   C#
   ۲۹۷۷۵
   دانلود
   محمد (برنا) پورحسین
   ۱۳۸۶/۱۱/۲۰
ارسال لینک صفحه برای دوستان ارسال لینک صفحه برای دوستان  اضافه کردن به علاقه مندیها اضافه کردن به علاقه مندیها   نسخه قابل چاپ نسخه قابل چاپ

 

تغيير قيافه ي ظاهري اشاره گر موس (cursor) موردي نيست که معمولا در پروژه هاي خود مجبور به انجام آن باشيم، اما اگر روزي نيازمند انجام چنين کاري شديم، اين امر مي تواند تفاوتهاي عظيمي در نحوه ي ارائه و به کارگيري پروژه هاي ما ايجاد کند. به همين دليل امروز من تحت يک پروژه ي ويندوزي کوچک #C به نحوه ي ساخت يک cursor سفارشي شده خواهم پرداخت (براي طرفداران WPF نيز به زودي زود، از اين حيث، مباحث جالبي خواهيم داشت)
تا زماني که بخواهيم در يک فرم ويندوزي (WinForm)، اشاره گر موس پروژه ي خود را به يکي از حالتهاي استاندارد ديگر تغيير دهيم، انجام اين کار بسيار ساده خواهد بود. تنها کاري که بايد بکنيم اين است property مورد نظر از کنترل خود را به يکي از حالت هاي تعبيه شده در شي Cursors تغيير دهيم. در حالي که سفارشي کردن cursor به طوري که جزئي از استاندارهاي موجود نبوده و دلخواه شخص ما باشد کمي سخت تر بوده و به صرف انرژي بيشتري نياز دارد...
براي ساخت يک cursor دلخواه راههاي بسياري وجود دارد و از طريق همه ي اين راهها در نهايت يک شي جديد cursor ساخته مي شود.
ساده ترين راه لود فايل cursor جديدي است که خود ايجاد کرده ايم. (که همانطوري که مي دانيد پسوند اين فايل "cur." خواهد بود). constructor نشانگر موس ما مي تواند به اين طريق ساخته شود:


Cursor myCursor = new Cursor("myCursor.cur");

و به اين ترتيب مي توانيم از اين به بعد، از آن به عنوان cursor خاص خود، در هر کنترلي استفاده کنيم. مانند:


myControl.Cursor = myCursor;

خوب، فکر مي کنم اين مطلب به اندازه کافي واضح و روشن و از طرف ديگر کاملا ساده بود. حال اينطور در نظر مي گيريم که ما فايل cursor بحث شده با پسوند "cur." را در اختيار نداشته تا از آن استفاده کنيد و مي خواهيم حالت سفارشي cursor را با چند خط برنامه نويسي ايجاد کنيم. در اين حالت کار کمي مشکل تر از حالت قبل خواهد بود. به علت اينکه تمام آن چيزي که ما نياز داريم در دنياي NET. ساخته نشده است و ما براي رسيدن به مقصود خود مجبوريم در بعضي متدهاي موجود تغييراتي ايجاد نمائيم:
اولين کاري که بايد انجام دهيم ايجاد يک معادل، براي ساختار ICONINFO پروژه هاي NET. است، براي تعيين اطلاعات مورد نياز ما براي cursor جديد. به اين صورت:


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

در اين حالت 3 متغيير اول کد فوق، اهميت بيشتري براي ما دارد و بيشتر به آنها مي پردازيم (براي کسب اطلاعات بيشتر در مورد دو متغير آخر ميتوانيد به MSDN مراجعه کنيد). اولين متغيير (fIcon) تعيين مي کند که icon مورد نظر cursor است يا يک icon عادي. اگر مقدار Flase گرفته بود به اين معني است که آيکون مذکور cursor مي باشد. xHotspot و yHotspot مختصات نقطه ي کليک شده توسط cursor را تعيين مي کنند. طبيعتا اندازه ي cursor هاي ما بزرگتر از اندازه ي 1x1 پيکسل خواهد بود، ولي در واقع تنها يک نقطه براي ما حائز اهميت است (نقطه اي که توسط مختصات hotspot معين مي گردد). به عنوان مثال مختصات نقطه ي کليک شده توسط يک cursor استاندارد، همان نوک پيکان اشاره گر موس مي باشد.
براي ساخت cursor دلخواه، دو متد ديگر نيز داريم که بايد به آنها ارجاع نمائيم: GetIconInfo و CreateIconIndirect. از آنها به اين صورت در پروژه ي خود استفاده مي نمائيم:


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

حال از قطعه کد زير، براي ساخت تابعي که cursor ما را ايجاد مي کند استفاده مي نمائيم:


public static Cursor CreateCursor(Bitmap bmp,
    int xHotSpot, int yHotSpot)
{
  IntPtr ptr = bmp.GetHicon();
  IconInfo tmp = new IconInfo();
  GetIconInfo(ptr, ref tmp);
  tmp.xHotspot = xHotSpot;
  tmp.yHotspot = yHotSpot;
  tmp.fIcon = false;
  ptr = CreateIconIndirect(ref tmp);
  return new Cursor(ptr);
}

اين تابع از يک bitmap که در cursor ساخته شده و يک hotspot براي آن استفاده مي کند. در ابتدا ما ساختار IconInfo را ايجاد مي کنيم، که اين کار را با صدا زدن متد GetIconInfo انجام مي دهيم. از طرف ديگر اين تابع از طريق صدا زدن متد ()GetHicon براي اشاره گر از آيکون مورد نظر استفاده مي کند. بعد از آن مقادير مختصات x و y را set  کرده و مقدار نادرست (false) را به fIcon مي دهيم. در نهايت تابع CreateIconIndirect را صدا مي زنيم، که pointer را به آيکون جديد cursor باز مي گرداند و ما از اين pointer براي ساخت cursor جديد استفاده مي کنيم. تابع CreateIconIndirect براي استفاده ي cursor يک کپي از آيکون مورد نظر مي سازد، براي همين نيازي نيست که نگران قفل شدن يا بروز موارد طبيعي ديگر در مورد bitmap خود باشيد. حال در قطعه کد زير تابع مورد بحث را خواهيم ساخت:


Bitmap bitmap = new Bitmap(140, 25);
Graphics g = Graphics.FromImage(bitmap);
using (Font f = new Font(FontFamily.GenericSansSerif, 9, FontStyle.Bold))
g.DrawString("\" 30SHARP.COM \"", f, Brushes.White, 0, 0);
this.Cursor = CreateCursor(bitmap, 3, 3);
bitmap.Dispose();

در اينجا، يک bitmap ساخته و عبارت " 30SHARP.COM " را بر روي آن رسم کرديم. (در مقاله هاي آتي به نحوه ي رسم يک متن بر روي عکس، در پروژه هاي C#.NET به صورت کاملا مفصل تر خواهيم پرداخت.) bitmap را با مختصات کليک (hotspot) طول و عرض 3 (3,3) به تابع ساخت cursor پاس داديم و اين مسئله باعث آن شد که cursor جديد ما براي استفاده در هر کجاي پروژه و بر روي کنترل هاي دلخواه آماده شود.
در عکس زير مي توانيد نمونه cursor سفارشي شده جديدي را که توسط کدهاي فوق ايجاد شده است، مشاهده نمائيد:

تمامي کدهايي که از ابتدا براي ساخت cursor جديد نوشتيم، در کنار يکديگر به اين صورت خواهند بود:


using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace CursorTest
{
  public struct IconInfo
  {
    public bool fIcon;
    public int xHotspot;
    public int yHotspot;
    public IntPtr hbmMask;
    public IntPtr hbmColor;
  }
  public class CursorTest : Form
  {  
    public CursorTest()
    {
      this.Text = "Custom Cursor - 30Sharp.com";
      this.BackColor = Color.Black;
      Bitmap bitmap = new Bitmap(140, 25);
      Graphics g = Graphics.FromImage(bitmap);
      using (Font f = new Font(FontFamily.GenericSansSerif, 9, FontStyle.Bold))
        g.DrawString("\" 30SHARP.COM \"", f, Brushes.White, 0, 0);
      this.Cursor = CreateCursor(bitmap, 3, 3);
      bitmap.Dispose();
    }
    [DllImport("user32.dll")]
    public static extern IntPtr CreateIconIndirect(ref IconInfo icon);
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);
    public static Cursor CreateCursor(Bitmap bmp, int xHotSpot, int yHotSpot)
    {
      IntPtr ptr = bmp.GetHicon();
      IconInfo tmp = new IconInfo();
      GetIconInfo(ptr, ref tmp);
      tmp.xHotspot = xHotSpot;
      tmp.yHotspot = yHotSpot;
      tmp.fIcon = false;
      ptr = CreateIconIndirect(ref tmp);
      return new Cursor(ptr);
    }
  }
}

در هر حال، روش ارائه شده در اين مقاله به هر کسي که سعي در ساخت يک اشاره گر موس (cursor) سفارشي شده ي دلخواه خود را دارد، کمک شاياني خواهد کرد. امکانات اين روش بينهايت بوده و شما به هر صورتي و با هر ايده اي منحصر به خود مي توانيد از اين روش استفاده نمائيد. تنها کافيست روش اصلي ساخت cursor را که در اين مقاله به آن پرداختيم خوب فرا گرفته و از اين پس هرگونه cursor دلخواه را در پروژه هاي خود ساخته و در هر کجاي آن استفاده نمائيد.
براي دريافت شهودي تر از اين روش و در اختيار داشتن کدهايي که از ابتدا با هم مرور کرديم مي توانيد پروژه ي اين مقاله رو از بالاي صفحه، لينک دانلود دريافت نمائيد.
در ضمن، ما را از نظرات، انتقادات و پيشنهادات خود بي نصيب نگذاريد... موفق و مويد باشيد.