ورود

View Full Version : Export کردن یک فانکشن به منظور ساخت CallBack Function



Hadizadeh
چهارشنبه 24 بهمن 1386, 15:39 عصر
سلام. یک کلاس دارم که در اون در پی رخ دادن یک رخداد یک فانکش X فراخوانی میشه. حالا می خوام کاربر قادر باشه تا آدرس فانکشن دلخواه خودش (Y) رو به این کلاس بده تا از این به بعد در هر رخداد به جای فراخوانده شدن تابع X، تابع Y کاربر به صورت خودکار صدا زده بشه. در حقیقت کاربر به نوعی فانکشن X این کلاس رو override بکنه و در عین حال ارتباط این فانکشن با کلاس اصلی هم قطع نشه. چه راه حلی پیشنهاد می دید؟ یه مثال:


MyClass=Tclass
....
public
procedure OnEvent;
end;
....
procedure MyFunc;
begin
//.....
end;

Now we want to pass @MyFunc to MyClass in order to replace MyFunc with OnEvent.

vcldeveloper
پنج شنبه 25 بهمن 1386, 04:49 صبح
unit Unit1;

interface

type

//Type of your event-handler
TMyEventHandler = procedure of object;

TMyClass = class
private
FMyEvent : TMyEventHandler;

procedure SetMyEvent(Value: TMyEventHandler);
protected
procedure DoMyJob; virtual;
public
property OnMyEvent: TMyEventHandler read FMyEvent write SetMyEvent;
end;

//A sample class which provides event-handler for TMyClass.OnMyEvent
TOtherClass = class
private
FMyClass : TMyClass;
protected
procedure EventImplementor;
public
constructor Create;
destructor Destroy; override;
end;

implementation

{ TMyClass }

procedure TMyClass.DoMyJob;
begin
//Here the event is triggered.
if Assigned(FMyEvent) then
FMyEvent;

// Your job is done here.
end;

procedure TMyClass.SetMyEvent(Value: TMyEventHandler);
begin
//Assigning a new handler to the event.
if Assigned(Value) then
FMyEvent := Value;
end;

{ TOtherClass }

constructor TOtherClass.Create;
begin
FMyClass := TMyClass.Create;
//EventImplementor is assigned to TMyClass.OnMyEvent as an event-handler.
if Assigned (FMyClass) then
FMyClass.OnMyEvent := EventImplementor;
end;

destructor TOtherClass.Destroy;
begin
if Assigned(FMyClass) then
FMyClass.Free;
end;

procedure TOtherClass.EventImplementor;
begin
// Here comes your event-handler's code.
end;

end.

Hadizadeh
پنج شنبه 25 بهمن 1386, 08:33 صبح
ممنونم. ولی مشکل اینه که MyClass من یک ActiveX Form هست:


TMyClass = class(TMyClass, IMyClass)

لذا برای اینکه بتونیم به خصوصیت OnMyEvent در متن برنامه های خارجی( که از این ActiveX استفاده می کنند) دسترسی پیدا کنیم باید اونو در Type Library پیاده سازی کنیم. حالا چه جوری میشه این کارو کرد؟

vcldeveloper
پنج شنبه 25 بهمن 1386, 17:59 عصر
لذا برای اینکه بتونیم به خصوصیت OnMyEvent در متن برنامه های خارجی( که از این ActiveX استفاده می کنند) دسترسی پیدا کنیم باید اونو در Type Library پیاده سازی کنیم. حالا چه جوری میشه این کارو کرد؟
میشه بیشتر توضیح بدی که دقیقا چیکار می خوای بکنی؟

Hadizadeh
جمعه 26 بهمن 1386, 11:23 صبح
ممنون. بحث اینه که من OnMyEvent رو دقیقا مثل مثال شما در کلاسم که یک ActiveX Form هست پیاده سازی کردم. بعد یک نمونه از این ActiveX Form رو تو برنامم به نام F ایجاد کردم ولی متاسفانه نمی تونم از طریق F.OnMyEvent تابع OnMyEvent رو پیدا کنم. خودم برای اینکه به متد های این کلاسم در محیط های خارجی دسترسی پیدا کنم اونها رو اول در Type Library ایجاد می کنم که Type Library یک فایل MyClassTLB.Pas به من می ده که من اونو در برنامه های خارجی use MyClassTLB می کنم تا از طریق اون به متدهای مورد نظر دسترسی پیدا کنم. حالا چه طور OnMyEvent رو از این طریق visible کنم؟

vcldeveloper
جمعه 26 بهمن 1386, 11:29 صبح
حالا چه طور OnMyEvent رو از این طریق visible کنم؟
منظور اینه که توی Object Properties نمایش داده بشه؟ اگه منظور اینه، باید Property مربوط به اون Event در بخش Published کلاس تعریف بشه.

Hadizadeh
جمعه 26 بهمن 1386, 14:22 عصر
نه. منظورم اینه که بشه به اون دسترسی پیدا کرد. مثلا وقتی زدم .F در باکسی که ظاهر میشه، تابع OnMyEvent هم لیست بشه. الان من نمی بینمش. فقط توابعی رو که توسط Type Library ایجاد کردم و اینترفیس اونها در MyClassTLB.pas تعریف شده لیست میشن. متوجه منظورم شدید؟ شما یک ActiveX Form ساده بسازید و همون مثال خودتون رو توش پیاده کنید. بعد این ActiveX رو از منوی Run رجیستر و سپس نصب کنید و تو یه پروژه جدید یه نمونه ازش ایجاد کنید. ببینید می تونید به تابع OnMyEvent دسترسی پیدا کنید یا نه.

vcldeveloper
جمعه 26 بهمن 1386, 20:31 عصر
برای اینکه Property مورد نظر شما در Code Completion نمایش داده بشه، باید حتما Type Library مربوطه Import بشه، در غیر اینصورت دلفی نمی تونه تشخیص بده که چه اجزایی برای Object مورد نظر در دسترس هستند. در واقع Late-binding صورت میگیره.
دقت کنید که هر Property ایی که به ActiveX Form اضافه می کنید، از طریق Type Library Editor یا Edit | Add to interface... باشه، وگرنه تغییرات شما در Type Library اعمال نمیشه. نباید Type Library را بصورت دستی تغییر بدید، چون Type Library Editor تغییراتی که خودتون بصورت دستی در کد اعمال کرده باشید رو نادیده میگیره. بعد از اینکه تغییرات را در Type Library Editor اعمال کردید، دکمه Refresh Implementation را در Type Library Editor کلیک کنید تا Type Library مربوطه آپدیت شود.

Hadizadeh
جمعه 26 بهمن 1386, 22:16 عصر
ممنون ولی من هم دقیقا با Type Library Editor کار می کنم ولی چه طور تابع OnMyEvent مثال شما رو در Type Library Editor اضافه کنم؟ این مشکل اگه حل بشه قضیه حله.

vcldeveloper
شنبه 27 بهمن 1386, 00:05 صبح
ولی چه طور تابع OnMyEvent مثال شما رو در Type Library Editor اضافه کنم؟ این مشکل اگه حل بشه قضیه حله.وقتی یک ActiveX Form درست می کنید، دلفی توی Type Library یه DispInterface براتون درست میکنه که اسمش هست IMyFormEvents که جای MyForm اسم کلاس فرمی که ساختید قرار میگیره. روش راست کلیک کنید و New | Method رو انتخاب کنید. Return Type هم بطور معمول None هست. اگه دقت کنید، خود دلفی چندتا Event مربوط به فرم را همینجا تعریف کرده، مثل OnActive, OnClick و...
وقتی تغییرات را انجام دادید، روی Refresh Implementation کلیک کنید. اگه به فایل Type Library ساخته شده مراجعه کنید، می بینید که خودش Event را به صورت زیر تعریف کرده:

property OnMyEvent: TNotifyEvent read FOnMyEvent write FOnMyEvent;اگر نیاز به تعریف پارامتر برای Event دارید، در Type Library Editor در تب Parameters می تونید هر کدوم رو تعریف کنید.

Hadizadeh
شنبه 27 بهمن 1386, 01:25 صبح
ممنونم. دقیقا به جایی رسیدید که می خواستم خودتون بهش برسید! حالا چون داریم:


property OnMyEvent: TMyEventHandler read FMyEvent write SetMyEvent;

یعنی OnMyEvent از جنس TMyEventHandler هست که یک Type تعریف شده توسط کاربر یعنی ما هست و لذا چه طور میشه اینو در Type Library Editor تعریف کرد؟ توجه کنید که در تب Parameters فقط یکسری تایپ های استاندارد مثل تایپ های OLE وجود دارند. این دیگه شلیک آخره! ;) ممنونم از کمک شما

vcldeveloper
شنبه 27 بهمن 1386, 03:11 صبح
برای منظور شما لازم نیست Type جدید تعریف بشه، شما Event مورد نظر خودتون رو ایجاد کنید، بعد پارامترهای آن را مشخص کنید. در برنامه مقصد هم کافیه متدی از یک کلاس داشته باشید که همین تعداد و نوع پارامتر داشته باشه و خروجی اش هم با Event شما یکسان باشه.
اگر اصرار دارید که خودتون Type جدید داشته باشید، باید یک Interface جدید درست کنید و براش متدها و Properties رو مشخص کنید. این Interface بصورت خودکار به لیست Type ها اضافه میشه.


در تب Parameters فقط یکسری تایپ های استاندارد مثل تایپ های OLE وجود دارند.

بله، چون شما دارید ActiveX Form میسازید و این کنترل جدید باید بتونه با زبانهای مختلفی کار کنه، در نتیجه باید از Type های استاندارد استفاده کنید، یا اگر Type ایی خودتون ساختید، در Type Library با استفاده از Type های استاندارد تعریف شده باشه، وگرنه سایر زبان های قادر به استفاده از این کنترل نخواهند بود.

Hadizadeh
شنبه 27 بهمن 1386, 08:47 صبح
بالاخره من نفهمیدم که OnMyEvent مثال شما را چه طور به این کلاسم اضافه کنم! میشه یک مثال برنید؟ OnMyEvent شما و مورد نیاز من هیچ نوع پارامتری نداره ولی همونطور که خودتون تعریف کردید از جنس TMyEventHandler هست. منظورم اینه که این Type رو چه طور اضافه کنم و یا استفاده کنم. یعنی خلاصه کلام اینکه کاربر مثلا در محیط VB یا ++VC خودش یک فانکشن بدون پارامتر بسازه و بتونه اونو به OnMyEvent این کلاس انتصاب بده و هر وقت این رخداد اتفاق افتاد فانکشن تعریف شده کاربر فراخوانی بشه.OnMyEvent رو از چه جنسی تعریف کنیم که در سایر زبانها هم بتونیم فانکشن ها رو به اون Assign کنیم. ممنون

Hadizadeh
شنبه 27 بهمن 1386, 09:24 صبح
من OnMyEvent رو از جنس TNotifyEvent مثل OnClick پیاده سازی کردم مشکل حل شد. ولی توابع از جنس TNotifyEvent به صورت


procedure FuncName(sender:TObject)

هستند اگه بخواهیم این پارامتر Sender رو هم نداشته باشیم چه کار باید بکنیم؟ در غیر این صورت کاربر مثلا در VB باید یک فانکشنی بسازه که یه پارامتر به صورت sender:TObject داشته باشه که البته نمی دونم در VB ، معادل TObject چیه.

Hadizadeh
شنبه 27 بهمن 1386, 09:58 صبح
یه مسئله دیگه: من یه نمونه از این ActiveX Form رو تو VB گذاشتم ولی هیچ کدوم از Event های اون مثلا OnClick و غیره در Code Completion لیست نمیشه. تو VB می دونید کجا باید رخداد گردان های یک Object رو لیست کرد یا بهشون دسترسی پیدا کرد؟