PDA

View Full Version : مقدمه ای بر GDI ویندوز - قسمت سوم



Vahid_Nasiri
پنج شنبه 12 تیر 1382, 01:00 صبح
بیت مپ ها :

تر سیم خطوط و اشکال جالب و مفید است اما راضی کننده نیست! ما به توانایی ترسیم تصاویر نیز نیاز داریم و اینجا است که بیت مپ ها وارد صحنه می شوند.
هنگامیکه تصویری را ترسیم می کنیم ، شیء بکار گرفته شده عموما بیت مپ است. این شیء گرافیکی تشکیل شده است از یک Header که حاوی اطلاعاتی مانند طول و عرض تصویر و غیره است و سپس داده های واقعی بیت مپ ( آرایه ای عظیم حاوی اطلاعاتی راجع به رنگ هر نقطه ) . خوشبختانه نیازی به نگران بودن در مورد این آیتم ها وجود نداشته و در دلفی می توان از TBitmap استفاده کرد.



ترسیم بیت مپ ها :

در مثال زیر می خواهیم یک بیت مپ را ترسیم کنیم :



procedure Form1.DrawBitmap(const Filename: String; const x,y: Integer);
var
Bmp: TBitmap;
begin
// Make sure the file exists first!
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;



بوسیله ی این تابع یک بیت مپ بارگذاری و سپس در x,y معین شده نمایش داده می شود و در قسمت finally کد فوق همواره منابع اختصاص داده شده ( حتی اگر تصویری نامعتبر را خواسته باشیم نمایش دهیم ) آزاد می گردد. روش فوق زیاد کارآمد نیست و هربار با فراخوانی آن یک بیت مپ ایجاد و تخریب می شود. اگر در طی برنامه تصاویر زیادی باید بارگذاری شوند بهتر است در FormCreate کار خلق شیء و سپس در FormDestroy کار آزاد سازی منابع صورت گیرد.


استفاده از توابع ترسیمی دلفی :

TCanvas توابع ترسیمی مفیدی دارد که تمام آنها با نوع TGraphic سروکار دارند. نوع TGraphic کلاسی است پایه برای اشیاء گرافیکی در دلفی مانند بیت مپ ها (TBitmap) ، آیکن ها (TIcon) ، متافایل ها (TMetaFile) و JPEGs در TJPESImage . تمام آنها از توابع ترسیمی مشابهی استفاده می کنند که به آنها پرداخته خواهد شد.
( تذکر : تمام توابع زیر متدهای TCanvas هستند)

Draw :
یک TGraphic را بر روی Canvas ترسیم می کند و ابعاد آنرا مطابق ناحیه ی مشخص شده تنظیم می نماید. مثال :


Canvas.Draw(5,10,MyGraphic);

StretchDraw :
یک قسمت از TCanvas را به قسمت دیگر کپی می کند و در صورت لزوم ابعاد آنرا تغییر می دهد. مثال :


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


CopyRect :
یک قسمت از TCanvas را به قسمت دیگر کپی می کند و در صورت لزوم ابعاد آنرا تغییر می دهد. مثال :


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


تابع TCanvas.Draw به سادگی یک Wrapper برای تابع BitBlt ویندوز GDI به شمار می رود :



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;



سایر گزینه های مهیا :

شاید تاکنون این سؤال برای شما پیش آمده باشد که بجای استفاده از این توابع می توان یک TImage را روی فرم قرار داد و خاصیت Picture آنرا تنظیم نمود. اما باید خاطر نشان کرد که توانایی عمده توابع فوق در ساخت انیمیشن (پویانمایی) می باشد.



روش هایی برای اجتناب از چشمک زدن صفحه (Flickering) :

چشمک زدن صحنه در حال حرکت اشیاء دلفی بسیار آزار دهنده است و 4 روش برای حل آن وجود دارد :
1- استفاده از خاصیت DoubleBuffered اشیاء مشتق شده از TWinControl . از دلفی 4 به بعد خاصیت ذکر شده معرفی گردیده که با تنظیم کردن آن به true مشکل چشمک زدن حل خواهد شد و تنها عیبی که دارد مصرف حافظه ی بیشتر است و برای ترسیم با استفاده از Canvas فرم مصرف دارد.
بهتر است این کار به صورت زیر انجام شود :


procedure TForm1.FormCreate(Sender: TObject);
begin
DoubleBuffered := True;
end;



2- خاصیت ControlStyle کنترل را به csOpaque تنظیم کنیم . یعنی :



ControlStyle := ControlStyle + [csOpaque];


در این صورت برنامه مطمئن می شود که کنترل پس زمینه ی پاک شده ی خود را نباید حفظ کند.

3- استفاده از بیت مپ های off-screen که در ادامه توضیح داده خواهد شد.
4- استفاده از پیغام WM_ERASEBKGND ویندوز .
این مورد به شدت باعث کاهش چشمک زدن می گردد. این پیغام هنگامی فرستاده می شود که پنجره نیاز دارد زمینه ی آن پاک شده باشد و آنرا در تعریف فرم و یا کلاس می توان به صورت زیر ارائه داد :

تعریف در قسمت Private کلاس :


procedure StopFlicker(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND;


و سپس به صورت زیر پیاده سازی می شود :


procedure T<<yourclassorform>>.StopFlicker(var Msg: TWMEraseBkgnd);
begin
Msg.Result := 1;
end;


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

نکته ای عجیب!
در دلفی 6 هنگام استفاده از کنترل TImage هنگامیکه خاصیت Stretch آن True شود مشکل چشمک زدن آن حل می شود!



بیت مپ های Off-Screen :

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

برای مثال هنگام ترسیم TImage به صورت مستقیم روی صفحه ، چشمک زدن مشاهده می شود زیرا با ترسیم هر خط از کارت گرافیکی استفاده می گردد اما در حالت بافر دوگانه ترسیم در حافظه و سپس نمایش دادن آن بکار برده می شود. در این صورت کارت گرافیکی فقط یکبار برای نمایش تصویر نهایی درگیر خواهد شد .

مثال ترسیم مستقیم روی صفحه :



for i := 0 to 20000 do
begin
Canvas.MoveTo(Random(ClientWidth), Random(ClientHeight));
Canvas.LineTo(Random(ClientWidth), Random(ClientHeight));
end;


مثال ترسیم با استفاده از بافر دوگانه :



Bmp := TBitmap.Create;
try
Bmp.Width := ClientWidth;
Bmp.Height := ClientHeight;

// Draw lines onto the **bitmap's** canvas
for i := 0 to 20000 do
begin
Bmp.Canvas.MoveTo(Random(ClientWidth), Random(ClientHeight));
Bmp.Canvas.LineTo(Random(ClientWidth), Random(ClientHeight));
end;

Canvas.Draw(0,0, Bmp); // draw the bitmap to screen now
finally
Bmp.Free;
end;


همانطور که ملاحظه می کنید ابتدا یک بیت مپ ایجاد و ترسیم روی Canvas آن صورت می گیرد و سپس حاصل روی صفحه کپی می شود.

GameBiz
پنج شنبه 12 تیر 1382, 23:54 عصر
hi vahid
don't you think that all these stuffs are much easier to get done in DX than in GL, why don't you switch to DX, it's more professional (!!) and faster too.
also tell me what is your field in IUST, I'm metallurgy

Vahid_Nasiri
جمعه 13 تیر 1382, 09:27 صبح
فعلا وقت نمی کنم سراغ دایرکت ایکس برم. البته از لحاظ سرعت زیاد موافق نیستم. چون این مطلب را با برنامه های موجود می توان محک زد :wink:

در ضمن این مطالب در مورد جی دی آی بود و به نظر من تا کسی این اصول را نداند عملا چیزی از OpenGL و DX سر در نمی آورد. به همین جهت این مطالب را گذاشتم. :oops:
فیلد من BioEng است......