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.