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 14. Mär 2007 · letzter Beitrag vom 20. Mär 2007
Antwort Antwort
Seite 2 von 2     12   
Benutzerbild von Kedariodakon
Kedariodakon

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

Re: "inherited" für umgeleitetes Event

  Alt 17. Mär 2007, 16:57
Zitat von Guido Eisenbeis:
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?
Öhm ka, hab ich einfach so gemacht, kann man auch ohne Property machen... Ist also nichts wildes, hatte glaub ich vorher noch eine SetButon1EventHandler um Irgendwas zu testen...



Zitat von Guido Eisenbeis:
Die brennende Frage ist nun: Warum funktioniert das? Oder funktioniert es nicht wirklich?
Jain, funktionieren schon aber nicht sauber!, zum einen:

Du erzeugst jedesmal solch eienn Eventhandler:
Delphi-Quellcode:
procedure InitClickEventRetouring(Ctrl: TObject);
begin
  MyEventReceiver := TMyEventReceiver.Create; // <- "Knackpunkt" !
  { ... }
end;
Aber du gibst schlussendlich nur einen frei!
Delphi-Quellcode:
finalization
  MyEventReceiver.Free;
Da musst du dir was anderes einfallen lassen, z.b. eine Liste mit Eventhandlern oder ähnliches....


So der nächste wichtige Punkt, du überprüfst nicht ob es vorher überhaupt ein Event gab!
Delphi-Quellcode:
procedure TMyEventReceiver.ClickIntern(Sender: TObject);
begin
  { ... }
  OnClickOrig(Sender);
end;
Das solltest du ändern in:
Delphi-Quellcode:
procedure TMyEventReceiver.ClickIntern(Sender: TObject);
begin
  { ... }
  If Assigned( OnClickOrig ) Then OnClickOrig(Sender);
end;
Sprich du schaust erstmal ob der Methodenzeichner belegt wurde, bevor du ihn ausführst...


Als leztes nur eine kleine Anmerkung:
Delphi-Quellcode:
procedure InitClickEventRetouring(Ctrl: TObject);
begin
  {...}
  TButton(Ctrl).OnClick := MyEventReceiver.ClickIntern;
end;
Hier solltest du eventuell nachschaun, ob Ctrl überhaupt ein Wert hat! Aber viel wichtiger, udem kann da ein Wert übergeben werden, der gar keine OnClick Ereigniss hat, bzw. schon gar nicht ein TButton ist!

Da gehört also sowas hin wie:
Delphi-Quellcode:
procedure InitClickEventRetouring(Ctrl: TObject);
begin
  {...}
  If Assigned( Ctrl ) And ( Ctrl Is TButton ) Then TButton(Ctrl).OnClick := MyEventReceiver.ClickIntern;
end;
das wärs erstmal von meinen Anmerkungen....

Bye Christian
Christian
  Mit Zitat antworten Zitat
Guido Eisenbeis

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

Re: "inherited" für umgeleitetes Event

  Alt 18. Mär 2007, 01:04
Zitat von Kedariodakon:
Öhm ka, hab ich einfach so gemacht, kann man auch ohne Property machen...
Das hab ich mir gedacht, jetzt hab ich Sicherheit! Thank you!

Zitat von Kedariodakon:
Zitat von Guido Eisenbeis:
Die brennende Frage ist nun: Warum funktioniert das? Oder funktioniert es nicht wirklich?
Jain, funktionieren schon aber nicht sauber!, zum einen:

Du erzeugst jedesmal solch eienn Eventhandler:
...
Aber du gibst schlussendlich nur einen frei!
...
DAS war an dieser Stelle die wichtige Frage! Danke für die Info! Ich hasse es, wenn andere Programmierer Anwendungen schreiben, die zwar irgendwie "funktionieren" aber man merkt am Programmverhalten, dass da was nicht sauber läuft. Da bleiben beim Beenden TrayIcons oder Taskbareinträge zurück oder das Programm bleibt zwischendurch hängen. Deshalb bemühe ich mich in meinen Programmen sauber zu arbeiten!

Zitat von Kedariodakon:
Da musst du dir was anderes einfallen lassen, z.b. eine Liste mit Eventhandlern oder ähnliches....
Mit Arrays habe ich schon oft gearbeitet. Diesmal werde ich mir mal TList vornehmen.


Zitat von Kedariodakon:
So der nächste wichtige Punkt, du überprüfst nicht ob es vorher überhaupt ein Event gab!
...
Das solltest du ändern in:
Delphi-Quellcode:
procedure TMyEventReceiver.ClickIntern(Sender: TObject);
begin
  { ... }
  If Assigned( OnClickOrig ) Then OnClickOrig(Sender);
end;
Sprich du schaust erstmal ob der Methodenzeichner belegt wurde, bevor du ihn ausführst...
Das hatte ich vorher. Das ging beim Testen/Probieren verloren.

Das ist ein sehr wichtiger Punkt, denn darum geht es in diesem Thread ja: Es soll ein (Click-)Event abgefangen und zurückgeleitet werden, falls auch was zum Zurückleiten da ist. Denn sonst könnte ich ja einfach im Original-(Click-)Event meinen ausgelagerten Code aufrufen. Der ausgelagete Code soll aber auch ausgeführt werden, wenn im Form garkein (Click-)Event existiert.


Zitat von Kedariodakon:
Als leztes nur eine kleine Anmerkung:
Delphi-Quellcode:
procedure InitClickEventRetouring(Ctrl: TObject);
begin
  {...}
  TButton(Ctrl).OnClick := MyEventReceiver.ClickIntern;
end;
Hier solltest du eventuell nachschaun, ob Ctrl überhaupt ein Wert hat! Aber viel wichtiger, udem kann da ein Wert übergeben werden, der gar keine OnClick Ereigniss hat, bzw. schon gar nicht ein TButton ist!

Da gehört also sowas hin wie:
Delphi-Quellcode:
procedure InitClickEventRetouring(Ctrl: TObject);
begin
  {...}
  If Assigned( Ctrl ) And ( Ctrl Is TButton ) Then TButton(Ctrl).OnClick := MyEventReceiver.ClickIntern;
end;
Bye Christian
Dazu habe ich mir auch schon Gedanken gemacht. Das kannst du daran erkennen, dass ich "Ctrl: TObject" verwendet habe. Prinzipiell könnte ich mit den obigen Codes und deiner Abfrage "If Assigned(Ctrl) ..." arbeiten. Aber du weißt ja wie das ist: hat man mal Blut geleckt, will man mehr! Hast du eine Idee, wie ich das OnClick allgemeiner gestalten kann? Also so, dass es für Buttons, Labels, Panels usw. gleichermaßen funktioniert? Ich hatte schon experimentiert, das OnClick selbst anstatt das Control zu übergeben. Das scheiterte jedoch daran, dass es sich nicht als "Var" übergeben lässt und ohne "Var" sich nichts zuweisen lässt.

Ein TypeCasting "(Ctrl as TButton).OnClick := ..." wirft ja bei Fehlern eine Exception während "TButton(Ctrl).OnClick := ..." gutmütig über ein übergebenes Label hinwegsieht. Das war schonmal mein Ansatz, den Code für mehrere Control-Typen benutzen zu können. Ich hätte es aber gerne noch sauberer!

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

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

Re: "inherited" für umgeleitetes Event

  Alt 18. Mär 2007, 01:44
Zitat von Guido Eisenbeis:
Mit Arrays habe ich schon oft gearbeitet. Diesmal werde ich mir mal TList vornehmen.
Nimm lieber eine TObjectList, die gibt gleich alle Objecte frei, wenn sie freigegeben wird (zumindest standardmäßig...

Zitat von Guido Eisenbeis:
Aber du weißt ja wie das ist: hat man mal Blut geleckt, will man mehr! Hast du eine Idee, wie ich das OnClick allgemeiner gestalten kann? Also so, dass es für Buttons, Labels, Panels usw. gleichermaßen funktioniert?


Delphi-Quellcode:
procedure InitClickEventRetouring(Ctrl: TObject);
begin
  {...}
  If Assigned( Ctrl ) And ( Ctrl Is TButton ) Then TButton(Ctrl).OnClick := MyEventReceiver.ClickIntern;
end;
ich schrieb weiter oben schonmal woher das Onlick kommt! Nimm statt TObject ein TControl...

Desweiteren hättest du die möglichkeit explezit nach den Klassen zu schauen ungefär so:

Delphi-Quellcode:
Procedure InitClickEventRetouring( Ctrl: TControl );
Begin
  If ( Ctrl Is TButton ) Then Begin
    // Mach was mit dem TButton
  End Else If ( Ctrl Is TLabel ) Then Begin
    // Mach was mit dem TLabel
  End Else If ( Ctrl Is TPanel ) Then Begin
    // Mach was mit dem TPanel
  End Else Begin
    // tja is was anderes, mach halt was anderes...
  End;
End;

Bye Christian
Christian
  Mit Zitat antworten Zitat
Guido Eisenbeis

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

Re: "inherited" für umgeleitetes Event

  Alt 18. Mär 2007, 03:52
Zitat von Kedariodakon:
Nimm lieber eine TObjectList, die gibt gleich alle Objecte frei, wenn sie freigegeben wird (zumindest standardmäßig...
Habe ich auch so gesehen. Hier der neue Code (Unit1 hat sich nicht verändert):

Delphi-Quellcode:
unit Unit2;

interface

procedure InitClickEventRetouring(Ctrl: TObject);

implementation

uses
  Dialogs, Classes, StdCtrls, Contnrs;

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
  EvRecvList: TObjectList;

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

procedure InitClickEventRetouring(Ctrl: TObject);
var
  MyEventReceiver: TMyEventReceiver;
begin
  try
    MyEventReceiver := TMyEventReceiver.Create;
    MyEventReceiver.OnClickOrig := TButton(Ctrl).OnClick;
    TButton(Ctrl).OnClick := MyEventReceiver.ClickIntern;
    EvRecvList.Add(MyEventReceiver);
  except
    ShowMessage('Error in ClickEventRetouring code');
  end;
end;

initialization
  EvRecvList := TObjectList.Create;

finalization
  EvRecvList.Free;

end.
Zitat von Kedariodakon:
Zitat von Guido Eisenbeis:
Hast du eine Idee, wie ich das OnClick allgemeiner gestalten kann? Also so, dass es für Buttons, Labels, Panels usw. gleichermaßen funktioniert?
ich schrieb weiter oben schonmal woher das Onlick kommt! Nimm statt TObject ein TControl...
Leider führt TControl sein OnClick nicht nach außen! Es ist protected.

Zitat von Kedariodakon:
Desweiteren hättest du die möglichkeit explezit nach den Klassen zu schauen ungefär so:

Delphi-Quellcode:
Procedure InitClickEventRetouring( Ctrl: TControl );
Begin
  If ( Ctrl Is TButton ) Then Begin
    // Mach was mit dem TButton
  End Else If ( Ctrl Is TLabel ) Then Begin
    // Mach was mit dem TLabel
  End Else If ( Ctrl Is TPanel ) Then Begin
    // Mach was mit dem TPanel
  End Else Begin
    // tja is was anderes, mach halt was anderes...
  End;
End;
Das wäre auch meine "Notlösung".

Gruß,
Guido.
Angehängte Dateien
Dateityp: zip _inherited__fuer_umgeleitetes_event_186.zip (2,6 KB, 4x aufgerufen)
  Mit Zitat antworten Zitat
Benutzerbild von Kedariodakon
Kedariodakon

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

Re: "inherited" für umgeleitetes Event

  Alt 18. Mär 2007, 11:44
Zitat von Guido Eisenbeis:
Leider führt TControl sein OnClick nicht nach außen! Es ist protected.
Das mag war sein, aber die Speicherstelle von OnClick sollte sich nicht verändern... Heißt du kannst auf TButton oder TPanel casten und kommst zum protected OnClick-Event... (aber das ist unsauber!...

Zitat von Guido Eisenbeis:
Das wäre auch meine "Notlösung".
Nunja, das ist die einzig wahre, um erhlich zu sein...


Desweiteren hast du noch eine unstimmigkeit in deinem Code!
Delphi-Quellcode:
procedure InitClickEventRetouring(Ctrl: TObject);
var
  MyEventReceiver: TMyEventReceiver;
begin
  try
    MyEventReceiver := TMyEventReceiver.Create;
    MyEventReceiver.OnClickOrig := TButton(Ctrl).OnClick;
    TButton(Ctrl).OnClick := MyEventReceiver.ClickIntern;
    EvRecvList.Add(MyEventReceiver);
  except
    ShowMessage('Error in ClickEventRetouring code');
  end;
end;
Du hast zwar einen Try..Except Block, aber das Object steht im Fehlerfall sicher nicht in der Liste und wird schlussendlich nicht freigegeben!
Du solltest es gleich nach dem Erzeugen in die Liste packen....

Eventuell ist es auch sinvoller den ursprünglichen Fehlercode nach außen zu geben!

ich hab das mal alles umgebaut... so sieht meine Lösung aus:
Delphi-Quellcode:
Procedure InitClickEventRetouring( Ctrl: TControl );
Var MyEventReceiver: TMyEventReceiver;
Begin
  If Assigned( Ctrl ) Then Begin // Wenn kein Object pbergeben wurde können wir uns gleich alles sparen...
    MyEventReceiver := TMyEventReceiver.Create; // Receiver erzeugen...
    EvRecvList.Add( MyEventReceiver ); // Receiver gleich in die Liste einfügen, damit es nicht verloren geht...
    Try
      If ( Ctrl Is TButton ) Then Begin
        // Es ist ein TButton
        MyEventReceiver.OnClickOrig := TButton( Ctrl ).OnClick;
        TButton( Ctrl ).OnClick := MyEventReceiver.ClickIntern;
      End Else If ( Ctrl Is TLabel ) Then Begin
        // Es ist ein TLabel
        MyEventReceiver.OnClickOrig := TLabel( Ctrl ).OnClick;
        TLabel( Ctrl ).OnClick := MyEventReceiver.ClickIntern;
      End Else If ( Ctrl Is TPanel ) Then Begin
        // Es ist ein TPanel
        MyEventReceiver.OnClickOrig := TPanel( Ctrl ).OnClick;
        TPanel( Ctrl ).OnClick := MyEventReceiver.ClickIntern;
      End Else Begin
        // Es ist ein was anderes, aber da wir mit einem TControl arbeiten, Casten wir einfach auf TButton ;=)
        MyEventReceiver.OnClickOrig := TButton( Ctrl ).OnClick;
        TButton( Ctrl ).OnClick := MyEventReceiver.ClickIntern;
      End;
    Except
      On Error: Exception Do Begin // Jeder Fehler ist eine Exception...
        ShowMessage( 'Error in ClickEventRetouring code: "' + Error.Message + '"' ); // zusätzlich geben wir den Fehler mit aus!
      End;
    End;
  End;
End;
BTW: Wenn du sowieso am testen bist, es gibt sicher auch eine Möglichkeit über die RTTI...
Du könntest dort in der Tabelle anch dem "OnClick" Property suchen und es dann benutzen, falls vorhanden...
Aber das wird alles nicht super schnell sein...
Ich würd das wenn, nur im letzten Else Block bei mir machen, um wirklich sicher zu sein, dass da was ist...
Ev. macht es dann auch sinn mit einem TObject zu arbeiten...


Bye Christian
Angehängte Dateien
Dateityp: pas unit2_531.pas (2,7 KB, 2x aufgerufen)
Christian
  Mit Zitat antworten Zitat
Guido Eisenbeis

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

Re: "inherited" für umgeleitetes Event

  Alt 19. Mär 2007, 20:17
Hallo Christian.

Die letzen beiden Tage war ich sehr beschäftigt und bin noch nicht dazu gekommen zu antworten. Sorry dafür.

Zitat von Kedariodakon:
Zitat von Guido Eisenbeis:
Leider führt TControl sein OnClick nicht nach außen! Es ist protected.
Das mag war sein, aber die Speicherstelle von OnClick sollte sich nicht verändern... Heißt du kannst auf TButton oder TPanel casten und kommst zum protected OnClick-Event... (aber das ist unsauber!...
Klar soweit.

Zitat von Kedariodakon:
Zitat von Guido Eisenbeis:
Das wäre auch meine "Notlösung".
Nunja, das ist die einzig wahre, um erhlich zu sein...
Sehe ich genauso! Deshalb "Notlösung" auch in Anführungszeichen.

Zitat von Kedariodakon:
Desweiteren hast du noch eine unstimmigkeit in deinem Code!
...
Du hast zwar einen Try..Except Block, aber das Object steht im Fehlerfall sicher nicht in der Liste und wird schlussendlich nicht freigegeben!
Du solltest es gleich nach dem Erzeugen in die Liste packen....

Eventuell ist es auch sinvoller den ursprünglichen Fehlercode nach außen zu geben!

ich hab das mal alles umgebaut...
Auch das sehe ich genauso (nachdem du es aufgedeckt hast *Dickes-Lob* ).

Deine an sich schon gute Routine habe ich so übernommen, habe mich aber dazu entschlossen bei einem Fehler die EventReceiver-Instanz garnicht erst in die Liste aufzunhemen.

Delphi-Quellcode:
procedure InitClickEventRetouring(Ctrl: TControl);
var
  MyEventReceiver: TMyEventReceiver;
begin
  if Assigned(Ctrl) then // wurde ein Objekt übergeben ?
  begin
    MyEventReceiver := nil;

    try
      MyEventReceiver := TMyEventReceiver.Create;
      MyEventReceiver.OnClickOrig := TButton(Ctrl).OnClick;
      TButton(Ctrl).OnClick := MyEventReceiver.ClickIntern;
    except

      On Error: Exception Do // Bei allen Fehlern den Speicher
      begin // freigeben und Nachricht ausgeben.
        // MyEventReceiver.Free;
        FreeAndNil(MyEventReceiver);
        ShowMessage('Error in ClickEventRetouring code with message:'
                     + #13#10 + #13#10 + '"' + Error.Message + '"');
      end;
    end;

    // nur in Liste einfügen, wenn kein Fehler aufgetreten ist
    if (Assigned(MyEventReceiver)) then
      EvRecvList.Add(MyEventReceiver);
  end;
end;

Zitat von Kedariodakon:
BTW: Wenn du sowieso am testen bist, es gibt sicher auch eine Möglichkeit über die RTTI...
Mit der RTTI bin ich noch nicht vertraut. Da müsste ich mich erst einarbeiten. Trotzdem danke für den Hinweis!

Danke für deine Unterstützung!

Gruß,
Guido.

Edit: TObject durch TControl ersetzt und "Free" durch "FreeAndNil" ersetzt.
  Mit Zitat antworten Zitat
Benutzerbild von Kedariodakon
Kedariodakon

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

Re: "inherited" für umgeleitetes Event

  Alt 19. Mär 2007, 20:47
Autsch

Deine If-Abfrage:
if (Assigned(MyEventReceiver)) then EvRecvList.Add(MyEventReceiver); Wird bei einem Fehler dein Freigegebenes Objekt trotzdem aufnehmen...

MyEventReceiver.Free; Zerstört nähmlich nur das Objekt und setzt es nicht Nil, was du aber mit Assigned abfragst...

Nimm stattdesen: FreeAndNil( MyEventReceiver )

Nunja Zerstören musst du das Object ja eh, ob du das nun im Exvept Teil machst oder am Programmende

Bye Christian
Christian
  Mit Zitat antworten Zitat
Guido Eisenbeis

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

Re: "inherited" für umgeleitetes Event

  Alt 19. Mär 2007, 23:10
Zitat von Kedariodakon:
Nunja Zerstören musst du das Object ja eh, ob du das nun im Exvept Teil machst oder am Programmende
Das stimmt. Iss gehüpft wie gehoppelt!

Zitat von Kedariodakon:
Nimm stattdesen: FreeAndNil( MyEventReceiver )
Hey, cool! Das hatte ich übersehen und FreeAndNil war mir noch nicht geläufig. Habe es in meinem Code eingebaut und im Beitrag 16 editiert (mit Hinweis ).

Ciao,
Guido.
  Mit Zitat antworten Zitat
Benutzerbild von Kedariodakon
Kedariodakon

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

Re: "inherited" für umgeleitetes Event

  Alt 19. Mär 2007, 23:16
So sieht das alles sauber aus. Ich denke so können wir den Code auf die öffentlichkeit loslassen

Ich hoffe du hast ein wenig was gelernt

Bye Christian
Christian
  Mit Zitat antworten Zitat
Guido Eisenbeis

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

Re: "inherited" für umgeleitetes Event

  Alt 20. Mär 2007, 11:35
Ein kleiner "Schriebfheler" hat sich eingeschlichen: Überall im Code/Posting wo "Retouring" steht, sollte das durch "Rerouting" ersetzt werden.

@Christian.

Gelernt dabei: einiges.
Dank dafür: vielen!

Ciao,
Guido.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


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 07:42 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