Sign in Join
Wiki copytemporary

How To Write Lazarus Component/de: what changed

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

OldNewLine
11Das ist eine Anleitung, wie man Komponenten erstellt.
22
33## Schritt 1: Erstellen des Packages
44
55- Klicken Sie im Lazarus Hauptmenue **Package -\> neues Package ...** um den Package-Manager ausführen.
66
7-<figure>
8-<img src="package_menu.png" title="package_menu.png" />
9-<figcaption>package_menu.png</figcaption>
10-</figure>
7+![](/wiki-images/7/7c/Package_menu.png)
118
129- Ein Datei-**Speichern**-Dialog öffnet sich. Wählen Sie ein Verzeichnis und einen Dateinamen für das neu anzulegende Package und klicken Sie auf **Speichern**. Wenn Lazarus Sie auffordert **Datei in Kleinbuchstaben umbenennen** klicken Sie auf **Ja**.
1310
1411- Glückwunsch: Sie haben soeben Ihr erstes Package erstellt!
1512
16-<figure>
17-<img src="How_to_write_lazarus_component_package_maker.png" title="Package Maker" />
18-<figcaption>Package Maker</figcaption>
19-</figure>
13+![](/wiki-images/3/37/How_to_write_lazarus_component_package_maker.png)
2014
2115## Schritt 2: Erstellen der Unit
2216
2317Sie können eine neue Unit erstellen oder eine existierende Datei nutzen. Beide Möglichkeiten sind nachfolgend beschrieben.
2418
2519### Erstellen einer neuen Unit
2620
2721- Nutzen Sie den **+ Hinzufügen** Button und klicken Sie auf den Reiter **Neue Komponente**.
2822
29-<figure>
30-<img src="package_new_component.png" title="package_new_component.png" />
31-<figcaption>package_new_component.png</figcaption>
32-</figure>
23+![](/wiki-images/5/56/Package_new_component.png)
3324
3425- Wählen Sie eine Komponente wie eine TComboBox.
3526- Wählen Sie *customcontrol1.pas* als Unit-Dateinamen und *CustomControl1* als Unit-Namen.
3627- Sie können jetzt der Komponente noch ein Icon geben, sowie festlegen, auf welcher Palette die Komponente später in der Lazarus-IDE erscheinen soll.
3728- Klicken Sie auf **Neue Komponente erzeugen**.
3829
3930``` pascal
4031unit CustomControl1;
4132
4233{$mode objfpc}{$H+}
4334
4435interface
4536
4637uses
4738 Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls;
4839
4940type
5041 TCustomControl1 = class(TComboBox)
5142 private
5243 { Private declarations }
5344 protected
5445 { Protected declarations }
5546 public
5647 { Public declarations }
5748 published
5849 { Published declarations }
5950 end;
6051
6152procedure Register;
6253
6354implementation
6455
6556procedure Register;
6657begin
6758 RegisterComponents('Standard',[TCustomControl1]);
6859end;
6960
7061end.
7162```
7263
7364- Installieren Sie die Package in dem Sie auf **Nutzung ... -\> Installieren** klicken.
7465
75-<figure>
76-<img src="package_install.png" title="package_install.png" />
77-<figcaption>package_install.png</figcaption>
78-</figure>
66+![](/wiki-images/3/36/Package_install.png)
7967
8068- Die IDE fragt Sie, ob Lazarus neu kompiliert werden soll. Bestätigen Sie mit **Ja**.
8169
82-<figure>
83-<img src="package_rebuild.png" title="package_rebuild.png" />
84-<figcaption>package_rebuild.png</figcaption>
85-</figure>
70+![](/wiki-images/9/9b/Package_rebuild.png)
8671
8772- Starten Sie Lazarus neu und sehen Sie Ihre neue Komponente in der entsprechenden Komponentenpalette. Glückwunsch: Sie haben eben Ihr erstes Package mit Ihrer ersten Package-Komponente erstellt.
8873
89-<figure>
90-<img src="package_installed.png" title="package_installed.png" />
91-<figcaption>package_installed.png</figcaption>
92-</figure>
74+![](/wiki-images/3/35/Package_installed.png)
9375
9476> **Note:** Wenn Sie die neue Komponente in der Komponente-Palette nicht angezeigt bekommen, ist es sehr wahrscheinlich, dass nicht die neu kompilierte Version von Lazarus ausgeführt wird. Sie können festlegen, wo Lazarus neu erstellt wird, unter Werkzeuge -\> Einstellungen -\> Dateien -\> Lazarus-Verzeichnis.
9577>
9678> Statt Lazarus direkt zu starten, können Sie auch Startlazarus ausführen, was das neu erstellte Lazarus aufruft, zum Besipiel die ausführbare Lazarus Datei im Verzeichnis ~/.lazarus, wenn Sie keinen Schreibzugriff auf das Verzeichnis haben, in dem Lazarus installiert wurde.
9779
9880### Zufügen einer vorhandenen Unit
9981
10082Wenn Sie schon eine vorhandene Unit haben, können Sie diese dem Package wie folgt zufügen:
10183
102-<figure>
103-<img src="package_existing_unit.png" title="package_existing_unit.png" />
104-<figcaption>package_existing_unit.png</figcaption>
105-</figure>
84+![](/wiki-images/1/11/Package_existing_unit.png)
10685
10786- Klicken Sie den **+ Hinzufügen** Button, gehen Sie auf dem Reiter **Dateien hinzufügen**.
10887- Klicken Sie auf **Dateien hinzufügen** und wählen Sie Ihre vorhandene Datei. Wenn Sie die aufzunehmende Datei hinzugefügt haben, klicken Sie auf **Dateien ins Package aufnehmen**.
10988- Wenn der Package-Manager anmahnt, daß die Unit nicht im Unit-Pfad ist, klicken Sie auf Ja um das Verzeichnis dem Unitpfad hinzuzufügen.
11089- Klicken Sie den **+ Hinzufügen** Button nochmal, gehen Sie auf dem Reiter **Dateien hinzufügen**, wählen Sie die *.lrs* Datei und Klicken Sie auf **Dateien ins Package aufnehmen** (Sehen Sie im Schritt 3 für weitere Informationen über das Erstellen des Icons).
11190- Klicken Sie den **+ Hinzufügen** Button nochmal, gehen Sie auf dem Reiter **Neue Anforderung**. In Package-Name klicken Sie auf **LCL** und bestätigen Sie die Auswahl mit **Neue Abhängigkeit erzeugen**.
11291
11392Das Endresultat sollte so aussehen:
11493
115-<figure>
116-<img src="How_to_write_lazarus_component_package_maker_done.png" title="Package Maker" />
117-<figcaption>Package Maker</figcaption>
118-</figure>
94+![](/wiki-images/d/d9/How_to_write_lazarus_component_package_maker_done.png)
11995
12096- Klicken Sie unterhalb des Dateibaumes den Paket-Manager. Stellen Sie sicher, daß in den Dateieigenschaften *Register Unit* aktiviert ist.
12197- Klicken Sie auf den Button *Optionen*. Wählen Sie die Registerkarte *IDE-Einbindung*. Stellen Sie sicher, dass Designtime und Runtime von Packagetyp aktiviert ist.
12298- Klicken Sie auf kompilieren, um zu überprüfen, dass die Dateien fehlerfrei kompilieren.
12399- Klicken Sie auf den Button *Installieren*. Lazarus wird neu erstellen und automatisch neu gestartet.
124100
125101Die Komponente ist erstellt und kann verwendet werden:
126102
127-<figure>
128-<img src="How_to_write_lazarus_component_created.png" title="Component Created" />
129-<figcaption>Component Created</figcaption>
130-</figure>
103+![](/wiki-images/3/3c/How_to_write_lazarus_component_created.png)
131104
132105## Schritt 3: Erstellen eines Icons für das Package
133106
134107Sie sollten 24x24 Pixel große PNG-Files als Icons verwenden.
135108
136109Das verwendete Iconformat ist `.lrs`. FPC kann standardmäßige auch Resourcedateien `.rc` oder kompilierte Ressourcedateien `.res` seit der FPC Version 2.6. verwenden. Siehe [[Lazarus Resources|FPC _resources]].
137110
138111### Mit dem Lazarus-Bild-Editor
139112
140113Mit dem [[Lazarus Image Editor]] können Sie die Symbole im .lrs-Format erstellen.
141114
142115### Mit Lazres
143116
144117`lazres` sollte sich normalerweise im Unterverzeichnis Tools von Lazarus befinden.
145118
146119Sie müssen möglicherweise Lazres vor der ersten Verwendung kompilieren. Öffnen Sie einfach die *lazres.lpi* in der IDE und wählen im Menü **Start -\> Komplieren** (Strg + F9).
147120
148121**lrs Datei erstellen**
149122
150123Um die lrs-Datei zu erstellen führen Sie einfach folgenden Befehl aus:
151124
152125`~/lazarus/tools/lazres samplepackage.lrs TMyCom.png`
153126
154127Wobei
155128
156129- *samplepackage* der Name Ihres Packages ist
157130- *TMyCom* der Name Ihrer Komponente ist.
158131
159132Sie können auch mehrere Images zu Ihrer lrs-Datei zufügen, indem Sie die entsprechenden Namen der Image-Dateien am Ende anhängen. zB: ~/lazarus/tools/lazres samplepackage.lrs TMyCom.png TMyOtherCom.png ...
160133
161134**Beispiel**
162135
163136So könnte zum Beispiel eine resultierende Datei *samplepackage.lrs* aussehen:
164137
165138 LazarusResources.Add('TMyCom','PNG',[
166139 #137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#24#0#0#0#24#8#2#0#0#0'o'#21#170#175
167140 +#0#0#0#4'gAMA'#0#0#177#143#11#252'a'#5#0#0#0'|IDAT8O'#237#212#209#10#192' '#8
168141 +#5'P'#247#231#251's'#215#138#133#164#166'\'#220#195'`'#209'c'#157'L'#173#131
169142 +#153#169'd4'#168'dP'#137'r_'#235'5'#136'@Zmk'#16'd9'#144#176#232#164'1'#247
170143 +'I'#8#160'IL'#206'C'#179#144#12#199#140'.'#134#244#141'~'#168#247#209'S~;'#29
171144 +'V+'#196#201'^'#10#15#150'?'#255#18#227#206'NZ>42'#181#159#226#144#15'@'#201
172145 +#148#168'e'#224'7f<@4'#130'u_YD'#23#213#131#134'Q]'#158#188#135#0#0#0#0'IEND'
173146 +#174'B`'#130
174147 ]);
175148
176149Achten Sie darauf, dass die Ressourcendatei in Ihren Quellcode der neuen Komponente eingebunden wird, indem Sie in die Uses-Klausel *LResources* und folgende Zeilen am Ende des Quellcodes einfügen:
177150
178151``` pascal
179152initialization
180153 {$I samplepackage.lrs}
181154```
182155
183156## Recompiling Packages
184157
185158Immer, wenn Sie in Ihrer Datei *mycom.pas* Änderungen vornehmen, müssen Sie anschließend das Package neu erstellen. Öffnen Sie dazu die Datei *samplepackage.lpk* im Package-Manager und klicken Sie auf *Nutzung* -\> *Installieren*.
186159
187160## Removing Packages
188161
189162- To remove installed components: on the IDE menu, click Package \> Configure installed packages. The following image shows the Installed Packages tool.
190163
191164![`Installed Components`](/wiki-images/0/0e/How_to_write_lazarus_component_installed_components.png)
192165
193166- Select the package you want to uninstall and click Uninstall selection.
194167
195168If something goes wrong with a package (e.g. package directory is deleted without first uninstalling it), Lazarus may not allow you to uninstall packages. To fix the problem, at the IDE menu click Tools \> Build Lazarus. Lazarus will rebuild all packages and restart. You should now be able to uninstall problematic packages.
196169
197170## Enhancing mycom.pas
198171
199172- The code in *mycom.pas* above gives you the basics on what you need to create a component. The following is an enhanced version with some tips on how to write procedures and events for components.
200173- The *OnChange2* shows how to create events
201174- The *OnSample* shows how to create custom events
202175- *MyText* and *MyText2* shows different ways to write properties.
203176- You can use TComboBox instead of TCustomComboBox as the base class, which publishes all properties as TComboBox.
204177- If TCustomComboBox is used as the base class, you'll notice a lot of properties and events will be missing in the IDE Object Inspector. To add those properties and events, just copy and paste the properties as listed below *// properties from TComboBox*. These list of properties can be got from the TComboBox declaration in the StdCtrls unit. Omit any property which you want to handle yourself.
205178
206179``` pascal
207180unit mycom;
208181
209182{$mode objfpc}{$H+}
210183
211184interface
212185
213186uses
214187 Classes, SysUtils, StdCtrls, Forms, Dialogs,
215188 LCLType,LCLIntf,lresources,LCLProc;
216189
217190type
218191
219192 TSampleEvent = procedure(MyText: String) of Object;
220193
221194 TMyCom = class (TCustomComboBox)
222195 private
223196 FMyText: String;
224197 FOnChange2: TNotifyEvent;
225198 FOnSample: TSampleEvent;
226199 public
227200 constructor Create(TheOwner: TComponent); override;
228201 procedure CreateWnd; override;
229202 procedure Change; override;
230203 protected
231204 function GetMyText2: String;
232205 procedure SetMyText2(MyText: String);
233206 published
234207 property MyText: String read FMyText write FMyText;
235208 property MyText2: String read GetMyText2 write SetMyText2;
236209 property OnChange2: TNotifyEvent read FOnChange2 write FOnChange2;
237210 property OnSample: TSampleEvent read FOnSample write FOnSample;
238211
239212 // properties from TComboBox
240213 property Align;
241214 property Anchors;
242215 property ArrowKeysTraverseList;
243216 property AutoComplete;
244217 property AutoCompleteText;
245218 property AutoDropDown;
246219 property AutoSelect;
247220 property AutoSize;
248221 property BidiMode;
249222 property BorderSpacing;
250223 property CharCase;
251224 property Color;
252225 property Ctl3D;
253226 property Constraints;
254227 property DragCursor;
255228 property DragMode;
256229 property DropDownCount;
257230 property Enabled;
258231 property Font;
259232 property ItemHeight;
260233 property ItemIndex;
261234 property Items;
262235 property ItemWidth;
263236 property MaxLength;
264237 property OnChange;
265238 property OnChangeBounds;
266239 property OnClick;
267240 property OnCloseUp;
268241 property OnContextPopup;
269242 property OnDblClick;
270243 property OnDragDrop;
271244 property OnDragOver;
272245 property OnDrawItem;
273246 property OnEndDrag;
274247 property OnDropDown;
275248 property OnEditingDone;
276249 property OnEnter;
277250 property OnExit;
278251 property OnGetItems;
279252 property OnKeyDown;
280253 property OnKeyPress;
281254 property OnKeyUp;
282255 property OnMeasureItem;
283256 property OnMouseDown;
284257 property OnMouseMove;
285258 property OnMouseUp;
286259 property OnStartDrag;
287260 property OnSelect;
288261 property OnUTF8KeyPress;
289262 property ParentBidiMode;
290263 property ParentColor;
291264 property ParentCtl3D;
292265 property ParentFont;
293266 property ParentShowHint;
294267 property PopupMenu;
295268 property ReadOnly;
296269 property ShowHint;
297270 property Sorted;
298271 property Style;
299272 property TabOrder;
300273 property TabStop;
301274 property Text;
302275 property Visible;
303276 end;
304277
305278procedure Register;
306279
307280implementation
308281
309282procedure Register;
310283begin
311284 RegisterComponents('Sample',[TMyCom]);
312285end;
313286
314287constructor TMyCom.Create(TheOwner: TComponent);
315288begin
316289 inherited Create(TheOwner);
317290 Self.Style := csDropDownList;
318291end;
319292
320293procedure TMyCom.CreateWnd;
321294begin
322295 inherited CreateWnd;
323296 Items.Assign(Screen.Fonts);
324297end;
325298
326299procedure TMyCom.Change;
327300begin
328301 inherited;
329302 if Assigned(FOnChange2) then FOnChange2(Self);
330303 if Assigned(FOnSample) then FOnSample(FMyText);
331304end;
332305
333306function TMyCom.GetMyText2: String;
334307begin
335308 Result:=FMyText;
336309end;
337310
338311procedure TMyCom.SetMyText2(MyText: String);
339312begin
340313 FMyText:=MyText;
341314end;
342315
343316initialization
344317 {$I samplepackage.lrs}
345318
346319end.
347320```
348321
349322## Using embedded (visual) components
350323
351324It's possible to use standard components embedded in your own components (look for example at TLabeledEdit or TButtonPanel).
352325
353326Let's say you want to create a custom panel with a TLabel on it. With the steps described above the base package and source files can be created. Now do the following to add a TLabel to the component:
354327
355328- Add a private attribute for the label component (FEmbeddedLabel: TLabel;).
356329- Add a published read-only property for the label component (property EmbeddedLabel: TLabel read FEmbeddedLabel;)
357330- Create the label in the component's (overridden) constructor (FEmbeddedLabel := TLabel.Create(self); )
358331- Set the parent of the component (FEmbeddedLabel.Parent := self;)
359332- If the component to be embedded is not a 'subcomponent' by default (like TBoundLabel, TPanelBitBtn etc) then add the call to SetSubComponent. This is necessary for the IDE so it knows that it has to store the properties of the embedded component as well. TLabel is not a subcomponent by default so the call to the method must be added (FEmbeddedLabel.SetSubComponent(true);).
360333
361334To sum it up you would get something like this (only the essential parts are shown):
362335
363336``` pascal
364337TEnhancedPanel = class(TCustomControl)
365338private
366339 { The new attribute for the embedded label }
367340 FEmbeddedLabel: TLabel;
368341
369342public
370343 { The constructor must be overriden so the label can be created }
371344 constructor Create(AOwner: TComponent); override;
372345
373346published
374347 { Make the label visible in the IDE }
375348 property EmbeddedLabel: TLabel read FEmbeddedLabel;
376349end;
377350
378351implementation
379352
380353constructor TEnhancedPanel.Create(AOwner: TComponent);
381354begin
382355 inherited Create(AOwner);
383356
384357 // Set default width and height
385358 with GetControlClassDefaultSize do
386359 SetInitialBounds(0, 0, CX, CY);
387360
388361 // Add the embedded label
389362 FEmbeddedLabel := TLabel.Create(Self); // Add the embedded label
390363 FEmbeddedLabel.Parent := self; // Show the label in the panel
391364 FEmbeddedLabel.SetSubComponent(true); // Tell the IDE to store the modified properties
392365 FLabel.Name := 'EmbeddedLabel';
393366 FLabel.Caption := 'Howdy World!';
394367
395368 // Make sure the embedded label can not be selected/deleted within the IDE
396369 FLabel.ControlStyle := FLabel.ControlStyle - [csNoDesignSelectable];
397370
398371 // Set other properties if necessary
399372 //...
400373
401374end;
402375```
403376
404377## Using custom paint procedure
405378
406379You can always subclass a component inside your program. For example, this implements a custom Paint procedure to a TLabel:
407380
408381``` pascal
409382type
410383 TMyLabel = class(TLabel)
411384 protected
412385 procedure Paint; override;
413386 end;
414387{...}
415388implementation
416389{...}
417390procedure TMyLabel.Paint;
418391begin
419392 // your code to implement Paint, for example
420393 Canvas.TextOut(0,0,Caption);
421394end;
422395```
423396
424397Now you can create a MyLabel inside your program, at run time, with that overridden Paint procedure instead of the standard one.
425398
426399For most components, and for most methods, it would be recommendable to call inherited procedure inside it:
427400
428401``` pascal
429402procedure TMyLabel.Paint;
430403begin
431404
432405 inherited Paint; /////////////////////
433406
434407 // your code to implement Paint, for example
435408 Canvas.TextOut(0,0,Caption);
436409end;
437410```
438411
439412However, inherited behavior is not desirable in this case, since the second writing action would overlap the first (inherited) one.
440413
441414## Integrating the component with the IDE
442415
443416### Property editors
444417
445418Property editors provide custom dialogs to edit properties in the object inspector. For most properties, like strings, string lists, images, enumerated types and others, there are already default property editors, but if a custom component has a special kind of property it may require a custom dialog to edit the property.
446419
447420Each property editor is a class, which should descend from TPropertyEditor or one of its descendents and implement methods from this base class. They should be registered in the 'Register' procedure by using the function RegisterPropertyEditor from the unit PropEdits. It is a standard to name property editors with the property name followed by 'Property', for example TFieldProperty for the property editor of the TField property.
448421
449422``` pascal
450423 TPropertyEditor = class
451424 public
452425 function AllEqual: Boolean; Virtual;
453426 function AutoFill: Boolean; Virtual;
454427 procedure Edit; Virtual; // Activated by double-clicking the property value
455428 procedure ShowValue; Virtual; // Activated by control-clicking the property value
456429 function GetAttributes: TPropertyAttributes; Virtual;
457430 function GetEditLimit: Integer; Virtual;
458431 function GetName: ShortString; Virtual;
459432 procedure GetProperties(Proc: TGetPropEditProc); Virtual;
460433 function GetHint(HintType: TPropEditHint; x, y: integer): String; Virtual;
461434 function GetDefaultValue: AnsiString; Virtual;
462435 procedure GetValues(Proc: TGetStrProc); Virtual;
463436 procedure SetValue(const NewValue: AnsiString); Virtual;
464437 procedure UpdateSubProperties; Virtual;
465438 function SubPropertiesNeedsUpdate: Boolean; Virtual;
466439 function IsDefaultValue: Boolean; Virtual;
467440 function IsNotDefaultValue: Boolean; Virtual;
468441 // ... shortened
469442 end;
470443```
471444
472445A good example for a property editor is the TFont property editor.
473446
474447One of the most common cases for property editors is properties which are classes. Because classes have many fields and can have a variety of formats, it's not possible for Lazarus to have the object inspector edit field able to edit it, like is done for strings and numeric types.
475448
476449For classes, a convention is to have the value field show permanently the name of the class in parentheses, for example "(TFont)" and the "..." button shows a dialog to edit this class. This behaviour, except for the dialog, is implemented by a standard property editor for classes called TClassPropertyEditor, which can be inherited from when writing property editors for classes:
477450
478451``` pascal
479452TClassPropertyEditor = class(TPropertyEditor)
480453public
481454 constructor Create(Hook: TPropertyEditorHook; APropCount: Integer); Override;
482455 function GetAttributes: TPropertyAttributes; Override;
483456 procedure GetProperties(Proc: TGetPropEditProc); Override;
484457 function GetValue: AnsiString; Override;
485458 property SubPropsTypeFilter: TTypeKinds Read FSubPropsTypeFilter
486459 Write SetSubPropsTypeFilter
487460 Default tkAny;
488461end;
489462```
490463
491464Going back to the TFont example, inheriting from TClassPropertyEditor already offers part of the desired behavior and then the TFontPropertyEditor class only needs to implement showing the dialog in the Edit method and set the attributes for the editor:
492465
493466``` pascal
494467 TFontPropertyEditor = class(TClassPropertyEditor)
495468 public
496469 procedure Edit; Override;
497470 function GetAttributes: TPropertyAttributes; Override;
498471 end;
499472
500473procedure TFontPropertyEditor.Edit;
501474var
502475 FontDialog: TFontDialog;
503476begin
504477 FontDialog := TFontDialog.Create(NIL);
505478 try
506479 FontDialog.Font := TFont(GetObjectValue(TFont));
507480 FontDialog.Options := FontDialog.Options + [fdShowHelp, fdForceFontExist];
508481 if FontDialog.Execute then SetPtrValue(FontDialog.Font);
509482 finally
510483 FontDialog.Free;
511484 end;
512485end;
513486
514487function TFontPropertyEditor.GetAttributes: TPropertyAttributes;
515488begin
516489 Result := [paMultiSelect, paSubProperties, paDialog, paReadOnly];
517490end;
518491```
519492
520493### Component editors
521494
522495Component editors control the behavior of right-clicking and double clicking components in the form designer.
523496
524497Each component editor is a class, which should descend from TComponentEditor or one of its descendents and implement methods from this base class. They should be registered in the 'Register' procedure by using the function RegisterComponentEditor from the unit ComponentEditors. It is a standard to name component editors with the component name followed by 'Editor', for example TStringGridComponentEditor for the property editor of the TStringGrid component. Although user component editors should be based in TComponentEditor, most of its methods are actually from an ancestor, so it is necessary to also know TBaseComponentEditor:
525498
526499``` pascal
527500 TBaseComponentEditor = class
528501 protected
529502 public
530503 constructor Create(AComponent: TComponent;
531504 ADesigner: TComponentEditorDesigner); Virtual;
532505 procedure Edit; Virtual; Abstract;
533506 procedure ExecuteVerb(Index: Integer); Virtual; Abstract;
534507 function GetVerb(Index: Integer): String; Virtual; Abstract;
535508 function GetVerbCount: Integer; Virtual; Abstract;
536509 procedure PrepareItem(Index: Integer; const AnItem: TMenuItem); Virtual; Abstract;
537510 procedure Copy; Virtual; Abstract;
538511 function IsInInlined: Boolean; Virtual; Abstract;
539512 function GetComponent: TComponent; Virtual; Abstract;
540513 function GetDesigner: TComponentEditorDesigner; Virtual; Abstract;
541514 function GetHook(out Hook: TPropertyEditorHook): Boolean; Virtual; Abstract;
542515 procedure Modified; Virtual; Abstract;
543516 end;
544517```
545518
546519The most important method of a component editor is Edit, which is called when the component is double clicked. When the context menu for the component is invoked the GetVerbCount and GetVerb methods are called to build the menu. If one of the verbs (which means menu items in this case) are selected, ExecuteVerb is called. There is a default component editor (TDefaultEditor) which implements Edit to search the properties of the component for the most appropriate one to be edited. It usually chooses an event, which is edited by adding it's skeleton code in the code editor and setting the cursor to be in place to add code for it.
547520
548521Other important methods from TBasComponentEditor are: ExecuteVerb(Index), which executes one of the extra menu items placed on the right-click popup menu; GetVerb – To return the name of each extra popup menu item. Note that t is the responsibility of the component editor to place special menu item caption characters like & to create a keyboard accelerator and “-” to create a separator; GetVerbCount – Returns the amount of items to be added to the popup menu. The index for the routines GetVerb and ExecuteVerb is zero based, going from 0 to GetVerbCount – 1; PrepareItem – Called for each verb after the menu item was created. Allows the menu item to be customized such as by adding subitems, adding a checkbox or even hiding it by setting Visible to false; Copy - Called when the component is being copied to the clipboard. The component data for use by Lazarus will always be added and cannot be modified. This method is instead for adding a different kind of clipboard information to paste the component in other applications, but which won't affect the Lazarus paste.
549522
550523A simple and interesting example is the TCheckListBox component editor which creates a dialog to edit. More convenient then implementing all methods from TBaseComponentEditor is inheriting from TComponentEditor, and this is what TCheckListBoxEditor does. This base class adds empty implementations for most methods and some default ones for others. For Edit it calls ExecuteVerb(0), so if the first item will be identical to the double-click action, which is a convention for editor, there is no need to implement Edit. This basic action for the double-click and first menu item is often a dialog, and for TCheckListBox this is also done:
551524
552525``` pascal
553526 TCheckListBoxComponentEditor = class(TComponentEditor)
554527 protected
555528 procedure DoShowEditor;
556529 public
557530 procedure ExecuteVerb(Index: Integer); override;
558531 function GetVerb(Index: Integer): String; override;
559532 function GetVerbCount: Integer; override;
560533 end;
561534
562535procedure TCheckGroupComponentEditor.DoShowEditor;
563536var
564537 Dlg: TCheckGroupEditorDlg;
565538begin
566539 Dlg := TCheckGroupEditorDlg.Create(NIL);
567540 try
568541 // .. shortened
569542 Dlg.ShowModal;
570543 // .. shortened
571544 finally
572545 Dlg.Free;
573546 end;
574547end;
575548
576549procedure TCheckGroupComponentEditor.ExecuteVerb(Index: Integer);
577550begin
578551 case Index of
579552 0: DoShowEditor;
580553 end;
581554end;
582555
583556function TCheckGroupComponentEditor.GetVerb(Index: Integer): String;
584557begin
585558 Result := 'CheckBox Editor...';
586559end;
587560
588561function TCheckGroupComponentEditor.GetVerbCount: Integer;
589562begin
590563 Result := 1;
591564end;
592565```
593566
594567## See also
595568
596569- [[Extending the IDE]]
597570- [[Lazarus Packages]] - A guide for creating a package under Lazarus
598571- [[Components and Code examples]]
599572- [[Lazarus Components]]
600573- [[IDE Window: Add to Package]]
601574
602575You can post questions regarding this page [here](http://forum.lazarus.freepascal.org/index.php/topic,5789.0.html)
603576
604577---
605578*From the Free Pascal wiki, page "How To Write Lazarus Component/de", as it stood on 2020-02-17 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).*

Back to history