Komponentenerstellung: Problem mit Unterkomponenten

Rund um die LCL und andere Komponenten
Antworten
CCRDudeLaz
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

Beitrag von CCRDudeLaz »

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

CCRDudeLaz
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

Beitrag von CCRDudeLaz »

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.

wp_xyz
Beiträge: 5129
Registriert: Fr 8. Apr 2011, 09:01

Re: Komponentenerstellung: Problem mit Unterkomponenten

Beitrag von wp_xyz »

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.
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):

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;

CCRDudeLaz
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

Beitrag von CCRDudeLaz »

wp_xyz hat geschrieben: Mo 25. Nov 2024, 19:48Was passt denn an dem Vorgehen in dem wiki-Artikel nicht?
Na die beschriebenen Fehler passen halt 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...

wp_xyz
Beiträge: 5129
Registriert: Fr 8. Apr 2011, 09:01

Re: Komponentenerstellung: Problem mit Unterkomponenten

Beitrag von wp_xyz »

CCRDudeLaz hat geschrieben: Mo 25. Nov 2024, 20:05 Vielleicht liegt es daran, das meine Oberklasse TFrame ist?
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.

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.

Sieben
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

Beitrag von Sieben »

CCRDudeLaz hat geschrieben:Vielleicht liegt es daran, das meine Oberklasse TFrame ist? Werde das mal auf TCustomControl runterschreiben...
Ich würde eher an T(Custom)Panel denken, das hat schon die entsprechenden Nehmerqualitäten.

Mathias
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

Beitrag von Mathias »

Ich würde eher an T(Custom)Panel denken, das hat schon die entsprechenden Nehmerqualitäten.
Ich nehme für solches in der Regel auch ein TPanel als Container.

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

CCRDudeLaz
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

Beitrag von CCRDudeLaz »

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.

wp_xyz
Beiträge: 5129
Registriert: Fr 8. Apr 2011, 09:01

Re: Komponentenerstellung: Problem mit Unterkomponenten

Beitrag von wp_xyz »

CCRDudeLaz hat geschrieben: Di 26. Nov 2024, 08:56 Ein Workaround erstmal wäre - dank eurer Hilfe nun herausgefunden - TCustomPanel zu nehmen [...]
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 [...] und das jeweils auf TFrame zu plazieren.
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.

CCRDudeLaz
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

Beitrag von CCRDudeLaz »

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.
Da hast Du ganz recht! Hatte das weiter oben gelesen, habe das aber als TCustomControl.
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.
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...
Doch, auf jeden Fall!

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.
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.
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.

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.

Bild

Bild

Antworten