Erstellen einer Komponente
-
- Beiträge: 607
- Registriert: Di 19. Mai 2015, 20:05
- OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
- CPU-Target: x86_64-linux-gtk2
Erstellen einer Komponente
Hallo,
ich versuche mich an der Erstellung einer eigenen Komponente. Bin eigentlich auch schon ganz zufrieden. Habe aber noch ein verständniss Problem. Ich muss die Startwerte wie Breite und Höhe usw. einmal am Anfang verrechnen bzw. möchte ich auch Einstellungen überprüfen. Wenn ich das in Create mache funktioniert es nur mit den Werten die im Quellcode stehen. Ich verrechne deshalb in Paint. Gibt es eine Procedure die nur beim Erzeugen einmal aufgerufen wird und die Werte aus dem Objektinspektor (oder auch laufzeiterzeugte Werte) verrechnet? Oder macht man das komplett Anders?
Außerdem ist mir noch aufgefallen das ich wenn ich eine Eigenschaft im OI ändere erst einmal in die Form klicken muss damit sich die Komponente ändert (z. Bsp. Farbe). Normal muss ich nur im OI das Feld wechseln.
Viele Grüße
Bernd
ich versuche mich an der Erstellung einer eigenen Komponente. Bin eigentlich auch schon ganz zufrieden. Habe aber noch ein verständniss Problem. Ich muss die Startwerte wie Breite und Höhe usw. einmal am Anfang verrechnen bzw. möchte ich auch Einstellungen überprüfen. Wenn ich das in Create mache funktioniert es nur mit den Werten die im Quellcode stehen. Ich verrechne deshalb in Paint. Gibt es eine Procedure die nur beim Erzeugen einmal aufgerufen wird und die Werte aus dem Objektinspektor (oder auch laufzeiterzeugte Werte) verrechnet? Oder macht man das komplett Anders?
Außerdem ist mir noch aufgefallen das ich wenn ich eine Eigenschaft im OI ändere erst einmal in die Form klicken muss damit sich die Komponente ändert (z. Bsp. Farbe). Normal muss ich nur im OI das Feld wechseln.
Viele Grüße
Bernd
- kupferstecher
- Beiträge: 431
- Registriert: Do 17. Nov 2016, 11:52
Re: Erstellen einer Komponente
Hallo Bernd,
nach meinem Verständnis nach funktioniert das so: Vorgabewerte programmierst du fest in den Create-Konstruktor ein. Bspw.:
Height:= 123;
Wenn der Wert Height dann im OI geändert wird, wird zur Laufzeit gleich nach Aufrufen des Create-Konstruktors der Setter für Height aufgerufen. Auf diese Weise wird der im Konstruktor gesetzte Wert überschrieben. Deine SetHeight (oder die automatisch gerufene ChangeBounds) muss dann die Berechnungen durchführen, d.h. auf die "neue" Einstellung reagieren. In Anführungsstrichen, da sie ja im OI gesetzt wurde.
nach meinem Verständnis nach funktioniert das so: Vorgabewerte programmierst du fest in den Create-Konstruktor ein. Bspw.:
Height:= 123;
Wenn der Wert Height dann im OI geändert wird, wird zur Laufzeit gleich nach Aufrufen des Create-Konstruktors der Setter für Height aufgerufen. Auf diese Weise wird der im Konstruktor gesetzte Wert überschrieben. Deine SetHeight (oder die automatisch gerufene ChangeBounds) muss dann die Berechnungen durchführen, d.h. auf die "neue" Einstellung reagieren. In Anführungsstrichen, da sie ja im OI gesetzt wurde.
Fehlt evtl. das "Invalidate" an der richtigen Stelle?wennerer hat geschrieben: Außerdem ist mir noch aufgefallen das ich wenn ich eine Eigenschaft im OI ändere erst einmal in die Form klicken muss damit sich die Komponente ändert (z. Bsp. Farbe).
-
- Beiträge: 607
- Registriert: Di 19. Mai 2015, 20:05
- OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
- CPU-Target: x86_64-linux-gtk2
Re: Erstellen einer Komponente
Hallo kupferstecher,
vielen Dank für deine Antwort. Zuerst zum Invalidate. Hab in die SetColor ein Invalidate eingefügt und siehe da es funktioniert! Zum Verrechnen muss ich vielleicht noch etwas ausholen. Ich möchte einen kleinen Schieberegler programmieren. Ich habe einen Minimalwert, einen Maximalwert und einen Startwert auf dem der Schieber stehen soll. Ich möchte nun am Anfang überprüfen ob der Startwert zwischen min und max liegt. Woher weiß ich jetzt das setmin und setmax vor setstartwert aufgerufen werden? Oder geht das nach der Reihenfolge in der es im Quelltext steht?
Viele Grüße Bernd
vielen Dank für deine Antwort. Zuerst zum Invalidate. Hab in die SetColor ein Invalidate eingefügt und siehe da es funktioniert! Zum Verrechnen muss ich vielleicht noch etwas ausholen. Ich möchte einen kleinen Schieberegler programmieren. Ich habe einen Minimalwert, einen Maximalwert und einen Startwert auf dem der Schieber stehen soll. Ich möchte nun am Anfang überprüfen ob der Startwert zwischen min und max liegt. Woher weiß ich jetzt das setmin und setmax vor setstartwert aufgerufen werden? Oder geht das nach der Reihenfolge in der es im Quelltext steht?
Viele Grüße Bernd
-
- Beiträge: 758
- Registriert: Di 23. Aug 2016, 14:25
- OS, Lazarus, FPC: Windows 11
- CPU-Target: 64Bit
- Wohnort: Berlin
Re: Erstellen einer Komponente
Hallo Bernd,
Das sollte in etwa so aussehen, das ist jetzt nciht fertig, sondern soll Dir lediglich als Anleitung dienen:
Ich hoffe, das hilft Dir etwas weiter
Siro
Das sollte in etwa so aussehen, das ist jetzt nciht fertig, sondern soll Dir lediglich als Anleitung dienen:
Code: Alles auswählen
Type TSlider = class(TCustomControl)
private // hier werden die Eigenschaften der Komponente gespeichert
// man schreibt hier gerne ein "F" vorne and die Variablen
FScaleMin : Integer; // minimal Wert
FScaleMax : Integer; // maximal Wert
FScalePos : Integer; // aktuelle Schiebeposition
protected // diese Funktionen/ Proceuduren sind nur innerhalb der Komponente aufrufbar
procedure SetScaleMin(newMin:Integer); // setzt den Wert FScaleMin jedoch mit voriger Bereichsprüfung
procedure SetScaleMax(newMax:Integer);
procedure SetScalePos(newPos:Integer);
procedure paint; override; // hier wird die Komponente gezeichnet
public // öffentliche Proceduren
constructor create(aOwner:TComponent); override;
// destructor destroy; override; // brauchen wir momentan nicht
published // diese Eigenschaften sind im Objektinspektor sichtbar / einstellbar
// wenn man auf den Wert ScaleMin zugreift (Read), wird beim Lesen direkt der Wert FScaleMin zurückgeliefert
// beim Ändern des Wertes (Write) wird die Procedure SetScaleMin aufgerufen, wo auch die Bereichsprüfung erfolgt
property ScaleMin : Integer read FScaleMin write SetScaleMin;
property ScaleMax : Integer read FScaleMax write SetScaleMax;
property ScalePos : Integer read FScalePos write SetScalePos;
end;
// Dies ist die Procedure zum Setzen von ScaleMin mit der entsprechenden Bereichsprüfung
procedure TSlider.SetScaleMin(newMin:Integer);
begin
if newMin = ScaleMin then exit; // Wenn der gleiche Wert gesetzt wird, nix machen
// das beugt auch rekursive Aufrufe vor
if newMin = ScaleMax then newMin:=newMin-1; // wenn Max und Min den gleichen Wert annimmt, gibts garantiert später eine Division durch 0
// das verhindern wir damit.
FScaleMin := newMin; // nun übernehmen wir den neuen Wert
// wir müssen nun prüfen ob die Schiebeposition sich noch innerhalb des gültigen Bereichs befindet
if ScalePos < ScaleMin then ScalePos:=ScaleMin; // ist die Schiebeposition kleiner als Min, dann setzen wir den Schieber auf Min
if ScalePos > ScaleMax then ScalePos:=ScaleMax; // ist die Schiebeposition grösser als Max, dann setzen wir den Schieber auf Max
Invalidate; // Komponente hat sich verändert und soll neu gezeichnet werden
end;
procedure TSlider.SetScaleMax(newMax:Integer);
begin
if newMax = ScaleMax then exit;
if newMax = ScaleMin then newMax:=newMax+1;
FScaleMax := newMax;
// Rangecheck für ScalePos
if ScalePos < FScaleMin then ScalePos:=ScaleMin;
if ScalePos > FScaleMax then ScalePos:=ScaleMax;
invalidate;
end;
procedure TSlider.SetScalePos(newPos:Integer);
begin
if FScalePos = newPos then exit;
// Rangecheck:
if newPos < FScaleMin then newPos:=FScaleMin;
if newPos > FScaleMax then newPos:=FScaleMax;
FScalePos:=NewPos; // neue Position übernehmen
Invalidate;
end;
procedure TSlider.paint;
begin
// den gesamten Hintergrund ausfüllen
canvas.Brush.Color:=color;
canvas.FillRect(ClientRect);
//... hier den rest zeichen
end;
// Hier machst Du deine grundlegenden Initialisierungen
constructor TSlider.create(aOwner:TComponent);
begin
inherited;
SetBounds(0,0,200,16); // dein Umschliessendes Rechteck wie gross es sein soll (Zeichenbereich)
// Deine Grundinitialisierung
FScaleMin :=0;
FScaleMax :=100;
FScalePos :=50; // Schieber auf Mitte setzen
end;
Siro
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
-
- Beiträge: 607
- Registriert: Di 19. Mai 2015, 20:05
- OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
- CPU-Target: x86_64-linux-gtk2
Re: Erstellen einer Komponente
Hallo Siro,
vielen Dank für die viele Arbeit. Kann auf Grund deines Beispiels noch etliches in meinem Code verbessern! Ich habe aber noch eins festgestellt.
Wenn ich meine Komponente nicht mit dem OI erzeuge, sondern per Laufzeit, wird z. Bsp. SetScalePos nur durchlaufen wenn ich ScalePos setze. Ändere ich z.Bsp. ScaleMin und /oder ScaleMax so ab das die Voreinstellung von ScalePos ausserhalb liegt und ich merke es nicht (setze also ScalePos auch nicht) wird die Überprüfung von ScalePos nicht durchlaufen. Du machst in deinem Code wahrscheinlich deshalb die Prüfung auch in ScaleMin/Max? Heisst dann für mich ich muss in jeder Set.. Procedure die nötigen Überprüfungen machen wie sich eine Änderung auswirkt.
Nochmal vielen Dank, ich glaube ich hab da einfach zu kompliziert gedacht.
Bernd
vielen Dank für die viele Arbeit. Kann auf Grund deines Beispiels noch etliches in meinem Code verbessern! Ich habe aber noch eins festgestellt.
Wenn ich meine Komponente nicht mit dem OI erzeuge, sondern per Laufzeit, wird z. Bsp. SetScalePos nur durchlaufen wenn ich ScalePos setze. Ändere ich z.Bsp. ScaleMin und /oder ScaleMax so ab das die Voreinstellung von ScalePos ausserhalb liegt und ich merke es nicht (setze also ScalePos auch nicht) wird die Überprüfung von ScalePos nicht durchlaufen. Du machst in deinem Code wahrscheinlich deshalb die Prüfung auch in ScaleMin/Max? Heisst dann für mich ich muss in jeder Set.. Procedure die nötigen Überprüfungen machen wie sich eine Änderung auswirkt.
Nochmal vielen Dank, ich glaube ich hab da einfach zu kompliziert gedacht.
Bernd
- kupferstecher
- Beiträge: 431
- Registriert: Do 17. Nov 2016, 11:52
Re: Erstellen einer Komponente
Ich hab deine Frage ja so verstanden, dass du ScalePos im Setter an die Grenzen anpassen möchtest, und deshalb die Aufrufreihenfolge (Min, Max und Pos) stimmen muss, wenn die Werte im OI gesetzt wurden.
Die Antwort darauf weiß ich nicht, ich würde aber vermuten, dass die Reihenfolge durchlaufen wird, wie die Variablen als Published deklariert wurden. Das kannst du ja mal ausprobieren. Der relevante Abschnitt wäre also:
Die Antwort darauf weiß ich nicht, ich würde aber vermuten, dass die Reihenfolge durchlaufen wird, wie die Variablen als Published deklariert wurden. Das kannst du ja mal ausprobieren. Der relevante Abschnitt wäre also:
Code: Alles auswählen
published
property ScaleMin: Integer read FScaleMin write SetScaleMin;
property ScaleMax: Integer read FScaleMax write SetScaleMax;
property ScalePos: Integer read FScalePos write SetScalePos;
Einfach die Überprüfung in eine eigene Prozedur auslagern, sie wird ja bei Min, Max und Pos benötigt.wennerer hat geschrieben: Heisst dann für mich ich muss in jeder Set.. Procedure die nötigen Überprüfungen machen wie sich eine Änderung auswirkt.
Code: Alles auswählen
Procedure TSlider.EnforcePosMinMax;
begin
if ScalePos < ScaleMin then ScalePos:=ScaleMin;
if ScalePos > ScaleMax then ScalePos:=ScaleMax;
end;
-
- Beiträge: 607
- Registriert: Di 19. Mai 2015, 20:05
- OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
- CPU-Target: x86_64-linux-gtk2
Re: Erstellen einer Komponente
Hallo Kupferstecher,
auch dir noch mal vielen Dank. Ich werde eure Anregungen jetzt mal durch probieren und schauen mit was ich am besten zurecht komme! Jedenfalls habe ich jetzt etliche Ansatzpunkte.
Viele Grüße Bernd
auch dir noch mal vielen Dank. Ich werde eure Anregungen jetzt mal durch probieren und schauen mit was ich am besten zurecht komme! Jedenfalls habe ich jetzt etliche Ansatzpunkte.
Viele Grüße Bernd
Re: Erstellen einer Komponente
Da würde ich mich nicht drauf verlassen, vielleicht kommt jemand daher wie ich, der die Properties gerne in alphabetische Reihenfolge sortiert...kupferstecher hat geschrieben:... ich würde aber vermuten, dass die Reihenfolge durchlaufen wird, wie die Variablen als Published deklariert wurden.
Also, wenn es auf die Reihenfolge der Abarbeitung ankommt, kannst du die Loaded-Methode überschreiben. Wenn diese drankommt, sind alle Properties geladen, und du hast nun alle Werte zur Verfügung für Folgeaktionen. Wenn es schädlich ist, dass vorher beim Laden der Setter ausgeführt wird, kann man dies mit "if csLoading in ComponentState" abfangen.
Code: Alles auswählen
procedure TSlider.Loaded;
begin
inherited;
if FScalePos < FScaleMin then
FScalePos := FScaleMin
else if FScalePos > FScaleMax then
FScalePos := FScaleMax;
end;
procedure TSlider.SetScalePos(NewValue: Integer);
begin
if FScalePs = NewPos then exit;
if (csLoading in ComponentState) then
FScalePos := NewPos
else begin
... (dein Code)
end;
end;
// analog für ScaleMin und ScaleMax
-
- Beiträge: 607
- Registriert: Di 19. Mai 2015, 20:05
- OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
- CPU-Target: x86_64-linux-gtk2
Re: Erstellen einer Komponente
Hallo wp_xyz,
das mit der Loaded Methode kommt meiner ursprünglichen Idee natürlich am Nähesten. Vielen Dank für deine Antwort. Ich werde mich dann mal weiter dran versuchen.
Viele Grüße Bernd
das mit der Loaded Methode kommt meiner ursprünglichen Idee natürlich am Nähesten. Vielen Dank für deine Antwort. Ich werde mich dann mal weiter dran versuchen.
Viele Grüße Bernd
Re: Erstellen einer Komponente
Das noch: In der Deklaration von Loaded das "override" nicht vergessen.
Code: Alles auswählen
type
TSlider= class (TCustomControl);
...
protected
procedure Loaded; override;
...
-
- Beiträge: 607
- Registriert: Di 19. Mai 2015, 20:05
- OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
- CPU-Target: x86_64-linux-gtk2
Re: Erstellen einer Komponente
Ja danke, werde dran denken.
Viele Grüße Bernd
Viele Grüße Bernd
- kupferstecher
- Beiträge: 431
- Registriert: Do 17. Nov 2016, 11:52
Re: Erstellen einer Komponente
@wp: Danke, wieder was gelernt!