Sign in Join
Wiki copytemporary

How To Write Lazarus Component/ru: what changed

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

OldNewLine
11Это руководство по созданию компонентов.
22
33## Шаг 1: Создание пакета
44
55- В меню IDE Lazarus нажмите "Package" \> "New package" для запуска диспетчера пакетов.
66
77![](/wiki-images/7/7c/Package_menu.png)
88
99- Появится диалоговое окно "Save". Выберите папку и имя файла и нажмите "Save". Если программа IDE предложит использовать строчные имена файлов, нажмите "да".
1010
1111- Поздравляем: вы только что создали свой первый пакет!
1212
1313![](/wiki-images/3/37/How_to_write_lazarus_component_package_maker.png)
1414
1515## Шаг 2: Создание модуля
1616
1717Вы можете создать новый модуль или использовать существующий файл. Оба варианта описаны ниже.
1818
1919### Создание нового модуля
2020
2121- Используйте кнопку **Add \> New component**.\
2222
2323![](/wiki-images/5/56/Package_new_component.png)\
2424
2525- Выберите компонент, \[например такой\] как TComboBox.
2626- Выберите *customcontrol1.pas* в качестве **Unit File Name** и *CustomControl1* в качестве **Unit Name**.
2727- Теперь вы можете задать иконку компоненту и определить, на какой палитре компонент должен появиться позже в Lazarus-IDE.
2828- Нажмите **OK**\[, чтобы создать новый компонент\].\
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- Установите пакет, кликнув кнопку **Use -\> Install** вверху редактора пакетов.\
6565
6666![](/wiki-images/3/36/Package_install.png)\
6767
6868- Теперь IDE спросит вас, должна ли она быть пересобрана. Ответьте "Да".\
6969
7070![](/wiki-images/9/9b/Package_rebuild.png)\
7171
7272- Перезапустите Lazarus\[, если он не сделал этого сам,\] и посмотрите на свой новый компонент в палитре компонентов. Поздравляем: вы только что установили свой первый пакет с вашим первым компонентом.\
7373
7474![](/wiki-images/3/35/Package_installed.png)\
7575
7676> **Note:** Если вы не видите свой новый компонент в палитре компонентов, скорее всего, вы используете не пересобранную версию Lazarus. Вы можете установить, где Lazarus пересобирается, используя \[пункт меню\] Tools -\> Options -\> Files -\> Lazarus directory.
7777>
7878> Вместо прямого вызова Lazarus вы также можете использовать startlazarus, который запускает недавно созданный Lazarus, например исполняемый файл Lazarus в каталоге ~ / .lazarus, если у вас нет доступа на запись в каталог, в который был установлен Lazarus.
7979
8080------------------------------------------------------------------------
8181
8282Прим.перев. 23:36, 1 December 2018 (CET): В корневом каталоге Lazarus'а после пересборки обычно содержится три исполняемых файла: lazarus (текущий запускаемый файл), startlazarus (лаучер для lazarus) и lazarus.old (старая версия исполняемого файла, существующая после последней удачной пересборки среды). В примечании, вероятнее всего, речь идет о них.
8383
8484------------------------------------------------------------------------
8585
8686### Добавление существующего модуля
8787
8888Если у вас уже есть модуль, вы можете добавить его в пакет:
8989
9090![](/wiki-images/1/11/Package_existing_unit.png)\
9191
9292- Нажмите кнопку **Add**, перейдите к вкладке **Add Files**. В \[колонке\] file name модуля добавьте ваш существующий файл. Нажмите **Add files to package**. Если диспетчер пакетов жалуется, что модуль находится вне заданных к модулям путей, нажмите "Да", чтобы добавить каталог в пути к модулям.
9393- Нажмите кнопку **Add** снова, перейдите на вкладку **Add Files**, найдите файл *.lrs* и нажмите "OK" (см. Шаг 3 о создании файла иконки).
9494- Снова нажмите кнопку **Add**, перейдите к вкладке **New Requirement** \[(новая зависимость)\]. В имени пакета выберите **LCL** и нажмите OK.
9595
9696Конечный результат должен выглядеть следующим образом:\
9797![Package Maker](/wiki-images/d/d9/How_to_write_lazarus_component_package_maker_done.png)\
9898
9999- Щелкните по дереву файлов в диспетчере пакетов. В свойствах файла убедитесь, что установлен флажок *Register unit*.
100100- Нажмите кнопку Options. Перейдите на вкладку IDE Integration. В опции Package Type убедитесь, что выбраны \[режимы\] Designtime и Runtime.
101101- Нажмите кнопку Compile, чтобы проверить, файлы компилируются без ошибок.
102102- Нажмите кнопку Install. Lazarus автоматически пересоберется и перезагрузится.
103103
104104Компонент создан и готов к использованию:\
105105![Component Created](/wiki-images/3/3c/How_to_write_lazarus_component_created.png)\
106106
107107## Шаг 3: Создание значков для пакета
108108
109109Вы должны создать PNG-файлы размером 24x24 пикселя в виде значков. Если для Lazarus 1.8+ вы хотите, чтобы значки палитры масштабировались при более высоких разрешениях экрана, вы также должны предоставлять значки 36x36 и 48x48 пикселей. Имена более крупных значков требуют добавления \[суффиксов\] "_150" и "_200" к имени файла, соответственно \[увеличению разрешения\] ("_150" для 150%, "_200" для 200%).
110110
111111FPC способен использовать стандартные файлы ресурсов `.rc` или скомпилированные ресурсы `.res`, \[начиная\] с версии fpc 2.6. См. [[Lazarus Resources/ru|FPC ресурсы]]. \[О файлах\] `.lrs`: см.ниже.
112112
113113### Использование редактора изображений Lazarus
114114
115115Вы можете использовать [[Lazarus Image Editor]] для создания изображений в .lrs формате.
116116
117117------------------------------------------------------------------------
118118
119119Прим.перев. 17:13, 3 December 2018 (CET): Поскольку старшие версии Лазаруса (насколько я помню, после v.1.6.х точно) позволяют задавать иконку изображения в png-формате, то удобнее всего для их создания использовать бесплатный векторный редактор [InkScape](https://inkscape.org/ru), "родным" для которого является формат SVG. Среди его преимуществ:
120120
121121- работа со слоями
122122- поддержка альфа-канала
123123- предосмотр иконок в разных разрешениях (в файле настроек можно задать даже нестандартные значения)
124124- вменяемый и оперативный саппорт (можно напрямую пообщаться с разработчиками в [чате](https://inkscape.org/ru/community/discussion))
125125- экспорт изображений в png-формат
126126
127127------------------------------------------------------------------------
128128
129129### Использование lazres
130130
131131`lazres` обычно находится в каталоге инструментов Lazarus.
132132
133133Вам может понадобиться скомпилировать [[lazres]] при первом использовании. Просто откройте *lazres.lpi* в среде IDE и нажмите **run \> build** в меню.
134134
135135#### Создание lrs-файла
136136
137137Для создания lrs-файла запустите:
138138
139139``` pascal
140140~/lazarus/tools/lazres samplepackage.lrs TMyCom.png
141141```
142142
143143или, если доступны изображения с высоким разрешением
144144
145145``` pascal
146146~/lazarus/tools/lazres samplepackage.lrs TMyCom.png TMyCom_150.pgn TMyCom_200.png
147147```
148148
149149где
150150
151151- *samplepackage* - имя вашего пакета
152152- *TMyCom* - имя вашего компонента. Имя изображения должно совпадать с именем вашего компонента!
153153
154154Вы можете добавить несколько изображений в файл lrs, добавив имя файла изображения в конец \[команды\]. Например:
155155
156156``` pascal
157157~/lazarus/tools/lazres samplepackage.lrs TMyCom.png TMyOtherCom.png ...
158158```
159159
160160**Пример**
161161
162162Ниже приведен образец полученного файла *samplepackage.lrs*.
163163
164164``` pascal
165165LazarusResources.Add('TMyCom','PNG',[
166166 #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
167167 +#0#0#0#4'gAMA'#0#0#177#143#11#252'a'#5#0#0#0'|IDAT8O'#237#212#209#10#192' '#8
168168 +#5'P'#247#231#251's'#215#138#133#164#166'\'#220#195'`'#209'c'#157'L'#173#131
169169 +#153#169'd4'#168'dP'#137'r_'#235'5'#136'@Zmk'#16'd9'#144#176#232#164'1'#247
170170 +'I'#8#160'IL'#206'C'#179#144#12#199#140'.'#134#244#141'~'#168#247#209'S~;'#29
171171 +'V+'#196#201'^'#10#15#150'?'#255#18#227#206'NZ>42'#181#159#226#144#15'@'#201
172172 +#148#168'e'#224'7f<@4'#130'u_YD'#23#213#131#134'Q]'#158#188#135#0#0#0#0'IEND'
173173 +#174'B`'#130
174174]);
175175```
176176
177177Обязательно включите свой файл ресурсов в исходник нового компонента, добавив нижеследующее в модуль вашего компонента и включив "LResources" в раздел uses
178178
179179``` pascal
180180initialization
181181 {$I samplepackage.lrs}
182182```
183183
184184#### Создание res-файла
185185
186186lazres также может создать скомпилированный файл ресурсов, просто укажите файл с расширением .res, например:
187187
188188``` pascal
189189~/lazarus/tools/lazres samplepackage.res TMyCom.png
190190```
191191
192192или, для иконок с высоким разрешением:
193193
194194``` pascal
195195~/lazarus/tools/lazres samplepackage.res TMyCom.png TMyCom_150.png TMyCom_200.png
196196```
197197
198198В этом случае вместо включения файла lrs в разделе инициализации просто укажите файл ресурсов в любом месте исходного файла компонента
199199
200200``` pascal
201201 {$R samplepackage.res}
202202```
203203
204204### Использование glazres
205205
206206**GLazRes** это графическая версия `lazres`, которая может собирать файлы в файл ресурсов Lazarus (.lrs). Его можно найти в каталоге инструментов установки Lazarus.
207207
208208## Перекомпиляция пакетов
209209
210210Вам нужно пересобирать пакет каждый раз, когда вы вносите изменения в файл *mycom.pas*. Чтобы пересобрать пакет, откройте файл *samplepackage.lpk* в диспетчере пакетов и нажмите кнопку Install.
211211
212212## Удаление пакетов
213213
214214- Чтобы удалить установленные компоненты: в меню IDE выберите Package \> Configure installed packages. На следующем рисунке показан инструмент Installed Packages.
215215
216-![`Installed Components`](/wiki-images/0/0e/How_to_write_lazarus_component_installed_components.png)
216+```text
217+Installed Components
218+```
217219
218220- Выберите пакет, который вы хотите удалить, и нажмите Uninstall selection.
219221
220222Если что-то пойдет не так с пакетом (например, каталог пакета удаляется без деинсталляции \[пакета в первую очередь\]), Lazarus может не разрешить вам удалять пакеты. Чтобы устранить проблему, в меню IDE выберите Tools \> Build Lazarus. Lazarus пересоберет все пакеты и перезапустит их. Теперь вы можете удалить проблемные пакеты.
221223
222224## Усовершенствование mycom.pas
223225
224226- Код в *mycom.pas* выше дает вам основы того, что вам нужно для создания компонента. Далее приведена усовершенствованная версия с некоторыми советами о том, как писать процедуры и события для компонентов.
225227- *OnChange2* показывает, как создавать события.
226228- *OnSample* показывает, как создавать пользовательские события.
227229- *MyText* и *MyText2* показывает различные способы записи свойств.
228230- Вы можете использовать TComboBox вместо TCustomComboBox в качестве базового класса, который \[объявляет\] публичными все свойства как TComboBox.
229231- Если TCustomComboBox используется в качестве базового класса, вы заметите, что в Инспекторе объектов IDE будет отсутствовать множество свойств и событий. Чтобы добавить эти свойства и события, просто скопируйте и вставьте свойства, перечисленные ниже \[комментария\] *// properties from TComboBox*. Этот список свойств можно получить из объявления TComboBox в модуле StdCtrls. Исключите \[из списка\] любое свойство, которое вы хотите \[определить\] самостоятельно.
230232
231233``` pascal
232234unit mycom;
233235
234236{$mode objfpc}{$H+}
235237
236238interface
237239
238240uses
239241 Classes, SysUtils, StdCtrls, Forms, Dialogs,
240242 LCLType,LCLIntf,lresources,LCLProc;
241243
242244type
243245
244246 TSampleEvent = procedure(MyText: String) of Object;
245247
246248 TMyCom = class (TCustomComboBox)
247249 private
248250 FMyText: String;
249251 FOnChange2: TNotifyEvent;
250252 FOnSample: TSampleEvent;
251253 public
252254 constructor Create(TheOwner: TComponent); override;
253255 procedure CreateWnd; override;
254256 procedure Change; override;
255257 protected
256258 function GetMyText2: String;
257259 procedure SetMyText2(MyText: String);
258260 published
259261 property MyText: String read FMyText write FMyText;
260262 property MyText2: String read GetMyText2 write SetMyText2;
261263 property OnChange2: TNotifyEvent read FOnChange2 write FOnChange2;
262264 property OnSample: TSampleEvent read FOnSample write FOnSample;
263265
264266 // properties from TComboBox
265267 property Align;
266268 property Anchors;
267269 property ArrowKeysTraverseList;
268270 property AutoComplete;
269271 property AutoCompleteText;
270272 property AutoDropDown;
271273 property AutoSelect;
272274 property AutoSize;
273275 property BidiMode;
274276 property BorderSpacing;
275277 property CharCase;
276278 property Color;
277279 property Ctl3D;
278280 property Constraints;
279281 property DragCursor;
280282 property DragMode;
281283 property DropDownCount;
282284 property Enabled;
283285 property Font;
284286 property ItemHeight;
285287 property ItemIndex;
286288 property Items;
287289 property ItemWidth;
288290 property MaxLength;
289291 property OnChange;
290292 property OnChangeBounds;
291293 property OnClick;
292294 property OnCloseUp;
293295 property OnContextPopup;
294296 property OnDblClick;
295297 property OnDragDrop;
296298 property OnDragOver;
297299 property OnDrawItem;
298300 property OnEndDrag;
299301 property OnDropDown;
300302 property OnEditingDone;
301303 property OnEnter;
302304 property OnExit;
303305 property OnGetItems;
304306 property OnKeyDown;
305307 property OnKeyPress;
306308 property OnKeyUp;
307309 property OnMeasureItem;
308310 property OnMouseDown;
309311 property OnMouseMove;
310312 property OnMouseUp;
311313 property OnStartDrag;
312314 property OnSelect;
313315 property OnUTF8KeyPress;
314316 property ParentBidiMode;
315317 property ParentColor;
316318 property ParentCtl3D;
317319 property ParentFont;
318320 property ParentShowHint;
319321 property PopupMenu;
320322 property ReadOnly;
321323 property ShowHint;
322324 property Sorted;
323325 property Style;
324326 property TabOrder;
325327 property TabStop;
326328 property Text;
327329 property Visible;
328330 end;
329331
330332procedure Register;
331333
332334implementation
333335
334336procedure Register;
335337begin
336338 RegisterComponents('Sample',[TMyCom]);
337339end;
338340
339341constructor TMyCom.Create(TheOwner: TComponent);
340342begin
341343 inherited Create(TheOwner);
342344 Self.Style := csDropDownList;
343345end;
344346
345347procedure TMyCom.CreateWnd;
346348begin
347349 inherited CreateWnd;
348350 Items.Assign(Screen.Fonts);
349351end;
350352
351353procedure TMyCom.Change;
352354begin
353355 inherited;
354356 if Assigned(FOnChange2) then FOnChange2(Self);
355357 if Assigned(FOnSample) then FOnSample(FMyText);
356358end;
357359
358360function TMyCom.GetMyText2: String;
359361begin
360362 Result:=FMyText;
361363end;
362364
363365procedure TMyCom.SetMyText2(MyText: String);
364366begin
365367 FMyText:=MyText;
366368end;
367369
368370initialization
369371 {$I samplepackage.lrs}
370372
371373end.
372374```
373375
374376Также вы заметите, что в Инспекторе объектов IDE существуют некоторые необъявленные и, возможно, нежелательные элементы. Чтобы удалить те из них, которые вам не нужны, вы можете переобъявить их в разделе *Published* как простые переменные. Например:
375377
376378``` pascal
377379Published
378380...
379381 property Height: Integer;
380382 property Width: Integer;
381383...
382384```
383385
384386## Использование встроенных (визуальных) компонентов
385387
386388Можно использовать стандартные компоненты, встроенные в ваши собственные компоненты (посмотрите для примера на TLabeledEdit или TButtonPanel).
387389
388390Предположим, вы хотите создать пользовательскую панель с TLabel на ней. С помощью описанных выше шагов можно создать базовый пакет и исходные файлы. Теперь сделайте следующее для добавления TLabel в компонент:
389391
390392- Добавьте приватный атрибут (поле) для компонента label (`FEmbeddedLabel: TLabel;`).
391393- Добавьте published-свойство только для чтения для компонента label (`property EmbeddedLabel: TLabel read FEmbeddedLabel;`)
392394- Создайте label в конструкторе (переопределенном) компонента (`FEmbeddedLabel: = TLabel.Create(self);`)
393395- Задайте родительский элемент компонента (`FEmbeddedLabel.Parent: = self;`)
394396- Если встроенный компонент не является 'субкомпонентом' по умолчанию (например, TBoundLabel, TPanelBitBtn и т.д.), то добавьте вызов в SetSubComponent. Это необходимо для IDE, чтобы она знала, что она также должна хранить свойства встроенного компонента. По умолчанию TLabel не является субкомпонентом, поэтому необходимо добавить вызов метода (`FEmbeddedLabel.SetSubComponent(true);`).
395397
396398В итоге вы получите что-то вроде этого (показаны только основные части):
397399
398400``` pascal
399401TEnhancedPanel = class(TCustomControl)
400402private
401403 { Новые аттрибуты для встроенного label }
402404 FEmbeddedLabel: TLabel;
403405
404406public
405407 { Конструктор должен быть переопределен, чтобы label могла быть создана}
406408 constructor Create(AOwner: TComponent); override;
407409
408410published
409411 { Сделаем label видимым в IDE }
410412 property EmbeddedLabel: TLabel read FEmbeddedLabel;
411413end;
412414
413415implementation
414416
415417constructor TEnhancedPanel.Create(AOwner: TComponent);
416418begin
417419 inherited Create(AOwner);
418420
419421 // Устанавливаем дефолтовые width и height
420422 with GetControlClassDefaultSize do
421423 SetInitialBounds(0, 0, CX, CY);
422424
423425 // Добавляем встроенный label
424426 FEmbeddedLabel := TLabel.Create(Self); // Добавляем встроенный label
425427 FEmbeddedLabel.Parent := self; // Показываем label на panel
426428 FEmbeddedLabel.SetSubComponent(true); // Говорим IDE сохранять измененные свойства
427429 FLabel.Name := 'EmbeddedLabel';
428430 FLabel.Caption := 'Howdy World!';
429431
430432 // Убеждаемся, что встроенная label не может быть выделена/удалена средствами IDE
431433 FLabel.ControlStyle := FLabel.ControlStyle - [csNoDesignSelectable];
432434
433435 // Задаем другие свойства, если необходимо
434436 //...
435437
436438end;
437439```
438440
439441## Использование пользовательской процедуры рисования
440442
441443Вы всегда можете переопределить компонент внутри вашей программы. Например, это реализует пользовательскую процедуру Paint для TLabel:
442444
443445``` pascal
444446type
445447 TMyLabel = class(TLabel)
446448 protected
447449 procedure Paint; override;
448450 end;
449451{...}
450452implementation
451453{...}
452454procedure TMyLabel.Paint;
453455begin
454456 // ваш код для реализации Paint, например
455457 Canvas.TextOut(0,0,Caption);
456458end;
457459```
458460
459461Теперь вы можете создать MyLabel внутри вашей программы во время выполнения с этой переопределенной процедурой Paint вместо стандартной.
460462
461463Для большинства компонентов и для большинства методов было бы полезно вызвать унаследованную процедуру внутри него:
462464
463465``` pascal
464466procedure TMyLabel.Paint;
465467begin
466468
467469 inherited Paint; /////////////////////
468470
469471 // ваш код для реализации Paint, например
470472 Canvas.TextOut(0,0,Caption);
471473end;
472474```
473475
474476Однако унаследованное поведение нежелательно в этом случае, поскольку второе действие записи будет перекрывать первый (унаследованный).
475477
476478## Интеграция компонента с IDE
477479
478480### Редакторы свойств
479481
480482Редакторы свойств предоставляют настраиваемые диалоги для редактирования свойств в инспекторе объектов. Для большинства свойств, таких как строки, строковые списки, изображения, перечисленные типы и другие, уже есть редакторы свойств по умолчанию, но если у пользовательского компонента есть особый вид свойства, для изменения свойства может потребоваться настраиваемый диалог.
481483
482484Каждый редактор свойств - это класс, который должен происходить из TPropertyEditor или одного из его потомков и реализовывать методы этого базового класса. Они должны быть зарегистрированы в процедуре 'Register', используя функцию RegisterPropertyEditor из модуля PropEdits. Это стандарт для имен редакторов свойств с именем свойства, за которым следует \[слово\] 'Property', например \[имя\] TFieldProperty для редактора свойств свойства TField.
483485
484486``` pascal
485487 TPropertyEditor = class
486488 public
487489 function AllEqual: Boolean; Virtual;
488490 function AutoFill: Boolean; Virtual;
489491 procedure Edit; Virtual; // Активируется двойным щелчком по значению свойства
490492 procedure ShowValue; Virtual; // Активируется щелчком по элементу управления значения свойства
491493 function GetAttributes: TPropertyAttributes; Virtual;
492494 function GetEditLimit: Integer; Virtual;
493495 function GetName: ShortString; Virtual;
494496 procedure GetProperties(Proc: TGetPropEditProc); Virtual;
495497 function GetHint(HintType: TPropEditHint; x, y: integer): String; Virtual;
496498 function GetDefaultValue: AnsiString; Virtual;
497499 procedure GetValues(Proc: TGetStrProc); Virtual;
498500 procedure SetValue(const NewValue: AnsiString); Virtual;
499501 procedure UpdateSubProperties; Virtual;
500502 function SubPropertiesNeedsUpdate: Boolean; Virtual;
501503 function IsDefaultValue: Boolean; Virtual;
502504 function IsNotDefaultValue: Boolean; Virtual;
503505 // ... укорочено
504506 end;
505507```
506508
507509Хорошим примером для редактора свойств является редактор свойств TFont.
508510
509511Один из наиболее распространенных случаев для редакторов свойств - это свойства, которые являются классами. Поскольку классы имеют много полей и могут иметь различные форматы, Lazarus не может иметь \[универсальное\] поле редактирования в инспекторе объектов, способное их редактировать, \[как это сделано,\] например, для строк и числовых типов.
510512
511513Для классов соглашение состоит в том, чтобы в поле значений постоянно отображалось имя класса в круглых скобках, например "(TFont)", а кнопка "..." показывала диалог для редактирования этого класса. Это поведение, за исключением диалога, реализуется стандартным редактором свойств для классов, называемых TClassPropertyEditor, который может быть унаследован при создании редакторов свойств для классов:
512514
513515``` pascal
514516TClassPropertyEditor = class(TPropertyEditor)
515517public
516518 constructor Create(Hook: TPropertyEditorHook; APropCount: Integer); Override;
517519 function GetAttributes: TPropertyAttributes; Override;
518520 procedure GetProperties(Proc: TGetPropEditProc); Override;
519521 function GetValue: AnsiString; Override;
520522 property SubPropsTypeFilter: TTypeKinds Read FSubPropsTypeFilter
521523 Write SetSubPropsTypeFilter
522524 Default tkAny;
523525end;
524526```
525527
526528Возвращаясь к примеру TFont, наследование от TClassPropertyEditor уже предлагает часть желаемого поведения, а затем классу TFontPropertyEditor необходимо реализовать отображение диалога в методе Edit и установить атрибуты для редактора:
527529
528530``` pascal
529531 TFontPropertyEditor = class(TClassPropertyEditor)
530532 public
531533 procedure Edit; Override;
532534 function GetAttributes: TPropertyAttributes; Override;
533535 end;
534536
535537procedure TFontPropertyEditor.Edit;
536538var
537539 FontDialog: TFontDialog;
538540begin
539541 FontDialog := TFontDialog.Create(NIL);
540542 try
541543 FontDialog.Font := TFont(GetObjectValue(TFont));
542544 FontDialog.Options := FontDialog.Options + [fdShowHelp, fdForceFontExist];
543545 if FontDialog.Execute then SetPtrValue(FontDialog.Font);
544546 finally
545547 FontDialog.Free;
546548 end;
547549end;
548550
549551function TFontPropertyEditor.GetAttributes: TPropertyAttributes;
550552begin
551553 Result := [paMultiSelect, paSubProperties, paDialog, paReadOnly];
552554end;
553555```
554556
555557### Редакторы компонентов
556558
557559Редакторы компонентов управляют поведением компонентов по щелчку правой кнопкой мыши и двойному щелчку в дизайнере форм.
558560
559561Каждый редактор компонентов - это класс, который должен происходить от TComponentEditor или одного из его потомков и реализовывать методы из этого базового класса. Он должен быть зарегистрирован в процедуре 'Register', использущей функцию RegisterComponentEditor из модуля ComponentEditors. Это стандарт для именования редакторов компонентов с именем компонента, за которым следует \[слово\] 'Editor', например TStringGridComponentEditor для редактора свойств компонента TStringGrid. Хотя редакторы пользовательских компонентов должны быть основаны на TComponentEditor, большинство его методов на самом деле \[берут начало\] от предка, поэтому необходимо также знать TBaseComponentEditor:
560562
561563``` pascal
562564 TBaseComponentEditor = class
563565 protected
564566 public
565567 constructor Create(AComponent: TComponent;
566568 ADesigner: TComponentEditorDesigner); Virtual;
567569 procedure Edit; Virtual; Abstract;
568570 procedure ExecuteVerb(Index: Integer); Virtual; Abstract;
569571 function GetVerb(Index: Integer): String; Virtual; Abstract;
570572 function GetVerbCount: Integer; Virtual; Abstract;
571573 procedure PrepareItem(Index: Integer; const AnItem: TMenuItem); Virtual; Abstract;
572574 procedure Copy; Virtual; Abstract;
573575 function IsInInlined: Boolean; Virtual; Abstract;
574576 function GetComponent: TComponent; Virtual; Abstract;
575577 function GetDesigner: TComponentEditorDesigner; Virtual; Abstract;
576578 function GetHook(out Hook: TPropertyEditorHook): Boolean; Virtual; Abstract;
577579 procedure Modified; Virtual; Abstract;
578580 end;
579581```
580582
581583Наиболее важным методом редактора компонентов является \[метод\] Edit, который вызывается по двойному щелчку на компоненте. Когда вызывается контекстное меню для компонента, запрашивается метод GetVerbCount и GetVerb для создания меню. Если выбран один из глаголов (что означает пункты меню в этом случае), вызывается ExecuteVerb. Существует редактор компонентов по умолчанию (TDefaultEditor), который реализует Edit для поиска свойств компонента для наиболее подходящего для редактирования. Обычно он выбирает событие, которое будет редактироваться, путем добавления скелета кода в редактор кода и установки курсора в это место.
582584
583585Другими важными методами из TBaseComponentEditor являются:
584586
585587- **ExecuteVerb(Index)** - Выполняет один из дополнительных пунктов меню, расположенных во всплывающем меню правой кнопки мыши;
586588- **GetVerb** – Возвращает имя каждого дополнительного пункта всплывающего меню. Обратите внимание, что редактор компонентов должен размещать специальные символы заголовка элемента, такие как &, для создания ускорителя клавиатуры и "-" для создания разделителя;
587589- **GetVerbCount** – Возвращает количество элементов, которые будут добавлены во всплывающее меню. Индекс для подпрограмм GetVerb и ExecuteVerb равен нулю, начиная от 0 до GetVerbCount - 1;
588590- **PrepareItem** – Вызывается для каждого глагола \[(GetVerbCount и GetVerb)\] после создания пункта меню. Позволяет настраивать элемент меню, например, добавляя подэлементы, добавляя флажок или даже скрывая его, устанавливая Visible в false;
589591- **Copy** - Вызывается, когда компонент копируется в буфер обмена. Данные компонента при использовании Lazarus'ом всегда будут \[только\] добавляться и не могут быть изменены. Этот метод предназначен для добавления различных типов из буфера обмена при вставке компонента в другие приложения, но не будет влиять на вставку в Lazarus'е.
590592
591593Простым и интересным примером является редактор компонентов TCheckListBox, который создает диалоговое окно для редактирования. Более удобный, чем реализация всех методов из TBaseComponentEditor, \[он\] наследуется от TComponentEditor, и это то, что делает TCheckListBoxEditor. Этот базовый класс добавляет пустые реализации для большинства методов и некоторые умолчательные для других. Для \[метода\] Edit он вызывает ExecuteVerb(0), поэтому, если первый пункт \[popup menu\] будет сопоставлен действию двойного щелчка мыши, что является условным обозначением для редактора, то нет необходимости в \[ручной\] реализации \[кода метода\] Edit. Это основное действие для двойного щелчка и первого элемента меню часто является диалогом, и для TCheckListBox это также реализуется \[так\]:
592594
593595``` pascal
594596 TCheckListBoxComponentEditor = class(TComponentEditor)
595597 protected
596598 procedure DoShowEditor;
597599 public
598600 procedure ExecuteVerb(Index: Integer); override;
599601 function GetVerb(Index: Integer): String; override;
600602 function GetVerbCount: Integer; override;
601603 end;
602604
603605procedure TCheckGroupComponentEditor.DoShowEditor;
604606var
605607 Dlg: TCheckGroupEditorDlg;
606608begin
607609 Dlg := TCheckGroupEditorDlg.Create(NIL);
608610 try
609611 // .. укорочено
610612 Dlg.ShowModal;
611613 // .. укорочено
612614 finally
613615 Dlg.Free;
614616 end;
615617end;
616618
617619procedure TCheckGroupComponentEditor.ExecuteVerb(Index: Integer);
618620begin
619621 case Index of
620622 0: DoShowEditor;
621623 end;
622624end;
623625
624626function TCheckGroupComponentEditor.GetVerb(Index: Integer): String;
625627begin
626628 Result := 'CheckBox Editor...';
627629end;
628630
629631function TCheckGroupComponentEditor.GetVerbCount: Integer;
630632begin
631633 Result := 1;
632634end;
633635```
634636
635637## Отладка компонента в Design-time
636638
637639Чтобы отловить ошибки времени разработки во (вновь созданном) *dbgcomponent*:
638640
639641- откройте проект `C:\lazarus\ide\lazarus.lpi`;
640642- запустите проект;
641643- установите точку останова в *dbgcomponent* в главном (1-ом) приложении;
642644- используйте паскалевский код *dbgcomponent* во втором приложении;
643645- выполнить пошагово код компонента времени разработки в режиме отладки; делайте все, что необходимо;
644646
645647## См. также
646648
647649- [[Extending the IDE/ru|Extending the IDE]]
648650- [[Lazarus Packages/ru|Lazarus Packages]] - A guide for creating a package under Lazarus
649651- [[Components and Code examples/ru|Components and Code examples]]
650652- [[Lazarus Components]]
651653- [[IDE Window: Add to Package]]
652654- [[IDE Window: Create new package component]]
653655- [Создание визуальных компонент для Lazarus](http://freepascal.ru/article/lazarus/20050530152619) - статья Сергея Смирнова с русскоязычного ресурса
654656
655657Все вопросы вы можете оставлять также [на этой](http://forum.lazarus.freepascal.org/index.php/topic,5789.0.html) странице
656658
657659---
658660*From the Free Pascal wiki, page "How To Write Lazarus Component/ru", 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