نمایش نتایج 1 تا 7 از 7

نام تاپیک: فراخوانی رویداد مربوط به ساب‌كامپوننت در توليد يك كامپوننت

  1. #1
    کاربر دائمی
    تاریخ عضویت
    آبان 1388
    محل زندگی
    اصفهان
    پست
    204

    فراخوانی رویداد مربوط به ساب‌كامپوننت در توليد يك كامپوننت

    سلام؛

    یك كامپوننت نوشتم كه دارای یك SubComponent از نوع TCustomEdit هست. در این كامپوننت، تعریف زیر را ایجاد كردم:

    FEdit.OnChange := MyOnChange;

    كه MyOnChange یك Procedure هست كه یك سری فعالیت‌های خاصی انجام می‌ده.

    حالا از این كامپوننت استفاده می‌كنم و به یك Edit كه توی فرم هست، متصل می‌كنم. ولی مشكل اینه كه رویداد OnChange مربوط به Edit كه توی فرم نوشتم، اجرا نمی‌شه.

    كسی می‌دونه راه حلش چیه؟



    نمونه ديگه‌اي كه از اين ايراد مي‌تونم مثلا بزنم، اينه كه مثلاً اگه دو تا از اين كامپوننت توي فرم داشته باشم كه هر دو تا به يك Edit وصل باشه، فقط يكي از كامپوننت‌ها مي‌تونه OnChange را پيگيري و اجرا كنه و كامپوننت دوم متوجه اين رويداد نمي‌شه.


    ممنون... یا علی... موفق باشید...




  2. #2

    نقل قول: فراخوانی رویداد مربوط به ساب‌كامپوننت در توليد يك كامپوننت

    به مثال زیر دقت کنید :
    type
    TMyComponent = Class(TComponent)
    Edit : TMyEdit;
    private
    FMyText : String;
    protected
    property MyText : String read FMyText write FMyText;
    constructor Create(X, Y : Integer; EParent : TWinControl);
    destructor Destroy;
    procedure OnChange(Sender : TObject);
    end;

    یک کامپوننت تعریف کردیم که یک Edit در خودش داره ، حالا به عنوان مثال می خوایم این Edit رو در زمان Create شدن کامپوننت نمایش بدیم و هر مقداری که در Edit قرار گرفت در رویداد MyText مربوط به کامپوننت قرار بگیره ، در این صورت باید رویداد برای Procedure OnChange مربوط به کامپوننت اصلی کد مورد نظر رو بنویسیم و اون رو به OnChange مربوط به Edit مربوط کنیم :
    procedure TMyComponent.OnChange(Sender : TObject);
    begin
    MyText := Edit.Text;
    end;

    برای Create کامپوننت :
    constructor TMyComponent.Create(X, Y : Integer; EParent : TWinControl);
    begin
    Edit := TEdit.Create(Owner);
    Edit.OnChange := OnChange;
    Edit.Left := X;
    Edit.Top := Y;
    Edit.Parent := EParent;
    Edit.Visible := True;
    end;

    در کد بالا ما مختصات Left و Top و یک Parent برای Edit دریافت کرده و اون رو می سازیم و نمایش میدیم و همچنین رویداد اون رو برابر با OnChange کامپوننت اصلی قرار می دیم ...
    برای Destroy هم به صورت زیر عمل می کنیم ( Edit رو Free می کنیم ) :
    destructor TMyComponent.Destroy;
    begin
    Edit.Free;
    end;

    حالا اگه کامپوننت اصلی رو بسازید Edit هم نمایش داده می شه و هر مقداری که در Edit تایپ بشه در مقدار MyText کامپوننت قرار می گیره ...
    اگر Edit مورد نظر شما تغییرات دیگه ای هم باید بکنه می تونید یک کامپوننت از نوع TCustomEdit ساخته و به جای TEdit یک نوع از کامپوننت خودتون رو در کامپوننت اصلی تعرفی کنید ...

    البته مطمئن نیستم که منظورتون رو درست فهمیده باشم ، اگر مشکل جای دیگه است توضیح کاملتری بدید ...

    موفق باشید ...

  3. #3

    نقل قول: فراخوانی رویداد مربوط به ساب‌كامپوننت در توليد يك كامپوننت

    حالا از این كامپوننت استفاده می‌كنم و به یك Edit كه توی فرم هست، متصل می‌كنم. ولی مشكل اینه كه رویداد OnChange مربوط به Edit كه توی فرم نوشتم، اجرا نمی‌شه.
    خب، یا باید متدی که شما به OnChange در داخل کد کامپوننت تان دادید به عنوان Event-handler اجرا بشه، یا متدی که کاربر به OnChange اون Edit در داخل Form Designer اختصاص میده. اگر میخواید هر دو متد اجرا بشند، یک کنترل جدید از TCustomEdit ارث بگیرید، و متدی که در TCustomEdit موجب فراخوانی رویداد OnChange میشه را پیدا کنید، و آن را در کنترل جدید خودتان override کنید. کد مورد نظرتان برای OnChange را در این متد بنویسید. دقت کنید که در کد خودتان نهایتا کد کلاس والد را با استفاده از Inherited اجرا کنید. از این کنترل جدید به عنوان SubComponent استفاده کنید، به این ترتیب، در صورت رخ دادن رویداد OnChange، ابتدا کد شما اجرا میشه، سپس کد TCustomEdit، و اگر کاربر متدی به OnChange اختصاص داده باشه، آن متد اجرا میشه.


    برای Destroy هم به صورت زیر عمل می کنیم ( Edit رو Free می کنیم ) :

    destructor TMyComponent.Destroy;
    begin
    Edit.Free;
    end;

    هیچ وقت Destroy را بدون Inherited ننویسید! الان این کد شما Memory Leak میده.


    وَ سَيَعْلَمُ الَّذِينَ ظَلَمُوا [آل محمد حقهم] أَيَّ مُنْقَلَبٍ يَنْقَلِبُونَ - الشعراء (227)
    و ظالمین [حق آل محمد (ص) ] به زودی خواهند دانست که به کدام بازگشتگاه بازخواهند گشت.

  4. #4
    کاربر دائمی
    تاریخ عضویت
    آبان 1388
    محل زندگی
    اصفهان
    پست
    204

    نقل قول: فراخوانی رویداد مربوط به ساب‌كامپوننت در توليد يك كامپوننت

    سلام؛

    اون چيزي كه من پرسيدم و دوستان جواب دادند، يه كم فرق مي‌كنه. يكي از دوستان خودم گفته بود يه رويداد جداگانه براي كامپوننت بسازم. اين كار را كردم. ولي به يه مشكل جديد برخورد كردم.

    البته جواب آقاي كشاورز را كمي متوجه شدم و تشكر مي‌كنم، ولي اين كار براي هر كنترلي قابل اجرا نيست و خيلي سخته. راه ديگه‌اي وجود نداره كه بشه رويدادها را به صورت مضاعف هندل كرد؟

    ضمناً فكر كنم درست بيان نكرده بودم دقيقاً چي مي‌گم:

    فرض كنيد من يك Edit دارم توي فرم به نام Edit1.

    يك كامپوننت ساختم مثلاً به نام MyComponent كه يكي از فيلدهاش به نام مثلاً EditBox از نوع TCustomEdit هست و مثلاً وصل‌ش مي‌كنم به Edit1. حالا Edit1 يك ساب‌كامپوننت براي MyComponent هست (اصطلاح SubComponent درسته؟)

    در اين كامپوننتي كه ساختم، گفتم در رويداد OnChange مربوط به EditBox (كه الآن به Edit1 وصل شده) يك كاري انجام بده (مثلاً SubComponentOnChange (كه يك كار كاملاً مستقل هست، مثلاً يك سري عمليات پردازشي)).

    حالا اگه يك كامپوننت ديگه از نوع MyComponent روي فرم بذارم و به Edit1 وصل كنم، براي اين يكي رويداد OnChange مربوط به Edit1 هندل نمي‌شه و اون كار مستقلي كه توي كامپوننت تحت عنوان SubComponentOnChange تعريف كردم اجرا نمي‌شه.

    اين مشكل مكمل مشكلي هست كه در بالا گفتم كه هم اينجوري توضيح مي‌دم:

    وقتي مرحله يك را انجام مي‌دم، يعني Edit1 را به عنوان فيلد EditBox كامپوننت خودم انتخاب مي‌كنم، ديگه رويداد OnChange مربوط به Edit1، هندل نمي‌شه و هر دستوري هم كه در Edit1.OnChange نوشته باشم، اجرا نمي‌شه و فقط دستوراتي كه در SubComponentOnChange نوشتم اجرا مي‌شه.

    در صورتي كه توضيحاتم مشخص نبود، تا يك نمونه ارسال كنم.


    باز هم ممنون... يا علي... موفق باشيد...

  5. #5

    نقل قول: فراخوانی رویداد مربوط به ساب‌كامپوننت در توليد يك كامپوننت

    يك كامپوننت ساختم مثلاً به نام MyComponent كه يكي از فيلدهاش به نام مثلاً EditBox از نوع TCustomEdit هست و مثلاً وصل‌ش مي‌كنم به Edit1. حالا Edit1 يك ساب‌كامپوننت براي MyComponent هست (اصطلاح SubComponent درسته؟)
    نه، SubComponent کامپوننتی هست که کامپوننت شما Owner آن باشه، به عنوان نمونه می تونید کامپوننت LabledEdit دلفی را ببینید که یک Edit هست که در داخل خودش از یک Label استفاده میکنه.

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

    شما اگر می خواید کامپوننت مربوطه کاملا در اختیار کامپوننت شما باشه، باید آن را به عنوان یکی از فیلدهای کامپوننت خودتان تعریف کنید، و خودتان آن را بسازید و آزاد کنید.

    راه ديگه‌اي وجود نداره كه بشه رويدادها را به صورت مضاعف هندل كرد؟
    در دلفی بطور عادی این قابلیت وجود نداره، ولی مثلا در #C این قابلیت وجود داره. در دلفی شما می تونید برای کامپوننت هایی که خودتان می نویسید، مکانیزمی طراحی کنید که رفتار مشابه ایی از خودشان نشان دهند، ولی تقریبا کار پیچیده ایی خواهد شد. قبلا دیدم که بعضی از برنامه نویسان دلفی همچین قابلیتی را برای خودشان پیدا سازی کردند.


    وَ سَيَعْلَمُ الَّذِينَ ظَلَمُوا [آل محمد حقهم] أَيَّ مُنْقَلَبٍ يَنْقَلِبُونَ - الشعراء (227)
    و ظالمین [حق آل محمد (ص) ] به زودی خواهند دانست که به کدام بازگشتگاه بازخواهند گشت.

  6. #6
    کاربر دائمی
    تاریخ عضویت
    آبان 1388
    محل زندگی
    اصفهان
    پست
    204

    نقل قول: فراخوانی رویداد مربوط به ساب‌كامپوننت در توليد يك كامپوننت

    سلام؛

    فكر كنم مسئله را به صورت زير مطرح كنم، مشخص‌تر باشه:

    به عنوان مثال، كد زير را در نظر بگيريد كه داراي يك فيلد از نوع Edit هست كه به Edit روي فرم متصل مي‌شه و يك فيلد از نوع String به نام TextNeed.
    قراره اين كامپوننت در صورتي كه متن Edit برابر متن فيلد TextNeed بود، يه پيام نشون بده.

    در عين حال، قراره در هنگامي كه درون Edit هم متني تايپ مي‌شه، به عنوان مثال متن عيناً در يك Lable نمايش داده بشه.
    حالا اگر دو تا از اين كامپوننت روي فرم استفاده كنيم و هر دو را هم به يك Edit كه روي فرم قرار داره، فقط كامپوننت دوم، رويداد OnChange مربوط به Edit را هندل مي‌كنه و ساير كامپوننت‌ها و حتي خود رويداد OnChange مربوط به Edit، اجرا نمي‌شه.

    كد مربوط به كامپوننت:


    unit MyComponentTest;

    interface

    uses
    SysUtils, Classes, Windows, StdCtrls, ComCtrls, Forms, Messages, Graphics, Controls, Dialogs;

    type
    TMyComponentTest = class(TComponent)
    private
    { Private declarations }

    FEditBox: TEdit;
    FTextNeed: String;

    procedure SetEditBox(AEditBox: TEdit);
    procedure SetTextNeed(ATextNeed: String);

    protected
    { Protected declarations }

    procedure Notification(AComponent: TComponent; Operation: TOperation);
    override;

    public
    { Public declarations }

    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure OnMyChange(Sender: TObject);

    published
    { Published declarations }

    property EditBox: TEdit read FEditBox write SetEditBox;
    property TextNeed: String read FTextNeed write SetTextNeed;

    end;

    procedure Register;

    implementation

    uses StrUtils;

    procedure Register;
    begin
    RegisterComponents('My Component', [TMyComponentTest]);
    end;


    constructor TMyComponentTest.Create(AOwner: TComponent);
    begin
    inherited Create(AOwner);
    FTextNeed := '';
    end;


    destructor TMyComponentTest.Destroy;
    begin
    inherited Destroy;
    end;


    procedure TMyComponentTest.Notification(AComponent: TComponent; Operation: TOperation);
    begin
    if Operation = opRemove then
    begin
    if AComponent = FEditBox then FEditBox := nil;
    end;
    end;


    procedure TMyComponentTest.OnMyChange(Sender: TObject);
    var
    TempString: String;
    begin
    inherited;
    if EditBox.Text = FTextNeed then
    ShowMessage(Self.Name + ': ' + FTextNeed);
    end;


    procedure TMyComponentTest.SetEditBox(AEditBox: TEdit);
    begin
    FEditBox := AEditBox;
    if FEditBox <> nil then
    FEditBox.OnChange := OnMyChange;
    end;


    procedure TMyComponentTest.SetTextNeed(ATextNeed: String);
    begin
    FTextNeed := ATextNeed;
    end;


    end.
    كد مربوط به فرم:



    unit Unit1;

    interface

    uses
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    Dialogs, StdCtrls, MyComponentTest;

    type
    TForm1 = class(TForm)
    MyComponentTest1: TMyComponentTest;
    Edit1: TEdit;
    Label1: TLabel;
    MyComponentTest2: TMyComponentTest;
    procedure Edit1Change(Sender: TObject);
    private
    { Private declarations }
    public
    { Public declarations }
    end;

    var
    Form1: TForm1;

    implementation

    {$R *.dfm}

    procedure TForm1.Edit1Change(Sender: TObject);
    begin
    Label1.Caption := Edit1.Text;
    end;

    end.

    و فرم به صورت متني:



    object Form1: TForm1
    Left = 336
    Top = 149
    Width = 979
    Height = 563
    Caption = 'Form1'
    Color = clBtnFace
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -11
    Font.Name = 'MS Sans Serif'
    Font.Style = []
    OldCreateOrder = False
    PixelsPerInch = 96
    TextHeight = 13
    object Label1: TLabel
    Left = 440
    Top = 160
    Width = 32
    Height = 13
    Caption = 'Label1'
    end
    object Edit1: TEdit
    Left = 440
    Top = 128
    Width = 121
    Height = 21
    TabOrder = 0
    Text = 'Edit1'
    end
    object MyComponentTest1: TMyComponentTest
    EditBox = Edit1
    TextNeed = 'Test'
    Left = 376
    Top = 120
    end
    object MyComponentTest2: TMyComponentTest
    EditBox = Edit1
    TextNeed = 'Ali'
    Left = 376
    Top = 160
    end
    end


    كه البته اين كامپوننت فقط يك مثال هست.


    حالا مي‌خوام، وقتي درون Edit متني وارد مي‌شه، هر دو تا كامپوننت بتونند متن را چك كنند، و در عين حال، متن به Label هم منتقل بشه.

    باز هم از همه دوستان، علي‌الخصوص آقاي كشاورز تشكر مي‌كنم.


    خيلي ممنون... يا علي... موفق باشيد...

  7. #7

    نقل قول: فراخوانی رویداد مربوط به ساب‌كامپوننت در توليد يك كامپوننت

    خب، این رفتار طبیعی هست، با توجه به کدی که برای SetEditBox نوشتید؛ وقتی فرم ساخته میشه، متد Edit1Change به رویداد OnChange مربوط به Edit1 اختصاص پیدا میکنه. وقتی MyComponent1 ساخته میشه، متد OnMyChange مربوط به MyComponent1 به رویداد OnChange مربوط به Edit1 اختصاص پیدا میکنه، و دیگه Edit1Change به این رویداد متصل نیست. وقتی MyComponent2 ساخته میشه، متد OnMyChange مربوط به آن به رویداد OnChange مربوط به Edit1 اختصاص پیدا میکنه، و متدهای Edit1Change و MyComponent1.OnMyChange دیگه به اون رویداد متصل نیستند. در نتیجه فقط متد MyComponent2.OnMyChange هست که در صورت رخ دادن رویداد Edit1.OnChange اجرا میشه.

    حالا شما دقیقا هدف تان از ساخت این کامپوننت چی هست؟ به چه منظوری همچین کامپوننتی طراحی کردید، و به این نتیجه رسیدید که باید یک Edit باشه که با نمونه های مختلف این کامپوننت به این شکل تعامل داشته باشه؟ شاید با دانستن هدف و منظور شما، بشه راه حل بهتری ارائه کرد.


    وَ سَيَعْلَمُ الَّذِينَ ظَلَمُوا [آل محمد حقهم] أَيَّ مُنْقَلَبٍ يَنْقَلِبُونَ - الشعراء (227)
    و ظالمین [حق آل محمد (ص) ] به زودی خواهند دانست که به کدام بازگشتگاه بازخواهند گشت.

برچسب های این تاپیک

قوانین ایجاد تاپیک در تالار

  • شما نمی توانید تاپیک جدید ایجاد کنید
  • شما نمی توانید به تاپیک ها پاسخ دهید
  • شما نمی توانید ضمیمه ارسال کنید
  • شما نمی توانید پاسخ هایتان را ویرایش کنید
  •