Einzelnen Beitrag anzeigen

berens

Registriert seit: 3. Sep 2004
434 Beiträge
 
Delphi 10.4 Sydney
 
#1

TNotifyEvent Objektbezogen in Variable speichern #2

  Alt 16. Jan 2012, 14:17
Delphi-Version: 2010
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!
  Mit Zitat antworten Zitat