AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

"inherited" für umgeleitetes Event

Ein Thema von Guido Eisenbeis · begonnen am 15. Mär 2007 · letzter Beitrag vom 20. Mär 2007
Antwort Antwort
Seite 1 von 2  1 2      
Guido Eisenbeis

Registriert seit: 9. Apr 2006
389 Beiträge
 
Delphi 10.3 Rio
 
#1

"inherited" für umgeleitetes Event

  Alt 15. Mär 2007, 00:38
Beispiel für ein umgeleitetes Event:

Delphi-Quellcode:
unit Unit1; // Enthält einen Button, dessen Click-Event
            // und das FormCreate-Event.
...

implementation

{$R *.dfm}

uses
  Unit2;


procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage('Ich bin im Original-Event.');
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1.OnClick := Unit2.MyEventReceiver.MyOwnButton1Click;
end;


end.
Delphi-Quellcode:
unit Unit2;

interface

type
  TMyEventReceiver = class
    procedure MyOwnButton1Click(Sender: TObject);
  end;

var
  MyEventReceiver: TMyEventReceiver;


implementation

uses
  Dialogs;


procedure TMyEventReceiver.MyOwnButton1Click(Sender: TObject);
begin
  ShowMessage('Ich bin im umgeleiteten Event.');
end;


end.
Wie kann man nun zusätzlich zu dem umgleitete Event das Original-Event auslösen?

Also quasi wie ein "inherited" bei überschriebenen Klassen-Methoden. Und zwar so, dass kein Fehler ausgelöst wird, wenn es das Original-Event nicht gibt.

Guido.
  Mit Zitat antworten Zitat
Benutzerbild von Kedariodakon
Kedariodakon

Registriert seit: 10. Sep 2004
Ort: Mönchengladbach
833 Beiträge
 
Delphi 7 Enterprise
 
#2

Re: "inherited" für umgeleitetes Event

  Alt 15. Mär 2007, 01:24
Nunja, falls da nochmehr OnClick-Events dazu kommen sollten, heißt das Unwort des Jahres "Observer"...
Sprich, leite den TButton ab und versehe diesen dann mit "Observer" Eigenschaften, am Besten natürlich mit hilfe von Interfaces (geht aber auch ohne)...
Als Ergebniss hast du dann einen Button der soviele OnClick-Events hat wie du magst...

Alles andere wär auch nur wildes rumgeflicke...
Beispiel wär, dass du die Klasse "TMyEventReceiver" mit einer Methode versiehst, die das OnClick-Event bespielt und sich den alten Wert merkt und ihn entsprechend ausführt...

Da mal so ein Flickwerk:

Delphi-Quellcode:
Unit Unit2;

Interface

Uses StdCtrls, Classes;

Type
  TMyEventReceiver = Class
  Private
    { Private-Deklaration }
    FOwnerButton: TButton; // Von wo kommt das Event?
    FOldOnClick: TNotifyEvent; // Speichern des alten Events
    Procedure SetOwnerButton( Const Value: TButton );
  Protected
    { Protected-Deklaration }
    Procedure InternOnClick( Sender: TObject );
    Property OwnerButton: TButton Read FOwnerButton Write SetOwnerButton;
    Property OldOnClick: TNotifyEvent Read FOldOnClick Write FOldOnClick;
    { ... }
    Procedure MyOwnButton1Click( Sender: TObject );
  Public
    { Public-Deklaration }
    Destructor Destroy; Override;
    Procedure SetButtonOnClick( Const aButton: TButton );
    Procedure Reset;
  End;

Var MyEventReceiver: TMyEventReceiver;

Implementation

Uses Dialogs;

Destructor TMyEventReceiver.Destroy;
Begin
  Reset; // Vor dem freigeben reseten...
  Inherited;
End;

Procedure TMyEventReceiver.SetButtonOnClick( Const aButton: TButton );
Begin
  OwnerButton := aButton; // initialisieren mit dem neuen Button...
End;

Procedure TMyEventReceiver.Reset;
Begin
  If Assigned( OwnerButton ) Then Begin // Wenn schonmal initialisiert, dann zurücksetzen
    OwnerButton.OnClick := OldOnClick; // Alter Click
    FOwnerButton := Nil; // Owner nil'en
  End;
  OldOnClick := Nil; // OldOnClick Speicher nil'en
End;

Procedure TMyEventReceiver.SetOwnerButton( Const Value: TButton );
Begin
  Reset; // Vor einem neubespielen reseten...
  If Assigned( Value ) Then Begin // Werte setzen nur, wenn auch was übergeben wurde...
    FOwnerButton := Value;
    OldOnClick := Value.OnClick;
    Value.OnClick := InternOnClick;
  End;
End;

Procedure TMyEventReceiver.InternOnClick( Sender: TObject );
Begin
  If Assigned( OldOnClick ) Then OldOnClick( Sender ); // Altes Event auslösen, falls es belegt war
  MyOwnButton1Click( Sender ); // Deine Funktion...
End;

Procedure TMyEventReceiver.MyOwnButton1Click( Sender: TObject );
Begin
  ShowMessage( 'Ich bin im umgeleiteten Event.' );
End;

end.
Der Aufruf in Unit1 sieht das so aus:
Delphi-Quellcode:
unit Unit1; // Enthält einen Button, dessen Click-Event
            // und das FormCreate-Event.
...

implementation

{$R *.dfm} 

uses
  Unit2;


procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage('Ich bin im Original-Event.');
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  Unit2.MyEventReceiver.SetButtonOnClick( Button1 );
end;
end.
Hoffe es funktioniert (ist ungetestet...)...

Bye Christian
Christian
  Mit Zitat antworten Zitat
Guido Eisenbeis

Registriert seit: 9. Apr 2006
389 Beiträge
 
Delphi 10.3 Rio
 
#3

Re: "inherited" für umgeleitetes Event

  Alt 15. Mär 2007, 02:48
Hallo Christian.

Also ich sehe das (bis jetzt noch) nicht als Flickwerk!

Ich habe es aber auch nur überflogen.

Zum Thema Observer hat Google leider "keinen" Treffer erzielt. *scherz*

Ok, jetzt im Ernst: Bei meiner Recherche nach dem Thema zeigte Freund Goolge zu diesem Stichwort 59.800.000 Treffer, die von einer englischen Zeitung bis zum Space-Observer reichten. Selbst nach Eingrenzung mit "Delphi Observer" zeigte er immer noch 524.000 Treffer.

Zum Glück stach da ein Beitrag der DP hervor, mit dem Titel "Events in einer Liste" bzw. "Ergänzung zu Events in einer Liste". Ich gehe mal davon aus, dass du das gemeint hast.

Jetzt gehe ich erstmal offline, mache heia-heia und sehe mir beide Möglichkeiten morgen an. Danach melde ich mich wieder.

Bis hierhin schon mal danke!

Gruß,
Guido.
  Mit Zitat antworten Zitat
Benutzerbild von Kedariodakon
Kedariodakon

Registriert seit: 10. Sep 2004
Ort: Mönchengladbach
833 Beiträge
 
Delphi 7 Enterprise
 
#4

Re: "inherited" für umgeleitetes Event

  Alt 15. Mär 2007, 09:26
Klick mich! FEST!!!

bye Christian
Christian
  Mit Zitat antworten Zitat
Guido Eisenbeis

Registriert seit: 9. Apr 2006
389 Beiträge
 
Delphi 10.3 Rio
 
#5

Re: "inherited" für umgeleitetes Event

  Alt 16. Mär 2007, 03:50
Hallo Christian.

Heute arbeite ich schon den ganzen Tag an dieser Sache. Und schon die halbe Nacht. Ich habe alle Beiträge durchglesen, die du geschrieben und auf die du verlinkt hast. Ebenso habe ich alle Codes aus diesen Sites (inklusive dem "Flickwerk") in jeweils ein eigenes Testprojekt implementiert und versucht zum Laufen zu bringen. Leider ohne Erfolg.

Zitat von Kedariodakon:
Hoffe es funktioniert (ist ungetestet...)...
Respekt, falls das bedeutet, dass du das aus dem Kopf heraus (also ohne IDE) geschrieben hast!

Auch diesen Code habe ich nicht zum Laufen bekommen. Ich habe auch eine Code für Multicast angeguckt, aber das ist nicht das Geeignete für mein Problem.

Als Test habe ich das Beispiel ganz oben genommen, wo ein ButtonClick von Form1 in Unit2 umgeleitet wird. Derzeit ist es ein wenig frustrierend, nach all den Stunden Arbeit daran.

Im Moment würde ich mich schon darüber freuen, wenn du mir ein funktionierendes/getestetes "Flickwerk" posten würdest!

Edit: Natürlich sind auch Lösungen von alle anderen willkommen!

Gruß,
Guido.
  Mit Zitat antworten Zitat
Muetze1
(Gast)

n/a Beiträge
 
#6

Re: "inherited" für umgeleitetes Event

  Alt 16. Mär 2007, 09:18
Merke dir einfach nur einen Original vorhandenen Eventhandler, welcher im OnClick stand, bevor du deinen zuweist. In deinem kannst du dann den Originalhandler aufrufen.

Delphi-Quellcode:
Type
  TFormClass = Class(TForm)
  ...
  Private
    lOldEventHandler: TNotifyEvent;
  ...
  End;

...

Procedure TFormClass.FormCreate(Sender: TObject)
Begin
  lOldEventHandler := Button1.OnClick;
  Button1.OnClick := MyNewHandler;
End;

Procedure TFormClass.MyNewHandler(Sender: TObject)
Begin
  // my code

  // call old handler (if found)
  If Assigned(lOldEventHandler) Then
    lOldEventHandler(Sender);
End;
  Mit Zitat antworten Zitat
Benutzerbild von Kedariodakon
Kedariodakon

Registriert seit: 10. Sep 2004
Ort: Mönchengladbach
833 Beiträge
 
Delphi 7 Enterprise
 
#7

Re: "inherited" für umgeleitetes Event

  Alt 16. Mär 2007, 09:50
Zitat von Guido Eisenbeis:
Respekt, falls das bedeutet, dass du das aus dem Kopf heraus (also ohne IDE) geschrieben hast!
Danke, aber da ist eigendlich nichts dabei...

Zitat von Guido Eisenbeis:
Im Moment würde ich mich schon darüber freuen, wenn du mir ein funktionierendes/getestetes "Flickwerk" posten würdest!
ich hab den obrigen Code genau so übernommen und eigendlich funktioniert es...


Nun und "Muetze1"s Codeschnippsel macht genau das selbe, nur eben in der Form


Bye Christian
Angehängte Dateien
Dateityp: rar ev_113.rar (4,3 KB, 5x aufgerufen)
Christian
  Mit Zitat antworten Zitat
Guido Eisenbeis

Registriert seit: 9. Apr 2006
389 Beiträge
 
Delphi 10.3 Rio
 
#8

Re: "inherited" für umgeleitetes Event

  Alt 16. Mär 2007, 20:01
Hallo Christian

Ein (funktionierendes) Demo sagt mehr als tausend Worte!

Nachdem ich die 'dof'-Datei gelöscht hatte, lieft das Demo dann auch! Danach habe ich (kurz) den Code aus dem obigen Download mit dem verglichen, den ich aus deinem Posting in ein eigenes Testprojekt gesetzt habe.

Nun ja, warum mein Testprojekt nicht funktionieren konnte, ist mir nun klar:

Delphi-Quellcode:
unit Unit1; // Enthält einen Button, dessen Click-Event
            // und das FormCreate-Event.

... // <- KEIN Eventhandler.

implementation

{$R *.dfm}

uses
  Unit2;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage('Ich bin im Original-Event.');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Unit2.MyEventReceiver.SetButtonOnClick( Button1 );
end;

end.
Den Code aus deinem Posting habe ich soweit verwendet, wie er zu ersehen war. Natürlich hatte ich keinen EventHandler in Unit1 deklariert/initalisiert! Der ging in den drei Punkten unter (siehe oben).

Ich habe mittlerweile eine andere Lösung erarbeitet. Nun werde ich diese andere Lösung noch überarbeiten/durchchecken. Danach werde ich deinen/Muetze1's Code durcharbeiten, damit ich verstehe wie da was gemacht wird.

Danach melde ich mich mit den Ergebnissen.

Grüße,
Guido.
  Mit Zitat antworten Zitat
Benutzerbild von Kedariodakon
Kedariodakon

Registriert seit: 10. Sep 2004
Ort: Mönchengladbach
833 Beiträge
 
Delphi 7 Enterprise
 
#9

Re: "inherited" für umgeleitetes Event

  Alt 17. Mär 2007, 00:29



Nunja, wir haben nichts wildes gemacht...

Wie du mitbekommen hast, wird deine OnClick Methode im OnClick (vom Typ TNotifyEvent) im TButton abgelegt...

Deklariert wurde sie aber schon in TControl im Protected Bereich, außerhalb sichtbar wird sie erst im TButton in dem OnClick Published wird...

Delphi-Quellcode:
Type
  TControl = class(TComponent)
  { ... }
  protected
    property OnClick: TNotifyEvent read FOnClick write FOnClick stored IsOnClickStored;
  { ... }
  end;

{ ... }

Type
  TWinControl = class(TControl)
  { ... }
  end;

{ ... }

Type
  TButtonControl = class(TWinControl)
  { ... }
  end;

{ ... }

Type
  TButton = class(TButtonControl)
  { ... }
  published
    property OnClick;
  { ... }
  end;
So nun ist natürlich noch viel interessanter, was TNotifyEvent nun eigendlich ist!
TNotifyEvent = procedure(Sender: TObject) of object; Da sieht man, dass TNotifyEvent ein Methodenzeiger ist, sprich der Inhalt soll zu solch einer Methode verweisen...


So, also was haben wir gemacht?
Muetze1 und ich haben also nichts anderes gemacht als uns eine Variable anzulegen, natürlich vom Typ TNotifyEvent und haben in diesem die OnClick Methode des TButtons gespeichert...
Anschliessend haben wir das OnClick des TButtons mit userer Methode überschrieben, ihm sozusagen einen neuen Methodenzeiger verpasst...

So, in unserer neuen Funktion haben wir sozusagen unseren Code ausgeführt und anschließend bzw. davor versucht die alte gespeicherte Methode aufgerufen, die wir gesichert haben...

Da ja ev. keine vorhanden gewesen sein könnte überprüfen wir natürlich mit Assigned( "TButtonOnClickSaveVariable" ) ob der Inhalt der gespeicherten alten OnClickMethode (bzw. den Zeiger dorthin) nicht NIL ist... Ist er nicht NIL rufen wir die Methode auf.

Das war es schon, keine Hexerei, kein Hockuspokus...
Ich hoffe die Erklärung konnte dir helfen...

Bye Christian
Christian
  Mit Zitat antworten Zitat
Guido Eisenbeis

Registriert seit: 9. Apr 2006
389 Beiträge
 
Delphi 10.3 Rio
 
#10

Re: "inherited" für umgeleitetes Event

  Alt 17. Mär 2007, 16:58
Hallo Christian.

Du hast scheinbar ein gutes Händchen dafür, wann ich welche Infos brauche!
Die haben geholfen!

Nun zum neuesten Stand:

Mittlerweile habe ich meinen eigenen Code überarbeitet und fertiggestellt und deinen Code verstanden. Die Bearbeitung meines Codes habe ich durchgeführt, bevor ich deinen Code studiert habe. Ich suchte zum einen nach einer einfacheren Lösung, zum anderen wollte ich verstehen was gemacht wird. Der Hammer ist nun, dass mein Code vom Prinzip her fast mit deinem Code identisch ist!


Wie gesagt, danach habe ich deinen/euren Code studiert. Davon habe ich auch alles verstanden bis auf eins:

In Unit1 wird ein Feld "FButon1EventHandler" angelegt. Bis hierhin ist das klar. Dann wird aber noch ein Property "Buton1EventHandler" angelegt, das lediglich in das Feld hineinschreibt oder daraus ausliest. Wozu dient der indirekte Weg über dieses Property?


Zu meinem Code:

Er hat nicht die Komfort-Features deines Codes, wie zum Beispiel "Reset". Dafür ist er einfacher gehalten. Und so sieht er aus:

Delphi-Quellcode:
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure Label1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  Unit2;

procedure TForm1.FormCreate(Sender: TObject);
begin
  InitClickEventRetouring(Label1);
  InitClickEventRetouring(Button1);
end;

procedure TForm1.Label1Click(Sender: TObject);
begin
  ShowMessage('Original-Event von (Label): ' + TLabel(Sender).Name);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage('Original-Event von (Button): ' + TButton(Sender).Name);
end;

end.
Delphi-Quellcode:
unit Unit2;

interface

uses
  StdCtrls;

procedure InitClickEventRetouring(Ctrl: TObject);

implementation

uses
  Dialogs, Classes;

type
  TClickEvnt = procedure (Sender: TObject) of object;
  TMyEventReceiver = class
    private
      FClickOrig: TClickEvnt;
      procedure ClickIntern(Sender: TObject);
    public
      property OnClickOrig: TClickEvnt read FClickOrig write FClickOrig;
  end;

var
  MyEventReceiver: TMyEventReceiver;

procedure TMyEventReceiver.ClickIntern(Sender: TObject);
begin
  ShowMessage('Umgeleitetes Event von: ' + TButton(Sender).Name);
  OnClickOrig(Sender);
end;

procedure InitClickEventRetouring(Ctrl: TObject);
begin
  MyEventReceiver := TMyEventReceiver.Create; // <- "Knackpunkt" !
  MyEventReceiver.OnClickOrig := TButton(Ctrl).OnClick;

  TButton(Ctrl).OnClick := MyEventReceiver.ClickIntern;
end;

initialization

finalization
  MyEventReceiver.Free;

end.
Als ich den Code erstellte, wollte ich ihn so anlegen, dass mehrere (verschiedene) Controls benutzt werden können. Wie man sehen kann, sind auch zwei Init-Aufrufe im FormCreate der Unit1. Einer für Label1 und einer für Button1. Zu diesem Zweck hatte ich vor, ein Array oder eine Liste mit MyEventReceiver-Instanzen zu erstellen.

Während des Programmierens kompiliere ich das Projekt bei bestimmten Gelegenheiten, um Fehler zu ermitteln die der Compiler erkennt. Als ich den obigen Code kompilierte, hatte ich eigentlich erwartet, dass entweder der Compiler an der mit "Knackpunkt" markierten Stelle einen Fehler wirft, oder dass der zweite Init-Aufruf mit der Create-Zuweisung den Wert in "MyEventReceiver" überschreibt. Dem war jedoch nicht so! Alles funktionierte einwandfrei, das jeweilige ClickInner wurde ausgelöst und das richtige Original-OnClick aufgerufen!

Die brennende Frage ist nun: Warum funktioniert das? Oder funktioniert es nicht wirklich?

Beim ersten Create wird Speicher reserviert. Wird vielleicht beim zweiten Create der neu reservierte Speicher wirklich reserviert und der vorherige ist nur "zufällig" noch da, bis ihn irgendein sonstiger Befehl oder ein anderes Programm überschreibt? Und wenn im fialization-Abschnitt "MyEventReceiver" freigegeben wird, wird dann auch sämtlicher Speicher freigegeben? Also auch der vom ersten Create?

Gruß.
Guido.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:33 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz