Sign in Join
Wiki copytemporary

How To Write Lazarus Component/de: what changed

Revision 2 to 3. 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
77![](/wiki-images/7/7c/Package_menu.png)
88
99- 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**.
1010
1111- Glückwunsch: Sie haben soeben Ihr erstes Package erstellt!
1212
1313![](/wiki-images/3/37/How_to_write_lazarus_component_package_maker.png)
1414
1515## Schritt 2: Erstellen der Unit
1616
1717Sie können eine neue Unit erstellen oder eine existierende Datei nutzen. Beide Möglichkeiten sind nachfolgend beschrieben.
1818
1919### Erstellen einer neuen Unit
2020
2121- Nutzen Sie den **+ Hinzufügen** Button und klicken Sie auf den Reiter **Neue Komponente**.
2222
2323![](/wiki-images/5/56/Package_new_component.png)
2424
2525- Wählen Sie eine Komponente wie eine TComboBox.
2626- Wählen Sie *customcontrol1.pas* als Unit-Dateinamen und *CustomControl1* als Unit-Namen.
2727- 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.
2828- Klicken Sie auf **Neue Komponente erzeugen**.
2929
3030``` pascal
3131unit CustomControl1;
3232
3333{$mode objfpc}{$H+}
3434
3535interface
3636
3737uses
3838 Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls;
3939
4040type
4141 TCustomControl1 = class(TComboBox)
4242 private
4343 { Private declarations }
4444 protected
4545 { Protected declarations }
4646 public
4747 { Public declarations }
4848 published
4949 { Published declarations }
5050 end;
5151
5252procedure Register;
5353
5454implementation
5555
5656procedure Register;
5757begin
5858 RegisterComponents('Standard',[TCustomControl1]);
5959end;
6060
6161end.
6262```
6363
6464- Installieren Sie die Package in dem Sie auf **Nutzung ... -\> Installieren** klicken.
6565
6666![](/wiki-images/3/36/Package_install.png)
6767
6868- Die IDE fragt Sie, ob Lazarus neu kompiliert werden soll. Bestätigen Sie mit **Ja**.
6969
7070![](/wiki-images/9/9b/Package_rebuild.png)
7171
7272- 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.
7373
7474![](/wiki-images/3/35/Package_installed.png)
7575
7676> **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.
7777>
7878> 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.
7979
8080### Zufügen einer vorhandenen Unit
8181
8282Wenn Sie schon eine vorhandene Unit haben, können Sie diese dem Package wie folgt zufügen:
8383
8484![](/wiki-images/1/11/Package_existing_unit.png)
8585
8686- Klicken Sie den **+ Hinzufügen** Button, gehen Sie auf dem Reiter **Dateien hinzufügen**.
8787- 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**.
8888- Wenn der Package-Manager anmahnt, daß die Unit nicht im Unit-Pfad ist, klicken Sie auf Ja um das Verzeichnis dem Unitpfad hinzuzufügen.
8989- 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).
9090- 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**.
9191
9292Das Endresultat sollte so aussehen:
9393
9494![](/wiki-images/d/d9/How_to_write_lazarus_component_package_maker_done.png)
9595
9696- Klicken Sie unterhalb des Dateibaumes den Paket-Manager. Stellen Sie sicher, daß in den Dateieigenschaften *Register Unit* aktiviert ist.
9797- Klicken Sie auf den Button *Optionen*. Wählen Sie die Registerkarte *IDE-Einbindung*. Stellen Sie sicher, dass Designtime und Runtime von Packagetyp aktiviert ist.
9898- Klicken Sie auf kompilieren, um zu überprüfen, dass die Dateien fehlerfrei kompilieren.
9999- Klicken Sie auf den Button *Installieren*. Lazarus wird neu erstellen und automatisch neu gestartet.
100100
101101Die Komponente ist erstellt und kann verwendet werden:
102102
103103![](/wiki-images/3/3c/How_to_write_lazarus_component_created.png)
104104
105105## Schritt 3: Erstellen eines Icons für das Package
106106
107107Sie sollten 24x24 Pixel große PNG-Files als Icons verwenden.
108108
109109Das 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]].
110110
111111### Mit dem Lazarus-Bild-Editor
112112
113113Mit dem [[Lazarus Image Editor]] können Sie die Symbole im .lrs-Format erstellen.
114114
115115### Mit Lazres
116116
117117`lazres` sollte sich normalerweise im Unterverzeichnis Tools von Lazarus befinden.
118118
119119Sie 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).
120120
121121**lrs Datei erstellen**
122122
123123Um die lrs-Datei zu erstellen führen Sie einfach folgenden Befehl aus:
124124
125125`~/lazarus/tools/lazres samplepackage.lrs TMyCom.png`
126126
127127Wobei
128128
129129- *samplepackage* der Name Ihres Packages ist
130130- *TMyCom* der Name Ihrer Komponente ist.
131131
132132Sie 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 ...
133133
134134**Beispiel**
135135
136136So könnte zum Beispiel eine resultierende Datei *samplepackage.lrs* aussehen:
137137
138138 LazarusResources.Add('TMyCom','PNG',[
139139 #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
140140 +#0#0#0#4'gAMA'#0#0#177#143#11#252'a'#5#0#0#0'|IDAT8O'#237#212#209#10#192' '#8
141141 +#5'P'#247#231#251's'#215#138#133#164#166'\'#220#195'`'#209'c'#157'L'#173#131
142142 +#153#169'd4'#168'dP'#137'r_'#235'5'#136'@Zmk'#16'd9'#144#176#232#164'1'#247
143143 +'I'#8#160'IL'#206'C'#179#144#12#199#140'.'#134#244#141'~'#168#247#209'S~;'#29
144144 +'V+'#196#201'^'#10#15#150'?'#255#18#227#206'NZ>42'#181#159#226#144#15'@'#201
145145 +#148#168'e'#224'7f<@4'#130'u_YD'#23#213#131#134'Q]'#158#188#135#0#0#0#0'IEND'
146146 +#174'B`'#130
147147 ]);
148148
149149Achten 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:
150150
151151``` pascal
152152initialization
153153 {$I samplepackage.lrs}
154154```
155155
156156## Recompiling Packages
157157
158158Immer, 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*.
159159
160160## Removing Packages
161161
162162- To remove installed components: on the IDE menu, click Package \> Configure installed packages. The following image shows the Installed Packages tool.
163163
164-![`Installed Components`](/wiki-images/0/0e/How_to_write_lazarus_component_installed_components.png)
164+```text
165+Installed Components
166+```
165167
166168- Select the package you want to uninstall and click Uninstall selection.
167169
168170If 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.
169171
170172## Enhancing mycom.pas
171173
172174- 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.
173175- The *OnChange2* shows how to create events
174176- The *OnSample* shows how to create custom events
175177- *MyText* and *MyText2* shows different ways to write properties.
176178- You can use TComboBox instead of TCustomComboBox as the base class, which publishes all properties as TComboBox.
177179- 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.
178180
179181``` pascal
180182unit mycom;
181183
182184{$mode objfpc}{$H+}
183185
184186interface
185187
186188uses
187189 Classes, SysUtils, StdCtrls, Forms, Dialogs,
188190 LCLType,LCLIntf,lresources,LCLProc;
189191
190192type
191193
192194 TSampleEvent = procedure(MyText: String) of Object;
193195
194196 TMyCom = class (TCustomComboBox)
195197 private
196198 FMyText: String;
197199 FOnChange2: TNotifyEvent;
198200 FOnSample: TSampleEvent;
199201 public
200202 constructor Create(TheOwner: TComponent); override;
201203 procedure CreateWnd; override;
202204 procedure Change; override;
203205 protected
204206 function GetMyText2: String;
205207 procedure SetMyText2(MyText: String);
206208 published
207209 property MyText: String read FMyText write FMyText;
208210 property MyText2: String read GetMyText2 write SetMyText2;
209211 property OnChange2: TNotifyEvent read FOnChange2 write FOnChange2;
210212 property OnSample: TSampleEvent read FOnSample write FOnSample;
211213
212214 // properties from TComboBox
213215 property Align;
214216 property Anchors;
215217 property ArrowKeysTraverseList;
216218 property AutoComplete;
217219 property AutoCompleteText;
218220 property AutoDropDown;
219221 property AutoSelect;
220222 property AutoSize;
221223 property BidiMode;
222224 property BorderSpacing;
223225 property CharCase;
224226 property Color;
225227 property Ctl3D;
226228 property Constraints;
227229 property DragCursor;
228230 property DragMode;
229231 property DropDownCount;
230232 property Enabled;
231233 property Font;
232234 property ItemHeight;
233235 property ItemIndex;
234236 property Items;
235237 property ItemWidth;
236238 property MaxLength;
237239 property OnChange;
238240 property OnChangeBounds;
239241 property OnClick;
240242 property OnCloseUp;
241243 property OnContextPopup;
242244 property OnDblClick;
243245 property OnDragDrop;
244246 property OnDragOver;
245247 property OnDrawItem;
246248 property OnEndDrag;
247249 property OnDropDown;
248250 property OnEditingDone;
249251 property OnEnter;
250252 property OnExit;
251253 property OnGetItems;
252254 property OnKeyDown;
253255 property OnKeyPress;
254256 property OnKeyUp;
255257 property OnMeasureItem;
256258 property OnMouseDown;
257259 property OnMouseMove;
258260 property OnMouseUp;
259261 property OnStartDrag;
260262 property OnSelect;
261263 property OnUTF8KeyPress;
262264 property ParentBidiMode;
263265 property ParentColor;
264266 property ParentCtl3D;
265267 property ParentFont;
266268 property ParentShowHint;
267269 property PopupMenu;
268270 property ReadOnly;
269271 property ShowHint;
270272 property Sorted;
271273 property Style;
272274 property TabOrder;
273275 property TabStop;
274276 property Text;
275277 property Visible;
276278 end;
277279
278280procedure Register;
279281
280282implementation
281283
282284procedure Register;
283285begin
284286 RegisterComponents('Sample',[TMyCom]);
285287end;
286288
287289constructor TMyCom.Create(TheOwner: TComponent);
288290begin
289291 inherited Create(TheOwner);
290292 Self.Style := csDropDownList;
291293end;
292294
293295procedure TMyCom.CreateWnd;
294296begin
295297 inherited CreateWnd;
296298 Items.Assign(Screen.Fonts);
297299end;
298300
299301procedure TMyCom.Change;
300302begin
301303 inherited;
302304 if Assigned(FOnChange2) then FOnChange2(Self);
303305 if Assigned(FOnSample) then FOnSample(FMyText);
304306end;
305307
306308function TMyCom.GetMyText2: String;
307309begin
308310 Result:=FMyText;
309311end;
310312
311313procedure TMyCom.SetMyText2(MyText: String);
312314begin
313315 FMyText:=MyText;
314316end;
315317
316318initialization
317319 {$I samplepackage.lrs}
318320
319321end.
320322```
321323
322324## Using embedded (visual) components
323325
324326It's possible to use standard components embedded in your own components (look for example at TLabeledEdit or TButtonPanel).
325327
326328Let'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:
327329
328330- Add a private attribute for the label component (FEmbeddedLabel: TLabel;).
329331- Add a published read-only property for the label component (property EmbeddedLabel: TLabel read FEmbeddedLabel;)
330332- Create the label in the component's (overridden) constructor (FEmbeddedLabel := TLabel.Create(self); )
331333- Set the parent of the component (FEmbeddedLabel.Parent := self;)
332334- 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);).
333335
334336To sum it up you would get something like this (only the essential parts are shown):
335337
336338``` pascal
337339TEnhancedPanel = class(TCustomControl)
338340private
339341 { The new attribute for the embedded label }
340342 FEmbeddedLabel: TLabel;
341343
342344public
343345 { The constructor must be overriden so the label can be created }
344346 constructor Create(AOwner: TComponent); override;
345347
346348published
347349 { Make the label visible in the IDE }
348350 property EmbeddedLabel: TLabel read FEmbeddedLabel;
349351end;
350352
351353implementation
352354
353355constructor TEnhancedPanel.Create(AOwner: TComponent);
354356begin
355357 inherited Create(AOwner);
356358
357359 // Set default width and height
358360 with GetControlClassDefaultSize do
359361 SetInitialBounds(0, 0, CX, CY);
360362
361363 // Add the embedded label
362364 FEmbeddedLabel := TLabel.Create(Self); // Add the embedded label
363365 FEmbeddedLabel.Parent := self; // Show the label in the panel
364366 FEmbeddedLabel.SetSubComponent(true); // Tell the IDE to store the modified properties
365367 FLabel.Name := 'EmbeddedLabel';
366368 FLabel.Caption := 'Howdy World!';
367369
368370 // Make sure the embedded label can not be selected/deleted within the IDE
369371 FLabel.ControlStyle := FLabel.ControlStyle - [csNoDesignSelectable];
370372
371373 // Set other properties if necessary
372374 //...
373375
374376end;
375377```
376378
377379## Using custom paint procedure
378380
379381You can always subclass a component inside your program. For example, this implements a custom Paint procedure to a TLabel:
380382
381383``` pascal
382384type
383385 TMyLabel = class(TLabel)
384386 protected
385387 procedure Paint; override;
386388 end;
387389{...}
388390implementation
389391{...}
390392procedure TMyLabel.Paint;
391393begin
392394 // your code to implement Paint, for example
393395 Canvas.TextOut(0,0,Caption);
394396end;
395397```
396398
397399Now you can create a MyLabel inside your program, at run time, with that overridden Paint procedure instead of the standard one.
398400
399401For most components, and for most methods, it would be recommendable to call inherited procedure inside it:
400402
401403``` pascal
402404procedure TMyLabel.Paint;
403405begin
404406
405407 inherited Paint; /////////////////////
406408
407409 // your code to implement Paint, for example
408410 Canvas.TextOut(0,0,Caption);
409411end;
410412```
411413
412414However, inherited behavior is not desirable in this case, since the second writing action would overlap the first (inherited) one.
413415
414416## Integrating the component with the IDE
415417
416418### Property editors
417419
418420Property 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.
419421
420422Each 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.
421423
422424``` pascal
423425 TPropertyEditor = class
424426 public
425427 function AllEqual: Boolean; Virtual;
426428 function AutoFill: Boolean; Virtual;
427429 procedure Edit; Virtual; // Activated by double-clicking the property value
428430 procedure ShowValue; Virtual; // Activated by control-clicking the property value
429431 function GetAttributes: TPropertyAttributes; Virtual;
430432 function GetEditLimit: Integer; Virtual;
431433 function GetName: ShortString; Virtual;
432434 procedure GetProperties(Proc: TGetPropEditProc); Virtual;
433435 function GetHint(HintType: TPropEditHint; x, y: integer): String; Virtual;
434436 function GetDefaultValue: AnsiString; Virtual;
435437 procedure GetValues(Proc: TGetStrProc); Virtual;
436438 procedure SetValue(const NewValue: AnsiString); Virtual;
437439 procedure UpdateSubProperties; Virtual;
438440 function SubPropertiesNeedsUpdate: Boolean; Virtual;
439441 function IsDefaultValue: Boolean; Virtual;
440442 function IsNotDefaultValue: Boolean; Virtual;
441443 // ... shortened
442444 end;
443445```
444446
445447A good example for a property editor is the TFont property editor.
446448
447449One 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.
448450
449451For 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:
450452
451453``` pascal
452454TClassPropertyEditor = class(TPropertyEditor)
453455public
454456 constructor Create(Hook: TPropertyEditorHook; APropCount: Integer); Override;
455457 function GetAttributes: TPropertyAttributes; Override;
456458 procedure GetProperties(Proc: TGetPropEditProc); Override;
457459 function GetValue: AnsiString; Override;
458460 property SubPropsTypeFilter: TTypeKinds Read FSubPropsTypeFilter
459461 Write SetSubPropsTypeFilter
460462 Default tkAny;
461463end;
462464```
463465
464466Going 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:
465467
466468``` pascal
467469 TFontPropertyEditor = class(TClassPropertyEditor)
468470 public
469471 procedure Edit; Override;
470472 function GetAttributes: TPropertyAttributes; Override;
471473 end;
472474
473475procedure TFontPropertyEditor.Edit;
474476var
475477 FontDialog: TFontDialog;
476478begin
477479 FontDialog := TFontDialog.Create(NIL);
478480 try
479481 FontDialog.Font := TFont(GetObjectValue(TFont));
480482 FontDialog.Options := FontDialog.Options + [fdShowHelp, fdForceFontExist];
481483 if FontDialog.Execute then SetPtrValue(FontDialog.Font);
482484 finally
483485 FontDialog.Free;
484486 end;
485487end;
486488
487489function TFontPropertyEditor.GetAttributes: TPropertyAttributes;
488490begin
489491 Result := [paMultiSelect, paSubProperties, paDialog, paReadOnly];
490492end;
491493```
492494
493495### Component editors
494496
495497Component editors control the behavior of right-clicking and double clicking components in the form designer.
496498
497499Each 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:
498500
499501``` pascal
500502 TBaseComponentEditor = class
501503 protected
502504 public
503505 constructor Create(AComponent: TComponent;
504506 ADesigner: TComponentEditorDesigner); Virtual;
505507 procedure Edit; Virtual; Abstract;
506508 procedure ExecuteVerb(Index: Integer); Virtual; Abstract;
507509 function GetVerb(Index: Integer): String; Virtual; Abstract;
508510 function GetVerbCount: Integer; Virtual; Abstract;
509511 procedure PrepareItem(Index: Integer; const AnItem: TMenuItem); Virtual; Abstract;
510512 procedure Copy; Virtual; Abstract;
511513 function IsInInlined: Boolean; Virtual; Abstract;
512514 function GetComponent: TComponent; Virtual; Abstract;
513515 function GetDesigner: TComponentEditorDesigner; Virtual; Abstract;
514516 function GetHook(out Hook: TPropertyEditorHook): Boolean; Virtual; Abstract;
515517 procedure Modified; Virtual; Abstract;
516518 end;
517519```
518520
519521The 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.
520522
521523Other 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.
522524
523525A 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:
524526
525527``` pascal
526528 TCheckListBoxComponentEditor = class(TComponentEditor)
527529 protected
528530 procedure DoShowEditor;
529531 public
530532 procedure ExecuteVerb(Index: Integer); override;
531533 function GetVerb(Index: Integer): String; override;
532534 function GetVerbCount: Integer; override;
533535 end;
534536
535537procedure TCheckGroupComponentEditor.DoShowEditor;
536538var
537539 Dlg: TCheckGroupEditorDlg;
538540begin
539541 Dlg := TCheckGroupEditorDlg.Create(NIL);
540542 try
541543 // .. shortened
542544 Dlg.ShowModal;
543545 // .. shortened
544546 finally
545547 Dlg.Free;
546548 end;
547549end;
548550
549551procedure TCheckGroupComponentEditor.ExecuteVerb(Index: Integer);
550552begin
551553 case Index of
552554 0: DoShowEditor;
553555 end;
554556end;
555557
556558function TCheckGroupComponentEditor.GetVerb(Index: Integer): String;
557559begin
558560 Result := 'CheckBox Editor...';
559561end;
560562
561563function TCheckGroupComponentEditor.GetVerbCount: Integer;
562564begin
563565 Result := 1;
564566end;
565567```
566568
567569## See also
568570
569571- [[Extending the IDE]]
570572- [[Lazarus Packages]] - A guide for creating a package under Lazarus
571573- [[Components and Code examples]]
572574- [[Lazarus Components]]
573575- [[IDE Window: Add to Package]]
574576
575577You can post questions regarding this page [here](http://forum.lazarus.freepascal.org/index.php/topic,5789.0.html)
576578
577579---
578580*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