Sign in Join
Wiki copytemporary

How To Write Lazarus Component/zh CN: what changed

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

OldNewLine
11以下介绍如何创建控件。
22
33## 第1步: 创建一个包
44
55- 在Lazarus IDE菜单中选择 **Package \> New Package** 打开包管理器。
66
77![](/wiki-images/7/7c/Package_menu.png)
88
99- 设置好路径和文件名后点击**保存**,如果IDE提示使用小写文件名,点击点击允许。
1010
1111- 一个package就创建好了。
1212
1313![](/wiki-images/3/37/How_to_write_lazarus_component_package_maker.png)
1414
1515## 第2步: 创建一个单元
1616
1717你可以完全新建一个单元或者使用已有的单元,以下界面中包含了这两种选项。
1818
1919### 创建新的单元
2020
2121- 在包管理器中点击**Add button \> New component**。
2222
2323![](/wiki-images/5/56/Package_new_component.png)
2424
2525- 选择一个诸如TComboBox的控件。
2626- 选择*customcontrol1.pas*作为**单元文件名**,选择*CustomControl1*作为**单元名称**.
2727- 之后你可以给新的控件指定图标,以及决定它安装之后出现在哪个控件选项卡中。
2828- 点击**Create New Component**创建。
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- 现在你就可以加入自己的代码了。切记,尽量避免在控件尚未完善之前去安装控件,因为空间安装后就会成为IDE的一部分。如果这个空间存在bug,很有可能导致IDE崩溃甚至无法打开。所以安装测试请务必小心谨慎。
6565- 当控件测试好之后,便可以进行安装。点击"Package" \> "Install/uninstall packages",点击"Compile"进行编译,然后点击**Use -\> Install**进行安装:
6666
6767![](/wiki-images/3/36/Package_install.png)
6868
6969- 这时IDE就会询问是否重构,选择是。
7070
7171![](/wiki-images/9/9b/Package_rebuild.png)
7272
7373- Lazarus会自动重新启动,重启后你就能看到新的控件在控件面板中,控件安装成功。
7474
7575![](/wiki-images/3/35/Package_installed.png)
7676
7777> **Note:** If you do not see your new component in the component palette, it is most likely that you are not running the re-compiled version of Lazarus. You can set where Lazarus builds to using Tools -\> Options -\> Files -\> Lazarus directory.
7878>
7979> Instead of calling Lazarus directly, you also can use startlazarus, which starts the newly created Lazarus, for example the Lazarus executable in the ~/.lazarus directory, if you don't have write access to the directory Lazarus was installed into.
8080
8181> **Note:** 如果安装后出现错误,导致无法重新打开IDE,可以使用重构前自动备份的lazarus.old.exe替换新的lazarus.exe。
8282
8383### 使用已有的单元
8484
8585如果你已经有写好的单元,你可以将它加入这个包:
8686
8787![](/wiki-images/1/11/Package_existing_unit.png)
8888
8989- 点击**Add**按钮,选择**Add Files**选项卡。单元文件名一项浏览选择已有的单元文件,然后点击**Add files to package**。如果包管理器提示找不到单元文件不在单元路径中,按照提示允许添加此路径。
9090- 再次点击**Add**按钮,选择**Add Files**选项卡,浏览*.lrs*文件并点击确认(参考第3步)。
9191- 又一次点击**Add**按钮,选择**New Requirement**选项卡,在包名称一项选择**LCL**,然后点击确定。
9292
9393最后的效果应该是这样的:
9494
9595![](/wiki-images/d/d9/How_to_write_lazarus_component_package_maker_done.png)
9696
9797- Click under the Files tree in the Package Manager. In the File Properties, make sure *Register unit* is checked.
9898- Click the Options button. Select the IDE Integration tab. In Package Type, make sure Designtime and Runtime is selected.
9999- Click the Compile button to check to see that the files compile without errors.
100100- Click the Install button. Lazarus will rebuild and restart automatically.
101101
102102空间创建成功,效果如下:
103103
104104![](/wiki-images/3/3c/How_to_write_lazarus_component_created.png)
105105
106106## 第3步: 创建图标
107107
108108你需要创建24x24像素大小的PNG图像作为图标,如果是 Laz 1.8以上版本,也可以额外提供36x36和48x48像素的图标,文件名之后加“_150”和“_200”用以表示150%和200%的缩放比例。
109109
110110FPC从2.6版本开始,可以使用标准资源文件格式(`.rc`)或已编译资源(`.res`)。参见[[Lazarus Resources|Lazarus_Resources#FPC_resources]]。
111111
112112至于使用`.lrs`文件:
113113
114114### 使用Laz图像编辑器
115115
116116你可以使用[[Lazarus Image Editor]]创建.lrs格式的图标。
117117
118118### 使用lazres
119119
120120`lazres`通常可以在Laz的工具目录中找到。
121121
122122第一次使用[[lazres]]时需要首先编译。 在IDE中打开*lazres.lpi*,然后点击菜单**run \> build**选项。
123123
124124**创建lrs文件**
125125
126126To create the lrs file run:
127127
128128`~/lazarus/tools/lazres samplepackage.lrs TMyCom.png`
129129
130130or, if high-resolution images are available
131131
132132`~/lazarus/tools/lazres samplepackage.lrs TMyCom.png TMyCom_150.pgn TMyCom_200.png`
133133
134134Where
135135
136136- *samplepackage* is the name of your package
137137- *TMyCom* is the name of your component! The name of the image must match the name of your component!
138138
139139You can add more than one image to the lrs file by appending the image file name at the end. Eg. ~/lazarus/tools/lazres samplepackage.lrs TMyCom.png TMyOtherCom.png ...
140140
141141**示例**
142142
143143Following is a sample of the resulting *samplepackage.lrs* file.
144144
145145 LazarusResources.Add('TMyCom','PNG',[
146146 #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
147147 +#0#0#0#4'gAMA'#0#0#177#143#11#252'a'#5#0#0#0'|IDAT8O'#237#212#209#10#192' '#8
148148 +#5'P'#247#231#251's'#215#138#133#164#166'\'#220#195'`'#209'c'#157'L'#173#131
149149 +#153#169'd4'#168'dP'#137'r_'#235'5'#136'@Zmk'#16'd9'#144#176#232#164'1'#247
150150 +'I'#8#160'IL'#206'C'#179#144#12#199#140'.'#134#244#141'~'#168#247#209'S~;'#29
151151 +'V+'#196#201'^'#10#15#150'?'#255#18#227#206'NZ>42'#181#159#226#144#15'@'#201
152152 +#148#168'e'#224'7f<@4'#130'u_YD'#23#213#131#134'Q]'#158#188#135#0#0#0#0'IEND'
153153 +#174'B`'#130
154154 ]);
155155
156156Make sure to include your resource file in your new component source by adding the following at the bottom your component's unit and including "LResources" in the uses clause
157157
158158``` pascal
159159initialization
160160 {$I samplepackage.lrs}
161161```
162162
163163**创建res文件**
164164
165165lazres can also create a compiled resource file, just specify a file with the .res extension, e.g.:
166166
167167`~/lazarus/tools/lazres samplepackage.`**`res`**` TMyCom.png`
168168
169169or, with high-res icons:
170170
171171`~/lazarus/tools/lazres samplepackage.`**`res`**` TMyCom.png TMyCom_150.png TMyCom_200.png`
172172
173173In this case, instead of including the lrs file in the initialization section, just include the resource file anywhere in your component source file
174174
175175``` pascal
176176 {$R samplepackage.res}
177177```
178178
179179### 使用glazres
180180
181181**GLazRes** is the graphical version of `lazres` that can assemble files into a Lazarus resource file (.lrs). It can be found in the tools directory of a Lazarus installation.
182182
183183## 重新编译包
184184
185185每一次修改*mycom.pas*文件后都需要重新编译包,需要在包管理器中打开*samplepackage.lpk*文件,而后点击Install按钮。
186186
187187## 移除包
188188
189189- 如需移除包,则需要在IDE菜单中点击**Package \> Install/Uninstall packages**选项,会跳出如下的界面:
190190
191-![`Installed Components`](/wiki-images/0/0e/How_to_write_lazarus_component_installed_components.png)
191+```text
192+Installed Components
193+```
192194
193195- 选择你想要卸载的包。
194196
195197如果卸载过程出现问题(例如包的路径在未卸载前就已经被删除),Laz可能会不允许卸载某个包。解决方法是,点击IDE菜单**Tools \> Build Lazarus**,重新编译IDE并重启之后就可以卸载出问题的包了。
196198
197199## 加强mycom.pas
198200
199201- 上文中*mycom.pas*的代码只是创建了一个最基本的控件,接下来是一些进阶内容,包括如何编写过程和事件。
200202- *OnChange2*展示如何创建一个事件;
201203- *OnSample*展示如何创建一个自定义事件;
202204- *MyText*和*MyText2*展示了两种不同的属性定义方式;
203205- 你可以使用TComboBox而不是TCustomComboBox作为基类,这样可以避免发布TComboBox的所有的属性。
204206- 如果使用TCustomComboBox作为基类,你会发现IDE的Object Inspector中会少很多属性和事件。如果需要这些属性,需要复制*// properties from TComboBox*之后的内容。这些属性定义在StdCtrls单元的TComboBox类之中,如果你不希望某个属性出现在Object Inspector中,就在published区域忽略它。
205207
206208``` pascal
207209unit mycom;
208210
209211{$mode objfpc}{$H+}
210212
211213interface
212214
213215uses
214216 Classes, SysUtils, StdCtrls, Forms, Dialogs,
215217 LCLType,LCLIntf,lresources,LCLProc;
216218
217219type
218220
219221 TSampleEvent = procedure(MyText: String) of Object;
220222
221223 TMyCom = class (TCustomComboBox)
222224 private
223225 FMyText: String;
224226 FOnChange2: TNotifyEvent;
225227 FOnSample: TSampleEvent;
226228 public
227229 constructor Create(TheOwner: TComponent); override;
228230 procedure CreateWnd; override;
229231 procedure Change; override;
230232 protected
231233 function GetMyText2: String;
232234 procedure SetMyText2(MyText: String);
233235 published
234236 property MyText: String read FMyText write FMyText;
235237 property MyText2: String read GetMyText2 write SetMyText2;
236238 property OnChange2: TNotifyEvent read FOnChange2 write FOnChange2;
237239 property OnSample: TSampleEvent read FOnSample write FOnSample;
238240
239241 // properties from TComboBox
240242 property Align;
241243 property Anchors;
242244 property ArrowKeysTraverseList;
243245 property AutoComplete;
244246 property AutoCompleteText;
245247 property AutoDropDown;
246248 property AutoSelect;
247249 property AutoSize;
248250 property BidiMode;
249251 property BorderSpacing;
250252 property CharCase;
251253 property Color;
252254 property Ctl3D;
253255 property Constraints;
254256 property DragCursor;
255257 property DragMode;
256258 property DropDownCount;
257259 property Enabled;
258260 property Font;
259261 property ItemHeight;
260262 property ItemIndex;
261263 property Items;
262264 property ItemWidth;
263265 property MaxLength;
264266 property OnChange;
265267 property OnChangeBounds;
266268 property OnClick;
267269 property OnCloseUp;
268270 property OnContextPopup;
269271 property OnDblClick;
270272 property OnDragDrop;
271273 property OnDragOver;
272274 property OnDrawItem;
273275 property OnEndDrag;
274276 property OnDropDown;
275277 property OnEditingDone;
276278 property OnEnter;
277279 property OnExit;
278280 property OnGetItems;
279281 property OnKeyDown;
280282 property OnKeyPress;
281283 property OnKeyUp;
282284 property OnMeasureItem;
283285 property OnMouseDown;
284286 property OnMouseMove;
285287 property OnMouseUp;
286288 property OnStartDrag;
287289 property OnSelect;
288290 property OnUTF8KeyPress;
289291 property ParentBidiMode;
290292 property ParentColor;
291293 property ParentCtl3D;
292294 property ParentFont;
293295 property ParentShowHint;
294296 property PopupMenu;
295297 property ReadOnly;
296298 property ShowHint;
297299 property Sorted;
298300 property Style;
299301 property TabOrder;
300302 property TabStop;
301303 property Text;
302304 property Visible;
303305 end;
304306
305307procedure Register;
306308
307309implementation
308310
309311procedure Register;
310312begin
311313 RegisterComponents('Sample',[TMyCom]);
312314end;
313315
314316constructor TMyCom.Create(TheOwner: TComponent);
315317begin
316318 inherited Create(TheOwner);
317319 Self.Style := csDropDownList;
318320end;
319321
320322procedure TMyCom.CreateWnd;
321323begin
322324 inherited CreateWnd;
323325 Items.Assign(Screen.Fonts);
324326end;
325327
326328procedure TMyCom.Change;
327329begin
328330 inherited;
329331 if Assigned(FOnChange2) then FOnChange2(Self);
330332 if Assigned(FOnSample) then FOnSample(FMyText);
331333end;
332334
333335function TMyCom.GetMyText2: String;
334336begin
335337 Result:=FMyText;
336338end;
337339
338340procedure TMyCom.SetMyText2(MyText: String);
339341begin
340342 FMyText:=MyText;
341343end;
342344
343345initialization
344346 {$I samplepackage.lrs}
345347
346348end.
347349```
348350
349351同时你也会发现一些没有声明的,或是你不希望他出现在Object Inspector中的属性,如果需要移除这些属性,只需要在*Published*区域将它们定义成简单的变量即可,例如:
350352
351353``` pascal
352354Published
353355...
354356 property Height: Integer;
355357 property Width: Integer;
356358...
357359```
358360
359361## 使用嵌入式组件 embedded (visual) components
360362
361363可以将标准的空间嵌入你自己的控件,就像TLabeledEdit或TButtonPanel那样。
362364
363365Let'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. 现在,按以下步骤就能够将TLabel控件嵌入自己的控件:
364366
365367- 添加一个私有的控件属性(FEmbeddedLabel: TLabel;);
366368- 为这个私有控件添加一个发布的只读属性(property EmbeddedLabel: TLabel read FEmbeddedLabel;);
367369- 在constructor的实现中创建这个label控件(FEmbeddedLabel := TLabel.Create(self););
368370- 将其parent属性修改为此控件(FEmbeddedLabel.Parent := self;);
369371- 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);).
370372
371373总体来说,你需要像这样来定义(只展示了关键部分):
372374
373375``` pascal
374376TEnhancedPanel = class(TCustomControl)
375377private
376378 { The new attribute for the embedded label }
377379 FEmbeddedLabel: TLabel;
378380
379381public
380382 { The constructor must be overriden so the label can be created }
381383 constructor Create(AOwner: TComponent); override;
382384
383385published
384386 { Make the label visible in the IDE }
385387 property EmbeddedLabel: TLabel read FEmbeddedLabel;
386388end;
387389
388390implementation
389391
390392constructor TEnhancedPanel.Create(AOwner: TComponent);
391393begin
392394 inherited Create(AOwner);
393395
394396 // Set default width and height
395397 with GetControlClassDefaultSize do
396398 SetInitialBounds(0, 0, CX, CY);
397399
398400 // Add the embedded label
399401 FEmbeddedLabel := TLabel.Create(Self); // Add the embedded label
400402 FEmbeddedLabel.Parent := self; // Show the label in the panel
401403 FEmbeddedLabel.SetSubComponent(true); // Tell the IDE to store the modified properties
402404 FLabel.Name := 'EmbeddedLabel';
403405 FLabel.Caption := 'Howdy World!';
404406
405407 // Make sure the embedded label can not be selected/deleted within the IDE
406408 FLabel.ControlStyle := FLabel.ControlStyle - [csNoDesignSelectable];
407409
408410 // Set other properties if necessary
409411 //...
410412
411413end;
412414```
413415
414416## 使用自定义的绘制过程
415417
416418你可以在自己的程序中构造控件的子类,在以下例子中,TMyLabel就定义了一个自定义的绘制过程:
417419
418420``` pascal
419421type
420422 TMyLabel = class(TLabel)
421423 protected
422424 procedure Paint; override;
423425 end;
424426{...}
425427implementation
426428{...}
427429procedure TMyLabel.Paint;
428430begin
429431 // your code to implement Paint, for example
430432 Canvas.TextOut(0,0,Caption);
431433end;
432434```
433435
434436这样一来,一个TMyLabel控件就会使用如上覆盖的方法来绘制。 但是更常见且更推荐的做法是在其中继承父类的绘制过程:
435437
436438``` pascal
437439procedure TMyLabel.Paint;
438440begin
439441
440442 inherited Paint; /////////////////////
441443
442444 // your code to implement Paint, for example
443445 Canvas.TextOut(0,0,Caption);
444446end;
445447```
446448
447449然而,以上例子也存在一定的问题,因为在重绘之后,第二句又会产生新的修改。
448450
449451## 整合控件和IDE
450452
451453### 属性编辑对话框
452454
453455属性编辑对话框在Object Inspector中提供了自定义的属性编辑窗口,对于大多数属性(字符串、字符串表,图像,枚举类型等),已经有默认的编辑窗口,但是如果控件中有特殊形式的属性,那么就需要对应的属性编辑窗口。
454456
455457每一个属性编辑对话框都是TPropertyEditor的子类,或是其后代的子类。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.
456458
457459``` pascal
458460 TPropertyEditor = class
459461 public
460462 function AllEqual: Boolean; Virtual;
461463 function AutoFill: Boolean; Virtual;
462464 procedure Edit; Virtual; // Activated by double-clicking the property value
463465 procedure ShowValue; Virtual; // Activated by control-clicking the property value
464466 function GetAttributes: TPropertyAttributes; Virtual;
465467 function GetEditLimit: Integer; Virtual;
466468 function GetName: ShortString; Virtual;
467469 procedure GetProperties(Proc: TGetPropEditProc); Virtual;
468470 function GetHint(HintType: TPropEditHint; x, y: integer): String; Virtual;
469471 function GetDefaultValue: AnsiString; Virtual;
470472 procedure GetValues(Proc: TGetStrProc); Virtual;
471473 procedure SetValue(const NewValue: AnsiString); Virtual;
472474 procedure UpdateSubProperties; Virtual;
473475 function SubPropertiesNeedsUpdate: Boolean; Virtual;
474476 function IsDefaultValue: Boolean; Virtual;
475477 function IsNotDefaultValue: Boolean; Virtual;
476478 // ... shortened
477479 end;
478480```
479481
480482A good example for a property editor is the TFont property editor.
481483
482484One 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.
483485
484486For 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:
485487
486488``` pascal
487489TClassPropertyEditor = class(TPropertyEditor)
488490public
489491 constructor Create(Hook: TPropertyEditorHook; APropCount: Integer); Override;
490492 function GetAttributes: TPropertyAttributes; Override;
491493 procedure GetProperties(Proc: TGetPropEditProc); Override;
492494 function GetValue: AnsiString; Override;
493495 property SubPropsTypeFilter: TTypeKinds Read FSubPropsTypeFilter
494496 Write SetSubPropsTypeFilter
495497 Default tkAny;
496498end;
497499```
498500
499501Going 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:
500502
501503``` pascal
502504 TFontPropertyEditor = class(TClassPropertyEditor)
503505 public
504506 procedure Edit; Override;
505507 function GetAttributes: TPropertyAttributes; Override;
506508 end;
507509
508510procedure TFontPropertyEditor.Edit;
509511var
510512 FontDialog: TFontDialog;
511513begin
512514 FontDialog := TFontDialog.Create(NIL);
513515 try
514516 FontDialog.Font := TFont(GetObjectValue(TFont));
515517 FontDialog.Options := FontDialog.Options + [fdShowHelp, fdForceFontExist];
516518 if FontDialog.Execute then SetPtrValue(FontDialog.Font);
517519 finally
518520 FontDialog.Free;
519521 end;
520522end;
521523
522524function TFontPropertyEditor.GetAttributes: TPropertyAttributes;
523525begin
524526 Result := [paMultiSelect, paSubProperties, paDialog, paReadOnly];
525527end;
526528```
527529
528530### 组件编辑器
529531
530532组件编辑器控制在设计窗口中组件的右键和双击行为。
531533
532534Each 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:
533535
534536``` pascal
535537 TBaseComponentEditor = class
536538 protected
537539 public
538540 constructor Create(AComponent: TComponent;
539541 ADesigner: TComponentEditorDesigner); Virtual;
540542 procedure Edit; Virtual; Abstract;
541543 procedure ExecuteVerb(Index: Integer); Virtual; Abstract;
542544 function GetVerb(Index: Integer): String; Virtual; Abstract;
543545 function GetVerbCount: Integer; Virtual; Abstract;
544546 procedure PrepareItem(Index: Integer; const AnItem: TMenuItem); Virtual; Abstract;
545547 procedure Copy; Virtual; Abstract;
546548 function IsInInlined: Boolean; Virtual; Abstract;
547549 function GetComponent: TComponent; Virtual; Abstract;
548550 function GetDesigner: TComponentEditorDesigner; Virtual; Abstract;
549551 function GetHook(out Hook: TPropertyEditorHook): Boolean; Virtual; Abstract;
550552 procedure Modified; Virtual; Abstract;
551553 end;
552554```
553555
554556The 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.
555557
556558Other important methods from TBaseComponentEditor are:
557559
558560- **ExecuteVerb(Index)** - Executes one of the extra menu items placed on the right-click popup menu;
559561- **GetVerb** – To return the name of each extra popup menu item. Note that it 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;
560562- **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;
561563- **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;
562564- **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.
563565
564566A simple and interesting example is the TCheckListBox component editor which creates a dialog to edit. More convenient than 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:
565567
566568``` pascal
567569 TCheckListBoxComponentEditor = class(TComponentEditor)
568570 protected
569571 procedure DoShowEditor;
570572 public
571573 procedure ExecuteVerb(Index: Integer); override;
572574 function GetVerb(Index: Integer): String; override;
573575 function GetVerbCount: Integer; override;
574576 end;
575577
576578procedure TCheckGroupComponentEditor.DoShowEditor;
577579var
578580 Dlg: TCheckGroupEditorDlg;
579581begin
580582 Dlg := TCheckGroupEditorDlg.Create(NIL);
581583 try
582584 // .. shortened
583585 Dlg.ShowModal;
584586 // .. shortened
585587 finally
586588 Dlg.Free;
587589 end;
588590end;
589591
590592procedure TCheckGroupComponentEditor.ExecuteVerb(Index: Integer);
591593begin
592594 case Index of
593595 0: DoShowEditor;
594596 end;
595597end;
596598
597599function TCheckGroupComponentEditor.GetVerb(Index: Integer): String;
598600begin
599601 Result := 'CheckBox Editor...';
600602end;
601603
602604function TCheckGroupComponentEditor.GetVerbCount: Integer;
603605begin
604606 Result := 1;
605607end;
606608```
607609
608610## Design-time component debugging
609611
610612To catch design-time-errors in a (newly created) *dbgcomponent*:
611613
612614- open project `C:\lazarus\ide\lazarus.lpi`;
613615- run project;
614616- set breakpoint in *dbgcomponent* in main (1st) app;
615617- use *dbgcomponent* pascal code in second app;
616618- step through design-time component code in debug-session; do whatever is necessary;
617619
618620## See also
619621
620622- [[Extending the IDE]]
621623- [[Lazarus Packages]] - A guide for creating a package under Lazarus
622624- [[Components and Code examples]]
623625- [[Lazarus Components]]
624626- [[IDE Window: Add to Package]]
625627- [[IDE Window: Create new package component]]
626628
627629You can post questions regarding this page [here](http://forum.lazarus.freepascal.org/index.php/topic,5789.0.html)
628630
629631---
630632*From the Free Pascal wiki, page "How To Write Lazarus Component/zh CN", as it stood on 2021-05-30 after a change by Apiglio, 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).*
631633Category: Code
632634Category: Component Creation
633635Category: Lazarus
634636Category: Packages
635637Category: Tutorials

Back to history