![]() |
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:
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
TBar = class(TCustomControl)
private FSomeVar: TFooBar; protected procedure WM_Paint(var Msg: TMessage) message WM_PAINT; public property OnGetSomeData; end;
Delphi-Quellcode:
Event erstellen und dann den Weg
ObGetSubComponents
Delphi-Quellcode:
durchlaufen.
TFoo (Auslöser) --> TFooBar --> TBar
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. |
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? |
AW: Komponentenentwicklung - Event weiterleiten - Denkfehler?
Zitat:
|
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; |
AW: Komponentenentwicklung - Event weiterleiten - Denkfehler?
Zitat:
Zitat:
|
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: |
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.) |
AW: Komponentenentwicklung - Event weiterleiten - Denkfehler?
Danke für die Antworten. Ich konkretisiere das Ganze aber mal noch ein bisschen.
Ausgehend von der Idee der ![]() 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:
An dieser Stelle kommt jetzt noch meine Basis BreadCrumbBar von der alle anderen Bars die speziell reagieren sollen abgeleitet werden können.
TBreadCrumb = class(TCustomControl)
private FButton: TBreadCrumbButton; // Hier der verschachtelte BreadCrumbButon auf dessen Klick ich reagieren will um ein Menü anzuzeigen end;
Delphi-Quellcode:
Hier die konkrete Implementierung der BreadCrumbBar die es zulässt, dass ich eigene Buttons hinzufügen kann wie ich das möchte.
TCustomBreadCrumbBar = class (TCustomControl)
private FRootButton: TBreadCrumbRootButton; FBreadCrumbs: TBreadCrumbs; [...] end;
Delphi-Quellcode:
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.
TBreadCrumbBar = class(TCustomBreadCrumbBar)
[...] end; 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 |
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... |
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 14:48 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