Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Event-Typen und warum deren Inhalte manchmal nicht stimmen (https://www.delphipraxis.net/137518-event-typen-und-warum-deren-inhalte-manchmal-nicht-stimmen.html)

BAMatze 22. Jul 2009 15:00


Event-Typen und warum deren Inhalte manchmal nicht stimmen
 
Hallo,

Hab nochmal eine Verständnisfrage zu Events. Lustiger Weise funktionieren sie irgendwann genau immer so, wie ich das will aber hab hier zum x.ten mal Anfangschwierigkeiten bei dem Einfügen eines neuen Events. Folgender Maßen führe ich in eine meiner Komponenten die Events ein:

Delphi-Quellcode:
Type TOnTischChange = procedure of Object;

Type TTischsteuerung = class(TWinControl)
  private
    ...
    // Variablen für Events
    FOnTischChange: TOnTischChange;
  published
    // OnTischChange soll dem Programm die Möglichkeit geben alle Eigenschaften auf den
    // ausgewählten Tisch auszurichten.
    property OnTischChange: TOnTischChange read FOnTischChange write FOnTischChange;
    ...
end;

...

// irgendwo in der createwnd-Procedure
  FCombBoxTischauswahl := CreateComboBox(17,35, 200);
  FCombBoxTischauswahl.Items.Add('Test1');
  FCombBoxTischauswahl.Items.Add('Test2');
  FCombBoxTischauswahl.Items.Add('Test3');
  FCombBoxTischauswahl.ItemIndex := 0;
  FCombBoxTischauswahl.OnChange := Tischaenderung;

// Die Procedure Tischaenderung
procedure TTischsteuerung.Tischaenderung(Sender: TObject);
begin
  case FCombBoxTischauswahl.ItemIndex of
  0: Komponentenanpassung(1);
  1: Komponentenanpassung(2);
  2: Komponentenanpassung(3);
  end;
  if assigned(OnTischChange) then OnTischChange;
end;
Also ich habe sicherlich in der Art und Weise schon mehrfach Events eingeführt und irgendwie funktioniert das am Anfang immer überhaupt nicht (so wie jetzt) und irgendwann ohne für mich ersichtlichen Grund (derzeit) funktioniert es. Ich habe schon das OnTischChange := nil gesetzt und trotzdem bleibt assigned(OnTischChange) = false.

Der Sinn hinter dem Event ist eigentlich, dass ich in meinem Composite Control das onChange-Event der Combonox weitergeben will.
Dafür habe ich auch schon die Komponente deinstalliert und neu installiert (verwende hier auf Arbeit Rad2007, nicht wie in Profil TD2006).

Kann mir jemand vieleicht sagen, warum das anscheinend derart flüchtig ist, was aus assigned(On...) herauskommt?

Vielen Dank BAMatze

hazard999 22. Jul 2009 15:10

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
probiers mal mit FOnTischChange

himitsu 22. Jul 2009 15:13

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Ganz ehrlich:

* an dem hier gezeigtem Code kann ich keinen Fehler finden, welcher dieses Problem erklären würde

* und ich äußere meine Vermutung gern nochmal (hab so langsam das Gefühl), wenn ich hier und da den einen oder anderen Post/Thread lese:

ein Bufferoverrun, bzw. ein verirrter Pointer oder Ähnliches, würden dieses Verhalten erklären.

Zitat:

probiers mal mit FOnTischChange
klar wäre es besser, wenn intern auch die internen Möglichkeiten genutzt würden,
aber dennoch würde das hier nix ändern, da eh direkt auf die Variable zugegriffen wird.

BAMatze 24. Jul 2009 06:48

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Hallo @himitsu und alle anderen natürlich auch,

Gibt es für mich als Anfänger da eine Möglichkeit eine Art Fehleranalyse zu machen, ohne den Quellcode Schritt für Schritt noch einmal durchzugehen (der Debugger an sich bringt mir ja keinen Fehler)? Ich glaube gelesen zu haben, dass es für Speicherlecks etwas in der Art gibt. Leider ist das Programm mittlerweile doch so groß, dass eine direkte Suche ohne Anhaltspunkt sehr lange dauern würde.

Vielen Dank
BAMatze

alzaimar 24. Jul 2009 06:52

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Besorge Dir FastMM, lies Dir die Gebrauchsanweisung gut durch, verwende es und fertig.

BAMatze 24. Jul 2009 07:27

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
@alzaimar: Danke schonmal, dass scheint genau das zu sein, was ich jetzt brauche. habe hier und in Google mal geschaut und folgende 2 Sachen gefunden (FastMM4 von SourceForge und Optionssoftware für FastMM). Allerdings ergeben sich hier noch ein paar Fragen, weil ich gelesen hab, dass FastMM ab D2007 wohl schon der Standardmanager sein soll (kann das aber auch falsch verstanden haben). Zumindest kann man wohl mit:
Delphi-Quellcode:
{$WARN SYMBOL_PLATFORM OFF}
  {$IF RTLVersion > 15.0}
   ReportMemoryLeaksOnShutDown := DebugHook<>0;
  {$IFEND}
{$WARN SYMBOL_PLATFORM ON}
Speicherlecks ohne Installation von FastMM finden/ erkennen. Ich verwende hier auf Arbeit D2007 für Win32 Professional. Muss ich jetzt das FastMM installieren (oder ist es eventuell nicht nötig, weil es ja schon der Standardmanager ist)?

Bernhard Geyer 24. Jul 2009 07:33

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Zitat:

Zitat von BAMatze
Speicherlecks ohne Installation von FastMM finden/ erkennen. Ich verwende hier auf Arbeit D2007 für Win32 Professional. Muss ich jetzt das FastMM installieren (oder ist es eventuell nicht nötig, weil es ja schon der Standardmanager ist)?

Die Sourceforge-Version ist neuern Datums. Schau doch mal was in der Release-Info (FastMM4Options.inc) steht was seit dem Release-Datum von D2007 neues dazu gekommen ist.

himitsu 24. Jul 2009 07:37

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
eine etwas abgespeckte FastMM-Version ist bei dir schon im Delphi drinnen
Codegear hatte den alten DelphiMM durch eine einfachere/schnellere FastMM-Version ersetzt.

falls du dir mit der Version nicht sicher bist, dann geht auch dieses:
Delphi-Quellcode:
{$IF Declared(ReportMemoryLeaksOnShutDown}
  ReportMemoryLeaksOnShutDown := DebugHook <> 0;
{$IFEND}
willst du alle Features (Speicheranalyse, besseren Fehlerreport usw.) nutzen, dann mußt du dir aber ein "vollständiges" FastMM installieren.

Uwe Raabe 24. Jul 2009 07:53

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Zitat:

Zitat von BAMatze
Ich habe schon das OnTischChange := nil gesetzt und trotzdem bleibt assigned(OnTischChange) = false.

Was anderes wäre auch mehr als seltsam!

Events sind Zeiger auf Methoden. Durch die Zuweisung "OnTischChange := <irgendwas>" weist du diesem Zeiger eine Methode zu, bei "OnTischChange := nil" wird auf keine Methode verwiesen. Da Methoden auch Funktionen mit Rückgabewerten sein können, würde ein Vergleich "if OnEvent <> nil then" nicht prüfen, ob OnEvent eine Methode zugewiesen ist, sondern ob das Funktionsergebnis von OnEvent ungleich nil ist. Daher gibt es die Funktion Assigned, die prüft, ob ein Pointer (in diesem Fall eine Methodenzeiger) auf einen (hoffentlich) gültigen Wert zeigt oder nicht. Bei Klassen-Instanzen oder Pointer auf Records oder einfache Typen ist Assigned(P) das Gleiche wie (P <> nil). Bei Methodenzeigern geht das aus oben genannten Gründen nicht.

Und nun sollte auch klar sein, warum nach einem "OnTischChange := nil" natürlich "Assigned(OnTischChange) = false" sein muss.

BAMatze 24. Jul 2009 08:01

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Liste der Anhänge anzeigen (Anzahl: 1)
Jetzt bin ich glaube ich vollends verwirrt :shock:

Hab ebend den von himitsu geposteten Quellcode verwendet Resultat -> keine Fehlermeldung nach Beenden des Programmes *grübel
Vorher hatte ich den von mir geposteten Quellcode drin Resultat siehe Bild im Anhang.

Hab ich da irgendwas übersehen oder falsch gemacht?

@Uwe Raabe: Ah gute Erklärung, danke dir dafür. Das mit dem nil, war auch nur mal ein Versuch und ist nach dem nicht funktionieren gleich wieder aus dem Quellcode geflogen und die Implementierung des Events entspricht somit der oben geposteten Variant und funktioniert leider immer noch nicht. :evil:

himitsu 24. Jul 2009 08:22

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
ups :oops:

$if Declared() und nicht $if Defined()

BAMatze 24. Jul 2009 08:45

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Liste der Anhänge anzeigen (Anzahl: 1)
jupp jetzt funktioniert es.

ist die FastMM4_Readme.txt = Anleitung?

Edit1: ok hab mich jetzt zumindest mal durch alle Anleitungen durchgewurschtelt, die ich hier gefunden hab und auch die Event-Log-Datei erstellt bekommen. Ich glaube gelesen zu haben, dass man diese von unten lesen soll und werde auch versuchen, mittels Auskommentieren, die Probleme zu finden und somit zu beseitigen. Bei einigen Speicherlecks steht ja auch glücklicher Weise drin, wo sie Auftreten, also die Unit.
Hänge mal die Log hier an, vieleicht kann ja mal jemand schauen, ob so ein Fehler drin ist (weiß ja nicht, ob man sowas auf einen Blick erkennt), der mir die Probleme bereitet, die zur Post-Topic gehören.

Vielen Dank
BAMatze

Blup 24. Jul 2009 15:26

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Ich vermute du hast nicht ganz verstanden was Uwe Raabe dir sagen wollte:
Delphi-Quellcode:
if Assigned(OnTischChange) then OnTischChange;
FOnTischChange wird abgerufen und sofort ausgeführt.
Dann wird geprüft ob das nicht vorhandene Funktionsergebnis ungleich nil ist.
Sollte das der Fall sein, wird FOnTischChange erneut abgerufen und ausgeführt.

Delphi-Quellcode:
if Assigned(FOnTischChange) then FOnTischChange;
Es wird geprüft ob FOnTischChange ungleich nil ist.
Sollte das der Fall sein, wird FOnTischChange ausgeführt.

Deshalb führt die erste Variante zur Zugriffsverletzung.

Unabhängig davon würde ich jedem Event immer den Sender mitliefern.

BAMatze 25. Jul 2009 18:45

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Ah ok dann werde ich die Variante auch nochmal testen am Montag. Wobei der Hinweis mit den Speicherlecks und so ja wie ich sehe auch berechtigt war.

Vielen Dank
BAMatze

BAMatze 27. Jul 2009 07:08

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Also hab heute mal beide Varianten nochmal durchprobiert, sowohl:

Delphi-Quellcode:
if assigned(OnTischChange) then OnTischChange;
also auch

Delphi-Quellcode:
if assigned(FOnTischChange) then FOnTischChange;
Bei beiden gibt der Debugger als Wert für FOnTischChange/ OnTischChange eine Zugriffsverletzung bei 00000000 aus. Sieht für mich aus, als wenn er sie gar nicht erzeugt. Hab nochmal direkt in die Komponente, in der ich dieses Event implementieren will geschaut und die dcu-Datei kontrolliert, ob sie im Verzeichnis liegt, wo Delphi drauf zugreift. Das scheint zu passen.

Kann es aber trotzdem sein, dass dort ein Problem mit dem Erzeugen des Events vorliegt?

BAMatze

Edit 1: Der Fehler hat sich gerade erledigt. Habe die Komponente nach dem Motto "keep it simple" in eine leere Form mal gezogen und und das Event getestet. Dort funktioniert es wunderbar. Darauf hin habe ich auch im großen Projekt nochmal die Procedure aus dem Objektinspektor und aus der Deklaration gelöscht. Alles kompilieren lassen, so dass die Event-Prozeduren auch wirklich weg waren und dann nochmal neu erzeugen lassen. Jetzt gibt es keine Probleme und das Event wird so erzeugt, wie ich das möchte. Bleibt eigentlich noch nur die Frage: Ist die Auslösung des Events mit OnTischChange (ist die published Variable) oder FOnTischChange (die private Variable)richtig, auf die OnTischChange eigentlich zurück greift? Denke mal FOnTischChange, sonst könnte man die private Variable ja ganz weg lassen, allerdings bin ich da überhaupt nicht sicher.

Uwe Raabe 27. Jul 2009 07:37

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Zitat:

Zitat von BAMatze
Bleibt eigentlich noch nur die Frage: Ist die Auslösung des Events mit OnTischChange (ist die published Variable) oder FOnTischChange (die private Variable)richtig, auf die OnTischChange eigentlich zurück greift? Denke mal FOnTischChange, sonst könnte man die private Variable ja ganz weg lassen, allerdings bin ich da überhaupt nicht sicher.

Die (meiner Meinung nach) beste Art einen Event auszulösen ist eine eigene Methode (protected oder public), die das erledigt. Da das private Feld FOnTischChange (auf das man sicher nicht verzichten kann, da es den Methodenzeiger speichert!) wäre für abgeleitete Klassen nicht zugänglich - somit könnten diese den Event auch nicht auslösen. Daher:

Delphi-Quellcode:
procedure TTischSteuerung.TischChange;
begin
  if Assigned(FOnTischChange) then FOnTischChange;
end;

BAMatze 27. Jul 2009 08:42

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Das ist schonmal gut zu wissen. Meine Erfahrung besteht ja eigentlich nur daraus, dass ich einige Varianten hier aus der DP genommen hab, die ich gefunden (oder genannt bekommen) habe und dann ausprobiert (wobei meistens noch mindestens so viele Fehler aufgetreten sind, dass ich hier nochmal nachfragen musste). Habe dich jetzt so verstanden, dass ich meine Komponente wie folgt abändern sollte:

Delphi-Quellcode:
Type TTischsteuerung = class(TWinControl)
  private
    ...
    //Variablen für Events
    FOnTischChange: TOnTischChange;
    ...
  protected
    //Events
    // OnTischChange soll dem Programm die Möglichkeit geben alle Eigenschaften auf den
    // ausgewählten Tisch auszurichten.
    property OnTischChange: TOnTischChange read FOnTischChange write FOnTischChange;
    ...
  published
    ...
  public
    //alternativ könnte auch die property OnTischChange hier aufgeführt sein
    ...
end;

// Rest wie am Anfang des Threats, außer dass if assigned(OnTischChange) then OnTischChange; in if assigned(FOnTischChange) then FOnTischChange; geändert wird

TheReaper 27. Jul 2009 11:14

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Zitat:

Zitat von BAMatze
Das ist schonmal gut zu wissen. Meine Erfahrung besteht ja eigentlich nur daraus, dass ich einige Varianten hier aus der DP genommen hab, die ich gefunden (oder genannt bekommen) habe und dann ausprobiert (wobei meistens noch mindestens so viele Fehler aufgetreten sind, dass ich hier nochmal nachfragen musste). Habe dich jetzt so verstanden, dass ich meine Komponente wie folgt abändern sollte:

Naja, falsch ist es nicht aber auch nicht wirklich richtig. Ich nutze immer eine do-Procedur um events zu triggern. Außerdem sollte Immer der Sender mit angegeben werden.
Delphi-Quellcode:
{$M+}

TOnTischChange = procedure(Sender: TObject) of object;

Type TTischsteuerung = class(TWinControl)
  private
    ...
    //Variablen für Events
    FOnTischChange: TOnTischChange;
    ...
  protected
    // die event auslöser
    procedure doTischChange;  
    ...
  published
    property OnTischChange: TOnTischChange read FOnTischChange write FOnTischChange;
    ...
  public
    //alternativ könnte auch die property OnTischChange hier aufgeführt sein
    ...
end;

procedure TTischsteuerung.doTischChange;
begin
  if Assigned(FOnTischChanged) then
    FOnTischChanged(self);
end;

procedure TTischsteuerung.foo
begin
  ...
  // Event(s) auslösen
  doTischChange;
  ...
end;
Das Ganze sieht erstmal etwas komplizierter aus aber es bringt viele Vorteile beim erweitern oder debuggen. Außerdem macht es Borland genauso. :-D

Optiplex 27. Jul 2009 11:45

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
möchte mich mal kurz hier einklinken, hoffe dass ich damit nicht gegen eine Regel verstoße.

warum verwendet ihr
Delphi-Quellcode:
TOnTischChange = procedure(Sender: TObject) of object;
für den Event und nicht TNotifyEvent

Danke und Gruß Dieter

TheReaper 27. Jul 2009 12:16

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Zitat:

Zitat von Optiplex
möchte mich mal kurz hier einklinken, hoffe dass ich damit nicht gegen eine Regel verstoße.

warum verwendet ihr
Delphi-Quellcode:
TOnTischChange = procedure(Sender: TObject) of object;
für den Event und nicht TNotifyEvent

Danke und Gruß Dieter

Weil es hier nur um das Prinzip von Events geht und TNotifyEvent und ähnliches steht nicht zum Thema. :wink:

Uwe Raabe 27. Jul 2009 12:58

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Die Version von TheReaper ist genau richtig! Das mit dem Sender ist zwar nicht notwendig, aber sinnvoll - somit kann dann der Event-Handler feststellen, wer den Event ausgelöst hat, wenn er sich bei mehreren eingeklinkt hat. Die Namensgebung von DoTischChange ist reine Geschmacksache, aber nicht unüblich.

BAMatze 27. Jul 2009 19:20

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
Ok dann danke ich auf jeden Fall für die Antworten, werde das auf jeden Fall so umsetzen, wie ihr das mir hier ratet. Ich denke auch, dass ich das auslösen von Events mal so gesehen hab, wie ihr das hier nochmal geschrieben habt. Leider hatte ich damals die DCU-Dateien immer in die Projektordner gepackt und nicht bei jeder Änderung immer kopiert. Deswegen hat das nicht richtig funktioniert und ich habe es geändert und irgendwann mal die DCU nachgepackt, was dann zu der verwurschtelten Version von mir führte.
Wo wir aber das Thema schonmal angesprochen haben, habe auch die ein oder andere TNotifyEvent im Projekt drin. Wo liegen denn die Unterschiede? sollte ich nur eins von beiden nehmen? oder gibt es Vorteile des ein oder anderen?

BAMatze 3. Aug 2009 10:08

Re: Event-Typen und warum deren Inhalte manchmal nicht stimm
 
So benutze diesen Post mal als kleines Danke schön, da es das wie es scheint erste zu einer 4- oder 5-reihigen FastMM-Frage-Serie gehört. Es hat zwar einiges an Arbeit gekostet, die ganzen Speicherlecks (derzeit waren es 105) zu suchen und zu beseitigen aber mit der großen Hilfestellung die mir hier geboten wurde bei der Suche und Lösung, denke ich mal ist 3,5 Tage Zeitinvestition für einen Anfänger nicht schlecht. Das hier gepostete Problem hat sich erfolgreich gelöst, nachdem ich die formal richtige Lösung, die hier gepostet wurde, umgesetzt war.

Ich Liste mal hier kurz die Threats auf, die sich damit erledigt haben (auch in der Erkenntnis, dass immer noch Lecks vorhanden sein können, die sich noch aufgrund von nicht Benutzung mir noch nicht erschließen).

Hilfe bei Speicherleckbeseitigung
Komponente verursacht Fehler bei beenden von Delphi/ Projekt
[FastMM] Free einer Klasse verhält sich unterschiedlich

und noch der ein oder andere Threat, den ich ebend vergessen hab :-D

Vielen Dank an euch :bounce1: :dp: :bounce1:
BAMatze


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:36 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz