Sign in Join
Wiki copytemporary

Extending the IDE/ru: what changed

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

Title: Extending the IDE/ru

OldNewLine
1+# Расширение IDE
2+
3+## Обзор
4+
5+Lazarus IDE поддерживает несколько типов плагинов:
6+
7+Компоненты
8+это элементы, найденные в палитре компонентов. Например, TButton (находится на странице Standard) можно использовать для создания кнопок.
9+
10+Редакторы компонентов
11+при двойном щелчке по компоненту в Дизайнере вызывается редактор компонентов. Редактор компонента также может добавить дополнительный элемент во всплывающее меню Дизайнера (доступ к нему осуществляется по щелчку правой кнопкой мыши на компоненте в конструкторе).
12+
13+Редакторы свойств
14+Каждая строка в разделе сетки Инспектора объектов использует редактор свойств, чтобы разрешить установку или изменение значения этого свойства.
15+
16+Эксперты
17+Эксперты охватывают все другие типы плагинов. Они могут регистрировать новые пункты меню, регистрировать ярлыки или расширять другие функции IDE.
18+
19+Есть два возможных способа добавить свои собственные плагины в IDE Lazarus:
20+
21+1. Напишите пакет, установите его и зарегистрируйте ваши плагины в процедуре 'Register' модуля.
22+2. Расширьте код Lazarus и отправьте свой svn diff в список рассылки Lazarus.
23+
24+## Пакеты и зависимости Makefile
25+
26+Следующие шаги необходимы, если добавляются новые зависимости пакета.
27+
28+- Создание/Обновление Makefile для пакета через Package editor / More ... / Create Makefile.
29+- Исправление всех зависимостей. См. tools/updatemakefiles.lpi
30+
31+# Пункты меню
32+
33+Вы можете добавлять новые пункты меню, скрывать или перемещать существующие и добавлять подменю, разделы. Для ваших собственных форм вы можете зарегистрировать TMainMenu/TPopupMenu, чтобы другие пакеты могли расширять вашу форму дальше. Модуль **MenuIntf** пакета IDEIntf содержит всю регистрацию для меню и множество стандартных пунктов меню самой IDE.
34+
35+## Добавление пункта меню
36+
37+Одиночный элемент меню, такой как \[, например,\] 'View Object Inspector', называется **TIDEMenuCommand**. Вы можете создать его с помощью **RegisterIDEMenuCommand**, который имеет две формы с большим количеством параметров:
38+
39+``` pascal
40+function RegisterIDEMenuCommand(Parent: TIDEMenuSection;
41+ const Name, Caption: string;
42+ const OnClickMethod: TNotifyEvent = nil;
43+ const OnClickProc: TNotifyProcedure = nil;
44+ const Command: TIDECommand = nil;
45+ const ResourceName: String = ''
46+ ): TIDEMenuCommand; overload;
47+function RegisterIDEMenuCommand(const Path, Name, Caption: string;
48+ const OnClickMethod: TNotifyEvent = nil;
49+ const OnClickProc: TNotifyProcedure = nil;
50+ const Command: TIDECommand = nil;
51+ const ResourceName: String = ''
52+ ): TIDEMenuCommand; overload;
53+```
54+
55+Разница между этими двумя \[функциями\] только в том, как вы указываете родительский раздел меню. Вы можете указать раздел меню прямо или косвенно через путь. Многие стандартные разделы можно найти в модуле *MenuIntf*. Например, раздел **mnuTools**, который является \[пунктом\] меню *Tools* главной панели IDE. Он содержит раздел **itmSecondaryTools**, рекомендуемый для сторонних инструментов.
56+
57+Следующий \[код\] регистрирует новую команду меню с именем 'MyTool', с заголовком 'Start my tool' и при нажатии выполняет процедуру *StartMyTool*:
58+
59+``` pascal
60+procedure StartMyTool;
61+begin
62+ ... выполняется при нажатии на пункт меню ...
63+end;
64+
65+procedure Register;
66+begin
67+ RegisterIDEMenuCommand(itmSecondaryTools, 'MyTool','Start my tool',nil,@StartMyTool);
68+end;
69+```
70+
71+Если вы хотите вызвать метод вместо процедуры, используйте параметр **OnClickMethod**.
72+
73+Этот пункт меню не имеет сочетания клавиш. Если вы хотите \[назначить ему\] сочетание клавиш, вы должны создать **TIDECommand** и передать его в параметре **Command**. Например:
74+
75+``` pascal
76+uses ... IDECommands, MenuIntf;
77+...
78+var
79+ Key: TIDEShortCut;
80+ Cat: TIDECommandCategory;
81+ CmdMyTool: TIDECommand;
82+begin
83+ // регистрация сочетаний клавиш IDE и пункта меню
84+ Key := IDEShortCut(VK_UNKNOWN,[],VK_UNKNOWN,[]);
85+ Cat:=IDECommandList.FindCategoryByName(CommandCategoryToolMenuName);
86+ CmdMyTool := RegisterIDECommand(Cat,'Start my tool', 'Starts my tool to do some stuff', Key, nil, @StartMyTool);
87+ RegisterIDEMenuCommand(itmSecondaryTools, 'MyTool', 'Start my tool', nil, nil, CmdMyTool);
88+end;
89+```
90+
91+# Сочетания клавиш
92+
93+Все сочетания клавиш (ключи, которые вызывают какое-либо действие) зарегистрированы в IDECommandList. Вот пример того, как найти все команды, которые реагируют на клавиши <span class="kbd">Ctrl</span>+<span class="kbd">D</span> или две комбинации клавиш, начинающиеся с <span class="kbd">Ctrl</span>+<span class="kbd">D</span>:
94+
95+``` pascal
96+uses
97+ Classes, SysUtils, LCLProc, IDECommands;
98+
99+procedure ListCtrlD;
100+// список всех команд IDE с комбинациями клавиш <Ctrl>+<D>
101+var
102+ i: integer;
103+ Cmd: TIDECommand;
104+ Commands: TFPList;
105+begin
106+ Commands:=IDECommandList.FindCommandsByShortCut(IDEShortCut(VK_D,[],VK_UNKNOWN,[]));
107+ try
108+ for i:=0 to Commands.Count-1 do begin
109+ Cmd:=TIDECommand(Commands[i]);
110+ writeln('Cmd: ',Cmd.Name,
111+ ' A=',dbgs(Cmd.ShortcutA.Shift1),'-',Cmd.ShortcutA.Key1,
112+ ',',dbgs(Cmd.ShortcutA.Shift2),'-',Cmd.ShortcutA.Key2,
113+ ' B=',dbgs(Cmd.ShortcutB.Shift1),'-',Cmd.ShortcutB.Key1,
114+ ',',dbgs(Cmd.ShortcutB.Shift2),'-',Cmd.ShortcutB.Key2
115+ );
116+ end;
117+ finally
118+ Commands.Free;
119+ end;
120+end;
121+```
122+
123+# Конфигурационные файлы
124+
125+## Загрузка/Сохранение настроек
126+
127+Все конфигурационные файлы IDE хранятся в одном каталоге в виде XML-файлов. Пакеты также могут добавлять свои собственные файлы туда. Каталог [[pcp|primary config path]] можно прочитать с помощью:
128+
129+``` pascal
130+uses LazIDEIntf;
131+...
132+ Directory := LazarusIDE.GetPrimaryConfigPath;
133+```
134+
135+Пакеты могут создавать свои собственные файлы XML с помощью:
136+
137+``` pascal
138+uses
139+ ..., LCLProc, BaseIDEIntf, LazConfigStorage;
140+
141+const
142+ Version = 1;
143+var
144+ Config: TConfigStorage;
145+ SomeValue: String;
146+ SomeInteger: Integer;
147+ SomeBoolean: Boolean;
148+ FileVersion: LongInt;
149+begin
150+ SomeValue:='Default';
151+ SomeInteger:=3;
152+ SomeBoolean:=true;
153+
154+ // сохранение настроек
155+ try
156+ Config:=GetIDEConfigStorage('mysettings.xml',false);
157+ try
158+ // сохраняем номер версии, чтобы будущие расширения могли обрабатывать старые файлы конфигурации
159+ Config.SetDeleteValue('Path/To/The/Version',Version,0);
160+ // сохраняем строковую переменную "SomeValue"
161+ // если SomeValue имеет значение по умолчанию, запись не сохраняется,
162+ // поэтому сохраняются только [значения,] отличающиеся от значения по умолчанию.
163+ // Таким образом, xml остается коротким, и значения по умолчанию могут измениться в будущем.
164+ Config.SetDeleteValue('Path/To/Some/Value',SomeValue,'Default');
165+ Config.SetDeleteValue('Path/To/Some/Integer',SomeInteger,3);
166+ Config.SetDeleteValue('Path/To/Some/Boolean',SomeBoolean,true);
167+ // далее [по коду] еще overloads-инструкции для SetDeleteValue,
168+ // которые [всплывают в редакторе кода по нажатию] <Ctrl>+<Space>
169+ finally
170+ Config.Free;
171+ end;
172+
173+ except
174+ on E: Exception do begin
175+ DebugLn(['Saving mysettings.xml failed: ',E.Message]);
176+ end;
177+ end;
178+
179+ // загрузка настроек
180+ try
181+ Config:=GetIDEConfigStorage('mysettings.xml',true);
182+ try
183+ // чтение версии конфигурации
184+ FileVersion:=Config.GetValue('Path/To/The/Version',0);
185+ // чтение строковой переменной "SomeValue". Если запись не существует, используется
186+ // значение по умолчанию
187+ SomeValue:=Config.GetValue('Path/To/Some/Value','Default');
188+ SomeInteger:=Config.GetValue('Path/To/Some/Integer',3);
189+ SomeBoolean:=Config.GetValue('Path/To/Some/Boolean',true);
190+ finally
191+ Config.Free;
192+ end;
193+ except
194+ on E: Exception do begin
195+ DebugLn(['Loading mysettings.xml failed: ',E.Message]);
196+ end;
197+ end;
198+end;
199+```
200+
201+На заметку:
202+
203+- Каждый плагин IDE должен использовать свой собственный файл конфигурации. Особенно вы не должны использовать стандартные файлы опций IDE, такие как [[editoroptions.xml]] или [[environmentmentoptions.xml]].
204+- GetIDEConfigStorage при загрузке проверяет, существует ли файл и, если нет, копирует шаблон из вторичного каталога конфигурации.
205+- Начиная с версии 0.9.31 вы можете использовать эту функцию для загрузки файла вне основного каталога конфигурации.
206+
207+# Компоненты
208+
209+## Расширение существующих компонентов
210+
211+Источник: [1](http://lazarus.freepascal.org/index.php/topic,17733.msg98425.html#msg98425) Это обычная настройка существующих компонентов LCL, например, если вы хотите добавить свойства.
212+
213+Добавьте необходимые свойства с соответствующими методами установки и получения и полями хранения.
214+
215+Затем создайте их экземпляр «вручную», предоставив компонент-владелец (для последующей обработки), и установите \[свойство\] Parent и, возможно, \[свойства\] Top и Left и любые другие значения по умолчанию, необходимые для вашего компонента при инициализации.
216+
217+Когда вы убедитесь, что ваш настроенный компонент отлажен, добавьте вызов `RegisterComponent()`, чтобы прикрепить его к палитре компонентов IDE и избавьте вас от необходимости выполнять код установки вручную (посмотрите на исходник любого компонента, чтобы узнать, как это сделать).
218+
219+Вот простой пример:
220+
221+``` pascal
222+unit Unit1;
223+
224+{$mode objfpc}{$H+}
225+
226+interface
227+
228+uses
229+ Classes, SysUtils, Forms, StdCtrls;
230+
231+type
232+ TEdX = class(TEdit)
233+ private
234+ FNewIntProp: integer;
235+ FNewStrProp: string;
236+ procedure SetNewIntProp(AValue: integer);
237+ procedure SetNewStrProp(AValue: string);
238+ public
239+ constructor Create(theComponent: TComponent); override;
240+ property NewIntProp: integer read FNewIntProp write SetNewIntProp;
241+ property NewStrProp: string read FNewStrProp write SetNewStrProp;
242+ end;
243+
244+ TForm1 = class(TForm)
245+ procedure FormCreate(Sender: TObject);
246+ private
247+ edX: TEdX;
248+ public
249+ end;
250+
251+var
252+ Form1: TForm1;
253+
254+implementation
255+
256+{ TForm1 }
257+
258+procedure TForm1.FormCreate(Sender: TObject);
259+begin
260+ edX:= TEdX.Create(Self);
261+ edX.Parent:= Self;
262+ edX.Caption:= IntToStr(edX.NewIntProp);
263+ Caption:= edX.NewStrProp;
264+end;
265+
266+{$R *.lfm}
267+
268+{ TEdX }
269+
270+procedure TEdX.SetNewIntProp(AValue: integer);
271+begin
272+ if FNewIntProp=AValue then Exit;
273+ FNewIntProp:=AValue;
274+ // добавьте свой код здесь
275+end;
276+
277+procedure TEdX.SetNewStrProp(AValue: string);
278+begin
279+ if FNewStrProp=AValue then Exit;
280+ FNewStrProp:=AValue;
281+ // добавьте свой код здесь
282+end;
283+
284+constructor TEdX.Create(theComponent: TComponent);
285+begin
286+ inherited Create(theComponent);
287+ FNewStrProp:= 'new string property value';
288+ FNewIntProp:= 99;
289+end;
290+
291+end.
292+```
293+
294+## Написание компонент
295+
296+*Основная статья: [[How To Write Lazarus Component/ru|How To Write Lazarus Component]]*
297+
298+Вы можете создавать новые компоненты через редактор пакетов.
299+
300+Создайте или откройте пакет, нажмите **add**(добавить), нажмите **New Component** (Новый компонент), заполните пункты: Ancestor Type(Тип предка) = TButton, New class name (Имя нового класса) = TMyButton, palette page (страница палитры) = Misc, Unit file name (имя файла модуля) = mybutton.pas (этот файл будет создан), имя модуля MyButton, и нажмите кнопку **ok**.
301+
302+### Предоставление новому компоненту иконки для палитры компонентов
303+
304+Создайте файл изображения в формате .bmp, .xpm или .png с тем же именем, что и класс компонента. Например, *tmybutton.png* и сохраните его в исходном каталоге пакета. Изображение может быть создано любой графической программой (например, GIMP \[или IncScape\]) и должно быть не больше 24x24 пикселей. Затем преобразуйте изображение в файл ресурсов с помощью инструмента lazres, который можно найти в каталоге lazarus/tools:
305+
306+``` bash
307+~/lazarus/tools/lazres mybutton.lrs tmybutton.png
308+```
309+
310+> **Note:** Лаззарус trunk/1.4+? использует файлы ресурсов .res взамен .lrs-файлов
311+
312+``` bash
313+~/lazarus/tools/lazres mybutton.res tmybutton.png
314+```
315+
316+Это создаст include-файл паскаля, который используется в разделе initialization mybutton.pas:
317+
318+``` pascal
319+initialization
320+ {$I mybutton.lrs}
321+ // или в более новой версии Lazarus - синтаксис docheck
322+ {$R mybutton.res}
323+```
324+
325+Установите пакет.
326+
327+### Скрытие компонента в палитре компонентов
328+
329+Пакет IDEIntf, модуль componentreg:
330+
331+`IDEComponentPalette.FindComponent('TButton').Visible:=false;`
332+
333+## Написание редактора компонента
334+
335+Редактор компонента обрабатывает такие вещи, как двойной щелчок по компоненту в конструкторе или добавление пунктов меню при щелчке правой кнопкой мыши по компоненту. Написать редактор компонентов легко. Посмотрите модуль componententeditors.pas пакета IDEIntf для \[просмотра\] кучи примеров. Например, чтобы показать редактор при двойном щелчке, см. TCheckListBoxComponentEditor.
336+
337+## Написание редакторов свойств
338+
339+Каждый тип свойства (integer, string, TFont, ...) в Инспекторе объектов нуждается в редакторе свойств. Если у вашего компонента есть свойство *Password* типа string, вы можете определить редактор свойств для вашего конкретного класса компонента со именем свойства *Password* типа string. Модуль propedits.pp пакета IDEIntf содержит многие стандартные редакторы свойств, используемые самой IDE. Например, TStringPropertyEditor является редактором свойств по умолчанию для всех строк, в то время как TComponentNamePropertyEditor является более конкретным и обрабатывает только TComponent.Name. Смотрите \[исходный код\] модуля для \[получения\] множества примеров.
340+
341+### Сокрытие свойства в инспекторе объектов
342+
343+Существует специальный редактор свойств для сокрытия \[свойств\]:
344+
345+``` pascal
346+ RegisterPropertyEditor(TypeInfo(TAnchorSide), TControl, 'AnchorSideLeft', THiddenPropertyEditor);
347+```
348+
349+### Поиск редактора свойств, используемого для свойства
350+
351+``` pascal
352+uses Classes, TypInfo;
353+var
354+ Instance: TPersistent; // ваш экземпляр
355+ PropInfo: PPropInfo;
356+ EdClass: TPropertyEditorClass;
357+begin
358+ PropInfo:=GetPropInfo(Instance.ClassType,'Name'); // замените Name именем свойства, которое вы ищете
359+ GetEditorClass(PropInfo, Instance);
360+end;
361+```
362+
363+# Формы
364+
365+IDE позволяет легко создавать потомков форм и фреймов. Эти формы могут иметь новые published-компоненты и новые published-методы. Но, когда вы добавляете новые published-свойства, они не доступны через инспектор объектов. Они работают только во время выполнения \[приложения\]. Методы в IDE являются поддельными, они не могут быть выполнены. В среде IDE можно создавать компоненты, поскольку их классы зарегистрированы в палитре компонентов. Ваши новые свойства существуют только в вашем исходном коде. IDE пока не может их подделать. Вот почему вы должны зарегистрировать новый класс. Это означает \[, что вы должны\]:
366+
367+- Создать пакет времени разработки (или расширить существующий)
368+- Ваша форма должна быть в модуле этого пакета
369+
370+``` pascal
371+...
372+interface
373+
374+uses FormEditingIntf, Forms;
375+
376+type
377+ TYourForm = class(TForm)
378+ private
379+ FYourProperty: integer;
380+ published
381+ property YourProperty: integer read FYourProperty write FYourProperty;
382+ end;
383+
384+procedure Register;
385+
386+implementation
387+
388+procedure Register;
389+begin
390+ FormEditingHook.RegisterDesignerBaseClass(TYourForm);
391+end;
392+...
393+```
394+
395+- Проверить \[наличие процедуры\] "Register" в редакторе пакетов для этого модуля.
396+- Установить пакет в IDE
397+
398+# Дизайнер
399+
400+## Написание дизайнера-посредника
401+
402+Стандартный конструктор позволяет визуально редактировать элементы управления LCL, тогда как все остальные отображаются в виде значков (например, TOpenDialog или TDataSource). Чтобы визуально редактировать элемент управления не \[из библиотеки\] LCL, вам нужно создать **designer mediator** (дизайнер-посредник). Он может быть использован для разработки веб-страниц, диаграмм UML или других наборов виджетов, таких как [[fpGUI]]. Полный пример приведен в examples/designnonlcl/.
403+
404+- Установите пакет с примерами examples/designnonlcl/notlcldesigner.lpk и перезапустите IDE. Это зарегистрирует дизайнер-посредник для компонентов TMyWidget и добавит новые компоненты TMyButton, TMyGroupBox в палитру компонентов.
405+- Откройте проект с примерами examples/designnonlcl/project/NonLCL1.lpi.
406+- Откройте unit1.pas и покажите дизайнер форм (F12). Вы должны увидеть компоненты в виде красных прямоугольников, которые можно выделять, перемещать и изменять их размер, как элементы управления LCL.
407+
408+## Создание нового уникального имени компонента
409+
410+``` pascal
411+uses FormEditingIntf;
412+
413+...
414+
415+NewName:=FormEditingHook.CreateUniqueComponentName(AComponent);
416+
417+// Или, если вам нужно создать имя перед созданием компонента:
418+
419+NewName:=FormEditingHook.CreateUniqueComponentName(ComponentClassName,OwnerComponent);
420+// ComponentClassName будет использоваться в качестве префикса без начального T.
421+// OwnerComponent является новым владельцем нового компонента.
422+```
423+
424+## Выбор компонента в конструкторе/инспекторе объектов
425+
426+``` pascal
427+uses propedits;
428+..
429+GlobalDesignHook.SelectOnlyThis(AComponent);
430+```
431+
432+## Получение файла модуля, дизайнера формы
433+
434+``` pascal
435+uses ProjectIntf, LazIDEIntf, ComponentEditors;
436+...
437+// открываем файл
438+if LazarusIDE.DoOpenEditorFile(Filename,-1,-1,[ofAddToRecent])<>mrOk then exit;
439+// получаем интерфейс файла
440+aFile:=LazarusIDE.ActiveProject.FindFile(Filename,[]);
441+// получаем дизайнер
442+aDesigner:=TComponentEditorDesigner(LazarusIDE.GetDesignerWithProjectFile(AFile,true));
443+if aDesigner=nil then
444+ exit; // этот модуль не имеет ресурса (форма, фрейм, модуль данных и т.д.)
445+// получаем форму
446+aForm:=aDesigner.Form;
447+```
448+
449+## Сохранение модуля, дизайнера формы
450+
451+``` pascal
452+uses LazIDEIntf;
453+...
454+if LazarusIDE.DoSaveEditorFile(Filename,[])<>mrOk then exit;
455+```
456+
457+## Сохранение формы дизайнера как кода Паскаль
458+
459+- Используйте функцию **FormEditingHook.SaveComponentAsPascal** модуля *FormEditingfIntf*. См. *examples/pascalstream/CopyAsPasPkg/copyaspasdemounit1.pas*.
460+
461+# Обработчики событий
462+
463+В IDE есть несколько событий, для которых плагины могут добавлять свои собственные обработчики.
464+
465+## События дизайнера
466+
467+В propedits.pp есть объект "GlobalDesignHook", который поддерживает несколько событий для проектирования. Каждое событие вызывает список обработчиков. Обработчики по умолчанию добавляются в среду IDE. Вы можете добавить свои собственные обработчики с помощью методов AddHandlerXXX и RemoveHandlerXXX. Они будут вызваны перед обработчиками по умолчанию.
468+
469+Примеры:
470+
471+- Добавление вашего обработчика (это обычно делается в конструкторе вашего объекта):
472+
473+` GlobalDesignHook.AddHandlerPersistentAdded(@YourOnPersistentAdded);`
474+
475+- Удаление вашего обработчика:
476+
477+` GlobalDesignHook.RemoveHandlerPersistentAdded(@YourOnPersistentAdded);`
478+
479+- Вы можете удалить все обработчики одновременно. Например, это хорошая идея - добавить эту строку в деструктор вашего объекта:
480+
481+` GlobalDesignHook.RemoveAllHandlersForObject(Self);`
482+
483+Обработчики GlobalDesignHook:
484+
485+- Поиск корня
486+ - ChangeLookupRoot - Вызывается при изменении "LookupRoot". "LookupRoot" является объектом-владельцем выбранных компонентов. Обычно это TForm.
487+- Методы
488+ - CreateMethod
489+ - GetMethodName
490+ - GetMethods
491+ - MethodExists
492+ - RenameMethod
493+ - ShowMethod
494+ - MethodFromAncestor
495+ - ChainCall
496+- Компоненты
497+ - GetComponent
498+ - GetComponentName
499+ - GetComponentNames
500+ - GetRootClassName
501+ - AddClicked - Вызывается, когда пользователь выбирает класс компонента и щелкает дизайнер, чтобы добавить новый компонент. Вы можете изменить класс компонента и родительский элемент.
502+ - ComponentRenamed - Вызывается, когда компонент был переименован
503+- Объекты TPersistent
504+ - PersistentAdded - Вызывается при добавлении нового TPersistent в LookupRoot
505+ - PersistentDeleting - Вызывается до освобождения TPersistent.
506+ - DeletePersistent - Вызывается IDE для удаления TPersistent.
507+ - GetSelectedPersistents - Вызывается при получении текущего выбора TPersistent.
508+ - SetSelectedPersistents - Вызывается при настройке текущего выбора TPersistent.
509+ - GetObject
510+ - GetObjectName
511+ - GetObjectNames
512+- Изменение
513+ - Modified
514+ - Revert
515+ - RefreshPropertyValues
516+- Выбор
517+ - SetSelection
518+ - GetSelection
519+
520+### Примеры для событий дизайнера
521+
522+#### Пример: когда \[на родителя\] помещается новый компонент, перемещать элемент управления в дочерний элемент
523+
524+``` pascal
525+...
526+type
527+ TYourDesignerExtension = class
528+ private
529+ function AddClicked(ADesigner: TIDesigner;
530+ MouseDownComponent: TComponent; Button: TMouseButton;
531+ Shift: TShiftState; X, Y: Integer;
532+ var AComponentClass: TComponentClass;
533+ var NewParent: TComponent): boolean of object;
534+ public
535+ constructor Create;
536+ destructor Destroy; override;
537+ end;
538+
539+...
540+constructor TYourDesignerExtension.Create;
541+begin
542+ // регистрация вашего обработчика
543+ GlobalDesignHook.AddHandlerAddClicked(@AddClicked);
544+end;
545+
546+destructor TYourDesignerExtension.Destroy;
547+begin
548+ // удаление вашего обработчика
549+ GlobalDesignHook.RemoveHandlerAddClicked(@AddClicked);
550+end;
551+
552+function TYourDesignerExtension.AddClicked(ADesigner: TIDesigner;
553+ MouseDownComponent: TComponent; Button: TMouseButton;
554+ Shift: TShiftState; X, Y: Integer;
555+ var AComponentClass: TComponentClass;
556+ var NewParent: TComponent): boolean of object;
557+begin
558+ // в этом примере TYourControl - это пользовательский элемент управления с ChildControl.
559+ // Всякий раз, когда пользователь помещает элемент управления на TYourControl, вместо добавления
560+  // нового элемента управления на TYourControl, [этот] новый элемент управления добавляется как дочерний элемент
561+  // [имеющегося] ChildControl.
562+ // создание
563+ if MouseDownComponent is TYourControl then
564+ NewParent:=TYourControl(MouseDownComponent).ChildControl;
565+ Result:=true;
566+end;
567+```
568+
569+### Отключение обработчика мыши в \[режиме\] дизайнера
570+
571+Обычно дизайнер ловит все события мыши компонента. Если ваш пользовательский элемент управления должен обрабатывать дескриптор событий мыши, вы можете либо установить **csDesignInteractive** **ControlStyle**, либо вы можете точно управлять им через сообщение *CM_DESIGNHITTEST* в вашем элементе управления:
572+
573+``` pascal
574+type
575+ TYourControl = class(TCustomControl)
576+ protected
577+ procedure CMDesignHitTest(var Message: TLMessage); message CM_DESIGNHITTEST;
578+ end;
579+...
580+procedure TYourControl.CMDesignHitTest(var Message: TLMessage);
581+var
582+ p: TSmallPoint;
583+ aShiftState: TShiftState;
584+begin
585+ aShiftState:=KeysToShiftState(PtrUInt(Message.WParam));
586+ p:=TSmallPoint(longint(Message.LParam));
587+ debugln(['TForm1.CMDesignHitTest ShiftState=',dbgs(aShiftState),' x=',p.x,' y=',p.y]);
588+ if SkipDesignerMouseHandler then
589+ Message.Result:=1; // теперь дизайнер вызывает обычные методы MouseUp, MouseMove и MouseDown.
590+end;
591+```
592+
593+## Получение уведомлений при изменении дизайнера форм
594+
595+Каждая разработанная форма LCL имеет конструктор типа TIDesigner. В среде IDE создаются конструкторы типа TComponentEditorDesigner, определенные в компонентных компонентах модуля IDEIntf. Например:
596+
597+``` pascal
598+procedure TYourAddOn.OnDesignerModified(Sender: TObject);
599+var
600+ IDEDesigner: TComponentEditorDesigner;
601+begin
602+ IDEDesigner:=TComponentEditorDesigner(Sender);
603+ ...
604+end;
605+
606+procedure TYourAddOn.ConnectDesignerForm(Form1: TCustomForm);
607+var
608+ IDEDesigner: TComponentEditorDesigner;
609+begin
610+ IDEDesigner:=TComponentEditorDesigner(Form1.Designer);
611+ IDEDesigner.AddHandlerModified(@OnDesignerModified);
612+end;
613+```
614+
615+## События проекта
616+
617+Эти события определены в модуле LazIDEIntf.
618+
619+- **LazarusIDE.AddHandlerOnProjectClose**: вызывается перед закрытием проекта
620+- **LazarusIDE.AddHandlerOnProjectOpened**: вызывается после полного открытия проекта (например, все необходимые пакеты были загружены, модули были открыты в редакторе исходного кода)
621+- **LazarusIDE.AddHandlerOnSavingAll**: вызывается перед тем, как IDE сохраняет все
622+- **LazarusIDE.AddHandlerOnSavedAll**: вызывается после того, как IDE сохранил все
623+- **LazarusIDE.AddHandlerOnProjectBuilding**: вызывается перед тем, как IDE создаст проект
624+- **LazarusIDE.AddHandlerOnProjectDependenciesCompiling**: вызывается перед тем, как IDE компилирует пакетные зависимости проекта
625+- **LazarusIDE.AddHandlerOnProjectDependenciesCompiled**: вызывается после компиляции зависимостей пакета IDE проекта
626+- **LazarusIDE.AddHandlerOnProjectBuildingFinished**: вызывается после того, как IDE собрал проект (успешно или нет) (начиная с 1.5)
627+
628+## Другие события IDE
629+
630+**uses** *LazIDEIntf;*
631+
632+Вызовите их в процедуре регистрации вашего пакета:
633+
634+- **LazarusIDE.AddHandlerOnIDERestoreWindows**: вызывается, когда IDE восстанавливает свои окна (перед открытием первого проекта)
635+- **LazarusIDE.AddHandlerOnIDEClose**: вызывается, когда IDE закрывается (после запроса закрытия, поэтому больше нет интерактивности)
636+- **LazarusIDE.AddHandlerOnQuickSyntaxCheck**: вызывается при выполнении пункта меню или ярлыка для быстрой проверки синтаксиса
637+- **LazarusIDE.AddHandlerOnLazarusBuilding**: вызывается перед тем, как IDE собирает Lazarus IDE (начиная с 1.5)
638+- **LazarusIDE.AddHandlerOnLazarusBuildingFinished**: вызывается после того, как IDE собирает Lazarus IDE (начиная с 1.5)
639+- **LazarusIDE.AddHandlerGetFPCFrontEndParams**: вызывается, когда IDE получает параметры клиентского инструмента интерфейса 'fpc' (начиная с 1.5)
640+- **LazarusIDE.AddHandlerGetFPCFrontEndPath**: вызывается, когда IDE получает параметры клиентского инструмента интерфейса 'fpc' (начиная с 1.5)
641+- **LazarusIDE.AddHandlerOnUpdateIDEComponentPalette**: ?
642+- **LazarusIDE.AddHandlerOnUpdateComponentPageControl**: ?
643+- **LazarusIDE.AddHandlerOnShowDesignerFormOfSource**: вызывается после показа конструктора формы для редактора кода (AEditor может быть nil!) (начиная с 1.5)
644+- **LazarusIDE.AddHandlerOnShowSourceOfActiveDesignerForm**: вызывается после показа кода формы дизайнера (начиная с 1.5)
645+- **LazarusIDE.AddHandlerOnChangeToolStatus**: вызывается, когда IDEToolStatus изменяется (например, itNone-\> itBuilder и т. д.) (начиная с 1.5)
646+
647+Вызовите их в разделе инициализации одного из модулей:
648+
649+- **AddBootHandler**
650+ - AddBootHandler(**libhTransferMacrosCreated**,@YourProc): вызывается после создания IDEMacros (начиная с версии 1.3)
651+ - AddBootHandler(**libhEnvironmentOptionsLoaded**,@YourProc): вызывается после загрузки параметров среды (начиная с версии 1.3)
652+
653+# Проект
654+
655+## Текущий проект
656+
657+Текущий основной проект может быть получен \[при помощи\] LazarusIDE.ActiveProject. (модуль LazIDEIntf)
658+
659+## Все модули текущего проекта
660+
661+Обратите внимание, что термин «юниты проекта» неоднозначен.
662+
663+- Инспектор проектов показывает список файлов .lpi. Проект может не использовать все эти модули на всех платформах, и, возможно, разработчик забыл добавить все используемые модули.
664+- Модули из использованных пакетов не являются модулями проекта.
665+
666+### Все модули инспектора проекта
667+
668+Чтобы перебрать все паскалевские модули, перечисленные в инспекторе проектов, вы можете использовать, например:
669+
670+``` pascal
671+uses
672+ LCLProc, FileUtil, LazIDEIntf, ProjectIntf;
673+
674+procedure ListProjectUnits;
675+var
676+ LazProject: TLazProject;
677+ i: Integer;
678+ LazFile: TLazProjectFile;
679+begin
680+ LazProject:=LazarusIDE.ActiveProject;
681+ if LazProject<>nil then
682+ for i:=0 to LazProject.FileCount-1 do
683+ begin
684+ LazFile:=LazProject.Files[i];
685+ if LazFile.IsPartOfProject
686+ and FilenameIsPascalUnit(LazFile.Filename)
687+ then
688+ debugln(LazFile.Filename);
689+ end;
690+end;
691+```
692+
693+### Все используемые модули проекта
694+
695+Чтобы найти все используемые в настоящее время модули проекта/пакета, вы можете использовать следующее. Обратите внимание, что в среде IDE необходимо проанализировать все модули, поэтому это может занять некоторое время.
696+
697+``` pascal
698+uses
699+ LazLoggerBase, LazIDEIntf, ProjectIntf;
700+
701+procedure ListProjectUnits;
702+var
703+ LazProject: TLazProject;
704+ i: Integer;
705+begin
706+ LazProject:=LazarusIDE.ActiveProject;
707+ if LazProject<>nil then
708+ begin
709+ Units:=LazarusIDE.FindUnitsOfOwner(LazProject,[fuooListed,fuooUsed]); // добавьте fuooPackages, чтобы включить модули из пакетов
710+ try
711+ for i:=0 to Units.Count-1 do
712+ debugln('Filename=',Units[i]);
713+ finally
714+ Units.Free;
715+ end;
716+ end;
717+end;
718+```
719+
720+## Файлы .lpr, .lpi и .lps проекта
721+
722+``` pascal
723+uses
724+ LCLProc, FileUtil, ProjectIntf, LazIDEIntf;
725+var
726+ LazProject: TLazProject;
727+begin
728+ LazProject:=LazarusIDE.ActiveProject;
729+ // у каждого проекта есть файл .lpi:
730+ DebugLn(['Файл проекта lpi: ',LazProject.ProjectInfoFile]);
731+
732+ // если информация о сеансе проекта хранится в отдельном файле .lps:
733+ if LazProject.SessionStorage<>pssNone then
734+ DebugLn(['Файл проекта lps: ',LazProject.ProjectSessionFile]);
735+
736+ // Если у проекта есть файл .lpr, то он является основным исходным файлом:
737+ if (LazProject.MainFile<>nil)
738+ and (CompareFileExt(LazProject.MainFile.Filename,'lpr')=0) then
739+ DebugLn(['Проект имеет файл lpr: ',LazProject.MainFile.Filename]);
740+end;
741+```
742+
743+## Имя исполняемого / целевого файла проекта
744+
745+Существует макрос \$(TargetFile), который можно использовать в путях и внешних инструментах. Вы можете запросить макрос в коде:
746+
747+``` pascal
748+uses MacroIntf;
749+
750+function MyGetProjectTargetFile: string;
751+begin
752+ Result:='$(TargetFile)';
753+ if not IDEMacros.SubstituteMacros(Result) then
754+ raise Exception.Create('невозможно получить целевой файл проекта');
755+end;
756+```
757+
758+См. здесь для более полной информации по макросам: [[IDE Macros in paths and filenames/ru|Макросы IDE в путях и именах файлов]].
759+
760+## Добавление своего собственного типа проекта
761+
762+Вы можете добавлять \[свои\] пункты в диалоговое окно 'New ...':
763+
764+- Смотрите модуль ProjectIntf пакета IDEIntf.
765+- См. [[Project Templates/ru|Шаблоны проекта]]
766+
767+## Добавление своих собственных типов файлов
768+
769+Вы можете добавлять \[свои\] пункты в диалоговое окно 'New ...':
770+
771+- Смотрите модуль ProjectIntf пакета IDEIntf.
772+- Выбрав базовый класс TFileDescPascalUnit для обычных модулей или TFileDescPascalUnitWithResource для новой формы/модуля данных.
773+
774+### Добавление нового типа файла
775+
776+``` pascal
777+uses ProjectIntf;
778+...
779+ { TFileDescText }
780+
781+ TFileDescMyText = class(TProjectFileDescriptor)
782+ public
783+ constructor Create; override;
784+ function GetLocalizedName: string; override;
785+ function GetLocalizedDescription: string; override;
786+ end;
787+...
788+
789+procedure Register;
790+
791+implementation
792+
793+procedure Register;
794+begin
795+ RegisterProjectFileDescriptor(TFileDescMyText.Create,FileDescGroupName);
796+end;
797+
798+{ TFileDescMyText }
799+
800+constructor TFileDescMyText.Create;
801+begin
802+ inherited Create;
803+ Name:='MyText'; // не переводите эту [строку]
804+ DefaultFilename:='text.txt';
805+ AddToProject:=false;
806+end;
807+
808+function TFileDescText.GetLocalizedName: string;
809+begin
810+ Result:='My Text'; // замените это строкой из resourcestring
811+end;
812+
813+function TFileDescText.GetLocalizedDescription: string;
814+begin
815+ Result:='Пустой текстовый файл';
816+end;
817+```
818+
819+### Добавление нового типа формы
820+
821+``` pascal
822+uses ProjectIntf;
823+
824+...
825+ TFileDescPascalUnitWithMyForm = class(TFileDescPascalUnitWithResource)
826+ public
827+ constructor Create; override;
828+ function GetInterfaceUsesSection: string; override;
829+ function GetLocalizedName: string; override;
830+ function GetLocalizedDescription: string; override;
831+ end;
832+...
833+
834+procedure Register;
835+
836+implementation
837+
838+procedure Register;
839+begin
840+ RegisterProjectFileDescriptor(TFileDescPascalUnitWithMyForm.Create,FileDescGroupName);
841+end;
842+
843+{ TFileDescPascalUnitWithMyForm }
844+
845+constructor TFileDescPascalUnitWithMyForm.Create;
846+begin
847+ inherited Create;
848+ Name:='MyForm'; // не переводите эту [строку]
849+ ResourceClass:=TMyForm;
850+ UseCreateFormStatements:=true;
851+end;
852+
853+function TFileDescPascalUnitWithMyForm.GetInterfaceUsesSection: string;
854+begin
855+ Result:='Classes, SysUtils, MyWidgetSet';
856+end;
857+
858+function TFileDescPascalUnitWithForm.GetLocalizedName: string;
859+begin
860+ Result:='MyForm'; // замените это строкой из resourcestring
861+end;
862+
863+function TFileDescPascalUnitWithForm.GetLocalizedDescription: string;
864+begin
865+ Result:='Создать новую MyForm из примера пакета NotLCLDesigner';
866+end;
867+```
868+
869+## Сохранение пользовательских значений в \[файлах\] lpi/lps
870+
871+Вы можете хранить свои собственные данные с помощью пар имя/значение в CustomData и CustomSessionData.
872+
873+`LazarusIDE.ActiveProject.CustomData['Name']:=Value; // хранится в lpi - x-platform, общие данные`\
874+`LazarusIDE.ActiveProject.CustomSessionData['Name']:=Value; // хранится в lpi - x-platform, общие данные`
875+
876+# Пакеты
877+
878+Вы можете выполнять различные действия с [[Lazarus Packages/ru|пакетами]]:
879+
880+## Поиск во всех пакетах
881+
882+Переберите все пакеты, загруженные в IDE (начиная с 0.9.29).
883+
884+``` pascal
885+uses PackageIntf;
886+...
887+for i:=0 to PackageEditingInterface.GetPackageCount-1 do
888+ writeln(PackageEditingInterface.GetPackages(i).Name);
889+```
890+
891+## Поиск в пакетах с \[определенным\] именем
892+
893+``` pascal
894+uses PackageIntf;
895+...
896+var
897+ Pkg: TIDEPackage;
898+begin
899+ Pkg:=PackageEditingInterface.FindPackageWithName('LCL');
900+ if Pkg<>nil then
901+ ...
902+end;
903+```
904+
905+> **Note:** FindPackageWithName не открывает редактор пакетов. Для этого используйте DoOpenPackageWithName.
906+
907+## Получение имени файла lpk установленного пакета
908+
909+``` pascal
910+uses PackageIntf;
911+...
912+var
913+ Pkg: TIDEPackage;
914+begin
915+ Pkg:=PackageEditingInterface.FindPackageWithName('LCL');
916+ if Pkg<>nil then
917+ LPKFilename:=Pkg.Filename;
918+end;
919+```
920+
921+## Установка пакетов
922+
923+> **Note:** Устанавливайте только пакеты с плагинами IDE. Установка других пакетов может привести к нестабильной работе среды IDE.
924+
925+``` pascal
926+uses PackageIntf, contnrs;
927+...
928+ PkgList:=TObjectList.create(true);
929+ try
930+ Pkg:=TLazPackageID.Create;
931+ Pkg.Name:='Cody';
932+ PkgList.Add(Pkg);
933+ // проверьте, может ли IDE найти cody.lpk и все зависимости
934+ // Среда IDE покажет некоторые предупреждения/подтверждения, если что-то выглядит странно.
935+ if not PackageEditingInterface.CheckInstallPackageList(PkgList,[]) then
936+ exit;
937+ // в этом примере мы [это] уже проверили, поэтому пропустите предупреждения
938+ // и пересоберите IDE
939+ if PackageEditingInterface.InstallPackages(PkgList,[piiifSkipChecks,piiifRebuildIDE])<>mrOK then
940+ exit;
941+ finally
942+ PkgList.Free;
943+ end;
944+```
945+
946+## Открытие файла пакета (lpk)
947+
948+``` pascal
949+uses PackageIntf, FileUtil;
950+...
951+var
952+ pkg: TIDEPackage;
953+begin
954+ if PackageEditingInterface.DoOpenPackageFile(LPKFilename,[pofAddToRecent],false)<>mrOk then
955+ exit;
956+ Pkg:=PackageEditingInterface.FindPackageWithName(ExtractFilenameOnly(LPKFilename));
957+ ...
958+end;
959+```
960+
961+> **Warning:** Среда IDE автоматически закрывает неиспользуемые пакеты в режиме ожидания. Никогда не храните ссылку на TIDEPackage.
962+
963+## Поиск пакета(-ов) модуля
964+
965+У вас есть имя файла модуля, например '/home/user/unit.pas', и \[если\] вы хотите знать, какому пакету(-ам) и проекту(-ам) он принадлежит, используйте это:
966+
967+``` pascal
968+uses Classes, PackageIntf, ProjectIntf;
969+...
970+var
971+ Owners: TFPList;
972+ i: Integer;
973+ o: TObject;
974+begin
975+ Owners:=PackageEditingInterface.GetPossibleOwnersOfUnit('/full/path/of/unit.pas',[]);
976+ if Owners=nil then begin
977+ // модуль не связан напрямую с проектом/пакетом
978+ // возможно модуль был по какой-то причине не добавлен, но доступен
979+ // поиск по всем путям модулей всех проектов/пакетов
980+ // Осторожно: это может привести к ложным попаданиям
981+ Owners:=PackageEditingInterface.GetPossibleOwnersOfUnit('/full/path/of/unit.pas',
982+ [piosfExcludeOwned,piosfIncludeSourceDirectories]);
983+ end;
984+ if Owners=nil then exit;
985+ try
986+ for i:=0 to Owners.Count-1 do begin
987+ o:=TObject(Owners[i]);
988+ if o is TIDEPackage then begin
989+ writeln('Owner is package ',TIDEPackage(o).Name);
990+ end else if o is TLazProject then begin
991+ writeln('Owner is project ',TLazProject(o).ProjectInfoFile);
992+ end;
993+ end;
994+ finally
995+ Owners.Free;
996+ end;
997+```
998+
999+# Окна
1000+
1001+Есть четыре основных типа окон IDE.
1002+
1003+- основная панель IDE - это Application.MainForm. Оно всегда присутствует.
1004+- плавающие / закрепляемые окна, такие как Редактор исходного кода, Инспекторы объектов и Сообщения.
1005+- модальные формы, такие как диалог поиска, диалоги настроек и вопросы.
1006+- подсказки и заполнение форм
1007+
1008+## Добавление нового закрепляемого окна IDE
1009+
1010+Что такое закрепляемое окно IDE: Окна, такие как Редактор исходного кода или Инспектор объектов, являются плавающими окнами, которые можно закрепить, если установлен пакет закрепления, а его состояние, положение и размер сохраняются и восстанавливаются при следующем запуске IDE. Для восстановления окна IDE нужен создатель, как определено в модуле **IDEWindowIntf** пакета IDEIntf. Каждое закрепляемое окно должно иметь уникальное имя. Не используйте общие имена, такие как 'FileBrowser', потому что это будет легко конфликтовать с другими пакетами. И не используйте короткие имена, такие как 'XYZ', потому что создатель отвечает за все формы, начинающиеся с этого имени.
1011+
1012+### Как зарегистрировать закрепляемое окно IDE
1013+
1014+Не забудьте выбрать длинное уникальное имя, которое является действительным идентификатором Паскаля. Ваше окно может иметь любой заголовок, который вы хотите.
1015+
1016+``` pascal
1017+uses SysUtils, IDEWindowIntf;
1018+...
1019+var MyIDEWindow: TMyIDEWindow = nil;
1020+
1021+procedure CreateMyIDEWindow(Sender: TObject; aFormName: string; var AForm: TCustomForm; DoDisableAutoSizing: boolean);
1022+begin
1023+ // проверяем имя
1024+ if CompareText(aFormName,MyIDEWindowName)<>0 then exit;
1025+ // создаем форму, если это еще не сделано, и отключаем автомасштабирование
1026+ IDEWindowCreators.CreateForm(MyIDEWindow,TMyIDEWindowm,DoDisableAutosizing,Application);
1027+ ... инициируем окно ...
1028+ AForm:=MyIDEWindow;
1029+end;
1030+
1031+procedure Register;
1032+begin
1033+ IDEWindowCreators.Add('MyIDEWindow',@CreateMyIDEWindow,nil,'100','50%','+300','+20%');
1034+ // стандартная граница формы - это:
1035+ // Left=100, Top=50% от [величины] Screen.Height, Width=300, Height=20% от [величины] Screen.Height
1036+ // когда IDE требуется экземпляр этого окна, она вызывает процедуру CreateMyIDEWindow.
1037+end;
1038+```
1039+
1040+### Отображение окна IDE
1041+
1042+> **Warning:** Не используйте \[процедуру\] Show.
1043+
1044+`Используйте:`
1045+
1046+``` pascal
1047+IDEWindowCreators.ShowForm(MyIDEWindow,false);
1048+```
1049+
1050+Это будет работать с \[механизмом\] пристыковки. Система пристыковки может обернуть форму в стыковочный узел. Параметр BringToFront указывает системе закрепления сделать форму и все ее родительские сайты видимыми и вывести сайт верхнего уровня вперед.
1051+
1052+### Заметки о IDEWindowCreators и SimpleLayoutStorage
1053+
1054+IDEWindowCreators.SimpleLayoutStorage просто хранит BoundsRect и WindowState всех форм, которые когда-то были открыты. Он используется как запасной вариант, если не установлен док-мастер. Он сохраняет состояние, даже если установлен DockMaster, поэтому, когда dockmaster удален, границы форм восстанавливаются.
1055+
1056+IDEWindowCreators используется всеми присоединяемыми формами для регистрации и отображения форм. При показе формы Создатель проверяет, установлен ли IDEDockMaster, и передает ему отображение. Если IDEDockMaster не установлен, он просто показывает форму. IDEDockMaster может использовать информацию в IDEWindowCreators для создания форм по именам и получить представление о том, где разместить форму при ее первом отображении. Для более подробной информации смотрите пакеты AnchorDockingDsgn и EasyDockMgDsgn.
1057+
1058+# CodeTools
1059+
1060+CodeTools - это пакет, предоставляющий огромное количество функций для анализа, поиска и изменения исходных текстов, а также некоторые основные функции для других языков. Вы можете использовать их также и без IDE. Рекомендуется сначала прочитать о CodeTools в целом, прежде чем использовать их в IDE: [[Codetools]].
1061+
1062+Перед вызовом любой из функций CodeTools в IDE вы должны зафиксировать текущие изменения редактора исходного кода в буферах CodeTools:
1063+
1064+``` pascal
1065+uses LazIDEIntf;
1066+...
1067+ // сохраняем изменения в редакторе исходного кода в codetools
1068+ LazarusIDE.SaveSourceEditorChangesToCodeCache(-1); // -1: фиксируем все редакторы исходного кода
1069+```
1070+
1071+## Добавление директивы ресурса в файл
1072+
1073+Это добавляет {\$R example.res} к модулю паскаля:
1074+
1075+``` pascal
1076+procedure AddResourceDirectiveToPascalSource(const Filename: string);
1077+var
1078+ ExpandedFilename: String;
1079+ CodeBuf: TCodeBuffer;
1080+begin
1081+ // убеждаемся, что имя файла обрезано [от концевых пробелов] и содержит полный путь
1082+ ExpandedFilename:=CleanAndExpandFilename(Filename);
1083+
1084+ // сохраняем изменения в редакторе исходного кода в codetools
1085+ LazarusIDE.SaveSourceEditorChangesToCodeCache(-1);
1086+
1087+ // загружаем файл
1088+ CodeBuf:=CodeToolBoss.LoadFile(ExpandedFilename,true,false);
1089+
1090+ // добавляем директиву ресурса
1091+ if not CodeToolBoss.AddResourceDirective(CodeBuf,'example.res') then
1092+ LazarusIDE.DoJumpToCodeToolBossError;
1093+end;
1094+```
1095+
1096+Codetools также предоставляет такие функции, как FindResourceDirective и RemoveDirective.
1097+
1098+## Получение путей поиска для модулей и включаемых файлов
1099+
1100+В среде IDE существует множество различных путей поиска из проектов, пакетов, каталога fpc и lazarus, и существует множество типов путей: до или после разрешения макросов, с унаследованными путями поиска или без них, как относительными или абсолютными путями. Все файлы в каталоге имеют одинаковый набор путей поиска. Вы можете получить пути поиска для каждого каталога, полностью решенного путем запроса codetools:
1101+
1102+``` pascal
1103+uses CodeToolManager;
1104+...
1105+
1106+Dir:=''; // пустой каталог для новых файлов и имеет те же настройки, что и каталог проекта
1107+
1108+// Получение путей поиска для включаемых файлов:
1109+Path:=CodeToolBoss.GetIncludePathForDirectory(Dir);
1110+
1111+// Получение путей поиска для модулей:
1112+// Этот путь поиска передается компилятору.
1113+// Он содержит выходные каталоги пакетов, но не каталоги с исходниками пакетов.
1114+Path:=CodeToolBoss.GetUnitPathForDirectory(Dir);
1115+
1116+// Могут быть дополнительные пути поиска модулей только для IDE (не передаются компилятору)
1117+Path:=CodeToolBoss.GetSrcPathForDirectory(Dir);
1118+
1119+// Полный путь поиска содержит также все исходные пути пакета для модулей:
1120+Path:=CodeToolBoss.GetCompleteSrcPathForDirectory(Dir);
1121+```
1122+
1123+# Редактор исходного кода
1124+
1125+## Активный редактор исходного кода
1126+
1127+``` pascal
1128+uses SrcEditorIntf;
1129+...
1130+Editor:=SourceEditorManagerIntf.ActiveEditor;
1131+if Editor=nil then exit;
1132+Filename:=Editor.FileName;
1133+ScreenPos:=Editor.CursorScreenXY;
1134+TextPos:=Editor.CursorTextXY;
1135+```
1136+
1137+# SynEdit
1138+
1139+## Получение настроек для TSynEdit
1140+
1141+Если у вас есть диалог с использованием TSynEdit, и вы хотите использовать тот же шрифт и настройки, которые использует редактор исходного кода:
1142+
1143+``` pascal
1144+uses SrcEditorIntf;
1145+...
1146+SourceEditorManagerIntf.GetEditorControlSettings(ASynEdit);
1147+```
1148+
1149+## Получение настроек для подсветки SynEdit
1150+
1151+Если у вас есть диалог, использующий TSynEdit с подсветкой, и вы хотите использовать те же цвета, что и для подсветки редактора исходного кода для этого языка, используйте:
1152+
1153+``` pascal
1154+uses SrcEditorIntf;
1155+...
1156+SourceEditorManagerIntf.GetHighlighterSettings(ASynHighlighter);
1157+```
1158+
1159+См. пример: TSQLStringsPropertyEditorDlg.Create in the unit [SQLStringsPropertyEditorDlg](http://svn.freepascal.org/svn/lazarus/trunk/components/sqldb/sqlstringspropertyeditordlg.pas).
1160+
1161+# Справка
1162+
1163+## Добавление справки для исходников
1164+
1165+Сначала создаем THelpDatabase:
1166+
1167+``` pascal
1168+HelpDB := TFPDocHTMLHelpDatabase(
1169+ HelpDatabases.CreateHelpDatabase('ANameOfYourChoiceForTheDatabase',
1170+ TFPDocHTMLHelpDatabase,true));
1171+HelpDB.DefaultBaseURL := 'http://your.help.org/';
1172+
1173+FPDocNode := THelpNode.CreateURL(HelpDB,
1174+ 'Package1 - A new package',
1175+ 'file://index.html');
1176+HelpDB.TOCNode := THelpNode.Create(HelpDB,FPDocNode);// один раз как оглавление TOC
1177+DirectoryItem := THelpDBISourceDirectory.Create(FPDocNode,'$(PkgDir)/lcl',
1178+ '*.pp;*.pas',false);// и один раз как обычная страница
1179+HelpDB.RegisterItem(DirectoryItem);
1180+```
1181+
1182+## Добавление строк в окно сообщений
1183+
1184+``` pascal
1185+unit IDEMsgIntf;
1186+...
1187+var Dir: String;
1188+begin
1189+ Dir:=GetCurrentDir;
1190+ IDEMessagesWindow.BeginBlock;
1191+ IDEMessagesWindow.AddMsg('unit1.pas(30,4) Error: Identifier not found "a"',Dir,0);
1192+ IDEMessagesWindow.EndBlock;
1193+end;
1194+```
1195+
1196+# Окно настроек IDE
1197+
1198+## Открытие параметров в определенном кадре
1199+
1200+``` pascal
1201+uses LazIDEIntf;
1202+...
1203+LazarusIDE.DoOpenIDEOptions(TYourIDEOptionsFrame);
1204+```
1205+
1206+# Прочее
1207+
1208+## Добавление макроса
1209+
1210+Вы можете добавить свои собственные макросы IDE:
1211+
1212+``` pascal
1213+uses MacroIntf, MacroDefIntf;
1214+
1215+procedure Register;
1216+begin
1217+ // регистрация макроса с фиксированным значением:
1218+ IDEMacros.Add(TTransferMacro.Create('MyMacro1','Value','Description',nil,[]));
1219+end;
1220+
1221+// регистрация макроса с динамическим значением требует метода объекта
1222+procedure TForm1.Init;
1223+begin
1224+ IDEMacros.Add(TTransferMacro.Create('MyMacro','Value','Description',@OnResolveMyMacro,[]));
1225+end;
1226+
1227+function TForm1.OnResolveMyMacro(const s: string; const Data: PtrInt;
1228+ var Abort: boolean): string;
1229+// s - это параметр. Например, $MyMacro(parameter)
1230+// Data - это экземпляр запроса. Может быть nil.
1231+// Если есть ошибка, установите Abort в true.
1232+// Результирующая строка может содержать макросы. Например, Result:='$(FPCVer)/$(TargetOS)';
1233+begin
1234+ Result:='MyValue';
1235+end;
1236+```
1237+
1238+## Отладка IDE
1239+
1240+- Скомпилируйте IDE как обычно, например, с помощью Tools/Build Lazarus. Убедитесь, что вы установили отладочные флаги, такие как -g или -gw2. Лучше всего использовать профиль "Debug IDE", который содержит много флагов, полезных для отладки.
1241+- Откройте проект ide\lazarus.lpi. Вы не можете напрямую скомпилировать этот проект.
1242+- Установите точки останова и пр. И запустите проект.
1243+
1244+## См. также
1245+
1246+- [[Creating IDE Help]]
1247+- [[Help protocol]]
1248+- [[How To Write Lazarus Component]]
1249+
1250+---
1251+*From the Free Pascal wiki, page "Extending the IDE/ru", as it stood on 2020-02-14 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