![]() |
Events in einer Liste: TEventList
Wie kann man Events in einer Liste speichern?
Manchmal möchte man beliebig viele Eventhandler mit einem Event verknüpfen. Wem jetzt konkret kein Beispiel einfällt, der denke an folgende Konstellation: Um bei einer Grafikengine die Auflösung ändern zu können muss man meistens die gesammte Engine "Runterfahren" und dann wieder "Hochfahren", was das komplette freigeben und wieder erstellen der Engine zur folge hat. Problem ist, dass dabei auch alle Texturdaten verloren gehen. Dabei wäre es doch praktisch wenn beim Finalisieren automatisch alle Texturobjekte dies mitbekommen und dabei noch ihre Daten sichern können und beim Initialisieren diese wieder in die Engine "hineinschieben". Dies kann mann über eine so genannte "Event-Liste" lösen. Allerdings müssen wir zwei Fälle unterscheiden:
Beginnen wir zunächst mit dem einfacheren, der Liste mit Prozedurzeigern: Eigentlich ist das Unterfangen ganz einfach. Man muss jedoch beachten, nur die Adressen auf die Methoden in der Liste zu speichern. Das Interface schaut folgendermaßen aus:
Delphi-Quellcode:
Sieht eigentlich wie eine normale typensichere Liste aus.
type
TMyEvent = procedure; //Die Prozedur darf frei herum stehen --> Einfacher Prozedur-, Funktionzeiger TMyEventList = class(TList) private function GetItem(AIndex:integer):TMyEvent; procedure SetItem(AIndex:integer;AItem:TMyEvent); protected public property Items[AIndex:integer]:TMyEvent read GetItem write SetItem;default; end; Die Implementierung:
Delphi-Quellcode:
Wie man sieht, wird jeweils nur die Adresse der Methode in der Liste gespeichert.
function TMyEventList.GetItem(AIndex:integer):TMyEvent;
begin @result := inherited Items[AIndex]; end; procedure TMyEventList.SetItem(AIndex:integer;AItem:TMyEvent); begin inherited Items[AIndex] := @AItem; end; Einfügen von Events in die Liste:
Delphi-Quellcode:
EventList.Add(@MyEventHandler);
Aufrufen von Events aus der Liste:
Delphi-Quellcode:
Schwieriger wird es mit der Liste auf Methodenzeiger:
EventList.Items[i](ggf, die, Parameter);
Erst das Interface:
Delphi-Quellcode:
Und jetzt die Implementierung:
type
TMyEvent = procedure of object; //Die Prozedur ist Teil eines Objekts --> Methodenzeiger PMyEvent = ^TMyEvent; TMyEventList = class(TList) private function GetItem(AIndex:integer):TMyEvent; procedure SetItem(AIndex:integer;AItem:TMyEvent); protected procedure Notify(Ptr: Pointer; Action: TListNotification);override; public property Items[AIndex:integer]:TMyEvent read GetItem write SetItem;default; procedure Add(Item:TMyEvent); procedure Remove(Item:TMyEvent); end;
Delphi-Quellcode:
Hier reicht es nich einfach nur den Pointer der Liste hinzuzufügen, da der Methodenzeiger eigentlich wie ein Record aufgebaut ist.
{ TMyEventList }
procedure TMyEventList.Add(Item: TMyEvent); var Event:PMyEvent; begin New(Event); Event^ := Item; inherited Add(Event); end; function TMyEventList.GetItem(AIndex:integer):TMyEvent; begin result := PSurfaceEvent(inherited Items[AIndex])^; end; procedure TMyEventList.Notify(Ptr: Pointer; Action: TListNotification); begin if Action = lnDeleted then begin Dispose(Ptr); end; inherited; end; procedure TMyEventList.Remove(Item: TMyEvent); var i:integer; begin i := 0; while i < Count do begin if (TMethod(Items[i]).Code = TMethod(Item).Code) and (TMethod(Items[i]).Data = TMethod(Item).Data) then begin Delete(i); end; i := i + 1; end; end; procedure TMyEventList.SetItem(AIndex:integer;AItem:TMyEvent); begin inherited Items[AIndex] := @AItem; end; Das hinzüfungen von Elementen geschieht folgendermaßen:
Delphi-Quellcode:
Und das aufrufen:
EventList.Add(Event);
Delphi-Quellcode:
EventList.Items[i](ggf,die,parameter);
Wie immer viel Spaß mit dem Code! igel457 Suchbegriffe: Eventlist, Events in Liste, TNotifyEvent, TEventlist, Eventlist, Methodenzeiger |
Re: Events in einer Liste: TEventList
Zitat:
|
Re: Events in einer Liste: TEventList
Hm...
Du hast recht, meistens gibt es einen anderen, objektorientierten Ansatz mit dem das Ganze besser funktioniert. In meinem Fall habe ich jedoch folgendes Problem: Ich habe eine Prozedur mit der ich Delphi Objekte auf den Stack der Scriptsprache Lua schieben kann (PushObject). Dazu verwende ich die RTTI. Allerdings habe ich ein Problem mit dem Pushen von Methoden, da ich die Parameter über RTTI nicht herausfinden kann (wenn ich mich irre sagt es mir, wäre nämlich cool). Allerdings möchte ich auch TObject Pushen können, weshalb ein objektorentierter Ansatz (über Vererbung) ausscheidet. (Ich könnte schließlich alle Objekte die ich Pushen will von einer gemeinsamen Basisklasse ableiten, die eine Prozedur hat, die ihre Prozeduren auf dem Stack schiebt.) Nun habe ich mir überlegt, dass meine "PushObject" Methode ein Event auslöst ("OnPushObject"). So kann ich einfach eine Unit schreiben, die sich mit diesem Event verknüpft und demnach Prozeduren der Objekte auf den Stack schiebt. Allerdings sind es mittlerweile so viele Objekte die ich Pushen will, sodass ich sie nach Themenbereichen aufteilen will. Die Game-Settings-Lua Wrapper kommt in die "Settings.pas", der Wrapper für meine "DXComponents" kommt in die "DXLua.pas". Deshalb benötige ich mehr als einen Eventhandler. Puh. Ich hoffe das war verständlich (mein Standardsatz nach solch langen Beiträgen). Igel457 |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:22 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