ارث بری فرم ویژوال چیست؟
VFI قابلیتی در دلفی است که اجازه می دهد فرمهای جدید از فرمهای موجود مشتق شوند یا قابلیتهای آن را به ارث برند. VFI به طور کلی همان مزایای ارث بری را در اختیار می گذارد که اولین آنها قابلیت بر گرفتن شباهتهای کلاسهای مختلف از کلاسهای بالاتر در یک سلسله مراتب است. در این مورد، کلاسها فرمهایی هستند که در ابزار طراحی فرم دلفی ساخته شده اند. به زبان دیگر VFI به شما اجازه می دهد یک کد را در جایی بنویسید که بین چندین فرم مشترک باشد. واضح است که یک بار نوشتن کد کارایی را بالا برده و امکان خطا را کاهش می دهد. حال این فرمهاممکن است همگی مربوط به یک برنامه یا برنامه های مختلف باشند.
VFI چیزی بیش از استفادهء مجدد از کد است. این همان جایی است که بخش ویژوال VFI وارد می شود. شما می توانید فرمهایی را در دلفی طراحی کنید، وهمان طرح بندی و ظاهر را بین فرمهای متفاوت به اشتراک گذارید. واداشتن فرمها به داشتن طرح بندی مشترک باعث ایجاد ثبات در ظاهر و بالا رفتن کارایی می شود.
همچنین استفاده از VFI به شما امکان طراحی سلسله وار فرمها را می دهد. هر تغییری در فرمهای مراتب بالاتر در فرمهای وارث تاثیر می گذارد. همین طور، می توانید اجزاء و یا کدهایی را به فرمها اضافه و در نتیجه تمام فرمهای وارث را تغییر دهید.
فرض کنید در حال نوشتن برنامه ای برای مدیریت مشتریان و صورتحساب هایشان هستید. شما برنامه را طراحی کرده و معین می کنید که برای کار با داده ها به سه فرم کلی نیاز دارید: یکی برای مشتریان، دومی برای صورتحساب ها و سومی برای قطعاتی که می فروشید. گرچه هر فرم اطلاعات متفاوتی ارائه می کند، عناصر مشابهی در فرمها هست. مثلا هر فرم باید دوبرگ داشته باشد. یکی با یک DBGrid بر رویش و دیگری با کنترلهای متفاوت برای ویرایش جدولی که در نظر دارید. همچنین هر برگ به چند دکمه برای ذخیره و لغو تغییرات و اضافه و حذف کردن رکوردها نیاز دارد. شما می توانید هر فرم را جداگانه طراحی کرده و برای هر کدام جداگانه کد بنویسید. اما راه بهترش آغاز کار با یک فرم کلی پیش ساخته حاوی کنترلها و کد مشترک است. بعد می توانید از VFI استفاده کرده، فرمهای مورد نظرتان را مبتنی بر این فرم اولیه بسازید و تغییرات لازم را در آنها ایجاد کنید.
وقتی فرمها را ساختید، باز هم می توانید امکانات جدیدی به فرم اولیه اضافه کنید. مثلا اگر بخواهید در پس زمینهء همهء فرمها آرم خاصی را نمایش دهید یا در همه امکاناتی کلی برای جستجو فراهم آورید. کافی است هر آنچه را می خواهید به فرم اولیه بیافزایید. فرمهای پایین دست خود به خود رفتار یا ظاهر جدید را به ارث می برند.
مروری کوتاه بر وراثت
وراثت یکی از ویژگیهای برنامه نویسی شیء گراست که به شما اجازهء ساخت کلاسهای تازه مبتنی بر کلاسهای موجود را می دهد. کلاس قدیمی، کلاس مافوق یا بالادست و کلاس جدید، کلاس زیر دست یا پایین دست خوانده می شود. کلاسها بالطبع دارای داده ها و کدهایی هستند. کلاسهای پایین رتبه تر می توانند داده ها و کدهای عمومی کلاسهای بالادست خود را ببینند. دلفی از یک مدل وراثت تکی پشتیبانی می کند. بدین معنی که هر کلاس می تواند به طور مستقیم وارث فقط یک کلاس باشد. (بعضی زبانها از نوع دیگری وراثت به نام وراثت چندتایی پشتیبانی میکنند. در این زبانها یک کلاس می تواند وارث چندین کلاس بالادست خود باشد.) همچنین می توانید به طور مکرر از وراثت استفاده کنید. یعنی می توانید مثلا کلاس A را وارث کلاس B و کلاس B را وارث کلاس C بسازید. در این حالت کلاس A می تواند کدها و داده های عمومی هر دو کلاس B و C را ببیند (شکل ۱ را ببینید).
شکل ۱

کلاس زیر را که ابزار طراحی فرم دلفی به طور خودکار برای فرم ما ایجاد کرده در نظر بگیرید:
Type
TFrmRichEdit = class(TForm)
btnCancel: TButton;
btnOk: TButton;
rtfNotes: TRichEdit;
private
{ Private declarations }
public
{ Public declarations }
end;
نام این کلاس TFrmRichEdit است و می بینید که به صورت وارثی از TForm تعریف شده. TForm یکی از کلاسهایی است که از قبل در VCL تعریف شده. TForm و کلاسهای بالاترش داده و کدی را که برای همهء انواع فرمها متعارف است تعریف می کند. خاصیتهایی مانند Font, Caption و Color و همین طور روالهایی چون Show, Close و ShowModal در همین کلاسها تعریف می شوند. پس TForm و پدرانش همهء شباهتهای میان انواع فرمها را در بر می گیرند. اگر دلفی از وراثت پشتیبانی نمی کرد، ابزار طرحی فرم دلفی می بایست هربار، برای هر فرم تمام این روالها و داده های مشترک را از اول می نوشت.
برای نمونه سازی از کلاس TFrmRichEdit، ابتدا باید یک شیء از آن نوع تعریف کنید:
Var
frmRichEdit: TFrmRichEdit
سپس می توانید کلاس را با صدا زدن روال سازنده اش ، Create، نمونه سازی کنید. Create یک پارامتر می گیرد، که به آن شیء Application را رد می کنیم:
frmRichEdit := TFrmRichEdit.Create(Application);
اینجا هم وراثت توی کار است! چه کسی Create را تعریف کرده؟ یکی از کلاسهای بالادست TFrmRichEdit. اگر بخواهیم دقیقتر بگوییم، TCustomForm.
هنگامی که از روی یک کلاس، شیئی می سازید، می توانید به طور مستقیم به روالها و داده های آن شیء دسترسی داشته باشید:
frmRichEdit.btnOk.Enabled := False;
همچنین به روالها و داده های کلاسهای بالادستش:
frmRichEdit.Caption := ‘RTF Editor’;
frmRichEdit.Show;
Caption در TControl (که چندین مرتبه بالاتر است) تعریف شده. روال Show هم در TCustomForm تعریف شده.
بالاتر دربارهء داده و کدهای عمومی یک کلاس صحبت کردیم. می دانید منظور ما از “Public” دقیقا چیست؟ آیا می شود کد و داده هایمان را به صورت دیگری هم تعریف کنیم؟ در حقیقت عمومی، میدان یا قلمرو تعریفمان را مشخص می کند. نشان می دهد که شیء یا متغیر تعریف شده در کجاها باید مرئی و قابل دستیابی باشد و در کجاها نباشد. داده و کد عمومی یک کلاس برای کاربرانش قابل رویت هستند. در مثال بالا هر سهء btnOk, btnCancel و rtfNotes، متغیرهای عمومی نمونهء ما هستند.
متغیرها، کدها و روالهای یک کلاس را دو جور دیگر هم می توانیم تعریف کنیم. به صورت خصوصی و حفاظت شده . اکنون اگر دوباره به کلاسی که تعریف کردیم، نگاهی بیندازید، دو بخش به نامهای public و private می بینید که هر دو تهی هستند. آنچه در این بخشها تعریف کنید، قلمروی همنام همان بخش خواهد داشت. کد و داده های شخصی تنها در روالهای درونی کلاس قابل رویت هستند و کاربران کلاس نمی توانند آنها را ببینند.
گرچه دلفی به طور پیش فرض بخش حفاظت شده را برای شما نمی سازد، ولی اگر نیاز باشد، خودتان می توانید آن را بسازید. هر چه در بخش حفاظت شده تعریف شود، مانند تعریفهای بخش خصوصی برنامه در اختیار روالهای خود کلاس خواهد بود. آنچه که این دو (خصوصی و حفاظت شده) را با هم متفاوت می سازد، روش برخورد با کلاسهای پایین دست است. کلاسهای زیر دست می توانند چیزهایی را که حفاظت شده تعریف شده، ببینند. اما آن چه که خصوصی تعریف شده، محدود به خود کلاس است و بس.
حال که وراثت را هر چند کوتاه مرور کردیم، اجازه بدهید VFI را در عمل ببینیم.
فوت و فن VFI
برای ساختن فرمهای جدید بر پایهء فرمهای موجود، باید از انبار اشیاء دلفی استفاده کنید. این انبار در بر گیرندهء تعدادی فرمهای پیش ساخته و همچنین فرمهای موجود برنامهء شماست که با انتخابشان می توانید فرمهای جدیدی مبتنی بر آنها بسازید. برای ساختن یک فرم جدید معمولا منوی File | New | Form را انتخاب می کنیم. ولی برای ساختن فرمی بر پایهء فرمهای موجود باید File | New | Other… را انتخاب کرد. این گزینه انبارهء اشیاء دلفی یا همان Object Repository را در مقابل ما می گشاید. اکنون می توانید آنچه را می خواهید بسازید، انتخاب کنید. شما می توانید خودتان فرمهایی به انبار اضافه کنید، ولی تعدادی فرم هم پیشاپیش همراه دلفی ارائه شده که به عنوان نقطهء شروع می توانید از آنها استفاده کنید.
حالا صفحهء Forms را انتخاب کنید. چندین فرم از جمله About box و Dual list box را مشاهده می کنید (شکل ۲ را ببینید). این فرمها را در همهء برنامه ها می توان به کار برد.
شکل ۲

به سه گزینهء Use, Copy و Inherit در پایین توجه کنید. اینها به دلفی می گویند که بین فرم جدید شما و فرمهای درون انبار چه رابطه ای باید برقرار باشد:
Copy: یعنی اینکه می خواهید عین فرم درون انبار در برنامهء شما بازنویسی شود. فرم جدید از فرم درون انبار کاملا” مستقل خواهد بود و تغییر در فرم درون انبار هیچ تاثیری بر فرم جدید نخواهد داشت.
Inherit: یعنی فرم جدید بر پایهء فرم درون انبار است و پیوندهایش را با آن برقرار نگه می دارد. اگر فرم درون انبار را تغییر دهید، تمام فرمهای مبتنی بر آن هم تغییر می کنند. معمولا در VFI این گزینه را انتخاب می کنیم.
Use: یعنی می خواهید فرم درون انبار را از همان جا که هست، مستقیما استفاده کنید. در این حالت دستکاری و تغییر در فرم، در واقع تغییر دادن فرم درون انبار است. این تغییرات بر همهء فرمهای وارث تاثیر خواهد داشت.
فرمهای برنامهء خودتان را هم به همین صورت می توانید مجددا استفاده کنید. پنجرهء Object Repository چندین برگ دارد. وقتی این پنجره را باز می کنید، یکی از صفحات باید همنام برنامهء شما باشد، که در بر گیرندهء فرمهای پروژهء حاضر است. فرق این فرمها با فرمهای خود انبار در این است که فرمهای برنامهء خودتان را فقط می توانید به ارث ببرید. در نتیجه تنها گزینهء قابل انتخاب در این صفحه، گزینهء Inherit است. به هر حال تنها گزیته ای هم هست که معنی می دهد.
وقتی بر مبنای یکی از فرمهای درون انبار یک فرم جدید می سازید، امکان تغییر در این فرم جدید وجود دارد. می توانید اجزاء جدیدی به آن افزوده یا روالهای جدیدی بنویسید. همین طور می توانید آنچه را به ارث برده اید تغییر دهید. می توانید اجزاء به ارث برده را حرکت داده یا تغییر اندازه دهید، ولی نمی توانید آنها را حذف کنید. اگر بخواهید چنین کاری بکنید، دلفی از شما ایراد خواهد گرفت. گر چه نمی توانید اجزاء به ارث برده را حذف کنید، ولی به جایش می توانید آنها را نامرئی کنید، یعنی ویژگی Visible آن را False کنید.
هنگامی که مقدار یکی از ویژگیهای به ارث برده را تغییر می دهید، پیوند بین ویژگیهای دو فرم بالا دست و پایین دست را شکسته اید. مثلا فرض کنید بر روی فرم پایین دست دکمه ای را به سمت چپ حرکت می دهید. حالا همان دکمه را در فرم توی انبار تکان می دهید. چون فرم پایین دست پیوند خود را با ویژگی Left فرم بالا دست شکسته، دکمهء روی فرم زیر دست حرکتی نمی کند. (روشن است که اگر پیوند را بر هم نزده بودید حرک می کرد.) می توانید این پیوند را با کلیک راست بر روی دکمه و انتخاب Revert to inherited دوباره برقرار سازید. این کار تمام تغییراتی را که در آن جزء فرم پایین دست (در اینجا دکمهء فرم جدید ما) ایجاد کرده اید، به حالت نخست بر می گرداند.
وقتی با روالهای ارث برده از کلاسهای بالا دست کار می کنید، اوضاع کمی متفاوت است و انتخابهای بیشتری دارید. می توانید روال بالا دست را جایگزین کنید، یا این که کدی بنویسید که علاوه بر روال بالا دست اجرا شود. در صفحهء Forms از پنجرهء New Items، گزینهء Inherit را کلیک کنید و Dual list box را برگزینید. فرم مورد نظر ساخته می شود. اگر روی دکمهء < دوبار کلیک کنید، دلفی برایتان روال زیر را می سازد. این دکمه برای جابجا کردن آیتمها از لیست چپ به لیست راست است.
procedure TDualListDlg2.IncludeBtnClick(Sender: TObject);
begin
inherited;
end;
سرواژهء inherited به معنی فراخوانی روال همنام در کلاس بالا دست است. در حقیقت کد مربوط به کلاس بالا دست است که موارد انتخابی را از لیست دست راست به لیست دست چپ جابجا می کند:
procedure TDualListDlg.IncludeBtnClick(Sender: TObject);
var
Index: Integer;
begin
Index := GetFirstSelection(SrcList);
MoveSelected(SrcList, DstList.Items);
SetItem(SrcList, Index);
end;
این سرواژهء inherited در روال بالاست که روال پایین را اجرا می کند. شما می توانید آزادانه کد دلخواهتان را قبل یا بعد از inherited اضافه کنید. همین طور می توانید آن را حذف کنید و دیگر روال بالا دستی را صدا نکنید.
یک مثال کوتاه
فرض کنید چندین فرم از Dual list box توی انبار به ارث برده اید. آنها را جوری که مناسب برنامه تان است آراسته اید و حالا ناگهان به این فکر افتاده اید که به کاربرتان اجازه دهید در فرمهایتان آیتمهای مورد نظرش را از یک لیست کشیده و در لیست دیگر بیندازد . اگر از VFI استفاده نکرده بودید، حالا ناگزیر بودید این قابلیت کشیدن و انداختن را برای همهء فرمهایتان یکی یکی بنویسید. ولی چون VFI را به کار برده اید، می توانید فقط یک بار این کد را به فرم درون انبار شیء بیافزایید. به صورت قدم به قدم:
box را در حالت Use از Object Repository برگزینید.
ویژگی DragMode لیست دست چپ، SrcList، را برابر dmAutomatic قرار دهید. این مقدار به لیست شما می فهماند که باید به طور خودکار به کاربر شما اجازهء کشیدن را بدهد. همین که کاربر یک آیتم را انتخاب کرده و دکمهء سمت چپ ماوس را نگه دارد، کشیدن آغاز می شود. روش دیگر، dmManual است که در آن برنامهء شما، خود باید مسوولیت آغاز کشیدن را بر دوش بگیرد.
رویداد OnDragOver را برای لیست دست راست، DstList، یه صورت زیر بنویسید:
Accept := (Source = SrcList);
رویداد OnDragOver هنگامی رخ می دهد که کاربر یک آیتم را به روی کنترل بکشد. این رویداد برای اطمینان یافتن از تناسب کنترل مقصد با آیتم کشیده شده به کار می رود. کدی که نوشتیم به DstList می گوید اگر مبدا آیتم کشیده شده SrcList بود، در صورت رها شدن بپذیرش.
رویداد OnDragDrop را برای DstList به صورت زیر بنویسید:
IncludeBtnClick(Sender);
رویداد OnDragDrop هنگامی رخ می دهد که کاربر یک آیتم را رها کند. این کد دقیقا همان کاری را باید بکند که به هنگام کلیک بر روی کلید < اتفاق می افتاد، پس بی دلیل آن را بازنویسی نمی کنیم.
دیدگاه خود را بیان کنید.
باید وارد سایت شده باشید برای دیدگاه دادن