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 Visuelle Komponente mit mehreren Klassen in unterschiedlichen Units (https://www.delphipraxis.net/213982-visuelle-komponente-mit-mehreren-klassen-unterschiedlichen-units.html)

fisipjm 2. Nov 2023 15:49

Visuelle Komponente mit mehreren Klassen in unterschiedlichen Units
 
Hallo,

ich arbeite gerade an meiner ersten visuellen Komponente in Delphi und habe einige Fragen dazu. Ursprünglich dachte ich, es wäre sinnvoll, zuerst die gesamte Funktionalität zu entwickeln und sie dann in eine visuelle Komponente umzuwandeln. Im Nachhinein scheint das jedoch keine gute Idee gewesen zu sein.:?

Ich habe eine Klasse erstellt, die von
Delphi-Quellcode:
TLayout
abgeleitet ist. Dies dient als Grundlage für meine visuelle Komponente, da
Delphi-Quellcode:
TLayout
bereits viele Grundfunktionen bietet, die ich benötige. Auf diesem Layout habe ich auch eine eigene Button-Komponente erstellt, die von
Delphi-Quellcode:
TRectangle
abgeleitet ist. Nennen wir diese Klasse einfach
Delphi-Quellcode:
TMyButton
. Ich habe
Delphi-Quellcode:
TMyButton
in einer eigenen Unit abgelegt und sie in den Uses-Teil meiner visuellen Komponente aufgenommen. Auf diese Weise kann ich die Komponente im Code erstellen, und sie funktioniert zur Laufzeit einwandfrei.

Das Problem tritt auf, wenn ich versuche, die Komponente zur Entwurfszeit auf die Form zu ziehen. Das funktioniert noch, aber ab diesem Zeitpunkt lässt sich die Form nicht mehr speichern und ein neu laden der Form ist auch nicht mehr möglich. Delphi meldet dann, dass es die Klasse
Delphi-Quellcode:
TMyButton
nicht finden kann. Ich habe gesehen, dass einige Beispiele alle Klassen in einer Unit zusammenfassen, was jedoch dazu führt, dass die Unit sehr groß wird. Ist dies die einzige Möglichkeit, oder wie sollte das Deployment einer visuellen Komponente in diesem Kontext richtig durchgeführt werden?

Hat jemand bereits Erfahrungen mit visuellen Komponenten und kann mir weiterhelfen?

himitsu 2. Nov 2023 18:07

AW: Visuelle Komponente mit mehreren Klassen in unterschiedlichen Units
 
Wo und in welchen Units/Packages was drin ist, ist eigentlich vollkommen egal.


Wie kommt TMyButton auf dein LayoutDingens?

Im FormDesigner (DesignTimePackage) müssen alle Komnponenten registriert sein (RegisterComponents/RegisterNoIcon/RegisterClasses ... jenachdem wie die "Sichtbarkeit" ist, bzw. ob in KomponentenPalette drin)

Zur Laufzeit müssen die Klassen auch registriert sein, damit der DFM-Loader sie auch finden/laden kann.

Gibt es für eine Komponente mindestens eine Published-Variable in der Klasse, dann registriert der DFM-Loader diese Klasse (RegisterClass anschließend wieder UnRegisterClass).
z.B. für SubComponenten (die z.B. nicht Owner=Form haben), welche dennoch vom DFM-Loader geladen/erstellt werden, aber die keine Variable besitzen, muß man vorher selber mit RegisterClass ran.

fisipjm 5. Nov 2023 12:16

AW: Visuelle Komponente mit mehreren Klassen in unterschiedlichen Units
 
Hi Himitsu,

danke für deine Antwort, ich glaub ich bin noch nicht tief genug in der Materie drin um deine Rückmeldung richtig einzuordnen. Ich versuche dir mal die Fragen zu beantworten:

Zitat:

Zitat von himitsu (Beitrag 1528912)
Wie kommt TMyButton auf dein LayoutDingens?

Meine TMyButtons werden im Create des abgeleiteten Layouts erzeugt, nennen wir das Layout mal TMyLayout. Das ist auch die Klasse, die in der register Procedure registriert wird. Die TMyButtons bekommen TMyLayout als Parent + unterschiedliche OnClickHandler.

Zitat:

Zitat von himitsu (Beitrag 1528912)
Im FormDesigner (DesignTimePackage) müssen alle Komnponenten registriert sein (RegisterComponents/RegisterNoIcon/RegisterClasses ... jenachdem wie die "Sichtbarkeit" ist, bzw. ob in KomponentenPalette drin)
Zur Laufzeit müssen die Klassen auch registriert sein, damit der DFM-Loader sie auch finden/laden kann.

Bedeutet das, dass ich für jede Klasse ein Register mit in die Register Procedure stecken muss? Ich möchte aber nicht, dass TMyButton als Element in der Komponentenpalette zur Verfügung steht, es sollte am Schluss nur TMyLaout zur Auswahl stehen.

Zitat:

Zitat von himitsu (Beitrag 1528912)
Gibt es für eine Komponente mindestens eine Published-Variable in der Klasse, dann registriert der DFM-Loader diese Klasse (RegisterClass anschließend wieder UnRegisterClass).
z.B. für SubComponenten (die z.B. nicht Owner=Form haben), welche dennoch vom DFM-Loader geladen/erstellt werden, aber die keine Variable besitzen, muß man vorher selber mit RegisterClass ran.

Da komm ich nicht ganz mit, hängt vielleicht auch mit der vorhergehenden Frage zusammen.:oops:

Grüße
PJM

himitsu 5. Nov 2023 13:52

AW: Visuelle Komponente mit mehreren Klassen in unterschiedlichen Units
 
Alle Klassen/Komponenten, welche der FormDesigner, bzw. der DFM-Loader erstellt, die müssen "bekannt" sein, damit er diese Klasse über ihren Namen finden kann.

Wenn ein TMyLayout diese Komponente erstellt, dann wird auch deine Komponete als Owner übergeben?
Steht der erstellte Button anschließend in der DFM drin? (wurde also beim Speichern "gefunden" und vom DFM-Streaming gespeichert, um wieder geladen zu werden)

fisipjm 6. Nov 2023 07:36

AW: Visuelle Komponente mit mehreren Klassen in unterschiedlichen Units
 
Moin Himitsu,

Also, ich entwickle in der FMX Ecke, deshalb ich meine .dfm eine .fmx, aber das sollte ja erst mal egal ein.
In der fmx steht nach dem reinladen erst mal alles drin. Ich sehe tatsächlich auch die Komponente wenn ich sie das erste mal auf meine Maske ziehe.
Erst wenn ich das erste mal versuche zu speichern, bzw. in die Codeansicht wechsle und dann wieder in die Designeransicht gehe (Tabs am unteren Rand der IDE), dann bekomme ich den Fehler das er die darunterliegenden Klassen nicht finden kann.

Als Owner übergebe ich immer die jeweils darüberliegende Klasse, also:
Owner von TMyLayout: Maske auf die ich die Komponente gelegt hab
Wowner von TMyButton: TMyLayout

fisipjm 6. Nov 2023 09:18

AW: Visuelle Komponente mit mehreren Klassen in unterschiedlichen Units
 
Zitat:

Zitat von himitsu (Beitrag 1529077)
Alle Klassen/Komponenten, welche der FormDesigner, bzw. der DFM-Loader erstellt, die müssen "bekannt" sein, damit er diese Klasse über ihren Namen finden kann.

Wenn ein TMyLayout diese Komponente erstellt, dann wird auch deine Komponete als Owner übergeben?
Steht der erstellte Button anschließend in der DFM drin? (wurde also beim Speichern "gefunden" und vom DFM-Streaming gespeichert, um wieder geladen zu werden)

Hi,

damit wir nicht die ganze Zeit über hypothetisches reden, hab ich das Verhalten mal nachgestellt. Das ist der Quellcode für die Unit. Einfach in ein Package werfen und als Komponente installieren. Beim versuch das ganze mit x64 laufen zu lassen, erhalte ich die Info, dass TMySpeedButton nicht gefunden werden kann. Das rein ziehen der Komponente funktioniert aber problemlos.

Delphi-Quellcode:
unit uMyVisualLayout;

interface

uses
  System.SysUtils, System.Classes, FMX.Types, FMX.Controls, FMX.Layouts, FMX.StdCtrls, FMX.Objects,
  FMX.Graphics;

Type
  TMyImage = class(TImage)

  private
    FBackupImage: TBitmap;

  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

Type
  TMySpeedbutton = class(TSpeedButton)

  private
    FLabelText: TLabel;
    function GetNewText: String;
    procedure SetNewText(const Value: String);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property NewText: String read GetNewText write SetNewText;
  end;

Type
  TMyLayout = class(TLayout)

  private
    { Private-Deklarationen }
    Speedbutton1, Speedbutton2, Speedbutton3: TMySpeedbutton;
    TopFlowLayout: TFlowLayout;
    procedure ButtonClick(Sender: Tobject);
  protected
    { Protected-Deklarationen }
  public
    constructor Create(AOwner: TComponent); override;
    { Public-Deklarationen }
  published
    { Published-Deklarationen }
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('TestVisualComponent', [TMyLayout]);
end;

{ TMyLayout }

procedure TMyLayout.ButtonClick(Sender: Tobject);
begin
  log.d(TSpeedButton(Sender).Name + ' Clicked!');
end;

constructor TMyLayout.Create(AOwner: TComponent);
begin
  inherited;
  TopFlowLayout := TFlowLayout.Create(self);
  TopFlowLayout.Parent := self;
  TopFlowLayout.Align := TAlignLayout.MostTop;

  Speedbutton1 := TMySpeedbutton.Create(self);
  Speedbutton1.Parent := TopFlowLayout;
  Speedbutton1.Align := TAlignLayout.Client;
  Speedbutton1.NewText := 'Speedbutton1';
  Speedbutton1.OnClick := ButtonClick;

  Speedbutton2 := TMySpeedbutton.Create(self);
  Speedbutton2.Parent := TopFlowLayout;
  Speedbutton2.Align := TAlignLayout.Client;
  Speedbutton2.NewText := 'Speedbutton2';
  Speedbutton2.OnClick := ButtonClick;

  Speedbutton3 := TMySpeedbutton.Create(self);
  Speedbutton3.Parent := TopFlowLayout;
  Speedbutton3.Align := TAlignLayout.Client;
  Speedbutton3.NewText := 'Speedbutton3';
  Speedbutton3.OnClick := ButtonClick;

end;

{ TMyImage }

constructor TMyImage.Create(AOwner: TComponent);
begin
  inherited;
  FBackupImage := TBitmap.Create;
end;

destructor TMyImage.Destroy;
begin
  FBackupImage.Free;
  inherited;
end;

{ TMySpeedbutton }

constructor TMySpeedbutton.Create(AOwner: TComponent);
begin
  inherited;
  FLabelText := TLabel.Create(self);
  FLabelText.Parent := self;
  FLabelText.Align := TAlignLayout.Client;
end;

destructor TMySpeedbutton.Destroy;
begin
  FLabelText.Free;
  inherited;
end;

function TMySpeedbutton.GetNewText: String;
begin
  Result := FLabelText.Text;
end;

procedure TMySpeedbutton.SetNewText(const Value: String);
begin
  FLabelText.Text := Value;
end;

end.

Olli73 6. Nov 2023 09:29

AW: Visuelle Komponente mit mehreren Klassen in unterschiedlichen Units
 
Also mir fehlt da schonmal ein
Delphi-Quellcode:
SetSubComponent(True)
.

fisipjm 6. Nov 2023 10:33

AW: Visuelle Komponente mit mehreren Klassen in unterschiedlichen Units
 
Zitat:

Zitat von Olli73 (Beitrag 1529109)
Also mir fehlt da schonmal ein
Delphi-Quellcode:
SetSubComponent(True)
.

Hi Oli,

https://docwiki.embarcadero.com/Libr...etSubComponent
Emba meint ich brauch es nur wenn ich was im Published hab, das ich gerne gespeichert hätte. Kannst du bissel näher ausführen für was das gebraucht wird?

himitsu 6. Nov 2023 21:13

AW: Visuelle Komponente mit mehreren Klassen in unterschiedlichen Units
 
Das SetSubKomponent braucht man nur, wenn man Objekte als Published veröffentlicht.

Normal werden hier nur Zeiger/Verlinkungen gespeichert, aber dadurch weiß der DFM-Writer/Reader dann, dass stattdessen die Eigenschaften der Subkomponente gespeichert werden sollen.

himitsu 7. Nov 2023 01:13

AW: Visuelle Komponente mit mehreren Klassen in unterschiedlichen Units
 
FLabelText.Free; bzw. ist unnötig TMySpeedbutton.Destroy, da es durch den Owner freigegeben wird. Aber Falsch ist es auch nicht.

Ansonsten seh ich eigentlich nichts Schlimmes.
Nach außen sind diese Subkomponenten ja nicht sichtbar, für den DFM-Reader/Writer. :gruebel:


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:22 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