Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Mehrfachbehandlung von Events (https://www.delphipraxis.net/185112-mehrfachbehandlung-von-events.html)

Delbor 16. Mai 2015 11:13

Delphi-Version: XE4

Mehrfachbehandlung von Events
 
Hi zusammen

Hintergrund ist: Ich habe mehrere Frames, die miteinander über Events kommunizieren:
  1. Ein ToolboxFrame enthält diverse Buttons zum kopieren, einfügen, löschen etc.
  2. Mehrere Frames mit jeweils einem Synedit
Erstmal bin ich davon ausgegangen, dass ein abgefeuerter Event von verschiedenen Empfängern gleichzeitig abgefangen werden können. Zum Beispiel feuert der ToolboxFrame einen Event, um der Anwendung mitzuteilen, dass ein Button geklickt wurde. Ein Syneditframe regiert darauf und kopiert Text des Syneedits; gleichzeitig reagiert die Mainform, indem sie diie Darstellung der Sidebar anpasst (zum Bleistift den Inhalt der Zwischenablage anzeigt).
Ausgehend von dieser Annahme war ich der Meinung, dass verschiedene, auch vedeckte(weil auf verschiedenen Tabsheets), SyneditFrames auf diesen Event aus dem Toolboxframe reagieren würden. Das wäre sehr problematisch gewesen. Zum Glück haben mich dieser Thread und eigene Tests davon überzeugt, dass dem anders ist - der Test hat ergeben, dass nur gerade der Frame auf dem ActiveTabsheet auf das Event reagiert, auch wenn der Eventhandler mehrfach vorhanden ist.
Soweit, so gut, es funktioniert so, wie ich will - oder eben doch nicht ganz so gut, da ich im Moment nicht wirklich nachvollziehen kann, weshalb dies so ist.Hier mal einige meiner beteiligten Events:
Delphi-Quellcode:
procedure TToolBoxWebFrame.TLB_CopyClick(Sender: TObject);
  var Event: String;
begin
  if Assigned(FCopyOnClipBoard) then begin  //procedure DoCopyOnClipBoard(Event: String);
    Event := 'TLB_CopyClick';
    FCopyOnClipBoard(Event);
    TLB_Einfuegen.Enabled := True;
    TLB_Ausschneiden.Enabled := True;
    TLB_Copy.Enabled:= False;
  end;
end;
Obiger Event könnte ein simpler TNotifyevent sein, zur Kontrolle wollte ich aber einen Parameter mitgeben, der mir die Quelle im Synedit ausgibt, da ich in Eventprogrammmierung noch nicht wirklich sattelfest bin..
Der Eventhandler im Syneditframe:
Delphi-Quellcode:
procedure THTMLFrame.DoCopyOnClipBoard(const Event: String);
begin
   if SynEdit1.SelText.Length > 0  then begin
       SynEdit1.CopyToClipboard;
   end;
   SynEdit1.Lines.Add(Event);
end;
Ausserdem:
Delphi-Quellcode:
procedure THTMLFrame.SynEdit1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Synedit1.SelText <> '' then begin
    if assigned(FOnSelectText) then    
      FOnSelectText(Self);            
  end;
end;
und der Eventhandler:
Delphi-Quellcode:
procedure TToolBoxWebFrame.DoOnSelectText(Sender: TObject);
begin
Self.TLB_Copy.Enabled := True;
Self.TLB_Ausschneiden.Enabled := True;
end;
Und natürlich, um es nicht zu vergessen:
Delphi-Quellcode:
{***************************************************************************}
procedure TDelborWebServerMain.FormCreate(Sender: TObject);
  var Event: String;
begin
  SideBarWebFrame1.FileTreeFrame1.OnFileFound := DoOnFileFound;
  ToolBoxWebFrame1.OnPCtrlActivePage := DoOnPCtrlActivePage;
  SideBarWebFrame1.FileTreeFrame1.OnPathlist := DoOnPathList;

  ManageEvents;
end;

procedure TDelborWebServerMain.ManageEvents;
begin
  ToolBoxWebFrame1.OnCutOnClipBoard := SynEditFrame1.DoCutOnClipBoard;
  ToolBoxWebFrame1.OnCopyOnClipBoard := SynEditFrame1.DoCopyOnClipBoard;
  ToolBoxWebFrame1.OnPasteFromClipBoard := SynEditFrame1.DoPasteFromClipBoard;
  ToolBoxWebFrame1.OnOnSafe := SynEditFrame1.DoOnSafeSynedit;
  ToolBoxWebFrame1.OnOnOpen := SynEditFrame1.DoOnOpenSynedit;
  ToolBoxWebFrame1.OnOnNew := SynEditFrame1.DoOnNewSynedit;
  SynEditFrame1.OnSelectText := ToolBoxWebFrame1.DoOnSelectText;
end;
Im Moment nachvollziehbar ist: das Frame auf dem ActiveTabsheet ist wegen seines Parenmts Enabled und kann deshalb das Event empfangen; die Edits auf den andern Tabsheets sind nicht enabled und deren Eventhandler desshalb nicht assigned. Soweit so gut?

Nun kommt aber die Sache mit der Liste aus dem verlinkten Thread ins Spiel:
Zitat:

Du brauchst eine "Liste" von solchen Zeigern

TList<TBarcodeEvent>

Und da kann man via Add was hinzufügen und per Remove wieder entfernen.
Ok, die Liste gehört dahin, wo gefeuert wird
Hier die Eventtypen, die in meinem ToolbarFrame definiert sind (wie schon gesagt: alle könnten auch TNotifyEvent sein):
Delphi-Quellcode:
type
  TCutOnClipBoard = procedure(const Event: string)of object;
  TCopyOnClipBoard = procedure(const Event: string) of object;
  TPasteFromClipBoard = procedure(const Event: string) of object;
  TOnSafe = procedure(const Event: string) of object;
  TOnOpen = procedure(const Event: string) of object;
  TOnNew = procedure(const Event: string) of object;
Wenn ich das mit der Liste richtig verstanden habe, müsste eine solche nun für jeden Typen, der von mehreren Zielen/Eventhandlern empfangen werden soll, eine solche Liste anlegen.
Und da ist nun mein gordischer Knoten: In der Liste sind die Eventtypen mehrfach aufgelistet, aber diese Typen kennen ja ihr Ziel nicht??
Oder hab ich jetzt die Antwort gefunden: ein abgefeuertes Event kann genau von einem Eventhandler behandelt werden und muss deshalb per Liste mehrmals abgefeuert werden?

Gruss
Delbor

jaenicke 16. Mai 2015 12:36

AW: Mehrfachbehandlung von Events
 
Ja, genau. Das nennt sich Multicastevent. Ich habe dafür eine von TList<T> abgeleitete generische Klasse gebaut, die die registrierten Eventhandler dann alle auslöst.

Ich schreibe auf der Autobahn im Auto, ein Beispiel folgt bei Bedarf später...

himitsu 16. Mai 2015 13:17

AW: Mehrfachbehandlung von Events
 
Als Fahrer? :shock:

Aber im Notfall gibt es hier und da auch schon mehrere Beispiele zum finden. (bin mir fast sicher, daß es das schon mehrmals in der DP gibt, wenn man nach dem Begriff sucht)


@Captnemo: Er fährt bestimmt ein Googleselbstfahrauto. :zwinker:

Captnemo 16. Mai 2015 13:19

AW: Mehrfachbehandlung von Events
 
Zitat:

Zitat von jaenicke (Beitrag 1301720)
Ich schreibe auf der Autobahn im Auto, ein Beispiel folgt bei Bedarf später...

Ich hoffe mal du fährst nicht selber, denn so wichtig kann keine Antwort sein, dass man das Risiko eingehen sollte.

Rollo62 17. Mai 2015 09:58

AW: Mehrfachbehandlung von Events
 
Schau doch mal bei Spring4D nach ...
Da gibt es soetwas unter anderem.

Rollo

Dejan Vu 17. Mai 2015 14:10

AW: Mehrfachbehandlung von Events
 
Zitat:

Zitat von Delbor (Beitrag 1301717)
Ok, die Liste gehört dahin, wo gefeuert wird

Wieso? Dann muss ja in Zukunft jede Klasse, die Multicast unterstützen soll, deine Logik nochmal implementieren. Schreib Dir doch lieber einen einzigen Multicasteventcontroller.
Derjenige, der etwas (ein Event) mitzuteilen hat, meldet sich und den Eventtyp beim Controller an.
Diejenigen, die benachrichtigt werden wollen, melden sich und den Eventtyp, über den sie benachrichtigt werden wollen, ebenfalls dort an. So hast Du eine lose Bindung und eine einzige Klasse, die alle Events verwaltet.

jaenicke 17. Mai 2015 15:08

AW: Mehrfachbehandlung von Events
 
Zitat:

Zitat von himitsu (Beitrag 1301722)
Als Fahrer? :shock:

Nein, ich habe nicht einmal einen Führerschein. ;-)

Ich habe einfach das nicht als Eventcontroller implementiert, sondern lieber die Liste entsprechend. Sprich:
Delphi-Quellcode:
public
  property OnTest: TMulticastEvent<T> read FOnTest;

...

  Example.OnTest.Add(procedure(const ATest: string)
    begin
      ...
    end);

Stevie 17. Mai 2015 17:38

AW: Mehrfachbehandlung von Events
 
Zitat:

Zitat von Dejan Vu (Beitrag 1301816)
Zitat:

Zitat von Delbor (Beitrag 1301717)
Ok, die Liste gehört dahin, wo gefeuert wird

Wieso? Dann muss ja in Zukunft jede Klasse, die Multicast unterstützen soll, deine Logik nochmal implementieren. Schreib Dir doch lieber einen einzigen Multicasteventcontroller.
Derjenige, der etwas (ein Event) mitzuteilen hat, meldet sich und den Eventtyp beim Controller an.
Diejenigen, die benachrichtigt werden wollen, melden sich und den Eventtyp, über den sie benachrichtigt werden wollen, ebenfalls dort an. So hast Du eine lose Bindung und eine einzige Klasse, die alle Events verwaltet.

Wo ist das Smiley mit Kreuz, Knoblauch und Pflock, wenn man es braucht? :P
Das klingt mir aber sehr nach einem Singleton - ne tolle lose Binding :shock:
Und EDA braucht man für diesen Anwendungsfall eher nicht.

Dejan Vu 17. Mai 2015 17:46

AW: Mehrfachbehandlung von Events
 
Wie kommst Du auf Singleton? :gruebel:

Stevie 17. Mai 2015 17:51

AW: Mehrfachbehandlung von Events
 
Zitat:

Zitat von Dejan Vu (Beitrag 1301840)
Wie kommst Du auf Singleton? :gruebel:

Hab ich einfach mal so angenommen (immerhin macht es System.Messaging so vor) - aber ok, kein Singleton. Und wie wissen nun Producer und Consumer von diesem "einen einzigen Multicasteventcontroller"?

Sir Rufo 17. Mai 2015 18:48

AW: Mehrfachbehandlung von Events
 
Zitat:

Zitat von Stevie (Beitrag 1301841)
Zitat:

Zitat von Dejan Vu (Beitrag 1301840)
Wie kommst Du auf Singleton? :gruebel:

Hab ich einfach mal so angenommen (immerhin macht es System.Messaging so vor) - aber ok, kein Singleton. Und wie wissen nun Producer und Consumer von diesem "einen einzigen Multicasteventcontroller"?

Wo ist denn bei System.Messaging ein Singleton? :gruebel:

Ja, es gibt eine Default-Instanz für den Anwendungs-Kontext, aber man kann sich soviele eigene Messenger erzeugen, wie man möchte, das spricht ja gegen Singleton.

Stevie 17. Mai 2015 20:49

AW: Mehrfachbehandlung von Events
 
Zitat:

Zitat von Sir Rufo (Beitrag 1301847)
Zitat:

Zitat von Stevie (Beitrag 1301841)
Zitat:

Zitat von Dejan Vu (Beitrag 1301840)
Wie kommst Du auf Singleton? :gruebel:

Hab ich einfach mal so angenommen (immerhin macht es System.Messaging so vor) - aber ok, kein Singleton. Und wie wissen nun Producer und Consumer von diesem "einen einzigen Multicasteventcontroller"?

Wo ist denn bei System.Messaging ein Singleton? :gruebel:

Ja, es gibt eine Default-Instanz für den Anwendungs-Kontext, aber man kann sich soviele eigene Messenger erzeugen, wie man möchte, das spricht ja gegen Singleton.

Dann grep doch mal den FMX Code durch, ob da jemals eine Instanz von TMessageManager erzeugt wird, oder ob nicht an allen knapp 200 Stellen TMessageManager.DefaultManager genutzt wird. Wenn man nämlich ne selbsterzeugte Instanz benutzt, dann müsste man sie ja irgendwo in die beteiligten Akteure übergeben (Stichwort Dependency Injection). Nur leider passt das ja nicht so ganz zu der TComponent Architektur, gell?

Zeig mir doch mal Code, wo TComponents mit einer injekteten TMessageManager Instanz arbeiten und das einfacher zu nutzen ist, als nen multicast event.

Sir Rufo 17. Mai 2015 21:13

AW: Mehrfachbehandlung von Events
 
Ahm, ja, aber das ist doch auch ok so, denn wenn ich etwas von der Anwendung mitbekommen möchte, dann klinke ich mich in den einen Messenger ein. Wie gesagt, dieser DefaultManager ist für den Anwendungs-Kontext. Da laufen zentral die internen Nachrichten drüber (Form erzeugt, Anwendung idle, ...)

Aber ist das schlimm?

Ich denke wir reden aneinander vorbei, denn diesen System.Messenger würde ich nicht für die Events benutzen von denen wir hier eigentlich sprechen wollten. Dafür baut man sich eine Struktur - so wie in Spring4D - und baut diese in die Klassen mit ein.

Stevie 18. Mai 2015 01:14

AW: Mehrfachbehandlung von Events
 
Du nicht, aber Dejan Vu, so wie ich #6 verstanden habe.

Dejan Vu 18. Mai 2015 07:49

AW: Mehrfachbehandlung von Events
 
Du meinst, das das eine blöde Idee war? Immerhin, es war Sonntag, out of office, Postvatertagnachwirkungsgehirnabsenkung. Aber immerhin. Eine Idee. :stupid:


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:18 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 by Thomas Breitkreuz