Autor |
Beitrag |
Pro7
Hält's aus hier
Beiträge: 11
|
Verfasst: Sa 21.08.04 15:17
Hallo  ,
so einen ähnlichen Thread hab ich schonmal gehabt, da ich da aber leider nur wenige (eine) antwort bekommen habe frag ich einfahc mal generell(vielleicht war das mit den sockets ja nicht ganz klar was ich meinte  ):
Wie überschreibe ich Ereignisse(events) ? Sagen wir mal das TMemo... es hat eine Ereignis "OnEnter". Wenn ich nun eine Klasse von TMemo ableite möchte ich dieses event überschreiben, weil ich bei "onenter" eben reagieren möchte...
Theoretisch habe ich mir das so vorgestellt:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| TMyClass = class(TMemo) published property OnEnter(?); override; end;
...
property TMyClass.OnEnter; begin inherited; end; |
...nur in der Praxis geht das natürlich nicht. Wie macht man soetwas?
|
|
.Chef
      
Beiträge: 1112
|
Verfasst: Sa 21.08.04 15:33
Wenn ich das richitg verstehe, möchtest du nicht das Ereignis überschreiben, sondern die Prozedur, die auf das Ereignis reagiert.
Hier ist das, was du dafür brauchst:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| type TMyClass = class(TMemo); private UserOnEnter : TNotifyEvent; procedure DeinOnEnter(Sender: TObject); end; |
Dann legst du zu Beginn (z.B. im AfterConstruction) deine Prozedure als Eventhandler fest:
Delphi-Quelltext 1: 2:
| if Assigned(OnEnter) then UserOnEnter:=OnEnter; OnEnter:=DeinOnEnter |
Der wird dann ausgeführt, wenn das Ereignis eintritt:
Delphi-Quelltext 1: 2: 3: 4: 5:
| procedure TMyClass.DeinOnEnter(Sender: TObject); begin if Assigned(UserOnEnter) then UserOnEnter(Sender); end; |
Gruß,
Jörg
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: Sa 21.08.04 15:37
Das Ereignis OnEnter wird von TWinControl eingeführt und dort findet man die Methode DoEnter die so ausschaut:
Delphi-Quelltext 1: 2: 3: 4:
| procedure TWinControl.DoEnter; begin if Assigned(FOnEnter) then FOnEnter(Self); end; |
Aufgabe von DoEnter ist es also das Ereignis OnEnter auszulösen, und nachdem DoEnter als dynamic deklariert ist kann es überschrieben und so eigener Code eingebracht werden.
Solche DoXXXX-Methode findet man eigentlich für so gut wie alle Events...
Edit: @.Chef: und was wenn man OnEnter zur Laufzeit einen Eventhandler zuweisen will?
_________________ gringo pussy cats - eef i see you i will pull your tail out by eets roots!
|
|
.Chef
      
Beiträge: 1112
|
Verfasst: Sa 21.08.04 15:45
Motzi hat folgendes geschrieben: | Edit: @.Chef: und was wenn man OnEnter zur Laufzeit einen Eventhandler zuweisen will? |
Das ist dann perönliches Pech. War ja nur eine Möglichkeit, den Pro7 auf den richtigen Weg zu bringen ...
|
|
Pro7 
Hält's aus hier
Beiträge: 11
|
Verfasst: So 22.08.04 01:29
Moin moin,
Zitat: | Wenn ich das richitg verstehe, möchtest du nicht das Ereignis überschreiben, sondern die Prozedur, die auf das Ereignis reagiert. |
genau. Dazu habe ich noch ein paar fragen...
Erstmal... wann wird ein ereignis "ausgelöst"? ich meinte irgendwie muss das ereignis ja aufrufen oder?
Dann....was mache ich wenn es für ein Ereignis keine methode gibt?
Und noch eine  ... Wieso muss ich eine "UserOnEnter" prozedur einführen? kann ich die alte nicht einfach überschreiben?
Danke schonmal für die Antworten euch beiden.
Gruss
|
|
.Chef
      
Beiträge: 1112
|
Verfasst: So 22.08.04 08:33
Pro7 hat folgendes geschrieben: | Erstmal... wann wird ein ereignis "ausgelöst"? ich meinte irgendwie muss das ereignis ja aufrufen oder? |
Das OnEnter wird in dem Fall schon von deiner Parent-Klasse ausgelöst, du musst es nur übernehmen. Als spontanes Beispiel für eigene Ereignisse könntest du mal im Open-Source-Units-Forum den TMutexIPC-Thread anschauen. Sowohl der BenBE als auch ich haben da eigene Ereignisse definiert, da dürfte das Prinzip klar werden.
Pro7 hat folgendes geschrieben: | Dann....was mache ich wenn es für ein Ereignis keine methode gibt? |
Dann passiert einfach nichts, wenn das Ereignis ausgelöst wird.
Pro7 hat folgendes geschrieben: | Und noch eine ... Wieso muss ich eine "UserOnEnter" prozedur einführen? kann ich die alte nicht einfach überschreiben? |
Du kannst auch die alte einfach überschreiben. Das Beispiel mit UserOnEnter führt bloß anschließend an deinen "internen" Eventhandler einen bereits vorhandenen "externen" aus. Wenn du das weglässt, wird er einfach ignoriert.
|
|
Pro7 
Hält's aus hier
Beiträge: 11
|
Verfasst: So 22.08.04 12:01
Moin .Chef,
danke für die Antworten.
Zitat: | Du kannst auch die alte einfach überschreiben. Das Beispiel mit UserOnEnter führt bloß anschließend an deinen "internen" Eventhandler einen bereits vorhandenen "externen" aus. Wenn du das weglässt, wird er einfach ignoriert. |
Kann ich den "externen" nicht mit inherited aufrufen?
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: So 22.08.04 13:19
.Chef hat folgendes geschrieben: | Motzi hat folgendes geschrieben: | Edit: @.Chef: und was wenn man OnEnter zur Laufzeit einen Eventhandler zuweisen will? |
Das ist dann perönliches Pech. War ja nur eine Möglichkeit, den Pro7 auf den richtigen Weg zu bringen ... |
Der richtige Weg ist es aber, die DoEvent-Methode zu überschreiben, dazu sind sie schließlich da..! Deine Methode ist nur ein halb funktionierender Workaround den ich nur anwenden würde wenn die Klasse keine entsprechenden DoEvent-Methoden bietet, allerdings würd ich dann doch noch ein bisschen anders vorgehen, indem ich neue Get- und Set-Methoden für das Event festleg, um eben zu verhindern, dass mein umgebogenes Event zur Laufzeit überschrieben wird..
Die VCL führt die DoEvent-Methoden eben ein, damit abgeleitete Klassen eben auf Events reagieren können und an dieser Stelle Code einschleusen können ohne die eigentliche Funktionalität zu beeinträchtigen (indem man die Methodenzeiger eben für eigene Zwecke verbiegt), denn die Events werden einfach ausgelöst indem man die entsprechende DoXXX-Methode aufruft. Man kann zB. auch verhindern, dass Ereignisse ausgelöst werden indem man die entsprechende DoEvent-Methode überschreibt und dort dann aber kein inherited aufruft.
Gute Komponenten-Entwickler stellen für ihre Events im protected-Abschnitt ebenfalls entsprechende DoXXX-Methoden zur Verfügung..!
_________________ gringo pussy cats - eef i see you i will pull your tail out by eets roots!
|
|
Pro7 
Hält's aus hier
Beiträge: 11
|
Verfasst: So 22.08.04 16:58
hallo motzi,
wenn ich z.b folgendes habe:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| type TMyClass = class(TClientSocket) private procedure DoConnect(MyRec: TMyRec); reintroduce; override; end;
implementation
procedure TTSSocketClass.DoConnect; begin inherited; with Socket do begin SendText(MyRec.var1); SendText(MyRec.var2; SendText(MyRec.var3); end; end; |
dann lässt sich die unit nicht kompilieren.
Fehler ist:
Zitat: | [Fehler] tsSocketClass.pas(10): Methode 'DoConnect' nicht in Basisklasse gefunden |
Ich möchte eben nach dem "OnConnect" eingetroffen ist etwas über die klasse direkt schon an den server senden. ABer "DoConnect" scheint nicht zu gehen. Wie kann man rauskriegen ob und welche Methode für ein Event ist? ich such schon überall in den vcl sourcen rum.... 
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: So 22.08.04 22:09
Aja.. ich liebe es wenn Leute am Anfang immer schreiben "sagen wir ich will zB das und das machen", aber eigentlich was ganz andres vorhaben..
Du willst also nicht das OnEnter vom Memo, sondern das OnConnect-Ereignis überschreiben. OnConnect wird von TCustomSocket eingeführt, also mal dort schauen... wie man in der recht kurzen Klassen-Deklaration sieht, gibt es hier ausnahmsweise keine DoXXX-Methoden, stattdessen aber eine Methode mit dem netten (und gar nicht aussagekräftigen  ) Namen "Event", welche bereits als "override" deklariert ist, folglich ist sie also virtual oder dynamic und kann auch in einer andren Klasse überschrieben werden. Und wenn man sich die Implementierung dieser Methode anschaut sieht man, dass dort alle Events ausgelöst werden die von TCustomSocket eingeführt werden. Die Unterscheidung welches Event ausgelöst wird erfolgt dabei über den Typ TSocketEvent:
Delphi-Quelltext 1: 2:
| TSocketEvent = (seLookup, seConnecting, seConnect, seDisconnect, seListen, seAccept, seWrite, seRead); |
Was also tun? Einfach die Methode Event überschreiben:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| type TMyClass = class(TClientSocket) protected procedure Event(Socket: TCustomWinSocket; SocketEvent: TSocketEvent); override; end;
implementation
procedure TTSSocketClass.Event(Socket: TCustomWinSocket; SocketEvent: TSocketEvent); begin inherited; if SocketEvent = seConnect then with Socket do begin SendText(MyRec.var1); SendText(MyRec.var2; SendText(MyRec.var3); end; end; |
_________________ gringo pussy cats - eef i see you i will pull your tail out by eets roots!
|
|
Pro7 
Hält's aus hier
Beiträge: 11
|
Verfasst: So 22.08.04 23:17
Hallo Motzi,
Danke für die ausführliche beschreibung
Genau das ist es was ich möchte
Natürlich hab ich wieder eine Frage dazu *gg*...
du siehst ja das:
Delphi-Quelltext 1: 2: 3:
| SendText(MyRec.var1); SendText(MyRec.var2); SendText(MyRec.var3); |
Ist es möglich diesen record über die überschriebene methode zu übergeben? als zusätzlichen parameter?
So das ich dann am ende die prozedur so habe:
Delphi-Quelltext 1:
| procedure TTSSocketClass.Event(Socket: TCustomWinSocket; SocketEvent: TSocketEvent; myRec: TMyRec); |
Vielen danke nochmal, das hilft mir schon sehr =)
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: So 22.08.04 23:24
Nein, das geht nicht.. erstens würde es die Parameterreihenfolge ändern womit die Basisklasse nicht mehr wüsste was sie damit machen soll und zweitens würde es dir auch nichts bringen, da ja nicht du die Methode aufrufst, sondern die Basisklasse ruft die Methode dann auf wenn ein Ereignis ausgelöst wird.
Beschreib mal was du vorhast, dann lässt sich da sicher eine Lösung finden.. ich würde momentan spontan sagen einfach über ein Feld der Klasse lösen, aber sag einfach mal genauer was genau du machen willst..! 
_________________ gringo pussy cats - eef i see you i will pull your tail out by eets roots!
|
|
.Chef
      
Beiträge: 1112
|
Verfasst: So 22.08.04 23:34
Pro7 hat folgendes geschrieben: | Kann ich den "externen" nicht mit inherited aufrufen? |
Um das erstmal zu klären: inherited führt die gleichnamige Methode der Parent-Klasse aus. Da die Parent-Klasse aber keinen eigenen Eventhandler (nicht mit Event verwechseln!!) hat, kannst du ihn auch nicht beerben.
Motzi hat folgendes geschrieben: | Du willst also nicht das OnEnter vom Memo, sondern das OnConnect-Ereignis überschreiben. OnConnect wird von TCustomSocket eingeführt, also mal dort schauen... wie man in der recht kurzen Klassen-Deklaration sieht, gibt es hier ausnahmsweise keine DoXXX-Methoden |
 So schnell kanns gehen ... 
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: So 22.08.04 23:45
_________________ gringo pussy cats - eef i see you i will pull your tail out by eets roots!
|
|
Pro7 
Hält's aus hier
Beiträge: 11
|
Verfasst: Mo 23.08.04 02:48
Moin
Zitat: | Nein, das geht nicht.. erstens würde es die Parameterreihenfolge ändern womit die Basisklasse nicht mehr wüsste was sie damit machen soll und zweitens würde es dir auch nichts bringen, da ja nicht du die Methode aufrufst, sondern die Basisklasse ruft die Methode dann auf wenn ein Ereignis ausgelöst wird. |
Jo, mein beispiel war doof geschrieben. Ich meinte es eigentlich so, das ich die methode überschreibe (mit nur meinem record als parameter) und dann mit inherited die methode der vorgängerklasse aufrufe, geht das?
Zitat: | Beschreib mal was du vorhast, dann lässt sich da sicher eine Lösung finden.. ich würde momentan spontan sagen einfach über ein Feld der Klasse lösen, aber sag einfach mal genauer was genau du machen willst..! |
Also, ich möchte eigentlich nur eine klasse von TClientSocket ableiten, von der klasse aus möchte ich dann "OnConnect" direkt daten senden (also das es halt "automatisch beim connect gesendet wird). Die daten die ich senden möchte sind in einem Record (den ich der überschrieben methode übergeben möchte).
Danke euch beiden schonmal für die Antwort 
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: Mo 23.08.04 19:31
Pro7 hat folgendes geschrieben: | Jo, mein beispiel war doof geschrieben. Ich meinte es eigentlich so, das ich die methode überschreibe (mit nur meinem record als parameter) und dann mit inherited die methode der vorgängerklasse aufrufe, geht das? |
Nein, das geht natürlich nicht.. damit wäre die Methode ja dann mit der Original-Methode inkompatibel..! Aber selbst wenn es ginge würde es dir nichts bringen, denn wer ruft die Methode denn auf? Richtig, die Basisklasse und die weiß ja von dem Parameter nix und wie sie damit umgehen soll...
Zitat: | Also, ich möchte eigentlich nur eine klasse von TClientSocket ableiten, von der klasse aus möchte ich dann "OnConnect" direkt daten senden (also das es halt "automatisch beim connect gesendet wird). Die daten die ich senden möchte sind in einem Record (den ich der überschrieben methode übergeben möchte). |
Achso.. also soweit ich das verstanden hab willst du im OnConnect-Ereignis Daten versenden die du im Ereignis selbst angeben können willst. Dann würd ich folgendermaßen vorgehen, dass du dir selbst ein neues OnConnect-Ereignis definierst, das einen zusätzlichen Parameter hat:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36:
| type TMyRec = record var1: type1; var2: type2; var3: type3; end;
TMyOnConnect = procedure (Sender: TObject; Socket: TCustomWinSocket; var aRec: TMyRec) of object;
TMyClass = class(TClientSocket) private FOnConnect: TMyOnConnect; protected procedure Event(Socket: TCustomWinSocket; SocketEvent: TSocketEvent); override; published property OnConnect: TMyOnConnect read FOnConnect write FOnConnect; end;
implementation
procedure TTSSocketClass.Event(Socket: TCustomWinSocket; SocketEvent: TSocketEvent); var aRec: TMyRec; begin inherited; if SocketEvent = seConnect then begin if Assigned(FOnConnect) then begin FOnConnect(Self, Socket, aRec); SendText(aRec.var1); SendText(aRec.var2; SendText(aRec.var3); end; end; end; |
Dadurch hat das OnConnect-Ereignis einen neuen Parameter vom Typ TMyRec (die Namensgebungen sind jetzt nur beispielhaft) und du kannst jetzt einfach im Event-Handler des OnConnect-Ereignis dem Record Werte zuweisen und diese werden dann verschickt...
_________________ gringo pussy cats - eef i see you i will pull your tail out by eets roots!
|
|
Pro7 
Hält's aus hier
Beiträge: 11
|
Verfasst: Mi 25.08.04 14:06
Hallo Motzi,
Zitat: | procedure TTSSocketClass.Event(Socket: TCustomWinSocket; SocketEvent: TSocketEvent);
var
aRec: TMyRec;
begin
inherited;
if SocketEvent = seConnect then
begin
if Assigned(FOnConnect) then
begin
FOnConnect(Self, Socket, aRec);
SendText(aRec.var1);
SendText(aRec.var2;
SendText(aRec.var3);
end;
end;
end;
|
dann könnte ich den record aber nicht ausserhalb der klasse füllen oder?
Und wieder mal die Frage zu "Assigned"  Mir wurde das schon 142424 mal erklärt aber verstanden hab ich das nie... wieso wir das hier gemacht:
Zitat: | if Assigned(FOnConnect) then |
?
ich weiss das assigned true is wenn FConnect nicht nil ist.... aber wann würde die methode (Event) aufgerufen werden und FConnect = nil? ich verstehe das irgendwie nicht :\
Danke für den Code übrigens 
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: Do 26.08.04 21:36
Pro7 hat folgendes geschrieben: | dann könnte ich den record aber nicht ausserhalb der klasse füllen oder? |
Doch, ganz genau das kannst du dann.. du kannst dann einfach im Objekt-Inspektor doppelt auf OnConnect klicken, Delphi erstellt den Event-Handler und dort findest du dann einen neuen Parameter "var aRec: TMyRec" und dem weißt du dann einfach die Daten zu...
Zitat: | Und wieder mal die Frage zu "Assigned" Mir wurde das schon 142424 mal erklärt aber verstanden hab ich das nie... wieso wir das hier gemacht:
Zitat: | if Assigned(FOnConnect) then |
?
ich weiss das assigned true is wenn FConnect nicht nil ist.... aber wann würde die methode (Event) aufgerufen werden und FConnect = nil? ich verstehe das irgendwie nicht :\ |
Ganz genau... Assigned überprüft einfach ob ein Zeiger nil ist, in dem Fall überprüft es einen Methodenzeiger.
Alle Ereignisse sind Methodenzeiger. Ein Methodenzeiger besteht eigentlich aus 2 Zeigern (siehe TMethod in der OH), ein Zeiger für den Code und einer für das Objekt. Der Zeiger für den Code zeigt einfach an die Stelle im Speicher an der der Code des Event-Handlers liegt und im Objekt wird einfach gespeichert auf welches Objekt sich der Code der Methode beziehen muss, also welches Objekt als Self-Parameter weitergegeben werden muss.
Mit Assigned() wird jetzt einfach geprüft ob dem Ereignis ein Methodenzeiger zugewiesen wurde, also ob es einen Event-Handelr für dieses Event gibt oder nicht. Wenn man also die Assigned-Prüfung weglassen würde und FOnConnect wäre nil würde man quasi ins Nirvana springen und eine nette AV wäre das Ergebnis...
_________________ gringo pussy cats - eef i see you i will pull your tail out by eets roots!
|
|