تبليغاتX
برنامه نویسی با دلفی

برنامه نویسی با دلفی

Graphics Device Interface

GDI در دلفی
 

GDI مخفف کلمه Graphics Device Interface و تکنیک رسم گرافیک دو بعدی ویندوز است. این روش متاسفانه روش بسیار کندی برای ترسم گرافیکی میباشد ولی بدلیل اینکه اساس برنامه نویسی گرافیک است یاد گیری آن بعنوان پایه برنامه نویسی گرافیک برای برنامه نویسان لازم به نظر میرسد. اولین نکته قابل توجه در این رابطه این است که نباید سعی کنید از GDI برای ایجاد هر جلوه خیالی گرافیکی استفاده کنید بدلیل اینکه GDI یک تکنیک ابتدایی در گرافیک است . برای استفاده حرفه ای از گرافیک سعی کنید از DirectX , OpenGL و ... بهره بگیرید. اگرچه شما با کمی خلاقیت قادر ید جلوه های ساده را با GDI ایجاد کنید . 

   یکی از کلمات عمومی که در GDI زیاد با آن برخورد خواهید کرد DC (Device Context ) است که نشان دهنده همان ناحیه ای است که ترسیم روی آن صورت میگیرد و در دلفی با TCanvas نشان داده میشود . در واقع DC  محل نشان دادن خروجی توابع گرافیکی است . بنابرین شما میتوانید از برخی توابع ترسیم برای ترسیم در صفحه نمایش یا پرینتر استفاده کنید . نکته دیگری که باید مورد توجه قرار بگیرد این است که توابعی که شما از آن استفاده میکنید توابع گرافیکی استاندارد دلفی بوده و پوششی برای توابع گرافیکی ویندوز است و دلفی آنها را برای ایجاد یک رابط کاربر خوب و مناسب آماده کرده است. در ابتدا برای آشنایی با سازماندهی GDI با معرفی بعضی از کلاسهای مهم GDI شروع میکنیم :

Pen   : برای رسم خطوط ساده ( مثال آن تابع LineTo است.) و ایجاد کادر برای اشکال دیگر استفاده میشود .

Brush : برای پر کردن یک محیط بسته با رنگ استفاده میشود .  مثال آن توابع,  FillRect   FloodFill. است .

Font : برای تعیین فونت و اندازه فونت در هر متنی که در ترسیم آن را مینویسید استفاده میشود .

Region : یک ناحیه بسته از فضای ویندوز که میتواند یه بیضی ، چهار ضلعی یا یه دوازه وجهی یا هر چیز دیگری باشد .

خوب ، حالا باید شروع به ترسیم کنیم . ابتدا با خطوط و اشکال ساده شروع میکنیم و بعد به سراغ توابع مورد استفاده در ترسیم Bitmap ها میرویم و در آخر راجع به تکنیکهای ترسیم در صفحه نمایش صحبت میکنیم . قبل از هر چیز باید بدانید که مختصات (0و0) نقطه بالا ، سمت چپ است . اگر یک تجسم ریاضی از مختصات داشته باشید ممکن است کمی گیج شوید . فراموش نکنید که در اینجا Y در بالاترین نقطه صفر و به سمت پایین صفحه نمایش مثبت و X در منتهی الیه سمت چپ صفر و به سمت راست صفحه نمایش مثبت است . در واقع مختصات اینجا بصورت (ارتفاع از بالا ، فاصله از چپ) میباشد. مثلا (0,50) یک نقطه در سمت چپ و 50 پیکسل پایین تر از بالای صفحه نمایش است.

خطوط و اشکال

رسم خطوط و اشکال خیلی ساده است. چیزی مهمی که اینجا باید بخاطر داشته باشید تفاوت میان Pen و Brush است. بطور ساده از Pen برای رسم خطوط استفاده میشود اگرچه ممکن است این خطوط یک چهار گوش را تشکیل دهد. ولیBrush   درون یک ناحیه ی بسته است که بوسیله خطوط بوجود آمده است. دو تابع برای رسم خطوط وجود دارد که هر دو از متعلقات TCanvas هستند .

MoveTo : با استفاده از این تابع موقعیت قلم را جابجا میکنیم . مثال :

Canvas.MoveTo(75,200);

LineTo : با استفاده از این تابع، از موقعیت فعلی قلم به یک نقطه خاص، خط رسم میکنیم . مثال:

Canvas.LineTo(50,150);

            شما میتوانید بجای استفاده از MoveTo موقعیت قلم را بوسیله تابع PenPos هم تغییر بدهید . برای مثال:

Canvas.PenPos.X:=150;
Canvas.PenPos.Y:=100;

یا

            Canvas.PenPos:=Point(150,100);

            به یاد داشته باشید که موقعیت پیش فرض قلم موقعیت (0,0) میباشد. اگر لازم است خط شما از نقطه دیگه ای شروع شود قبل از استفاده از LineTo باید موقعیت قلم را اصلاح کنید . بعد از استفاده از LineTo موقعیت قلم همان نقطه ای است که خط به آن کشیده شده مثلا بعد از اجرای Canvas.LineTo(100;200); موقعیت قلم نقطه (100,200) خواهد بود. خطوط رسم شده بوسیله Pen (TPen) در Canvas ایجاد میشود . شما براحتی میتوانید پارامترهای قلم را همانطور که میخواهید تغییر بدهید. مثلا برای تغییر اندازه قلم Canvas.Pen.Width:=4; و برای تغییر رنگ Canvas.Pen.Color:=clBlack; عمل کنید. یک مثال ساده را ببینیم . یک پروژه جدید ایجاد کنید و یک عدد Button روی آن قرار دهید و کد رویداد کلیک Button را بصورت زیر بنویسید.

 

procedure TForm1.Button1Click(Sender: TObject);

const NUM_LINES = 2000;

var i:integer;

begin

  Randomize;

  for i := 0 to NUM_LINES - 1 do

  begin

    Canvas.Pen.Color :=

        RGB(Random(256),Random(256),Random(256));

    Canvas.LineTo

        (Random(ClientWidth),Random(ClientHeight));

  end;

end;

 

 

در مثال بالا، 2000 خط با جهت های تصادفی و با رنگهای تصادفی فرم را پر میکند . تابع RGB   برای ایجاد رنگ با تعیین مقادیر قرمز، سبز و آبی مورد استفاده قرار میگیرد. RGB(Red,Green,Blue) . این مقادیر میتواند مابین 0 تا 255 باشد . این تابع به شما مقداری از نوع TColor بر میگرداند . در این مرحله به سراغ رسم اشکال میرویم. تابع رسم اشکال زیادی در TCanvas وجود دارند که براحتی قابل استفاده هستند.  چند مورد از پر استفاده ترین آنها به قرار زیرند:

Ellipse : برای رسم بیضی . مثال : Canvas.Ellipse(0,0,100,50); (پارامتر ها به ترتیب : X سمت چپ بیضی ، X سمت راست بیضی ، Y بالای بیضیی ، Y پایین بیضی).

FillRect : پر کردن یک چهارگوش با Brush Color  ولی بدون خط دور آن . مثال : Canvas.FillRect(Bounds(0,0,150,200));

FloodFill : پر کردن یک ناحیه یا Brush Color  با ایجاد خطوط لبه مثال : Canvas.FloodFill(10,10,clBlue,fsBorder);

Rectangle : رسم چهارگوش و پرکردن آن با Brosh Color  و  خطوط لبه آن با Pen Color . مثال : Canvas.Rectangle( Bounds(20, 20, 50, 50));

RoundRect : ایجاد چهارگوش با گوشه های منحنی. مثال : Canvas.RoundRect(20, 20, 50, 50, 3, 3);

(تابع Bounds یک مقدار TRect برمیگرداند. TRect چهار مقدار top, left, bottom, right را نگه میدارد. بجای این تابع میتوانید از Rect هم استفاده کنید که تفاوت چندانی با هم ندارند ) .

یک تابع مفید دیگر هم وجود دارد که برای ایجاد متن به کار میرود . این تابع به شما اجازه میدهد که متن مورد نظر خود را با فونت تعیین شده (Canvas font) ایجاد کنید . مثال :

Canvas.TextOut(20,50,'GDI in Delphi');

شما میتوانید نوع قلم ، رنگ و اندازه قلم را به دلخواه خود تغییر دهید. مثال :

Canvas.Font.Name := 'Verdana';
Canvas.Font.Size := 24;
Canvas.Font.Color := clRed;

در زیر یک مثال را میبینیم که 200 شکل را بصورت تصادفی روی فرم رسم میکند .

 

 


procedure TForm1. Button1Click(Sender: TObject);;

const

  NUM_SHAPES = 200;

var

  i,ShapeLeft,ShapeTop: Integer;

begin

  for i := 0 to NUM_SHAPES - 1 do

  begin

    Canvas.Brush.Color :=

        RGB(Random(256),Random(256),Random(256));

    ShapeLeft := Random(ClientWidth);

    ShapeTop := Random(ClientHeight);

    case Random(3) of

      0: Canvas.Rectangle(ShapeLeft,

                          ShapeTop,

                          ShapeLeft + Random(50),

                          ShapeTop + Random(50));

      1: Canvas.Ellipse(ShapeLeft,

                        ShapeTop,

                        ShapeLeft + Random(50),

                        ShapeTop + Random(50));

      2: begin

           Canvas.Font.Size := 10 + Random(7);

           Canvas.TextOut ( ShapeLeft, ShapeTop, 'Delphi');

         end;

    end;

  end;

end;

                در مثال بالا وقتی برنامه را اجرا میکنید فرم برنامه در حال اجرا را کمینه (Minimize) کنید و دوباره آنرا به حالت اول برگردانید . میبینید که خطوط پاک شدند . اصلا نگران نباشید. ناپدید شدن اشکالی که شما رسم کردید یکی از امتیازات مهم GDI است و برمیگردد به تفاوت بین Drawing و  Panting.

Drawing: Drawing بهمان صورتی است که در مثال قبل مشاهده فرمودید. گرافیک ایجاد شده بوسیله آن تا وقتی وجود دارد که پنجره Refresh نشده باشد.

            Painting: هر گاه یک پنجره نیاز به Refresh شدن دارد ویندوز یک پیام به پنجره مورد نظر ارسال میکند. این پیام میتواند Handle رویداد OnPaint فرم باشد . پس وقتی شما گرافیک مورد نظر خود را در رویداد OnPaint تعریف کنید جلوه ایجاد شده در هنگام Refresh ناپدید نمیشود. این تفاوت اساسی بین این دو است. Drawing فقط یک رویداد موقتی است در صورتی که Painting هر گاه پنجره احتیاج به Refresh داشته باشد فرا خونده میشود.

            بطور کلی اگه خواسته باشیم در صفحه بوسیله Drawing ترسم را انجام دهیم در حالیکه این تغییرات موقتی ایجاد شده به نحوی ذخیره شوند چند راه وجود دارد. یک را استفاده از Bitmap است به این صورت که میتوانیم یک Bitmap ایجاد کنیم و این تغییرات را همزمان با صفحه نمایش در Bitmap هم اعمال کنیم و بعد در زمان لازم این Bitmap را در صفحه نمایش، نمایش بدهیم.   

            استفاده از Handle ها

اگر چه هنگام استفاده از دلفی شما میتوانید بدون نگرانی از توابع گرافیکی دلفی استفاده کنید با این حال دسترسی شما به API ویندوز، بصورت مستقیم هم به هیچ وجه محدود نشده است. اما برای استفاده از توابع API ویندوز، این توابع از شما HDC میخواهند. اما میدانید HDC چیست؟

شاید بدانید که برای هر چیزی در ویندوز یک Handle (دستگیره) در نظر گرفته میشود. این Handle  ها برای شناسایی آبجکت ها استفاده میشوند. تمام پنجره ها، کلید ها، منو ها و... داری دستگیره هستند. پس نباید تعجب کنید اگه بفهمید که تمام آبجکت های شما این دستگیره را بصورت یک خصوصیت در خود دارند. مثلا:

Form1.Canvas.Handle

توضیح دستگیره ها در Win32.hlp دلفی به این صورت است:

"An application must obtain an object handle and use this handle to examine or modify the system resource (or both). In the Microsoft® Win32® application programming interface (API), handles are usually implemented as indirect pointers, but this is not always the case."

HDC ها یک نوع دستگیره هستند که مشخص کننده بخشی از فضای زمینه (Device Context) می باشند. همانطور که گفته شد TCanvas بیشترین توابع DC (فضای زمینه) را دارد. کافیست دستگیره  TCanvas آبجکت مورد نظر را در توابع API ویندوز استفاده کنید.

Abject .Canvas.Handle

در اینجا برخی از توابع API که معادل VCL آنها گفته شد را ببینید.

 VCL

WINDOWS API

Canvas.TextOut(x,y,myString);

TextOut(Canvas.Handle, x, y, PChar(myString), Length(String));

Canvas.FloodFill(X, Y, Color,fsBorder);

ExtFloodFill(Canvas.Handle, x, y, YourColour, FLOODFILLBORDER);

Canvas.LineTo(x,y);

LineTo(Canvas.Handle, x, y);

Canvas.MoveTo(x,y);

MoveToEx(Canvas.Handle, x, y, nil);

 

بطور کلی توابع بهمان صورت قابل استفاده هستند با این تفاوت که اول باید Handle را پاس کنید. بخاطر داشته باشید که شما میتوانید دستگیره ها متفاوت برای Drawing در محلهای مختلف استفاده کنید. مثلا از Bitmap1.Canvas.Handle برای یک Bitmap و از Form1.Canvas.Handle  برای فرم.

دقت داشته باشید که برای استفاده از داده رشته ای در این توابع، داده مورد نظر باید از نوع PChar باشد. (مثلا تابع TextOut()). گاهی ممکن است شما مجبور باشید طول رشته را نیز در تابع وارد کنید که در این صورت کافیست از تابع Length استفاده کنید.

Bitmap چیست؟

رسم خطوط و اشکال به روش فوق روش مفیدی است ولی توانایی شما برای رسم عکسها مستلزم شناخت و استفاده از Bitmap هاست.

آبجکتی که معمولا برای رسم تصاویر استفاده میشود Bitmap است. Bitmap یک آبجکت گرافیکی است که دارای دو قسمت میباشد 1- هدری شامل اطلاعات مهمی درباره تصویر است (شامل طول، ارتفاع، اطلاعات رنگ و...) 2- بخشی که شامل داده های خود تصویر است (شامل یک آرایه بزرگ ار رنگ هر پیکسل). خوشبختانه شما نباید برای استفاده از Bitmap هیچ نگرانی داشته باشید بدلیل اینکه کلاس Bitmap از قبل در دلفی وجود داشته که TBitmap نامیده میشود. Bitmap ها خارق العاده هستند، آنها به ما آزادی عمل خیلی زیادی نسبت به خطوط و اشکال میدهند. شما حتی میتوانید Bitmap ها را بوسیله برنامه مورد نظرتان ایجاد نمایید و در برنامه خودتان از آنها استفاده نمایید. لازم است اول یک مثال از استفاده از Bitmap ها ببینیم.

procedure Form1.DrawBitmap(const Filename: String; const x,y: Integer);

var

  Bmp: TBitmap;

begin

  if not FileExists(Filename) then

  begin

    ShowMessage('The bitmap ' + Filename + ' was not found!');

    Exit;

  end;

  Bmp := TBitmap.Create;

  try

    Bmp.LoadFromFile(Filename);

    Canvas.Draw(x, y, Bmp);

  finally

    Bmp.Free;

  end;
end;

این تابع سعی در نمایش دادن تصویر Filename روی فرم در موقعیت (x,y) دارد. اگر شما قصد ندارید آبجکت های مورد نظر را در زمان راه اندازی (Run-Time) ایجاد کنید من شدیدا استفاده از اشاره گرها را توصیه میکنم. بهر حال در بالای رویه، Bitmap را ایجاد کنید و تصویر مورد نظر را در آن لود نمایید. استفاده از بلوک Try … Finally هم شما را از عدم ایجاد خطا مطمئن مینمایید حتی در صورت وجود فایل با فرمت نا معتبر. روش استفاده شده در مثال بالا همیشه موثر نیست. این روش ابتدا وجود فایل را چک میکند سپس Bitmap را ایجاد کرده و پس از استفاده آزاد میکند. یک روش بهتر برای استفاده و نمایش تصویر، ایجاد Bitmap و لود کردن تصویر در FormCreate و آزاد کردن آن در FormDestory است. این روش موثر تر است و در سراسر عمل قابل دسترسی است.

توابع رسم در GDI

TCanvas توابع رسم زیادی دارد که همه آنها با TGraphic سر و کار دارند. TGraphic کلاس پایه آبجکت های گرافیکی در دلفی است. برخی از مثال های آن عبارتند از: TBitmap برای Bitmap ها، Ticon برای icon ها، TMetafile برای Metafile ها و TJPEGImage برای JPEG ها. در زیر لیست سایر تابع رسم در GDI را میبینید.(تمام این توابع متدهای Tcanvas هستند.)

نام

توضیح

مثال

Draw

رسم تصویر در نقطه مورد نظر.

 

    Canvas.Draw(5,10,MyGraphic);

StrechDraw

رسم تصویر در محدوده مورد نظر با ایجاد وضعیت ارتجاعی.

 

   Canvas.StretchDraw( Bounds(0,0,32,32), MyGraphic);

CopyRect

کپی کردن بخشی از یک Tcanvas به دیگری و ایجاد حالت ارتجاعی در صورت لزوم

   Canvas.CopyRect( Bounds(0,0,32,32), MyBmp.Canvas, Bounds(0, 0, 640, 480));

همه این توابع راحت و آسان هستند اگرچه تابعی که در زیر با آن آشنا میشوید کمی مشکل تر است و نیاز به دقت بیشتری دارد. این تابع BitBlt است.

 

function BitBlt(

  hdcDest: HDC;     // handle to destination device context

  nXDest,           // x-coordinate of destination rectangle's upper-left corner

  nYDest,           // y-coordinate of destination rectangle's upper-left corner

  nWidth,           // width of destination rectangle

  nHeight: Integer; // height of destination rectangle

  hdcSrc: HDC;      // handle to source device context

  nXSrc,            // x-coordinate of source rectangle's upper-left corner

  nYSrc: Integer;   // y-coordinate of source rectangle's upper-left corner

  dwRop: DWORD      // raster operation code
): Boolean;

همانطور که میبینید این تابع برای ترسیم تصویر یک DC در محدوده یک DC دیگر است. درک این تابع کمی مشکل به نظر میرسد ولی با وجود Canvas.Draw شما احتمالا نیازی به استفاده از این تابع پیدا نخواهید کرد. برای درک بهتر این تابع به مثال زیر توجه فرمایید.

 

procedure TForm1.Button1Click(Sender: TObject);
var MyBitmap:TBitmap;
begin
  MyBitmap:=TBitmap.Create;
  MyBitmap.Width:=Screen.Width;
  MyBitmap.Height:=screen.Height;   
  BitBlt(MyBitmap.canvas.handle, 0, 0, MyBitmap.width, MyBitmap.height, GetDC(0),0,0,Srccopy);
  image1.Picture.Bitmap:= MyBitmap;
  MyBitmap.Free;
end;

 

      در مثال بالا برنامه بوسیله این تابع از صفحه نمایش عکس گرفته و در Image1 نمایش داده میشود. از تابع GetDC برای بدست آوردن دستگیره فضای زمینه یک ناحیه که Handle آن را داریم استفاده میکنیم. در این مثال برای اشاره به تمامی صفحه نمایش مقدار صفر را در تابع GetDC قرار میدهیم.

            تا اینجا فرض بر این بود که شما Bitmap را در زمان راه اندازی ترسیم میکنید. اما راه بهتر در این موارد استفاده از TImage و تنظیم کردن خاصیت Picture آن در زمان طراحی، برای نمایش تصویر از زمان راه اندازی است. این روش گذشته از دقت در محل روی فرم، حرکت دادن تصویر روی فرم را در زمان اجرا آسانتر میکند.

منبع: انجمن دلفی ایران


نوشته شده توسط ابراهیم خدائی در چهارشنبه بیست و دوم فروردین 1386 ساعت 2:50 | لینک ثابت |

منوی اصلی

صفحه نخست
آرشيو وبلاگ
پروفایل مدیر وبلاگ
عناوین مطالب وبلاگ
درباره دلفی
نكات مفيد براي كار در محيط دلفي
دلفی NET.
مقدمات دلفی
برنامه ها‎ ‏و مثالهای‎ دلفی
کامپوننتهای دلفی

درباره ی ما


این وبلاگ برای توسعه برنامه نویسی دلفی با ارائه ابزارها و مثالها و توضیحات کامل شروع به کار کرده که امیدواریم دوستان عزیز با ارائه نظرات و پیشنهادات خود ما را در این راه یاری نمایند تا بتوانیم قدم کوچکی در توسعه این زبان برنامه نویسی قدرتمند اما راحت داشته باشیم.

با تشکر: ابراهیم خدائی

پیوند های روزانه

آرشیو

پیوند های وبلاگ

دانشگاه نبی اکرم (ص)
سايت اختصاصي كامپيوتر ورودی 85
سازمان فناوری اطلاعات و ارتباطات
وزارت علوم و تحقیقات و فناوری
سازمان سنجش آموزش کشور
سایت دکتر مهدوی
قالب وبلاگ
جستجوگر قالب وبلاگ

آخرین پست ها

سری جدید کامپوننت برای دلفی 7
کدها ومثالها و ترفندهای دلفی
دانلود کامپوننت
5 کامپوننت برای دانلود
آموزش نصب انواع کامپوننتها در دلفی
کار با تلفن و مودم با استفاده از کامپوننت KDTele
راهنما
الگوريتم تبديل تاريخ ميلادي به تاريخ شمسي همراه با کد کامل آن به زبان دلفی
بخشی از ويژگيهای جديد Borland Developer Studio 2006
Graphics Device Interface
Borland Developer Studio 2006 (دلفی 2006)
بورلند استودیو در یک نگاه
فایل های INI در دلفی
ساختار رکوردها در دلفی
آرایه ها در دلفی
استفاده از DLL در دلفی
انواع متغیر ها در دلفی
مدیریت حافظه در دلفی
گزارش از دلفي 9- Delphi 2005
حركت از دلفي به دلفي NET.
تكنولوژي NET.
تاریخچه دلفی
نكات مفيد براي كار در محيط دلفي
سال خوک

RSS

POWERED BY
BLOGFA.COM

کلیه ی حقوق مادی و معنوی وبلاگ ebrahimkhodaei محفوظ می باشد.
طراحی شده توسط یاس تم