Komponentenerstellung: Problem mit Unterkomponenten
-
- Beiträge: 54
- Registriert: Do 25. Jan 2024, 08:33
- OS, Lazarus, FPC: Win/macOS (L trunk FPC trunk)
- CPU-Target: 32+64
Komponentenerstellung: Problem mit Unterkomponenten
Hallo miteinander,
Mit der Komponentenerstellung tue ich mir immer schwer. Ein paar eigene visuelle Komponenten habe ich inzwischen auch zur DesignTime, aber aktuell möchte ich ein paar "zusammenfassen".
Genauer gesagt: ein TFrame with Unterkomponenten, die nicht bewegt werden sollen (csNoDesignSelectable - der Teil funktioniert).
Ich hab mir dazu mal TLabeledEdit aus ExtCtrls angeschaut und versucht, "nachzumachen". Leider scheint der feine Unterschied zu sein, dass ich meine Unterkomponenten innerhalb der Komponente haben will. Hier gäbe es das hier im Wiki, hilft mir auch nicht weiter.
1. Zur DesignTime beim Hinzufügen wird meine Komponente richtig angezeigt.
2. Zur Runtime hängt das Programm bevor das Fenster auch nur aufgeht mit 0% CPU-Last, im Debugger manchmal: EClassNotFound, "No field of class TMemo in TForm1".
3. Zur DesignTime, wenn ich das Projekt neu lade, erhalte ich Fehlermeldungen bzgl. "identifier Memo not found in pascal code TForm1".
Laut allen Quellen, die ich finden konnte, ist SetSubComponent der Schlüssel, und ggfls. noch, Name und published property gleichlautend zu haben.
Was mache ich falsch, worauf muss ich noch achten?
Mein Versuch (Mini-Projekt und Package) sind hier:
https://gitlab.com/ccrdude-pascal/playg ... components
Mit der Komponentenerstellung tue ich mir immer schwer. Ein paar eigene visuelle Komponenten habe ich inzwischen auch zur DesignTime, aber aktuell möchte ich ein paar "zusammenfassen".
Genauer gesagt: ein TFrame with Unterkomponenten, die nicht bewegt werden sollen (csNoDesignSelectable - der Teil funktioniert).
Ich hab mir dazu mal TLabeledEdit aus ExtCtrls angeschaut und versucht, "nachzumachen". Leider scheint der feine Unterschied zu sein, dass ich meine Unterkomponenten innerhalb der Komponente haben will. Hier gäbe es das hier im Wiki, hilft mir auch nicht weiter.
1. Zur DesignTime beim Hinzufügen wird meine Komponente richtig angezeigt.
2. Zur Runtime hängt das Programm bevor das Fenster auch nur aufgeht mit 0% CPU-Last, im Debugger manchmal: EClassNotFound, "No field of class TMemo in TForm1".
3. Zur DesignTime, wenn ich das Projekt neu lade, erhalte ich Fehlermeldungen bzgl. "identifier Memo not found in pascal code TForm1".
Laut allen Quellen, die ich finden konnte, ist SetSubComponent der Schlüssel, und ggfls. noch, Name und published property gleichlautend zu haben.
Was mache ich falsch, worauf muss ich noch achten?
Mein Versuch (Mini-Projekt und Package) sind hier:
https://gitlab.com/ccrdude-pascal/playg ... components
-
- Beiträge: 54
- Registriert: Do 25. Jan 2024, 08:33
- OS, Lazarus, FPC: Win/macOS (L trunk FPC trunk)
- CPU-Target: 32+64
Re: Komponentenerstellung: Problem mit Unterkomponenten
Etwas weiter dran gearbeitet - wenn ich SetSubComponent entferne, läuft alles, nur die Properties der Subkomponenten werden nicht gespeichert, bzw. zur Laufzeit habe ich die Subkomponente doppelt.
Re: Komponentenerstellung: Problem mit Unterkomponenten
Was passt denn an dem Vorgehen in dem wiki-Artikel nicht? Ich hab mal, basierend auf dem Beitrag, selbst versucht, ein Label und ein Memo zu kombinieren, und das funktioniert einwandfrei. Kleiner Schönheitsfehler, natürlich: Die kombinierte Klasse stammt von TCustomControl ab und nicht von TMemo. Daher muss man bei Zugriff auf die Memo-Properties immer das "Memo" dazu schreiben (siehe ganz unten im folgenden Code-Block):CCRDudeLaz hat geschrieben: Fr 22. Nov 2024, 11:19 Leider scheint der feine Unterschied zu sein, dass ich meine Unterkomponenten innerhalb der Komponente haben will. Hier gäbe es das hier im Wiki, hilft mir auch nicht weiter.
Code: Alles auswählen
unit uLabeledMemo;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Types, Controls, StdCtrls;
type
TLabeledMemo = class(TCustomControl)
private
FEmbeddedLabel: TLabel;
FMemo: TMemo;
protected
class function GetControlClassDefaultSize: TSize; override;
public
constructor Create(AOwner: TComponent); override;
published
property EmbeddedLabel: TLabel read FEmbeddedLabel;
property Memo: TMemo read FMemo;
property Align;
property Anchors;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Test', [TLabeledMemo]);
end;
constructor TLabeledMemo.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
with GetControlClassDefaultSize do
SetInitialBounds(0, 0, CX, CY);
FEmbeddedLabel := TLabel.Create(self);
FEmbeddedLabel.Parent := Self;
FEmbeddedLabel.SetSubComponent(true);
FEmbeddedLabel.Align := alTop;
FEmbeddedLabel.Caption := 'Embedded Label';
FEmbeddedLabel.ControlStyle := FEmbeddedLabel.ControlStyle - [csNoDesignSelectable];
FMemo := TMemo.Create(self);
FMemo.Parent := Self;
FMemo.SetSubComponent(true);
FMemo.Align := alClient;
FMemo.Lines.Clear;
FMemo.ControlStyle := FMemo.ControlStyle - [csNoDesignSelectable];
end;
class function TLabeledMemo.GetControlClassDefaultSize: TSize;
begin
Result.CX := 200;
Result.CY := 100;
end;
end.
----------------------
procedure TForm1.Button1Click(Sender: TObject);
begin
LabeledMemo1.Memo.Lines.Add('Das ist ein Test.');
LabeledMemo1.EmbeddedLabel.Caption := 'Beschreibung';
end;
-
- Beiträge: 54
- Registriert: Do 25. Jan 2024, 08:33
- OS, Lazarus, FPC: Win/macOS (L trunk FPC trunk)
- CPU-Target: 32+64
Re: Komponentenerstellung: Problem mit Unterkomponenten
Na die beschriebenen Fehler passen halt nichtwp_xyz hat geschrieben: Mo 25. Nov 2024, 19:48Was passt denn an dem Vorgehen in dem wiki-Artikel nicht?

Wie ich schon schrieb - zur Runtime hängt das Programm, zur Designtime beim erneuten Laden sind die Properties nicht geladen, bzw. es gibt eigentlich zwei Subkomponenten.
Vielleicht liegt es daran, das meine Oberklasse TFrame ist? Werde das mal auf TCustomControl runterschreiben...
Re: Komponentenerstellung: Problem mit Unterkomponenten
Ehrlich gesagt, habe ich noch nie versucht, einen Frame in der IDE als eigene Komponente in einem Package zu installieren. Ich könnte mir durchaus vorstellen, dass da einige Probleme auftreten können.CCRDudeLaz hat geschrieben: Mo 25. Nov 2024, 20:05 Vielleicht liegt es daran, das meine Oberklasse TFrame ist?
In all meinen Projekten, die Frames verwenden, wird der Frame über das vorletzte Icon "TFrame" der "Standard"-Komponenten-Palette auf das Formular gesetzt. Wenn der Frame in einem Package gespeichert ist (aber nicht registriert!) und das Package im Projekt verwendet wird, dann wird der Frame in der erscheinenden Auswahlliste angeboten und kann dann ganz normal eingefügt werden. Aber ich denke nicht, dass das geht, wenn der Frame registriert ist, also ein eigenes Icon auf der Komponenten-Palette hat.
-
- Beiträge: 289
- Registriert: Mo 24. Aug 2020, 14:16
- OS, Lazarus, FPC: Ubuntu Xenial 32, Lazarus 2.2.0, FPC 3.2.2
- CPU-Target: i386
Re: Komponentenerstellung: Problem mit Unterkomponenten
Ich würde eher an T(Custom)Panel denken, das hat schon die entsprechenden Nehmerqualitäten.CCRDudeLaz hat geschrieben:Vielleicht liegt es daran, das meine Oberklasse TFrame ist? Werde das mal auf TCustomControl runterschreiben...
-
- Beiträge: 6899
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
Re: Komponentenerstellung: Problem mit Unterkomponenten
Ich nehme für solches in der Regel auch ein TPanel als Container.Ich würde eher an T(Custom)Panel denken, das hat schon die entsprechenden Nehmerqualitäten.
Was ich auch noch mache, wen ich solche eigenen Komponenten erstelle, integriere ich dies nicht in die IDE, sondern lade sie dynamisch in mein Project rein. Dies ist weniger Fehleranfällig und man muss nicht bei jeder Änderung die IDE neu kompilieren.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
-
- Beiträge: 54
- Registriert: Do 25. Jan 2024, 08:33
- OS, Lazarus, FPC: Win/macOS (L trunk FPC trunk)
- CPU-Target: 32+64
Re: Komponentenerstellung: Problem mit Unterkomponenten
Danke für euer aller Antworten
Hab ein wenig weiter probiert. Der Fehler tritt mit aktuellem Code auch auf auch auf, wenn ich TCustomControl als Oberklasse nehme. Bei TLabeledMemo tritt er nicht auf. Also mein Beispiel auf das Minimum von TLabeledMemo reduziert. Läuft. Wieder auf TFrame. Läuft nicht.
Also scheint das Problem tatsächlich irgendwo bei TFrame als Oberklasse zu liegen. Mal die Hierarchie durchgegangen, it TCustomDesignControl geht es noch, mit TCustomFrame erstmal scheinbar auch. Der noch fehlende Schritt ist ja eh, das über das Datei-Menü als neuen "Speziell-Frame" anlegen zu lassen.
Rein zur Runtime erzeugt läuft das bei mir mit TFrame seit Jahren super. Meine Software hat diverse Views, deren Logik ich ich gerne getrennt in eigener Unit haben möchte - daher die Frames, die lassen sich super individuell bearbeiten. Dabei geht es aber immer um verschiedene Grund-Typen, und diese Grund-Typen versuche ich nun zur DesignTime verfügbar zu machen, weil es andersrum eben durchaus Probleme in der IDE gibt (immer mal wieder, dass meine von TFrame abgeleitete Klasse nicht gefunden wurde - Frame schließen und neu öffnen hilft dann meist, aber trotzdem...).
Ein Workaround erstmal wäre - dank eurer Hilfe nun herausgefunden - TCustomPanel zu nehmen, und das jeweils auf TFrame zu plazieren.

Hab ein wenig weiter probiert. Der Fehler tritt mit aktuellem Code auch auf auch auf, wenn ich TCustomControl als Oberklasse nehme. Bei TLabeledMemo tritt er nicht auf. Also mein Beispiel auf das Minimum von TLabeledMemo reduziert. Läuft. Wieder auf TFrame. Läuft nicht.
Also scheint das Problem tatsächlich irgendwo bei TFrame als Oberklasse zu liegen. Mal die Hierarchie durchgegangen, it TCustomDesignControl geht es noch, mit TCustomFrame erstmal scheinbar auch. Der noch fehlende Schritt ist ja eh, das über das Datei-Menü als neuen "Speziell-Frame" anlegen zu lassen.
Rein zur Runtime erzeugt läuft das bei mir mit TFrame seit Jahren super. Meine Software hat diverse Views, deren Logik ich ich gerne getrennt in eigener Unit haben möchte - daher die Frames, die lassen sich super individuell bearbeiten. Dabei geht es aber immer um verschiedene Grund-Typen, und diese Grund-Typen versuche ich nun zur DesignTime verfügbar zu machen, weil es andersrum eben durchaus Probleme in der IDE gibt (immer mal wieder, dass meine von TFrame abgeleitete Klasse nicht gefunden wurde - Frame schließen und neu öffnen hilft dann meist, aber trotzdem...).
Ein Workaround erstmal wäre - dank eurer Hilfe nun herausgefunden - TCustomPanel zu nehmen, und das jeweils auf TFrame zu plazieren.
Re: Komponentenerstellung: Problem mit Unterkomponenten
Weiß nicht... Mit TCustomPanel holst du dir eine Menge Zeug in die Komponente, was du nicht brauchst: Die Ausgabe und das Alignment der Caption, die Bevels. Und du kannst andere Komponenten in deine Komponente einfügen - das willst du sicher nicht... Daher musst du Aufwand treiben, Features, die du nicht brauchst oder sogar stören, abzuschalten. Dass ein TCustomControl reicht, wurde doch in TEmbeddedMemo gezeigt.CCRDudeLaz hat geschrieben: Di 26. Nov 2024, 08:56 Ein Workaround erstmal wäre - dank eurer Hilfe nun herausgefunden - TCustomPanel zu nehmen [...]
Wieso brauchst du für die kombinierte Komponenten (Label + Memo, oder Label + Synedit) überhaupt noch einen Frame? Das sind doch selbständige Komponenten. Wenn du sie registrierst, erscheinen sie in der Komponentenpalette, und du kannst sie aufs Formular klicken, wie jede andere Komponente auch.
-
- Beiträge: 54
- Registriert: Do 25. Jan 2024, 08:33
- OS, Lazarus, FPC: Win/macOS (L trunk FPC trunk)
- CPU-Target: 32+64
Re: Komponentenerstellung: Problem mit Unterkomponenten
Da hast Du ganz recht! Hatte das weiter oben gelesen, habe das aber als TCustomControl.wp_xyz hat geschrieben: Di 26. Nov 2024, 12:20 Weiß nicht... Mit TCustomPanel holst du dir eine Menge Zeug in die Komponente, was du nicht brauchst: Die Ausgabe und das Alignment der Caption, die Bevels.
Noch weiter gedacht könnte ich bei BGRA schauen, was es da als Oberklasse gibt, weil meine Controls alle auf BGRABitmap basieren. Eventuell könnte ich dann noch besser Transparenz unterstützen.
Doch, auf jeden Fall!wp_xyz hat geschrieben: Di 26. Nov 2024, 12:20 Und du kannst andere Komponenten in deine Komponente einfügen - das willst du sicher nicht...
Ich erstellte damit Grund-Container für meine Views, die können bei Bedarf um weitere Controls ergänzt werden. Beispiel: der Grund-Frame mit SynEdit könnte für die Implementierung der Debug-Ausgaben mit einer Leiste zur Filterung der Debug-Ausgaben ergänzt werden. Der Grund-Frame zur HTML-Anzeige könnte für die Hilfe um einen Baum links mit Übersicht der Hilfe-Struktur ergänzt werden. Solche Sonderfälle müssen ja keine eigenen Komponenten werden.
Label + X stammen ja nur aus dem Beispiel. Meine Verwendung sind ganze Views in meiner Software, die ich logisch in eigener Unit kapsele. Und ich will sie gar nicht auf's Formular klicken, mein App-Framework soll sie laden, wenn ich sie brauche.wp_xyz hat geschrieben: Di 26. Nov 2024, 12:20Wieso brauchst du für die kombinierte Komponenten (Label + Memo, oder Label + Synedit) überhaupt noch einen Frame? Das sind doch selbständige Komponenten. Wenn du sie registrierst, erscheinen sie in der Komponentenpalette, und du kannst sie aufs Formular klicken, wie jede andere Komponente auch.
Hier mal zwei Beispiele. Die obere und untere Leiste gehören zur Form, dazwischen sind diverse TFrame, beispielsweise einer mit der Tabellenkomponente (Bild 1), oder einer mit Links, Status, Wheel & Tabelle (Bild 2). Genau so habe ich welche mit About-Screen, oder, oder...
Teilweise verwende ich spezielle Views in unterschiedlichen Apps wieder (die Spezial-Form mit SynEdit für Debugausgaben, &c.), auch alleine dafür lohnt schon die Kapselung in Frames.

