Sign in Join
Wiki copytemporary

Building components 01/de: what changed

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

OldNewLine
11## Einleitung
22
33In 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.
44
55## Ziel dieses Kapitels
66
77Die 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)
88
99## Voraussetzungen
1010
11111.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.
1212
13132.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.
1414
15153.Erfahrung um Umgang mit der OOP sind unbedingt erforderlich.
1616
1717Alle drei Punkte sind nicht Teil dieses Tutorials. Wenn trotzdem damit angefangen wird, kann es sehr schnell zu Problemen und zu Frust führen.
1818
1919## Sonstige Hinweise
2020
2121Das Tutorial kann auf eigene Verantwortung durchgearbeitet werden. Für Schäden jeglicher Art bin ich nicht verantwortlich/haftbar.
2222
2323## Einige Hinweise und Tricks im Umgang mit Klassen
2424
2525Hier 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.
2626
2727### Klassen schneller erzeugen
2828
2929Um 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.
3030
3131### Typische Fehler vermeiden
3232
3333Wenn 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:
3434
3535property Test:String read fTest write fTest default „Hallo“;
3636
3737Das ist allerdings nur für das Streaming relevant, daher müssen trotzdem alle Variablen im Konstruktor mit relevanten Werten belegt werden.
3838
3939### Methoden schneller erzeugen
4040
4141Um 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
4242
4343### Die Übersicht in großen Units mit vielen Klassen und Datentypen behalten
4444
4545Wer 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.
4646
4747### Lösungen zu Problemen finden
4848
4949Da 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.
5050
5151## Los geht's
5252
5353Wir erstellen uns eine neue Unit. Die Unit sollte so aussehen:
5454
5555``` pascal
5656unit Unit1;
5757
5858{$mode objfpc}{$H+}
5959
6060interface
6161
6262uses
6363 Classes, SysUtils;
6464
6565implementation
6666
6767end.
6868```
6969
7070jetzt werden wir diese Unit erweitern.
7171
7272``` pascal
7373unit Unit1;
7474
7575{$mode objfpc}{$H+}
7676
7777interface
7878
7979uses
8080 Classes, SysUtils, Controls, Graphics;
8181
8282type
8383 TMyPanel = class(TCustomControl)
8484 private
8585
8686 protected
8787
8888 public
8989 constructor Create(AOwner: TComponent); override;
9090 destructor Destroy; override;
9191
9292 procedure Paint; override;
9393 published
9494
9595 end; // TMyPanel
9696
9797implementation
9898
9999end.
100100```
101101
102102Zunä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:
103103
104104**Create** Wird beim Initialisieren der Klasse aufgerufen.
105105
106106**Destroy** Wird beim Freigeben der Klasse aufgerufen.
107107
108108**Resize** Wenn die Komponente vergrößert wird.
109109
110110**MouseDown** Bei einem Mausklick.
111111
112112**MouseUp** Wenn die Maustaste losgelassen wird.
113113
114114**MouseMove** Wenn die Maus bewegt wird.
115115
116116**KeyDown** Wenn eine Steuertaste, wie z.B. die Pfeiltasten, gedrückt wird.
117117
118118**KeyUp** Wenn eine Taste losgelassen wird.
119119
120120**KeyPress** Wenn ein Buchstabe gedrückt wird.
121121
122122**WMEraseBkgnd** Ist für das Löschen des Hintergrunds gedacht.
123123
124124**EraseBackground** Ist für das Löschen des Hintergrunds gedacht.
125125
126126Je 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.
127127
128128Hier eine weitere Übersicht, welche Aufgaben von der Klasse übernommen werden:
129129
1301301. User Events werden automatisch zur Verfügung gestellt.
1311312. Wenn das Fenster neu gezeichnet wird, werden automatisch alle Komponenten neu gezeichnet.
1321323. Wenn das darunter liegende Fenster vergrößert wird, werden alle Komponenten benachrichtigt.
1331334. Bei Bedarf werden Scrollbalken angezeigt.
1341345. Die Integration in die Lazarus IDE wird zur Verfügung gestellt.
135135
136136Zur Erinnerung: Unser Sourcecode sieht im Moment so aus:
137137
138138``` pascal
139139unit Unit1;
140140
141141{$mode objfpc}{$H+}
142142
143143interface
144144
145145uses
146146 Classes, SysUtils, Controls, Graphics;
147147
148148type
149149 TMyPanel = class(TCustomControl)
150150 private
151151
152152 protected
153153
154154 public
155155 constructor Create(AOwner: TComponent); override;
156156 destructor Destroy; override;
157157
158158 procedure Paint; override;
159159 published
160160
161161 end; // TMyPanel
162162
163163implementation
164164
165165end.
166166```
167167
168168Für das Panel, das wir erstellen wollen, werden wir es so erweitern:
169169
170170``` pascal
171171unit Unit1;
172172
173173{$mode objfpc}{$H+}
174174
175175interface
176176
177177uses
178178 Classes, SysUtils, Controls, Graphics;
179179
180180type
181181 TMyPanel = class(TCustomControl)
182182 private
183183 fTextStyle:TTextStyle;
184184 fGradientDirection:TGradientDirection;
185185 fStartColor, fEndColor:TColor;
186186
187187 protected
188188
189189 public
190190 constructor Create(AOwner: TComponent); override;
191191 destructor Destroy; override;
192192
193193 procedure Paint; override;
194194 published
195195 property GradientDirection:TGradientDirection read fGradientDirection write SetGradientDirection;
196196 property StartColor:TColor index 0 read GetColor write SetColor;
197197 property EndColor:TColor index 1 read GetColor write SetColor;
198198
199199 property Alignment:TAlignment read fTextStyle.Alignment write SetAlignment;
200200 property Layout:TTextLayout read fTextStyle.Layout write SetLayout;
201201 property ShowPrefix:boolean read fTextStyle.ShowPrefix write SetShowPrefix;
202202 property Wordbreak:Boolean read fTextStyle.Wordbreak write SetBreak;
203203 property SystemFont:Boolean read fTextStyle.SystemFont write SetSystemFont;
204204
205205 end; // TMyPanel
206206
207207implementation
208208
209209end.
210210```
211211
212212Ganz 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.
213213
214214``` pascal
215215function TMyPanel.GetColor(AIndex: integer): TColor;
216216begin
217217 case AIndex of
218218 0: result:=fStartColor;
219219 1: result:=fEndColor;
220220 end; // case
221221end; // TMyPanel.GetColor
222222
223223procedure TMyPanel.SetAlignment(const AValue: TAlignment);
224224begin
225225 if fTextStyle.Alignment=AValue then exit;
226226 fTextStyle.Alignment:=AValue;
227227 Paint;
228228end; // TMyPanel.SetAlignment
229229
230230procedure TMyPanel.SetBreak(const AValue: Boolean);
231231begin
232232 if fTextStyle.Wordbreak=AValue then exit;
233233 fTextStyle.Wordbreak:=AValue;
234234 Paint;
235235end; // TMyPanel.SetBreak
236236
237237procedure TMyPanel.SetColor(AIndex: integer; const AValue: TColor);
238238begin
239239 case AIndex of
240240 0: fStartColor:=AValue;
241241 1: fEndColor:=AValue;
242242 end; // case
243243 Paint;
244244end; // TmyPanel.SetColor
245245
246246procedure TMyPanel.SetGradientDirection(const AValue: TGradientDirection);
247247begin
248248 if fGradientDirection=AValue then exit;
249249 fGradientDirection:=AValue;
250250 Paint;
251251end; // TmyPanel.SetGradientDirection
252252
253253procedure TMyPanel.SetLayout(const AValue: TTextLayout);
254254begin
255255 if fTextStyle.Layout=AValue then exit;
256256 fTextStyle.Layout:=AValue;
257257 Paint;
258258end; // TmyPanel.SetLayout
259259
260260constructor TMyPanel.Create(AOwner: TComponent);
261261begin
262262 inherited Create(AOwner);
263263 fGradientDirection:=gdVertical;
264264 fStartColor:=clBlue;
265265 fEndColor:=clYellow;
266266 fTextStyle.Layout:=tlCenter;
267267 fTextStyle.Alignment:=taCenter;
268268end; // TMyPanel.Create
269269
270270destructor TMyPanel.Destroy;
271271begin
272272 inherited Destroy;
273273end; // TMyPanel.Destroy
274274
275275procedure TMyPanel.Paint;
276276var
277277 r:TRect;
278278begin
279279 inherited Paint;
280280 r:=Rect(0,0,Width,Height);
281281 Canvas.GradientFill(r,StartColor, EndColor,GradientDirection);
282282 Canvas.TextRect(r,r.left,r.top,Caption,fTextStyle);
283283end; // TMyPanel.Paint
284284
285285end.
286286```
287287
288288Fü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.
289289
290290``` pascal
291291procedure TForm1.FormCreate(Sender: TObject);
292292begin
293293 myPanel:=TMyPanel.Create(Panel1);
294294 myPanel.Align:=alClient;
295295 myPanel.Parent:=Panel1;
296296 myPanel.Caption:='Dies ist ein einfacher Test von Heute';
297297 Button:=TButton.Create(myPanel);
298298 Button.Left:=10;
299299 Button.Top:=10;
300300 Button.Caption:='Klick Mich';
301301 Button.Parent:=myPanel;
302302end;
303303```
304304
305305From Die Variable **myPanel** und **Button** sollte im private Bereich des Forms angelegt werden. Ein erster Test sollte folgendes Bild zeigen
306306
307-<figure>
308-<img src="MyCreateComponentImage01.png" title="MyCreateComponentImage01.png" />
309-<figcaption>MyCreateComponentImage01.png</figcaption>
310-</figure>
307+![](/wiki-images/5/57/MyCreateComponentImage01.png)
311308
312309## Die IDE Integration
313310
314311Im letzten Schritt geht es darum, die Komponente zu installieren. Da das jedoch nicht Teil dieses Tutorials ist, verweise ich einfach auf die Lazarus Dokumentation:
315312
3163131. Pakete erstellen und Komponente installieren [[Lazarus Packages/de]]
3173142. 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]]
318315
319316## Weitere Nützliche Links zum Thema
320317
3213181. [[Extending the IDE/de]]
3223192. [[Streaming components/de]]
323-
324-\
325-\
326320
327321---
328322*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).*
329323Category: Tutorials/de

Back to history