TNotifyEvent i podmienianie procedure

0

Witam.

Sprawa wynika z dziedziczenia i tworzenia dynamicznego.. chcąc sobie ułatwić zadanie o ile się da do tworzonego dynamicznie komponentu chciałem przypisać w klasie rodzica TNotifyEvent a potem żeby np. w klasie potomnej nie musieć wyszukiwać komponentu po nazwie próbuję "podmienić/ przypisać" do zmiennej TNotifyEvent dowolna procedurę z klasy dziecka.
Wszystko się ładnie kompiluje ale ... ta podmianka nie wnosi nic nawet jeśli wszystko się dzieje w obrębie jednej klasy. Exe "nie widzi" przypisania wykonanego w stylu poniżej przedstawionego.
Ma ktoś receptę na to?

Na razie robię tak jak w FormShow. Jest pusta forma i:

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    procedure FormShow(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
  public
     pButtonOnbClick: PPointer; //zmienna

     procedure Button2Click(Sender: TObject);
  end;


type
   TKlasa = class

   private
   protected
   public
      constructor Create();
      destructor Destroy();override;
      procedure ShowKomunikat;
   end;


var
  Form1: TForm1;
  Klasa: TKlasa;

implementation

{$R *.dfm}

constructor TKlasa.Create();
begin //
end;

destructor TKlasa.Destroy();
begin //
end;

procedure TKlasa.ShowKomunikat();
begin //
   ShowMessage('Komunikat z TKlasa');
end;





procedure TForm1.Button2Click(Sender: TObject);
begin
   ShowMessage('Reakcja');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
   Klasa:= TKlasa.Create;

   With TButton.Create(Application) do
   begin
      Parent:= Self;
      Name := 'Button2';
      Caption := 'Kliknij';
      Left := 100;
      Top := 50;
      Width := 75;
      Height := 25;
      // OnClick := Proc_Kliknij;
      Visible:= True;
   end;

end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
   FreeAndNil(Klasa);
end;

{
 To działa

procedure TForm1.FormShow(Sender: TObject);
var
   Event: TNotifyEvent;
begin //
   // pButtonOnbClick:= @@OnClick
   pButtonOnbClick:= @@TButton(Application.FindComponent( 'Button2' )).OnClick;

   Event:= Button2Click;
   pButtonOnbClick^:= @Event;
end;
}


procedure TForm1.FormShow(Sender: TObject);
var
   Event: TNotifyEvent;
begin //
   pButtonOnbClick:= @@TButton(Application.FindComponent( 'Button2' )).OnClick;

   Event:= Klasa.ShowKomunikat;  // <-- A to nie działa i nie chce się kompilować
   pButtonOnbClick^:= @Event;
end;

end.

Pozdrawiam.

0

Nawet mi się nie chce sprawdzać bo kod jest bez sensu OnShow wykonuje się przecież później niż OnCreate to i normalne że nie działa...

0

No to nie wiem jakiego efektu oczekujesz. Ponieważ póki co jest tak, jak pisze poprzednik. I po prostu u Ciebie z takim kodem Proc_Kliknij jest nilem. I według mnie nie da się tego zrobić tak, jak chcesz. Chyba że jakiś Pointer, ale poza domem nie mam jak sprawdzić.

0

Szukałem innego sposobu na ograniczenie ilości kodu.. to może tak: jak pobrać wskaźnik na OnClick po utworzeniu przycisku

Coś := PobierzAdres( TButton( Application.FindComponent('Button2')).OnClick );

żebym potem podpiąć

PrzypiszDoAdres( Coś, Button2Click) 

i żeby już widziało Button2Click a nie nil.

0

to co zrobiłeś to

a := 1;
b := a;
a := 3;

dlaczego b = 1 a nie 3??

jak chcesz żeby to zadziałało to musisz zrobić tak

tform1=class
private
  FButKlik: TNotifyEvent;
  procedure ButKlikProc(Sender: TComponent);

 property ButKlik: TNotifyEvent read FButKlik write FButKlik;
end;

w create

with TButton.Create(nil) do
begin
  OnClick := ButKlikProc;
end;

a w ButKlikProc

  if FButKlik <> nil then
    FButKlik(Sender);

i gdzieś tam
FButKlik := Button2Click

0

@abrakadaber właśnie o to chodzi, że w trakcie działania programu chcę podmieniać wartość żeby wskazywała na nowy TNotifyEvent; i sposób

i gdzieś tam
FButKlik := Button2Click

gdzie TNotifyEvent; jest zadeklarowany w klasie (niekoniecznie w klasie formy) właśnie nie działa.. i o to to całe zamieszanie.

Tak jak @olesio wspomniał trzeba by zapewne zrobić podmiankę na Pointerach
i zamiast:

   FButKlik: TNotifyEvent;

program by pamiętał np.

   FButKlik: Pointer;

Pointer lub cokolwiek innego, do którego potem gdzieś w kodzie byłby by przypisanie Button2Click tylko pytanie jak.. jak pobrać wskaźnik lub adres OnClick i potem jak do niego (do tego popranego wskaźnika) przypisać?

1

Ja w ogóle nie rozumiem idei zastosowania tego (gdybym dokładnie wiedział co chcesz osiągnąć prawdopodobnie znalazło by się lepsze rozwiązanie) ale skoro tak chcesz to można tak:

private
  pButtonOnbClick: PPointer; //zmienna
//ciach
  pButtonOnbClick:= @@OnClick; //odczyt adresu OnClick tworzonego Buttona
//ciach
procedure TForm1.FormShow(Sender: TObject);
var
  Event: TNotifyEvent;
begin
  Event:= Button2Click; //zapis wymaga dodatkowej zmiennej
  pButtonOnbClick^:= @Event;
end;

Tylko wg. mnie kod jest pozbawiony sensu, bo równie dobrze mona było przechowywać całego Buttona w zmiennej a nie tylko adres zdarzenia.

0

@kAzek co do konkretnego zastosowania nie bardzo wiem co mogę jeszcze opisać właściwie to co jest mi potrzebne jest opisane bardziej lub mniej umiejętnie w moim 1 i 2 poście. Chcę zrobić w miarę uniwersalny i w miarę czytelny mechanizm podpinania procedur do zdarzenia. Wydaje mi się że łatwiej mi wyciągnąć tuż po Create komponentu zmienną do której mogę podpiąć w dowolnej chwili procedurę niż potem przeszukiwać klasę/ klasy. Podmianka będzie stosowana wielokrotnie. A liczyłem na to, że ten PPointer mimo że zadeklarowany w obrębie public danej klasy będzie działał w różnych kombinacjach z różnymi klasami. Ale czy to się uda to się jeszcze okaże.

Duże dzięki, jest pół sukcesu bo w obrębie danej klasy działa świetnie. To rozwiązanie się przyda. Chyba właśnie tej przejściówki gdzie

zapis wymaga dodatkowej zmiennej
mi brakowało.
Natomiast pół sukcesu bo może to wymagać innego rozwiązania i tu moja wina bo dopiero w kolejnym poście naświetliłem sprawę dokładnie .. myślałem że TNotifyEvent załatwi sprawę ale nie załatwiło.

Ale już daję przykład .. wystarczy wkleić cały aktualny/ nowy kod z pierwszego postu. Wstawiłem tam żeby niepotrzebnie nie mnożyć zbędnego kodu .. możliwe, że potrzebna jest drobna korekta. Kod w procedurze FormShow w klamrach ładnie działa natomiast ten "aktywny" z użyciem osobnej klasy nie chce się kompilować.

edit:
A możliwe że będzie wymagało to większych zabiegów ale dobrze by było spróbować.

3

W zasadzie może być tak (z TForm1 też tak można zrobić jednak nie musi być tej dodatkowej zmiennej o której poprzednio pisałem):

pButtonOnbClick^:= @TKlasa.ShowKomunikat;
0

No i super, stokrotne dzięki. Nic więcej nie potrzeba :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1