Hallo zusammen!
Ich hoffe, es ist laut den Regeln wunschgemäß, für eine weiterführende Frage zum selben Thema nach solch langer Zeit einen neuen Thread anzufangen.
Dabei beziehe ich mich hier auf mein vorhergehendes Thema
http://www.delphipraxis.net/139677-t...speichern.html , bei dem jetzt doch (immer noch) ein Problem aufgetreten ist.
In dem unten aufgeführen Beispiel geht das darum, dass alle dynamisch erzeuten TMeinButton "in einem Rutsch" gedrückt werden sollen. Da sich die ausgeführten Prozeduren "Pressed" bzw. "OnClick" -trotz gleicher Komponente- von Button zu Buton unterschiedlich verhalten können (je nach Variable etc.), will ich natürlich in diesem Beispiel
jeden Button
genau einmal drücken, und nicht einfach nur das TMeinButton.Pressed Event 2x auslösen.
Die Buttons verstehen sich hier bitte nur als Sinnbild für viele verschiedene Komponenten, die alle eine TNotifyEvent Prozedur anbieten. Da ich bei Register nur das TNotifyEvent der Instanz einer Komponente übergebe, hoffe ich ansich, dass das auch funktioniert.
Ich könnte mir denken, dass die korrekte Implementierung nur und ausschließlich sich über Interfaces durchführen lässt, aber aus meiner laienhafen Sicht halte ich persönlich das für mit Kanonen nach Spatzen geschossen.
Da dieses Beispiel generell funktioniert, denke ich, dass das Problem wirklich mit dem Pointer-Problem zu tun hat:
"Blup" schrieb in seinem letzten Beitrag
Zitat:
Auch in der Funktion "IndexOfEvent" hat das @ nichts zu suchen.
Wenn ich beide @ dort entferne, kompiliert er nicht: "if THAL_ObserverItem(FListSubscriber[i]).Event = _Event then" --> "[DCC Fehler] Unit2.pas(121): E2035 Nicht genügend wirkliche Parameter"
Also mal angenommen, meine Ziele lassen sich generell mit dieser Technik erreichen, gibt es einige Fragen und Probleme:
1) Wenn ich RegisterEvent(b.Pressed) aufrufe, schlägt dies fehl, da IndexOfEvent(_Event)
> -1 ( = also bereits vorhanden) ist. Darf ja so nicht sein.
2) Warum ist das so?
3) Wie korrigiert man das?
Delphi-Quellcode:
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, contnrs;
// Aufgabenstellung: Alle dynamisch erzeuten TMeinButton sollen "in einem Rutsch" gedrückt werden
type
// Sinnbild für irgendeine Komponente, die zurückgerufen werden soll
// In diesem Fall soll einfach der Button gedrückt werden
TMeinButton =
class(TButton)
public
procedure Pressed(Sender: TObject);
end;
// Hilfsobjekt, um das TNotifyEvent zu speichern
THAL_ObserverItem =
class(TObject)
public
Event: TNotifyEvent;
end;
TForm2 =
class(TForm)
Button1: TButton;
// dieser Button soll alle dynamisch erzeugten TMeinButton "in einem Rutsch" drücken
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
FListSubscriber: TObjectList;
// hier werden die TNotifyEvent (über Hilfsobjekt THAL_ObserverItem) gespeichert
function IndexOfEvent(_Event: TNotifyEvent): Integer;
// wurde das Event bereits in der Liste gespeichert? < 0 bedeutet Nein; >= 0 bedeutet Ja
public
a, b: TMeinButton;
procedure RegisterEvent(_Event: TNotifyEvent);
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
{$o-}
procedure TMeinButton.Pressed(Sender: TObject);
begin
// Einfach den Komponentennamen anzeigen, damit man weiß,
// welche Instanz von TMeinButton gedrückt wurde
ShowMessage(
Name);
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
FListSubscriber := TObjectList.Create;
// Die Liste für die Callback-Prozeduren
a := TMeinButton.Create(Self);
with a
do begin
Name := '
Button_A';
Left := 10;
Top := 10;
Parent := Self;
OnClick := a.Pressed;
// Beim Klick erscheint also "Button_A"
end;
b := TMeinButton.Create(Self);
with b
do begin
Name := '
Button_B';
Left := 10;
Top := 100;
Parent := Self;
OnClick := b.Pressed;
// Beim Klick erscheint also "Button_B"
end;
RegisterEvent(a.Pressed);
RegisterEvent(b.Pressed);
end;
procedure TForm2.RegisterEvent(_Event: TNotifyEvent);
var
tmp: THAL_ObserverItem;
begin
// Mein Ziel: Wenn von GENAU DIESEM Object (a.Pressed, b.Pressed),
// GENAU DIESES Event noch nicht in der Liste ist,
// dann der Liste hinzufügen
if IndexOfEvent(_Event) = -1
then begin
tmp := THAL_ObserverItem.Create;
// Hilfsobjekt erzeugen
tmp.Event := _Event;
// Callback-Prozedur übergeben
FListSubscriber.Add(tmp);
// Hilfsobjekt in Liste aufnehmen
end;
end;
procedure TForm2.Button1Click(Sender: TObject);
var
i: integer;
begin
// Alle Subscriber benachrichtigen
for i := 0
to FListSubscriber.Count - 1
do begin
THAL_ObserverItem(FListSubscriber.Items[i]).Event(Self);
end;
// In meinem Beispiel ist mein Ziel dass das dann später so abläuft:
// a.Pressed(Self);
// b.Pressed(Self);
end;
function TForm2.IndexOfEvent(_Event: TNotifyEvent): Integer;
var
i: Integer;
begin
Result := -1;
// Siehe Oben: Mein Ziel: Wenn von GENAU DIESEM Object (a.Pressed, b.Pressed),
// GENAU DIESES Event gefunden wird, dann gebe dessen Index zurück
// wird bei RegisterEvent(a.Pressed) NICHT durchlaufen, da hier FListSubscriber.Count noch 0 ist!
for i := 0
to FListSubscriber.Count - 1
do begin
if @THAL_ObserverItem(FListSubscriber[i]).Event = @_Event
then
// ^-- HIER ist das Hauptproblem: Sei _Event = b.Pressed ergibt der Vergleich True, obwohl bisher nur a.Pressed in der Liste ist!
begin
Result := i;
Exit;
end;
end;
end;
end.
Vielen Dank für Eure Hilfe!