Sign in Join
Wiki copytemporary

Building components 01/de: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Building components 01/de

OldNewLine
1+## Einleitung
2+
3+In diesem Tutorial geht es darum, eine komplett eigene Komponente zu erstellen und sie in Lazarus zu integrieren. Ihr werdet sehen, dass es gar nicht so schwer ist. Zunächst die Frage was ist eine Komponente eigentlich? Eine Komponente ist eine einfache Klasse, die meistens von einer vorherigen Klasse abgeleitet wird. Diese Klasse heißt auch „Abstracte Bases Klasse“, weil sie stellt ein Standardverhalten, welches für alle Komponenten gilt, zur Verfügung. Die meisten GUIs (engl. Graphical User Interface), haben sogar mehrere Bases Klassen,je nach Aufgabe. Es gibt in einer GUI verschiedene Bereiche z.b. eine sichtbare Komponente wie das TMemo, oder auch zunächst unsichtbare Komponenten wie einen Dialog oder die Timer Komponenten. Lazarus unterscheidet grob gesehen zwei Bereiche: Der Erste besteht aus Komponenten die vom Toolkit wie z.b. GTK2 zur Vergfügung gestellt wird. Diese Komponenten sind dann von TWinControl abgeleitet. Der ander Bereich besteht aus eigenen Komponenten, wie z.B. das Panel oder die OI-Komponente. Diese sind dann direkt von TCustomControl abgeleitet. TCustomControl spielt in diesem Kapitel ein große Rolle, denn wir wollen eine komplett eigene Komponente entwickeln.
4+
5+## Ziel dieses Kapitels
6+
7+Die Komponente wird nur eine einfache Aufgabe erfüllen, aber sie zeigt wie in Lazarus üblicherweise vorgegangen wird. Das Ziel ist es, ein eigenes Panel zu entwickeln, welches im Gegensatz zum Standardpanel von Lazarus nicht nur eine Farbe hat, sondern ein Farbverlauf anzeigt, auf dem ein Text dargestellt werden kann. Wir werden Standardmethoden und Eigenschaften von TCustomControl verwenden. Außerdem werde ich zeigen, wie diese Komponente in Lazarus integriert werden kann und wie ein eigenes Icon zugewiesen werden kann. Auf einer Extraseite gebe ich einige Tipps, wie die Entwicklung beschleunigt werden kann. Es gibt eine ganze Reihe praktischer aber oft versteckter Funktionen im Code Editor (SynEdit) von Lazarus. Mein Lazarus: Version: 0.9.29 Beta, SVN-Revison: 22080M I386-linux-gtk2(beta)
8+
9+## Voraussetzungen
10+
11+1.Eine funktionsfähige Lazarus-Umgebung, die jederzeit neu erstellt werden kann. Um das zu testen im Menü unter Werkzeuge\Lazarus kompilieren ausführen. Wenn das fehlerfrei durchgeführt wird, kann davon ausgegangen werden, dass es keine Probleme gibt.
12+
13+2.Elementare Kenntnisse der Syntax von Object Pascal, außerdem sollte die Umgebung von Lazarus vertraut sein, z.B. wie kompiliere ich Programme und so weiter.
14+
15+3.Erfahrung um Umgang mit der OOP sind unbedingt erforderlich.
16+
17+Alle drei Punkte sind nicht Teil dieses Tutorials. Wenn trotzdem damit angefangen wird, kann es sehr schnell zu Problemen und zu Frust führen.
18+
19+## Sonstige Hinweise
20+
21+Das Tutorial kann auf eigene Verantwortung durchgearbeitet werden. Für Schäden jeglicher Art bin ich nicht verantwortlich/haftbar.
22+
23+## Einige Hinweise und Tricks im Umgang mit Klassen
24+
25+Hier habe ich einige Hinweise, Tricks und Tipps zusammengetragen, die den Umgang mit Klassen vereinfachen soll und die Entwicklung erheblich beschleunigen kann. Das geht meistens so, dass lästige Tipparbeit abgenommen wird.
26+
27+### Klassen schneller erzeugen
28+
29+Um eine Klasse schneller zu erzeugen und nicht immer die gleichen Sachen schreiben zu müssen, gibt es die Code-Schablonen. Genutzt werden können sie mit STRG+J. Davor ein Wort eingeben, für Klassen z.B. classC und dann STRG+J und es wird der Standardheader einer Klasse erzeugt.
30+
31+### Typische Fehler vermeiden
32+
33+Wenn eine Eigenschaft nicht im OI auftaucht, liegt es meistens daran, dass sie nicht installiert wurde. Das tritt meistens im Zusammenhang mit Klassen auf, beispielweise bei einer TStringList. Es empfiehlt sich auch bei jeder Eigenschaft das Schlüsselwort default zu nutzen. Beispiel:
34+
35+property Test:String read fTest write fTest default „Hallo“;
36+
37+Das ist allerdings nur für das Streaming relevant, daher müssen trotzdem alle Variablen im Konstruktor mit relevanten Werten belegt werden.
38+
39+### Methoden schneller erzeugen
40+
41+Um Methoden schneller zu erzeugen, gibt es die Funktion Quelltext vervollständigen. Über eine Tastenkombination kann sie aufgerufen werden, bei mir ist das STRG+UMSCHALT+C
42+
43+### Die Übersicht in großen Units mit vielen Klassen und Datentypen behalten
44+
45+Wer eine Unit mit sehr vielen Klassen und Datentypen hat, verliert schnell die Übersicht. Um das zu vermeiden, gibt es in Lazarus den Code-Explorer. Er analysiert den Code und erstellt einen Baum, um das Navigieren zu erleichtern.
46+
47+### Lösungen zu Problemen finden
48+
49+Da Lazarus komplett Open Source ist, gibt es für sehr viele Probleme bereits Lösungen. Um in Erfahrung zu bringen, wie z.b. ein OI-Editor geschrieben wird, kann folgendermaßen vorgegangen werden: Wenn in der Komponenten-Leiste der Eintrag RTTI auftaucht, kann dort der OI aufs Form platziert werden. Jetzt einfach im Source-Code-Editor die rechte Maustaste drücken und den ersten Menüeintrag auswählen: Zur Deklaration springen. Jetzt könnt ihr euch z.b. die uses Klausel anschauen. Einige Namen dürften sofort auffallen. Eine andere Möglichkeit ist die Funktion in Dateien Suchen.
50+
51+## Los geht's
52+
53+Wir erstellen uns eine neue Unit. Die Unit sollte so aussehen:
54+
55+``` pascal
56+unit Unit1;
57+
58+{$mode objfpc}{$H+}
59+
60+interface
61+
62+uses
63+ Classes, SysUtils;
64+
65+implementation
66+
67+end.
68+```
69+
70+jetzt werden wir diese Unit erweitern.
71+
72+``` pascal
73+unit Unit1;
74+
75+{$mode objfpc}{$H+}
76+
77+interface
78+
79+uses
80+ Classes, SysUtils, Controls, Graphics;
81+
82+type
83+ TMyPanel = class(TCustomControl)
84+ private
85+
86+ protected
87+
88+ public
89+ constructor Create(AOwner: TComponent); override;
90+ destructor Destroy; override;
91+
92+ procedure Paint; override;
93+ published
94+
95+ end; // TMyPanel
96+
97+implementation
98+
99+end.
100+```
101+
102+Zunächst habe ich zwei Units hinzugefügt. In der Unit **Controls** Steckt die Klasse **TCustomControl**, die wir verwenden wollen. In der Unit **Graphics** sind einige sinnvolle Konstanten definiert, wie z.b. clRed oder auch die Systemfarben. Jetzt habe ich eine erste Klasse erstellt, die direkt von **TCustomControl** abgeleitet ist. Ich habe der Klasse den Namen **TMyPanel** gegeben. Das T ist nur Geschmackssache. Es hat sich in der Benutzergemeinde eingebürgert, vor komplexeren eigenen Datentypen wie Klassen oder Record z.b. ein T zu schreiben. Meiner Meinung nach basiert das auf historischen Gründen. Früher gab es für DOS ein GUI mit dem Namen TVision. Dieses gibt es sogar noch heute und ist sogar in FPC enthalten. In dieser Klasse werden einige Standarmethoden überschrieben wie z.b. **Create** und **Destroy**. An dieser Stelle eine kleine Übersicht über weitere nützliche Methoden:
103+
104+**Create** Wird beim Initialisieren der Klasse aufgerufen.
105+
106+**Destroy** Wird beim Freigeben der Klasse aufgerufen.
107+
108+**Resize** Wenn die Komponente vergrößert wird.
109+
110+**MouseDown** Bei einem Mausklick.
111+
112+**MouseUp** Wenn die Maustaste losgelassen wird.
113+
114+**MouseMove** Wenn die Maus bewegt wird.
115+
116+**KeyDown** Wenn eine Steuertaste, wie z.B. die Pfeiltasten, gedrückt wird.
117+
118+**KeyUp** Wenn eine Taste losgelassen wird.
119+
120+**KeyPress** Wenn ein Buchstabe gedrückt wird.
121+
122+**WMEraseBkgnd** Ist für das Löschen des Hintergrunds gedacht.
123+
124+**EraseBackground** Ist für das Löschen des Hintergrunds gedacht.
125+
126+Je nach Aufgabe können die hier vorgestellten Methoden praktisch sein. Diese Methoden werden automatisch aufgerufen von der LCL, je nach Botschaft die eingeht. Es gibt sehr viele Botschaften. Für einige gibt es eine Methode, für andere nicht. Wenn eine Botschaft wie z.b. **WMEraseBkgnd** aufgerufen werden soll, muss die Unit **Messages** eingebunden werden. Wie hier gesehen werden kann, übernimmt die Klasse **TCustomControl** sehr viele Aufgaben für uns.
127+
128+Hier eine weitere Übersicht, welche Aufgaben von der Klasse übernommen werden:
129+
130+1. User Events werden automatisch zur Verfügung gestellt.
131+2. Wenn das Fenster neu gezeichnet wird, werden automatisch alle Komponenten neu gezeichnet.
132+3. Wenn das darunter liegende Fenster vergrößert wird, werden alle Komponenten benachrichtigt.
133+4. Bei Bedarf werden Scrollbalken angezeigt.
134+5. Die Integration in die Lazarus IDE wird zur Verfügung gestellt.
135+
136+Zur Erinnerung: Unser Sourcecode sieht im Moment so aus:
137+
138+``` pascal
139+unit Unit1;
140+
141+{$mode objfpc}{$H+}
142+
143+interface
144+
145+uses
146+ Classes, SysUtils, Controls, Graphics;
147+
148+type
149+ TMyPanel = class(TCustomControl)
150+ private
151+
152+ protected
153+
154+ public
155+ constructor Create(AOwner: TComponent); override;
156+ destructor Destroy; override;
157+
158+ procedure Paint; override;
159+ published
160+
161+ end; // TMyPanel
162+
163+implementation
164+
165+end.
166+```
167+
168+Für das Panel, das wir erstellen wollen, werden wir es so erweitern:
169+
170+``` pascal
171+unit Unit1;
172+
173+{$mode objfpc}{$H+}
174+
175+interface
176+
177+uses
178+ Classes, SysUtils, Controls, Graphics;
179+
180+type
181+ TMyPanel = class(TCustomControl)
182+ private
183+ fTextStyle:TTextStyle;
184+ fGradientDirection:TGradientDirection;
185+ fStartColor, fEndColor:TColor;
186+
187+ protected
188+
189+ public
190+ constructor Create(AOwner: TComponent); override;
191+ destructor Destroy; override;
192+
193+ procedure Paint; override;
194+ published
195+ property GradientDirection:TGradientDirection read fGradientDirection write SetGradientDirection;
196+ property StartColor:TColor index 0 read GetColor write SetColor;
197+ property EndColor:TColor index 1 read GetColor write SetColor;
198+
199+ property Alignment:TAlignment read fTextStyle.Alignment write SetAlignment;
200+ property Layout:TTextLayout read fTextStyle.Layout write SetLayout;
201+ property ShowPrefix:boolean read fTextStyle.ShowPrefix write SetShowPrefix;
202+ property Wordbreak:Boolean read fTextStyle.Wordbreak write SetBreak;
203+ property SystemFont:Boolean read fTextStyle.SystemFont write SetSystemFont;
204+
205+ end; // TMyPanel
206+
207+implementation
208+
209+end.
210+```
211+
212+Ganz wichtig sind die Property's im **published** Bereich. Die hier eingetragenen Eigenschaften werden beim drauf klicken im Lazarus-Designer im OI (Objekt Inspektor) angezeigt. Die Setter Methoden sind insofern notwendig, da hier ein automatisches Neuzeichnen der Komponenten realisiert werden kann. mit **fTextStyle** hat es eine Besonderheit: Beim Datentyp **TTextStyle** handelt es sich um einen **Record**, dieses wird aber im OI nicht angezeigt. Auch wenn die RTTI hierfür Methoden und Möglichkeiten vorsieht, wird es einfach vom OI nicht unterstützt. Jetzt sind wir soweit und können die Methoden ausschreiben. Um das zu vereinfachen, und um Zeit zu sparen, gibt es im Kapitel mit den Hinweisen ein Trick.
213+
214+``` pascal
215+function TMyPanel.GetColor(AIndex: integer): TColor;
216+begin
217+ case AIndex of
218+ 0: result:=fStartColor;
219+ 1: result:=fEndColor;
220+ end; // case
221+end; // TMyPanel.GetColor
222+
223+procedure TMyPanel.SetAlignment(const AValue: TAlignment);
224+begin
225+ if fTextStyle.Alignment=AValue then exit;
226+ fTextStyle.Alignment:=AValue;
227+ Paint;
228+end; // TMyPanel.SetAlignment
229+
230+procedure TMyPanel.SetBreak(const AValue: Boolean);
231+begin
232+ if fTextStyle.Wordbreak=AValue then exit;
233+ fTextStyle.Wordbreak:=AValue;
234+ Paint;
235+end; // TMyPanel.SetBreak
236+
237+procedure TMyPanel.SetColor(AIndex: integer; const AValue: TColor);
238+begin
239+ case AIndex of
240+ 0: fStartColor:=AValue;
241+ 1: fEndColor:=AValue;
242+ end; // case
243+ Paint;
244+end; // TmyPanel.SetColor
245+
246+procedure TMyPanel.SetGradientDirection(const AValue: TGradientDirection);
247+begin
248+ if fGradientDirection=AValue then exit;
249+ fGradientDirection:=AValue;
250+ Paint;
251+end; // TmyPanel.SetGradientDirection
252+
253+procedure TMyPanel.SetLayout(const AValue: TTextLayout);
254+begin
255+ if fTextStyle.Layout=AValue then exit;
256+ fTextStyle.Layout:=AValue;
257+ Paint;
258+end; // TmyPanel.SetLayout
259+
260+constructor TMyPanel.Create(AOwner: TComponent);
261+begin
262+ inherited Create(AOwner);
263+ fGradientDirection:=gdVertical;
264+ fStartColor:=clBlue;
265+ fEndColor:=clYellow;
266+ fTextStyle.Layout:=tlCenter;
267+ fTextStyle.Alignment:=taCenter;
268+end; // TMyPanel.Create
269+
270+destructor TMyPanel.Destroy;
271+begin
272+ inherited Destroy;
273+end; // TMyPanel.Destroy
274+
275+procedure TMyPanel.Paint;
276+var
277+ r:TRect;
278+begin
279+ inherited Paint;
280+ r:=Rect(0,0,Width,Height);
281+ Canvas.GradientFill(r,StartColor, EndColor,GradientDirection);
282+ Canvas.TextRect(r,r.left,r.top,Caption,fTextStyle);
283+end; // TMyPanel.Paint
284+
285+end.
286+```
287+
288+Für einen ersten Test sollten wir diese Komponente dynamisch erzeugen, dass heißt manuell per Sourcecode. Dazu fügen wir die **unit2** in **unit1** ein. Mit folgendem Code kann nun die Komponente erzeugt werden, vorausgesetzt es befindet sich ein Panel mit dem Namen **Panel1** auf dem From.
289+
290+``` pascal
291+procedure TForm1.FormCreate(Sender: TObject);
292+begin
293+ myPanel:=TMyPanel.Create(Panel1);
294+ myPanel.Align:=alClient;
295+ myPanel.Parent:=Panel1;
296+ myPanel.Caption:='Dies ist ein einfacher Test von Heute';
297+ Button:=TButton.Create(myPanel);
298+ Button.Left:=10;
299+ Button.Top:=10;
300+ Button.Caption:='Klick Mich';
301+ Button.Parent:=myPanel;
302+end;
303+```
304+
305+From Die Variable **myPanel** und **Button** sollte im private Bereich des Forms angelegt werden. Ein erster Test sollte folgendes Bild zeigen
306+
307+<figure>
308+<img src="MyCreateComponentImage01.png" title="MyCreateComponentImage01.png" />
309+<figcaption>MyCreateComponentImage01.png</figcaption>
310+</figure>
311+
312+## Die IDE Integration
313+
314+Im letzten Schritt geht es darum, die Komponente zu installieren. Da das jedoch nicht Teil dieses Tutorials ist, verweise ich einfach auf die Lazarus Dokumentation:
315+
316+1. Pakete erstellen und Komponente installieren [[Lazarus Packages/de]]
317+2. Icon für die Eigene Komponente erstellen [[Extending the IDE/de|Extending_the_IDE/de#Einer_neuen_Komponente_ein_Icon_für_die_Komponentenpalette_verpassen]]
318+
319+## Weitere Nützliche Links zum Thema
320+
321+1. [[Extending the IDE/de]]
322+2. [[Streaming components/de]]
323+
324+\
325+\
326+
327+---
328+*From the Free Pascal wiki, page "Building components 01/de", as it stood on 2020-02-10 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
329+Category: Tutorials/de

Back to history