Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Komponentenentwicklung - Event weiterleiten - Denkfehler? (https://www.delphipraxis.net/190360-komponentenentwicklung-event-weiterleiten-denkfehler.html)

Aviator 27. Sep 2016 13:50

Komponentenentwicklung - Event weiterleiten - Denkfehler?
 
Hallo Delphianer,

ich bin gerade dabei mir für einen ganz speziellen Fall eine Komponente zu basteln. Dabei bin ich auf ein Problem gestoßen für das ich aktuell keine Lösung kenne und auch nur bedingt etwas im Internet (auch bei der DP) gefunden hatte. Die vorhandenen Threads zu dem Thema haben mir leider nicht so wirklich weitergeholfen.

Nun hoffe ich, dass ihr das könnt. :)


Folgendes Szenario:

Ich habe folgende Klasse (allgemeingehaltene Namen zur besseren Übersicht):

Delphi-Quellcode:
TFoo = class(TCustomControl)
private
  FSomeVar: TSomeType;
protected
  procedure WM_Paint(var Msg: TMessage) message WM_PAINT;
public
  property OnGetSubComponents;
end;

Delphi-Quellcode:
TFooBar = class(TCustomControl)
private
  FSomeVar: TFoo;
protected
  procedure WM_Paint(var Msg: TMessage) message WM_PAINT;
end;

Delphi-Quellcode:
TBar = class(TCustomControl)
private
  FSomeVar: TFooBar;
protected
  procedure WM_Paint(var Msg: TMessage) message WM_PAINT;
public
  property OnGetSomeData;
end;
Jetzt habe ich das Problem, dass ich auf den Klick auf die TFoo Komponente reagieren können muss. Die einzige Möglichkeit die ich jetzt kennen würde wäre, das Event durchzuschleifen. Also in jeder Klasse ein
Delphi-Quellcode:
ObGetSubComponents
Event erstellen und dann den Weg
Delphi-Quellcode:
TFoo (Auslöser) --> TFooBar --> TBar
durchlaufen.

Irgendwie kommt mir das aber falsch vor.

Die andere Möglichkeit wäre, dass ich (hier geht es um eine Mausklickfunktion) die Mausposition bspw. auswerte und dann errechne wo ich bin. Aber die Subkomponente selbst bietet das ja schon durch die WM_LBUTTONDOWN Message an, sodass ich da eben gar nix mehr machen müsste.

Habe ich jetzt einen grundlegenden Denkfehler wie meine Klassen aufgebaut sind, oder gibt es genau hierfür schon bestimmte Lösungsansätze? Wie macht ihr das wenn ihr unterschiedliche Komponenten ineinander verschachteln müsst?

Bin über jeden Lösungsvorschlag dankbar. Falls noch Informationen fehlen sollten, dann kann ich die gerne zur Verfügung stellen.

stahli 27. Sep 2016 13:59

AW: Komponentenentwicklung - Event weiterleiten - Denkfehler?
 
Kannst Du die Fragestellung nochmal anders formulieren?

Du hast 3 verschachtelte Controls und möchtest wie reagieren, wenn das innerste geklickt wird?

Warum reagierst Du nicht auf OnClick oder OnMouseDown?

Aviator 27. Sep 2016 14:02

AW: Komponentenentwicklung - Event weiterleiten - Denkfehler?
 
Zitat:

Zitat von stahli (Beitrag 1348953)
Warum reagierst Du nicht auf OnClick oder OnMouseDown?

Du hast das Problem denke ich schon richtig verstanden. Ich habe eben diverse Events die beim Klick auf die innerste Komponente ausgelöst werden sollen. Meine GUI Klasse kann aber nur die Events der äußersten Komponente abonnieren. Nicht aber die der innersten. Und jetzt wäre die Frage, wie ich auf bspw. die OnClick oder auch meine speziellen Events der innersten Komponente reagieren kann.

Neutral General 27. Sep 2016 14:09

AW: Komponentenentwicklung - Event weiterleiten - Denkfehler?
 
Ja gut, dann musst du wirklich in der innersten Komponente im Event ein Event feuern und das nach oben leiten bis zu TBar und dann zum User.
Finde ich aber besser als irgendwo irgendwelche Koordinaten abzufragen oder sowas..
Delphi-Quellcode:
TFoo = class(TCustomControl)
private
  FSomeVar: TSomeType;
protected
  procedure WM_Paint(var Msg: TMessage) message WM_PAINT;
public
  property OnGetSubComponents;
  property OnButtonClick: TNotifyEvent read FOnButtonClick write FOnButtonClick;
end;

procedure TFoo.Button1Click(Sender: TObject);
begin
  if Assigned(FOnButtonClick) then
    FOnButtonClick(Sender);
end;

// TFooBar

TFooBar = class(TCustomControl)
private
  FSomeVar: TFoo;
protected
  procedure WM_Paint(var Msg: TMessage) message WM_PAINT;
  property OnButtonClick: TNotifyEvent read FOnButtonClick write FOnButtonClick;
end;

constructor TFooBar.Create()
begin
  FSomeVar.OnButtonClick := InternalButtonClick;
end;

procedure TFooBar.InternalButtonClick()
begin
  if Assigned(FOnButtonClick) then
    FOnButtonClick(Sender);
end;

// TBar

TBar = class(TCustomControl)
private
  FSomeVar: TFooBar;
protected
  procedure WM_Paint(var Msg: TMessage) message WM_PAINT;
public
  property OnGetSomeData;
end;

constructor TBar.Create()
begin
  FSomeVar.OnButtonClick := InternalButtonClick;
end;

procedure TBar.InternalButtonClick()
begin
  if Assigned(FOnButtonClick) then
    FOnButtonClick(Sender);
end;

Aviator 27. Sep 2016 14:12

AW: Komponentenentwicklung - Event weiterleiten - Denkfehler?
 
Zitat:

Zitat von Neutral General (Beitrag 1348956)
Ja gut, dann musst du wirklich in der innersten Komponente im Event ein Event feuern und das nach oben leiten bis zu TBar und dann zum User.

Wow. Ich hätte wirklich gedacht, dass das einfacher gehen müsste und ich etwas falsch mache. Dann muss ich mir jetzt was überlegen ...
Zitat:

Zitat von Neutral General (Beitrag 1348956)
Finde ich aber besser als irgendwo irgendwelche Koordinaten abzufragen oder sowas..

Ja. Einfacher ist es bestimmt.

Neutral General 27. Sep 2016 14:17

AW: Komponentenentwicklung - Event weiterleiten - Denkfehler?
 
Mir fällt zumindest nichts einfacheres ein :?
Will nicht ausschließen, dass es dafür eine einfachere/elegantere Lösung gibt.
Falls ja, wäre ich auch daran interessiert zu wissen wie :mrgreen:

stahli 27. Sep 2016 14:19

AW: Komponentenentwicklung - Event weiterleiten - Denkfehler?
 
[Trotz rotem Kasten aus Zeitgründen mal rausgehauen...]

Da musst man noch unterscheiden.


1) Soll es eine fixe Behandlung geben?

Dann kannst Du eine Methode
procedure MyInnerControlClick(Sender: TObject);
dem
InnerControl.OnClick
einfach zuweisen.

Dein InnerControl muss dann den Context kennen, in dem es existiert und Zugriff auf die benötigten Daten haben.


2) Soll eine freie Behandlung definierbar sein?

Dann musst Du Dir anschauen, wie OnClick implementiert ist und das mit OnInnerClick nachbauen.
Dann kannst Du in Deinem Projektcode die Behandlung individuell regeln.
Das ist natürlich komplexer.
(Das ich so etwas gemacht habe ist Jahre her. Ich könnte bei Bedarf mal suchen, ob ich dazu noch etwas finde.)

Aviator 27. Sep 2016 14:58

AW: Komponentenentwicklung - Event weiterleiten - Denkfehler?
 
Danke für die Antworten. Ich konkretisiere das Ganze aber mal noch ein bisschen.

Ausgehend von der Idee der TVirtualBreadCrumb Komponente von Codehunter habe ich meine eigene BreadCrumbBar schreiben wollen. Hintergrund ist der, dass ich nicht nur auf den VST reagieren, sondern bei Bedarf auch eine eigene Struktur aufbauen können will. Eine Frage habe ich diesbezüglich auch bereits in seinem Thread geschrieben.

Konkret geht es jetzt darum, dass ich eine folgende Klassenstruktur habe:

Delphi-Quellcode:
TBreadCrumbButtonBase = class(TCustomControl)
[...] // BasisButton von dem alle anderen Buttons abgeleitet werden
end;
Delphi-Quellcode:
TBreadCrumbRootButton = class(TBreadCrumbButtonBase)
[...] // Button der angezeigt wird, wenn nicht alle Breadcrumbs in die Bar passen
end;
Delphi-Quellcode:
TBreadCrumbButton = class(TBreadCrumbButtonBase)
[...] // Das ist der DropDown Button der hinter dem BreadCrumb hängt
end;
Delphi-Quellcode:
TBreadCrumb = class(TCustomControl)
private
  FButton: TBreadCrumbButton; // Hier der verschachtelte BreadCrumbButon auf dessen Klick ich reagieren will um ein Menü anzuzeigen
end;
An dieser Stelle kommt jetzt noch meine Basis BreadCrumbBar von der alle anderen Bars die speziell reagieren sollen abgeleitet werden können.
Delphi-Quellcode:
TCustomBreadCrumbBar = class (TCustomControl)
private
  FRootButton: TBreadCrumbRootButton;
  FBreadCrumbs: TBreadCrumbs;
[...]
end;
Hier die konkrete Implementierung der BreadCrumbBar die es zulässt, dass ich eigene Buttons hinzufügen kann wie ich das möchte.
Delphi-Quellcode:
TBreadCrumbBar = class(TCustomBreadCrumbBar)
[...]
end;
Später soll es dann noch eine andere Ableitung geben, die die Buttons dann selbst erstellt (abhängig von einem VirtualTreeView). Diese Ableitung wird dann noch erweitert, dass ich zusätzlich zu den VirtualTreeView Buttons auch eigene vorne dran stellen kann.

Da wie beim Windows Explorer beim Klick auf den TBreadCrumbButton ein Menü erscheinen soll welches diverse Auswahlmöglichkeiten bietet, muss ich ja das ClickEvent des TBreadCrumbButtons durchschleifen damit dies auf meiner GUI Form ankommt.

Und hier setzt meine Frage an. Wie kann ich das Vorhaben vereinfachen?

Diese vielen Klassen habe ich eben gemacht, damit ich nur noch eine TBreadCrumb Instanz erzeugen muss und dadurch dann entsprechend auch der DropDownButton erzeugt wird und sich auch alles selbst zeichnet. Deshalb auch TCustomControl. Wenn ich alles in der TCustomBreadCrumbBar zeichnen würde, dann müsste ich die Mausposition auswerten und errechnen, an welcher Stelle ich geklickt habe um entsprechend reagieren zu können. Durch die vielen Komponenten habe ich eben schon diverse Features die ich nicht mehr selbst implementieren muss.

Ich hoffe ich habe es jetzt ausführlicher und damit etwas verständlicher beschrieben. :-D

stahli 27. Sep 2016 17:11

AW: Komponentenentwicklung - Event weiterleiten - Denkfehler?
 
So ganz kann ich nicht folgen, aber mal ein Versuch (etwas PseudoCode):


Delphi-Quellcode:
TBreadCrumb = class(TCustomControl)
private
   FButton: TBreadCrumbButton; // Hier der verschachtelte BreadCrumbButon auf dessen Klick ich reagieren will um ein Menü anzuzeigen
   procedure BreadCrumbButtonClick(Sender...);
end;

constructor TBreadCrumb.Create(...)
begin
  inherited;
  FButton := TBreadCrumbButton.Create(Self);
  fButton.Parent := Self;
  fButton.OnClick := BreadCrumbButtonClick;
end;

procedure TBreadCrumb.BreadCrumbButtonClick(...)
var
  P: TPoint;
begin
  P := TPoint.Create(IrgendEinX, IrgendEinY);
  P := ClientToSreen(P);
  PopupMenueÖffnenMitBestimmtenEintraegenAnPos(P);
end;

Ich weiß nicht, ob Dich das weiter bringt.
Zumindest kann der Button selbst auf den Klick reagieren.
Was er dann machen soll, wird sicher schon schwieriger.
Dazu muss er halt wissen, für welche Aufgabe er in welchem aktuellen Kontext steht.


Frag doch sonst mal CodeHunter, ob er Dir weiter helfen kann, er hat ja da offenbar schon etwas vorgelegt...

Uwe Raabe 27. Sep 2016 18:57

AW: Komponentenentwicklung - Event weiterleiten - Denkfehler?
 
Wenn du die gekapselte Komponente als SubKomponente anlegst, bekommst du die Eigenschaften und Events im Objektinspektor angezeigt. Hier als Beispiel ein Panel mit einem Button drauf.

Delphi-Quellcode:
unit PanelExt;

interface

uses
  System.SysUtils, System.Classes, Vcl.Controls, Vcl.ExtCtrls, Vcl.StdCtrls;

type
  TPanelExt = class(TPanel)
  private
    FButton: TButton;
  protected
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Button: TButton read FButton;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TPanelExt]);
end;

constructor TPanelExt.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FButton := TButton.Create(Self);
  FButton.SetSubComponent(true);
  FButton.Parent := Self;
  FButton.Name := 'TestButton';
end;

destructor TPanelExt.Destroy;
begin
  FButton.Free;
  inherited Destroy;
end;

end.


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:29 Uhr.
Seite 1 von 2  1 2      

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