Sign in Join
Wiki copytemporary

Extending the IDE/zh CN: what changed

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

OldNewLine
11# 扩展 IDE
22
33## 概述
44
55Lazarus IDE 支持以下几种类型的插件:
66
77组件(Components)
88这些是“组件面板”上的项目。例如 TButton(可以在“标准”页面上找到)可用于创建按钮。
99
1010组件编辑器(Component Editors)
1111当你在“界面设计器(Designer)”中双击一个组件时(比如“TMainMenu”组件),将调用组件编辑器(比如“菜单编辑器”)。组件编辑器还可以在“界面设计器”的右键菜单中添加一个额外的菜单项(右键单击“界面设计器”中的组件时可以访问)。
1212
1313属性编辑器(Property Editors)
1414“对象查看器”的列表中的每一行都使用属性编辑器来设置或更改该属性的值。
1515
1616专家(Experts)
1717专家包含所有其他插件类型。他们可能会注册新的菜单项,注册快捷方式或扩展其他 IDE 功能。
1818
1919有两种方式可以将自己的插件添加到 Lazarus IDE:
2020
21211. 编写一个包,安装它并在包单元的“Register”过程中注册你的插件。
22222. 扩展 Lazarus 代码,并将您的 svn diff 发送到 Lazarus 邮件列表。
2323
2424## 包和 Makefile 依赖项
2525
2626如果添加新的包依赖项,则必须执行以下步骤。
2727
2828- 创建 / 通过包编辑器更新包的 MakeFile/ 更多 .../ 创建 Makefile。
2929- 修复所有依赖项。请参阅 tools/updatemakefiles.lpi
3030
3131# 菜单项
3232
3333您可以添加新菜单项,隐藏或移动现有菜单项并添加子菜单、菜单区(菜单区是整个菜单中的一块区域,它可以是一个包含子菜单的菜单项,也可以是由分隔符分隔出来的一块区域。如果菜单区中没有子项,则该菜单区将不可见。比如 itmFileNew 就是一个用分隔符分隔的菜单区,它里面包含了“新建单元”、“新建窗体”、“新建 ...” 等菜单项,itmFileRecentOpen 也是一个菜单区,它只是一个菜单项,包含“最近打开的文件”子菜单)。对于您自己的窗体,您可以注册 TMainMenu/TPopupMenu,以便其它包可以进一步扩展您的窗体。**IDEIntf** 包的 MenuIntf 单元包含菜单的所有注册函数和 IDE 本身的许多标准菜单项。
3434
3535## 添加菜单项
3636
3737像“查看 -\> 对象查看器”这样的单个菜单项称为 **TIDEMenuCommand**。您可以使用 **RegisterIDEMenuCommand** 创建一个,它有两个带有大量参数的格式:
3838
3939``` pascal
4040function RegisterIDEMenuCommand(
4141 Parent: TIDEMenuSection;
4242 const Name, Caption: string;
4343 const OnClickMethod: TNotifyEvent = nil;
4444 const OnClickProc: TNotifyProcedure = nil;
4545 const Command: TIDECommand = nil;
4646 const ResourceName: String = ''
4747 ): TIDEMenuCommand; overload;
4848
4949function RegisterIDEMenuCommand(
5050 const Path, Name, Caption: string;
5151 const OnClickMethod: TNotifyEvent = nil;
5252 const OnClickProc: TNotifyProcedure = nil;
5353 const Command: TIDECommand = nil;
5454 const ResourceName: String = ''
5555 ): TIDEMenuCommand; overload;
5656```
5757
5858这两者之间的区别仅在于指定父菜单区的方式。您可以通过 Path 参数直接或间接地给出菜单区。*MenuIntf* 单元中可以找到许多标准菜单区。例如 **mnuTools** 菜单区,它是主 IDE 栏的 *Tools* 菜单。它包含一个子菜单区 **itmSecondaryTools**,用于第三方工具的推荐菜单区。
5959
6060下面的代码注册了一个新的菜单命令,菜单名(Name)为“MyTool”,菜单标题(Caption)为“我的工具(&T)”,点击后执行 StartMyTool 过程:
6161
6262``` pascal
6363procedure StartMyTool;
6464begin
6565 ... 点击菜单项后要执行的代码 ...
6666end;
6767
6868procedure Register;
6969begin
7070 RegisterIDEMenuCommand(itmSecondaryTools, 'MyTool', ' 我的工具(&T)', nil, @StartMyTool);
7171end;
7272```
7373
7474如果要调用方法而不是过程,请使用 **OnClickMethod** 参数。
7575
7676此菜单项没有快捷键。如果需要快捷键,则必须创建一个 **TIDECommand** 对象并将其传递给 **Command** 参数。例如:
7777
7878``` pascal
7979uses
8080 ... Classes, LCLType, Dialogs, IDECommands, MenuIntf;
8181
8282...
8383
8484procedure StartMyTool(Sender :TObject);
8585begin
8686 ShowMessage('Hello World!');
8787end;
8888
8989procedure Register;
9090var
9191 Key: TIDEShortCut;
9292 Cat: TIDECommandCategory;
9393 CmdMyTool: TIDECommand;
9494begin
9595 // 注册 IDE 快捷键(Ctrl+Alt+Shift+T)和菜单项
9696 Key := IDEShortCut(VK_T,[ssCtrl,ssAlt,ssShift],VK_UNKNOWN,[]);
9797 Cat := IDECommandList.FindCategoryByName(CommandCategoryToolMenuName);
9898 CmdMyTool := RegisterIDECommand(Cat, 'StartMyTool', ' 启动我的工具 ', Key, nil, @StartMyTool);
9999 RegisterIDEMenuCommand(itmSecondaryTools, 'MyTool', ' 我的工具 (&T)', nil, nil, CmdMyTool);
100100end;
101101```
102102
103103## 快捷键
104104
105105所有快捷键都在 IDECommandList 中注册。下面是一个示例,将查找所有使用 Ctrl-D 作为快捷键的命令:
106106
107107``` pascal
108108uses
109109 Classes, SysUtils, Dialogs, LCLType, LCLProc, IDECommands, MenuIntf;
110110
111111// 列出所有使用 Ctrl-D 的 IDE 命令
112112procedure ListCtrlD;
113113var
114114 i :integer;
115115 Cmd :TIDECommand;
116116 Commands :TFPList;
117117begin
118118 Commands := IDECommandList.FindCommandsByShortCut(IDEShortCut(VK_D, [ssCtrl], VK_UNKNOWN, []));
119119 try
120120 for i := 0 to Commands.Count - 1 do
121121 begin
122122 Cmd := TIDECommand(Commands[i]);
123123 ShowMessage(format('Cmd: %s, A = %s - %d, %s - %d' + #13#10 + 'B = %s - %d, %s - %d',
124124 [Cmd.Name,
125125 dbgs(Cmd.ShortcutA.Shift1),
126126 Cmd.ShortcutA.Key1,
127127 dbgs(Cmd.ShortcutA.Shift2),
128128 Cmd.ShortcutA.Key2,
129129 dbgs(Cmd.ShortcutB.Shift1),
130130 Cmd.ShortcutB.Key1,
131131 dbgs(Cmd.ShortcutB.Shift2),
132132 Cmd.ShortcutB.Key2]));
133133 end;
134134 finally
135135 Commands.Free;
136136 end;
137137end;
138138```
139139
140140# 配置文件
141141
142142加载和保存配置
143143
144144IDE 的所有配置文件都以 xml 格式存储在一个目录中(主配置目录)。包也可以在那里添加自己的配置文件。可以使用下面的方式读取“主配置目录”:
145145
146146``` pascal
147147uses LazIDEIntf;
148148...
149149 Directory := LazarusIDE.GetPrimaryConfigPath;
150150```
151151
152152包可以创建自己的 xml 文件:
153153
154154``` pascal
155155uses
156156 ..., LCLProc, BaseIDEIntf, LazConfigStorage;
157157
158158const
159159 Version = 1;
160160var
161161 Config: TConfigStorage;
162162 SomeValue: String;
163163 SomeInteger: Integer;
164164 SomeBoolean: Boolean;
165165 FileVersion: LongInt;
166166begin
167167 SomeValue:='Default';
168168 SomeInteger:=3;
169169 SomeBoolean:=true;
170170
171171 // 保存配置
172172 try
173173 Config:=GetIDEConfigStorage('mysettings.xml',false);
174174 try
175175 // 存储版本号,以便将来的扩展可以处理旧的配置文件
176176 Config.SetDeleteValue('Path/To/The/Version',Version,0);
177177 // 存储字符串变量 “someValue”
178178 // 如果 someValue 的值和默认值相同,则不会存储该项
179179 // 因此只有与默认值不同的项才会被存储
180180 // 这样能使 XML 保持简短,并且便于在将来改变默认值。
181181 Config.SetDeleteValue('Path/To/Some/Value',SomeValue,'Default');
182182 Config.SetDeleteValue('Path/To/Some/Integer',SomeInteger,3);
183183 Config.SetDeleteValue('Path/To/Some/Boolean',SomeBoolean,true);
184184 // 还有很多 SetDeleteValue 的重载,通过 Ctrl+Space(代码提示的快捷键)查看它们。
185185 finally
186186 Config.Free;
187187 end;
188188
189189 except
190190 on E: Exception do begin
191191 DebugLn(['Saving mysettings.xml failed: ',E.Message]);
192192 end;
193193 end;
194194
195195 // 加载配置
196196 try
197197 Config:=GetIDEConfigStorage('mysettings.xml',true);
198198 try
199199 // 读取配置的版本
200200 FileVersion:=Config.GetValue('Path/To/The/Version',0);
201201 // 读取字符串变量“SomeValue”。如果该项不存在,则使用默认值。
202202 SomeValue:=Config.GetValue('Path/To/Some/Value','Default');
203203 SomeInteger:=Config.GetValue('Path/To/Some/Integer',3);
204204 SomeBoolean:=Config.GetValue('Path/To/Some/Boolean',true);
205205 finally
206206 Config.Free;
207207 end;
208208 except
209209 on E: Exception do begin
210210 DebugLn(['Loading mysettings.xml failed: ',E.Message]);
211211 end;
212212 end;
213213end;
214214```
215215
216216注意:
217217
218218- 每个 IDE 插件都应该使用自己的配置文件。特别是您不能使用标准 IDE 选项文件,如 editoroptions.xml 或 environmentoptions.xml。
219219- GetIDEConfigStorage 在加载时,会检查文件是否存在,如果不存在,它将从辅助配置目录复制模板。
220220- 从 0.9.31 开始,您可以使用此函数在主配置目录之外加载文件。
221221
222222# 组件
223223
224224## 扩展现有组件
225225
226226来源:[1](http://lazarus.freepascal.org/index.php/topic,17733.msg98425.html#msg98425) 定制现有的 LCL 组件很简单,例如,如果要添加属性。
227227
228228使用字段及其相应的 setter 和 getter 方法来添加所需的属性。
229229
230230然后“手动”实例化它们,给出一个 OWner 组件(以便处理稍后的销毁操作),并设置 Parent 和可能的 Top 和 Left 以及组件在初始化时需要的任何其他默认值。
231231
232232如果您对自定义组件的调试感到满意,请添加一个 RegisterComponent() 调用以将其加入到 IDE 的组件面板中,并保存您必须“手动”编写的设置代码(查看任一个组件的源代码以了解如何执行此操作)。
233233
234234这是一个简单的例子:
235235
236236``` pascal
237237unit Unit1;
238238
239239{$mode objfpc}{$H+}
240240
241241interface
242242
243243uses
244244 Classes, SysUtils, Forms, StdCtrls;
245245
246246type
247247 TEdX = class(TEdit)
248248 private
249249 FNewIntProp: integer;
250250 FNewStrProp: string;
251251 procedure SetNewIntProp(AValue: integer);
252252 procedure SetNewStrProp(AValue: string);
253253 public
254254 constructor Create(theComponent: TComponent); override;
255255 property NewIntProp: integer read FNewIntProp write SetNewIntProp;
256256 property NewStrProp: string read FNewStrProp write SetNewStrProp;
257257 end;
258258
259259 TForm1 = class(TForm)
260260 procedure FormCreate(Sender: TObject);
261261 private
262262 edX: TEdX;
263263 public
264264 end;
265265
266266var
267267 Form1: TForm1;
268268
269269implementation
270270
271271{ TForm1 }
272272
273273procedure TForm1.FormCreate(Sender: TObject);
274274begin
275275 edX:= TEdX.Create(Self);
276276 edX.Parent:= Self;
277277 edX.Caption:= IntToStr(edX.NewIntProp);
278278 Caption:= edX.NewStrProp;
279279end;
280280
281281{$R *.lfm}
282282
283283{ TEdX }
284284
285285procedure TEdX.SetNewIntProp(AValue: integer);
286286begin
287287 if FNewIntProp=AValue then Exit;
288288 FNewIntProp:=AValue;
289289 // 这里填写自定义代码
290290end;
291291
292292procedure TEdX.SetNewStrProp(AValue: string);
293293begin
294294 if FNewStrProp=AValue then Exit;
295295 FNewStrProp:=AValue;
296296 // 这里填写自定义代码
297297end;
298298
299299constructor TEdX.Create(theComponent: TComponent);
300300begin
301301 inherited Create(theComponent);
302302 FNewStrProp:= 'new string property value';
303303 FNewIntProp:= 99;
304304end;
305305
306306end.
307307```
308308
309309## 编写组件
310310
311311主要文章:[[How To Write Lazarus Component]]
312312
313313您可以通过包编辑器创建新组件。
314314
315315创建或打开一个包,单击“添加 -\> 新组件”,填写项目: Ancestor Type = TButton, New class name = TMyButton, palette page = Misc, Unit name = mybutton.pas(将创建此文件) , 单位名称 MyButton,然后单击确定。
316316
317317### 为组件面板提供一个新组件图标
318318
319319创建格式为 .bmp、.xpm 或 .png 的图像文件,其名称与组件类相同。例如 tmybutton.png 并将其保存在包源目录中。图像可以由任何图形程序(例如 gimp)创建,并且不应大于 24x24 像素。然后使用 lazres 工具将图像转换为资源文件,该工具可以在 lazarus/tools 目录中找到:
320320
321321``` bash
322322~/lazarus/tools/lazres mybutton.lrs tmybutton.png
323323# note: Laz trunk/1.4+? uses .res resource files instead of .lrs files:
324324~/lazarus/tools/lazres mybutton.res tmybutton.png
325325```
326326
327327这将创建一个 pascal include 文件,该文件在 mybutton.pas 的初始化部分中使用:
328328
329329``` pascal
330330initialization
331331 {$I mybutton.lrs}
332332 // 或在较新的 Lazarus 版本中 - to docheck 语法
333333 {$R mybutton.res}
334334```
335335
336336安装包。
337337
338338### 隐藏组件面板中的组件
339339
340340Package IDEIntf, unit componentreg:
341341
342342``` pascal
343343 IDEComponentPalette.FindComponent('TButton').Visible:=false;
344344```
345345
346346## 编写组件编辑器
347347
348348组件编辑器处理诸如双击设计器中的组件或右键单击组件时添加菜单项之类的操作。编写组件编辑器很简单。有关大量示例,请参阅 IDEIntf 包的 componenteditors.pas 单元。例如,双击时显示编辑器,请参阅 TCheckListBoxComponentEditor。
349349
350350## 编写属性编辑器
351351
352352“属性查看器”中的每种属性(整数、字符串、TFont、...)都需要属性编辑器。如果组件具有字符串类型的属性 Password,则可以为特定组件类定义属性编辑器,并使用字符串类型的名为 Password 的属性。在 IDEIntf 的 propedits.pp 单元中包含 IDE 本身使用的许多标准属性编辑器。例如 TStringPropertyEditor 是所有字符串的默认属性编辑器,而 TComponentNamePropertyEditor 更有针对性,它只处理 TComponent.Name。请参阅示例中的单元文件。
353353
354354### 在 Object Inspector 中隐藏属性
355355
356356有一个特殊的属性编辑器用于隐藏:
357357
358358``` pascal
359359 RegisterPropertyEditor(TypeInfo(TAnchorSide), TControl, 'AnchorSideLeft', THiddenPropertyEditor);
360360```
361361
362362### 找出属性使用的属性编辑器
363363
364364``` pascal
365365uses Classes, TypInfo;
366366var
367367 Instance: TPersistent; // 你的实例
368368 PropInfo: PPropInfo;
369369 EdClass: TPropertyEditorClass;
370370begin
371371 PropInfo:=GetPropInfo(Instance.ClassType,'Name'); // 将 Name 替换为您要搜索的属性名称
372372 GetEditorClass(PropInfo, Instance);
373373end;
374374```
375375
376376## 窗体
377377
378378IDE 允许轻松创建窗体和框架的后代。这些窗体可以包含新的 published 组件和新的 published 方法。但是,当您添加新的 published 属性时,无法通过“对象查看器”访问它们。它们仅在运行时工作。IDE 中的方法是伪造的,无法执行。IDE 可以创建组件,因为它们的类已在组件面板中注册。你的新属性仅存在于源代码中,IDE 还不能伪造它们。这就是你必须注册新类的原因。这意味着:
379379
380380- 创建设计时包(或扩展现有包)
381381- 您的窗体必须在此包的单元中
382382
383383``` pascal
384384...
385385interface
386386
387387uses FormEditingIntf, Forms;
388388
389389type
390390 TYourForm = class(TForm)
391391 private
392392 FYourProperty: integer;
393393 published
394394 property YourProperty: integer read FYourProperty write FYourProperty;
395395 end;
396396
397397procedure Register;
398398
399399implementation
400400
401401procedure Register;
402402begin
403403 FormEditingHook.RegisterDesignerBaseClass(TYourForm);
404404end;
405405...
406406```
407407
408408- 检查包编辑器中本单元的“Register”。
409409- 在 IDE 中安装包
410410
411411# 界面设计器(Designer)
412412
413413### 编写一个设计器中间层
414414
415415标准设计器允许可视化编辑 LCL 控件,而所有其它控件都显示为图标(如 TOpenDialog 或 TDataSource)。要可视地编辑非 LCL 控件,您需要创建一个 **设计器中间层**。这可用于设计网页,UML 图或其它小部件集,如 [[fpGUI]]。在 examples/designnonlcl/ 中有一个完整的例子。
416416
417417- 安装示例包 examples/designnonlcl/notlcldesigner.lpk 并重新启动 IDE。这将为 TMyWidget 组件注册设计器中间层,并将新组件 TMyButton,TMyGroupBox 添加到组件面板中。
418418- 打开示例项目 examples/designnonlcl/project/NonLCL1.lpi。
419419- 打开 unit1.pas 并切换到设计器界面(F12)。您应该看到组件为红色矩形,可以像 LCL 控件一样选择,移动和调整大小。
420420
421421## 创建一个新的唯一组件名称
422422
423423``` pascal
424424uses FormEditingIntf;
425425
426426...
427427
428428NewName:=FormEditingHook.CreateUniqueComponentName(AComponent);
429429
430430// 或者如果您需要在创建组件之前创建名称:
431431
432432NewName:=FormEditingHook.CreateUniqueComponentName(ComponentClassName,OwnerComponent);
433433// ComponentClassName 将用作前缀,没有前导 T.
434434// OwnerComponent 是新组件的新所有者。
435435```
436436
437437## 在设计器 / 对象检查器中选择一个组件
438438
439439``` pascal
440440uses propedits;
441441..
442442GlobalDesignHook.SelectOnlyThis(AComponent);
443443```
444444
445445## 获取单元,设计器,文件的形式
446446
447447``` pascal
448448uses ProjectIntf, LazIDEIntf, ComponentEditors;
449449...
450450// 打开文件
451451if LazarusIDE.DoOpenEditorFile(Filename,-1,-1,[ofAddToRecent])<>mrOk then exit;
452452// 获取文件界面
453453aFile:=LazarusIDE.ActiveProject.FindFile(Filename,[]);
454454// 获取设计器
455455aDesigner:=TComponentEditorDesigner(LazarusIDE.GetDesignerWithProjectFile(AFile,true));
456456if aDesigner=nil then
457457 exit; // 这个单元没有资源(形式,框架,数据模块等)
458458// 获取表单
459459aForm:=aDesigner.Form;
460460```
461461
462462## 保存单元,设计器窗口
463463
464464``` pascal
465465uses LazIDEIntf;
466466...
467467if LazarusIDE.DoSaveEditorFile(Filename,[])<>mrOk then exit;
468468```
469469
470470## 将设计器窗口保存为 Pascal
471471
472472- 使用 *FormEditingfIntf* 单元的 **FormEditingHook.SaveComponentAsPascal** 函数。请参阅 *examples/pascalstream/CopyAsPasPkg/copyaspasdemounit1.pas*。
473473
474474# 事件处理程序
475475
476476IDE 中有几个事件,插件可以为其添加自己的处理程序。
477477
478478## 设计器活动
479479
480480在 propedits.pp 中有一个“GlobalDesignHook”对象,它维护了几个用于设计的事件。每个事件都会调用一个处理程序列表。IDE 添加了默认处理程序。您可以使用 AddHandlerXXX 和 RemoveHandlerXXX 方法添加自己的处理程序。它们将在默认处理程序之前调用。
481481
482482例子:
483483
484484- 添加处理程序(通常在对象的构造函数中完成):
485485
486-` GlobalDesignHook.AddHandlerPersistentAdded(@YourOnPersistentAdded);`
486+```text
487+ GlobalDesignHook.AddHandlerPersistentAdded(@YourOnPersistentAdded);
488+```
487489
488490- 删除处理程序:
489491
490-` GlobalDesignHook.RemoveHandlerPersistentAdded(@YourOnPersistentAdded);`
492+```text
493+ GlobalDesignHook.RemoveHandlerPersistentAdded(@YourOnPersistentAdded);
494+```
491495
492496- 您可以一次删除所有处理程序。例如,在对象的析构函数中添加此行是个好主意:
493497
494-` GlobalDesignHook.RemoveAllHandlersForObject(Self);`
498+```text
499+ GlobalDesignHook.RemoveAllHandlersForObject(Self);
500+```
495501
496502GlobalDesignHook 的处理程序:
497503
498504- 查找根目录
499505 - ChangeLookupRoot - 当“LookupRoot”发生变化时调用。“LookupRoot”是当前所选组件的所有者对象。通常这是一个 TForm。
500506
501507- 方法
502508 - CreateMethod
503509 - GetMethodName
504510 - 的 getMethods
505511 - MethodExists
506512 - RenameMethod
507513 - ShowMethod
508514 - MethodFromAncestor
509515 - ChainCall
510516
511517- 组件
512518 - GetComponent
513519 - GetComponentName
514520 - GetComponentNames
515521 - GetRootClassName
516522 - AddClicked - 在用户选择组件类并单击设计器以添加新组件时调用。您可以更改组件类和父组件。
517523 - ComponentRenamed - 在重命名组件时调用
518524
519525- TPersistent 对象
520526 - PersistentAdded - 在将新的 TPersistent 添加到 LookupRoot 时调用
521527 - PersistentDeleting - 在释放 TPersistent 之前调用。
522528 - DeletePersistent - 由 IDE 调用以删除 TPersistent。
523529 - GetSelectedPersistents - 获取当前 TPersistent 选择时调用。
524530 - SetSelectedPersistents - 在设置 TPersistent 的当前选择时调用。
525531 - GetObject
526532 - GetObjectName
527533 - GetObjectNames
528534
529535- 修改
530536 - Modified
531537 - Revert
532538 - RefreshPropertyValues
533539
534540- 选区
535541 - SetSelection
536542 - GetSelection
537543
538544### 设计器活动的例子
539545
540546#### 示例:当放置新组件时,将新组件移动到子组件中
541547
542548``` pascal
543549...
544550type
545551 TYourDesignerExtension = class
546552 private
547553 function AddClicked(ADesigner: TIDesigner;
548554 MouseDownComponent: TComponent; Button: TMouseButton;
549555 Shift: TShiftState; X, Y: Integer;
550556 var AComponentClass: TComponentClass;
551557 var NewParent: TComponent): boolean of object;
552558 public
553559 constructor Create;
554560 destructor Destroy; override;
555561 end;
556562
557563...
558564constructor TYourDesignerExtension.Create;
559565begin
560566 // 注册你的处理程序
561567 GlobalDesignHook.AddHandlerAddClicked(@AddClicked);
562568end;
563569
564570destructor TYourDesignerExtension.Destroy;
565571begin
566572 // 删除你的处理程序
567573 GlobalDesignHook.RemoveHandlerAddClicked(@AddClicked);
568574end;
569575
570576function TYourDesignerExtension.AddClicked(ADesigner: TIDesigner;
571577 MouseDownComponent: TComponent; Button: TMouseButton;
572578 Shift: TShiftState; X, Y: Integer;
573579 var AComponentClass: TComponentClass;
574580 var NewParent: TComponent): boolean of object;
575581begin
576582 // 在此示例中,TYourControl 是一个带有 ChildControl 的自定义控件。
577583 // 每当用户删除 TYourControl 上的控件而不是将新控件添加到 TYourControl 时,新控件将被添加为 ChildControl 的子控件。
578584 // 已创建
579585 if MouseDownComponent is TYourControl then
580586 NewParent:=TYourControl(MouseDownComponent).ChildControl;
581587 Result:=true;
582588end;
583589```
584590
585591### 禁用设计器鼠标处理程序
586592
587593通常,设计人员会捕获组件的所有鼠标事件。如果您的自定义控件应该处理鼠标事件句柄,您可以设置 **csDesignInteractive** **控件样式**,也可以通过控件中的消息 CM_DESIGNHITTEST 对其进行精确控制:
588594
589595``` pascal
590596type
591597 TYourControl = class(TCustomControl)
592598 protected
593599 procedure CMDesignHitTest(var Message: TLMessage); message CM_DESIGNHITTEST;
594600 end;
595601...
596602procedure TYourControl.CMDesignHitTest(var Message: TLMessage);
597603var
598604 p: TSmallPoint;
599605 aShiftState: TShiftState;
600606begin
601607 aShiftState:=KeysToShiftState(PtrUInt(Message.WParam));
602608 p:=TSmallPoint(longint(Message.LParam));
603609 debugln(['TForm1.CMDesignHitTest ShiftState=',dbgs(aShiftState),' x=',p.x,' y=',p.y]);
604610 if SkipDesignerMouseHandler then
605611 Message.Result:=1; // 现在设计器调用了正常的 MouseUp、MouseMove 和 MouseDown 方法。
606612end;
607613```
608614
609615## 在修改设计器窗体时收到通知
610616
611617每个设计的 LCL 表格都有一个 TIDesigner 类型的设计器。IDE 将创建在 IDEIntf 单元组件中定义的 TComponentEditorDesigner 类型的设计器。例如:
612618
613619``` pascal
614620procedure TYourAddOn.OnDesignerModified(Sender: TObject);
615621var
616622 IDEDesigner: TComponentEditorDesigner;
617623begin
618624 IDEDesigner:=TComponentEditorDesigner(Sender);
619625 ...
620626end;
621627
622628procedure TYourAddOn.ConnectDesignerForm(Form1: TCustomForm);
623629var
624630 IDEDesigner: TComponentEditorDesigner;
625631begin
626632 IDEDesigner:=TComponentEditorDesigner(Form1.Designer);
627633 IDEDesigner.AddHandlerModified(@OnDesignerModified);
628634end;
629635```
630636
631637## 项目事件
632638
633639这些事件在单元 LazIDEIntf 中定义。
634640
635641- LazarusIDE.AddHandlerOnProjectClose:在项目关闭之前调用
636642- LazarusIDE.AddHandlerOnProjectOpened:在项目完全打开后调用(例如,加载了所有必需的包,在源代码编辑器中打开了单元)
637643- LazarusIDE.AddHandlerOnSavingAll:在 IDE 保存所有内容之前调用
638644- LazarusIDE.AddHandlerOnSavedAll:在 IDE 保存所有内容后调用
639645- LazarusIDE.AddHandlerOnProjectBuilding:在 IDE 构建项目之前调用
640646- LazarusIDE.AddHandlerOnProjectDependenciesCompiling:在 IDE 编译项目的包依赖项之前调用
641647- LazarusIDE.AddHandlerOnProjectDependenciesCompiled:在 IDE 编译包项目依赖项后调用
642648- LazarusIDE.AddHandlerOnProjectBuildingFinished:在 IDE 构建项目后调用(成功与否)(自 1.5 起)
643649
644650## 其他 IDE 事件
645651
646652uses LazIDEIntf;
647653
648654在包的注册过程中调用这些:
649655
650656- LazarusIDE.AddHandlerOnIDERestoreWindows:在 IDE 恢复其窗口时调用(在打开第一个项目之前)
651657- LazarusIDE.AddHandlerOnIDEClose:在 IDE 关闭时调用(在 closequery 之后调用,因此不再进行交互)
652658- LazarusIDE.AddHandlerOnQuickSyntaxCheck:执行菜单项或快速语法检查的快捷方式时调用
653659- LazarusIDE.AddHandlerOnLazarusBuilding:// 在 IDE 构建 Lazarus IDE 之前调用(从 1.5 开始)
654660- LazarusIDE.AddHandlerOnLazarusBuildingFinished:// 在 IDE 构建 Lazarus IDE 后调用(自 1.5 起)
655661- LazarusIDE.AddHandlerGetFPCFrontEndParams:// 当 IDE 获取 'fpc' 前端工具的参数时调用(自 1.5 起)
656662- LazarusIDE.AddHandlerGetFPCFrontEndPath:// 当 IDE 获取 'fpc' 前端工具的路径时调用(从 1.5 开始)
657663- LazarusIDE.AddHandlerOnUpdateIDEComponentPalette:?
658664- LazarusIDE.AddHandlerOnUpdateComponentPageControl :?
659665- LazarusIDE.AddHandlerOnShowDesignerFormOfSource:// 在显示代码编辑器的设计器表单后调用(AEditor 可以是 nil!)(自 1.5 起)
660666- LazarusIDE.AddHandlerOnShowSourceOfActiveDesignerForm:// 显示设计器表单代码后调用(自 1.5 起)
661667- LazarusIDE.AddHandlerOnChangeToolStatus:// 在 IDEToolStatus 发生变化时调用(例如 itNone-\> itBuilder 等)(自 1.5 起)
662668
663669在您的某个单元的初始化部分中调用它们:
664670
665671- AddBootHandler
666672- AddBootHandler(libhTransferMacrosCreated, @YourProc):创建 IDEMacros 后调用(自 1.3 起)
667673- AddBootHandler(libhEnvironmentOptionsLoaded, @YourProc):加载环境选项后调用(自 1.3 起)
668674
669675# 项目
670676
671677## 当前的项目
672678
673679目前的主要项目可以通过 LazarusIDE.ActiveProject 获得。(单元 LazIDEIntf)
674680
675681## 当前项目的所有单元
676682
677683请注意,术语“项目单元”是不明确的。
678684
679685- 项目检查器显示 .lpi 文件的列表。该项目可能不会在所有平台上使用所有这些单元,也许开发人员忘记添加所有使用过的单元。
680686- 使用过的包中的单元不是项目单元。
681687
682688### 项目检查员的所有单元
683689
684690要遍历项目检查器中列出的所有 pascal 单元,您可以使用例如:
685691
686692``` pascal
687693uses
688694 LCLProc, FileUtil, LazIDEIntf, ProjectIntf;
689695
690696procedure ListProjectUnits;
691697var
692698 LazProject: TLazProject;
693699 i: Integer;
694700 LazFile: TLazProjectFile;
695701begin
696702 LazProject:=LazarusIDE.ActiveProject;
697703 if LazProject<>nil then
698704 for i:=0 to LazProject.FileCount-1 do
699705 begin
700706 LazFile:=LazProject.Files[i];
701707 if LazFile.IsPartOfProject
702708 and FilenameIsPascalUnit(LazFile.Filename)
703709 then
704710 debugln(LazFile.Filename);
705711 end;
706712end;
707713```
708714
709715### 所有用过的项目单元
710716
711717要查找项目 / 包的所有当前使用单元,您可以使用以下内容。请注意,IDE 需要解析所有单元,因此可能需要一些时间。
712718
713719``` pascal
714720uses
715721 LazLoggerBase, LazIDEIntf, ProjectIntf;
716722
717723procedure ListProjectUnits;
718724var
719725 LazProject: TLazProject;
720726 i: Integer;
721727begin
722728 LazProject:=LazarusIDE.ActiveProject;
723729 if LazProject<>nil then
724730 begin
725731 Units:=LazarusIDE.FindUnitsOfOwner(LazProject,[fuooListed,fuooUsed]); // 添加 fuooPackages 以包含包中的单位
726732 try
727733 for i:=0 to Units.Count-1 do
728734 debugln('Filename=',Units[i]);
729735 finally
730736 Units.Free;
731737 end;
732738 end;
733739end;
734740```
735741
736742## 项目的 .lpr、.lpi 和 .lps 文件
737743
738744``` pascal
739745uses
740746 LCLProc, FileUtil, ProjectIntf, LazIDEIntf;
741747var
742748 LazProject: TLazProject;
743749begin
744750 LazProject:=LazarusIDE.ActiveProject;
745751 // 每个项目都有一个 .lpi 文件:
746752 DebugLn(['Project'' lpi file: ',LazProject.ProjectInfoFile]);
747753
748754 // 如果项目会话信息存储在单独的 .lps 文件中:
749755 if LazProject.SessionStorage<>pssNone then
750756 DebugLn(['Project'' lps file: ',LazProject.ProjectSessionFile]);
751757
752758 // 如果项目有 .lpr 文件,那么它是主要的源文件:
753759 if (LazProject.MainFile<>nil)
754760 and (CompareFileExt(LazProject.MainFile.Filename,'lpr')=0) then
755761 DebugLn(['Project has lpr file: ',LazProject.MainFile.Filename]);
756762end;
757763```
758764
759765## 项目的可执行文件 / 目标文件名
760766
761767有一个宏 \$(TargetFile),可用于路径和外部工具。您可以在代码中查询宏:
762768
763769``` pascal
764770uses MacroIntf;
765771
766772function MyGetProjectTargetFile: string;
767773begin
768774 Result:='$(TargetFile)';
769775 if not IDEMacros.SubstituteMacros(Result) then
770776 raise Exception.Create('unable to retrieve target file of project');
771777end;
772778```
773779
774780有关更多宏的信息,请参阅此处:[[IDE Macros in paths and filenames]]。
775781
776782## 添加您自己的项目类型
777783
778784您可以在“新建 ...”对话框中添加项目:
779785
780786- 请参阅 IDEIntf 包的单元 ProjectIntf。
781787- 请参阅项目模板
782788
783789## 添加您自己的文件类型
784790
785791您可以在“新建 ...”对话框中添加项目:
786792
787793- 请参阅 IDEIntf 包的单元 ProjectIntf。
788794- 为普通单元选择基类 TFileDescPascalUnit,为新表单 / 数据模块选择 TFileDescPascalUnitWithResource。
789795
790796## 添加新文件类型
791797
792798``` pascal
793799uses ProjectIntf;
794800...
795801 { TFileDescText }
796802
797803 TFileDescMyText = class(TProjectFileDescriptor)
798804 public
799805 constructor Create; override;
800806 function GetLocalizedName: string; override;
801807 function GetLocalizedDescription: string; override;
802808 end;
803809...
804810
805811procedure Register;
806812
807813implementation
808814
809815procedure Register;
810816begin
811817 RegisterProjectFileDescriptor(TFileDescMyText.Create,FileDescGroupName);
812818end;
813819
814820{ TFileDescMyText }
815821
816822constructor TFileDescMyText.Create;
817823begin
818824 inherited Create;
819825 Name:='MyText'; // 不要翻译这个
820826 DefaultFilename:='text.txt';
821827 AddToProject:=false;
822828end;
823829
824830function TFileDescText.GetLocalizedName: string;
825831begin
826832 Result:='My Text'; // 用 resourcestring 替换它
827833end;
828834
829835function TFileDescText.GetLocalizedDescription: string;
830836begin
831837 Result:='An empty text file';
832838end;
833839```
834840
835841### 添加新表单类型
836842
837843``` pascal
838844uses ProjectIntf;
839845
840846...
841847 TFileDescPascalUnitWithMyForm = class(TFileDescPascalUnitWithResource)
842848 public
843849 constructor Create; override;
844850 function GetInterfaceUsesSection: string; override;
845851 function GetLocalizedName: string; override;
846852 function GetLocalizedDescription: string; override;
847853 end;
848854...
849855
850856procedure Register;
851857
852858implementation
853859
854860procedure Register;
855861begin
856862 RegisterProjectFileDescriptor(TFileDescPascalUnitWithMyForm.Create,FileDescGroupName);
857863end;
858864
859865{ TFileDescPascalUnitWithMyForm }
860866
861867constructor TFileDescPascalUnitWithMyForm.Create;
862868begin
863869 inherited Create;
864870 Name:='MyForm'; // 不要翻译这个
865871 ResourceClass:=TMyForm;
866872 UseCreateFormStatements:=true;
867873end;
868874
869875function TFileDescPascalUnitWithMyForm.GetInterfaceUsesSection: string;
870876begin
871877 Result:='Classes, SysUtils, MyWidgetSet';
872878end;
873879
874880function TFileDescPascalUnitWithForm.GetLocalizedName: string;
875881begin
876882 Result:='MyForm'; // 用 resourcestring 替换它
877883end;
878884
879885function TFileDescPascalUnitWithForm.GetLocalizedDescription: string;
880886begin
881887 Result:='Create a new MyForm from example package NotLCLDesigner';
882888end;
883889```
884890
885891## 以 lpi/lps 存储自定义值
886892
887893您可以通过 CustomData 和 CustomSessionData 中的键值对存储您自己的数据。
888894
889-` LazarusIDE.ActiveProject.CustomData['Name'] := Value ; // 存储在 lpi-x-platform 中,共享数据`\
890-` LazarusIDE.ActiveProject.CustomSessionData['Name'] := Value ; // 存储在 lps 中 - 只有本机`
895+``` pascal
896+ LazarusIDE.ActiveProject.CustomData['Name'] := Value ; // 存储在 lpi-x-platform 中,共享数据
897+ LazarusIDE.ActiveProject.CustomSessionData['Name'] := Value ; // 存储在 lps 中 - 只有本机
898+```
891899
892900# 包
893901
894902您可以使用 Packages 执行各种操作:
895903
896904## 搜索所有包
897905
898906迭代 IDE 中加载的所有包(自 0.9.29 起)。
899907
900908``` pascal
901909uses PackageIntf;
902910...
903911for i:=0 to PackageEditingInterface.GetPackageCount-1 do
904912 writeln(PackageEditingInterface.GetPackages(i).Name);
905913```
906914
907915## 搜索包含名称的包
908916
909917``` pascal
910918uses PackageIntf;
911919...
912920var
913921 Pkg: TIDEPackage;
914922begin
915923 Pkg:=PackageEditingInterface.FindPackageWithName('LCL');
916924 if Pkg<>nil then
917925 ...
918926end;
919927```
920928
921929注意:FindPackageWithName 不会打开包编辑器。为此使用 DoOpenPackageWithName。
922930
923931## 获取已安装软件包的 lpk 文件名
924932
925933``` pascal
926934uses PackageIntf;
927935...
928936var
929937 Pkg: TIDEPackage;
930938begin
931939 Pkg:=PackageEditingInterface.FindPackageWithName('LCL');
932940 if Pkg<>nil then
933941 LPKFilename:=Pkg.Filename;
934942end;
935943```
936944
937945## 安装包
938946
939947注意:仅安装带有 IDE 插件的软件包。安装其他软件包可能会使 IDE 不稳定。
940948
941949``` pascal
942950uses PackageIntf, contnrs;
943951...
944952 PkgList:=TObjectList.create(true);
945953 try
946954 Pkg:=TLazPackageID.Create;
947955 Pkg.Name:='Cody';
948956 PkgList.Add(Pkg);
949957 // 检查 IDE 是否可以找到 cody.lpk 和所有依赖项
950958 // 如果看起来很奇怪,IDE 会提示一些警告 / 确认。
951959 if not PackageEditingInterface.CheckInstallPackageList(PkgList,[]) then
952960 exit;
953961 // 在这个例子中我们已经检查过,所以跳过警告并重建 IDE
954962 if PackageEditingInterface.InstallPackages(PkgList,[piiifSkipChecks,piiifRebuildIDE])<>mrOK then
955963 exit;
956964 finally
957965 PkgList.Free;
958966 end;
959967```
960968
961969## 打开包文件(lpk)
962970
963971``` pascal
964972uses PackageIntf, FileUtil;
965973...
966974var
967975 pkg: TIDEPackage;
968976begin
969977 if PackageEditingInterface.DoOpenPackageFile(LPKFilename,[pofAddToRecent],false)<>mrOk then
970978 exit;
971979 Pkg:=PackageEditingInterface.FindPackageWithName(ExtractFilenameOnly(LPKFilename));
972980 ...
973981end;
974982```
975983
976984> **Warning:** IDE 会在空闲时自动关闭未使用的软件包。永远不要引用 TIDEPackage。
977985
978986## 找到一个单元的包裹
979987
980988你有一个单元的文件名,例如 '/home/user/unit.pas',你想知道它属于哪个包和项目使用这个:
981989
982990``` pascal
983991uses Classes, PackageIntf, ProjectIntf;
984992...
985993var
986994 Owners: TFPList;
987995 i: Integer;
988996 o: TObject;
989997begin
990998 Owners:=PackageEditingInterface.GetPossibleOwnersOfUnit('/full/path/of/unit.pas',[]);
991999 if Owners=nil then begin
9921000 // 单元与项目 / 包没有直接关联
9931001 // 也许单元出于某种原因没有添加,但可以访问
9941002 // 搜索所有项目 / 包的所有单元路径
9951003 // 注意:这会导致错误命中
9961004 Owners:=PackageEditingInterface.GetPossibleOwnersOfUnit('/full/path/of/unit.pas',
9971005 [piosfExcludeOwned,piosfIncludeSourceDirectories]);
9981006 end;
9991007 if Owners=nil then exit;
10001008 try
10011009 for i:=0 to Owners.Count-1 do begin
10021010 o:=TObject(Owners[i]);
10031011 if o is TIDEPackage then begin
10041012 writeln('Owner is package ',TIDEPackage(o).Name);
10051013 end else if o is TLazProject then begin
10061014 writeln('Owner is project ',TLazProject(o).ProjectInfoFile);
10071015 end;
10081016 end;
10091017 finally
10101018 Owners.Free;
10111019 end;
10121020```
10131021
10141022## 查找项目 / 包所需的包
10151023
10161024您有一个项目或包,并且您想知道需要哪个包,使用:
10171025
10181026``` pascal
10191027uses Classes, PackageIntf, ProjectIntf;
10201028...
10211029var
10221030 lPkgList: TFPList;
10231031 i: Integer;
10241032begin
10251033 PackageEditingInterface.GetRequiredPackages(LazarusIDE.ActiveProject, lPkgList, [pirNotRecursive]);
10261034 try
10271035 for i := 0 to lPkgList.Count - 1 do begin
10281036 writeln('required package is ' + TIDEPackage(lPkgList[i]).Filename);
10291037 end;
10301038 finally
10311039 lPkgList.Free;
10321040 end;
10331041...
10341042```
10351043
10361044# 窗口(Windows)
10371045
10381046基本上有四种类型的 IDE 窗口。
10391047
10401048- 主 IDE 栏是 Application.MainForm。它始终存在。
10411049- 浮动 / 可停靠窗口,如源代码编辑器,对象检查器和消息。
10421050- 模态表单,如查找对话框,选项对话框和问题。
10431051- 提示和完成表格
10441052
10451053## 添加新的可停靠 IDE 窗口
10461054
10471055什么是可停靠的 IDE 窗口:像源代码编辑器或对象检查器这样的 Windows 是浮动窗口,如果安装了扩展包,则可以停靠它,并在下次 IDE 启动时存储和恢复其状态,位置和大小。为了恢复窗口,IDE 需要在 IDEIntf 包的单元 IDEWindowIntf 中定义的创建者。每个可停靠窗口必须具有唯一名称。不要使用像 'FileBrowser' 这样的通用名称,因为这很容易与其他包冲突。并且不要使用像“XYZ”这样的短名称,因为创建者负责以此名称开头的所有表单。
10481056
10491057### 如何注册可停靠的 IDE 窗口
10501058
10511059请记住选择一个有效的 pascal 标识符的长唯一名称。您的窗口可以包含您想要的任何标题。
10521060
10531061``` pascal
10541062uses SysUtils, IDEWindowIntf;
10551063...
10561064var MyIDEWindow: TMyIDEWindow = nil;
10571065
10581066procedure CreateMyIDEWindow(Sender: TObject; aFormName: string; var AForm: TCustomForm; DoDisableAutoSizing: boolean);
10591067begin
10601068 // 检查名称
10611069 if CompareText(aFormName,MyIDEWindowName)<>0 then exit;
10621070 // 如果尚未创建表单并禁用自动调整大小
10631071 IDEWindowCreators.CreateForm(MyIDEWindow,TMyIDEWindowm,DoDisableAutosizing,Application);
10641072 ... init the window ...
10651073 AForm:=MyIDEWindow;
10661074end;
10671075
10681076procedure Register;
10691077begin
10701078 IDEWindowCreators.Add('MyIDEWindow',@CreateMyIDEWindow,nil,'100','50%','+300','+20%');
10711079 // 表单的默认边界是:
10721080 // Left=100, Top=Screen.Height div 2, Width=300, Height=Screen.Height div 5
10731081 // 当 IDE 需要此窗口的实例时,它会调用 CreateMyIDEWindow 过程。
10741082end;
10751083```
10761084
10771085### 显示 IDE 窗口
10781086
10791087不要使用 Show。使用:
10801088
10811089``` pascal
10821090IDEWindowCreators.ShowForm(MyIDEWindow,false);
10831091```
10841092
10851093这将适用于对接。对接系统可以将表格包裹到对接站点中。BringToFront 参数告诉对接系统使表单及其所有父站点可见,并将顶层站点放在前面。
10861094
10871095### 有关 IDEWindowCreators 和 SimpleLayoutStorage 的注释
10881096
10891097IDEWindowCreators.SimpleLayoutStorage 只存储曾经打开过的所有表单的 BoundsRect 和 WindowState。如果没有安装 dockmaster,它将用作后备。即使安装了 DockMaster,它也会存储状态,因此在卸载 dockmaster 时,将恢复表单边界。
10901098
10911099所有可停靠表单都使用 IDEWindowCreators 来注册自己并显示表单。在显示表单时,Creator 会检查是否安装了 IDEDockMaster,并将显示委托给它。如果没有安装 IDEDockMaster,它只显示表单。IDEDockMaster 可以使用 IDEWindowCreators 中的信息按名称创建表单,并在第一次显示表单时了解放置表单的位置。有关更多详细信息,请参阅包 AnchorDockingDsgn 和 EasyDockMgDsgn。
10921100
10931101# 代码工具
10941102
10951103CodeTools 是一个包,提供了大量的功能来解析、搜索和更改 pascal 源代码以及其他语言的一些基本功能。您也可以在没有 IDE 的情况下使用它们。在 IDE 中使用它们之前,建议您首先阅读 [[Codetools]]。
10961104
10971105在调用 IDE 中的任何 CodeTools 函数之前,您应该将源代码编辑器的当前更改提交到 CodeTools 缓冲区:
10981106
10991107``` pascal
11001108uses LazIDEIntf;
11011109...
11021110 // 将源代码编辑器中的更改保存到 codetools
11031111 LazarusIDE.SaveSourceEditorChangesToCodeCache(-1); // -1:提交所有源代码编辑器
11041112```
11051113
11061114## 将资源指令添加到文件中
11071115
11081116这为 pascal 单元添加 {\$R example.res}:
11091117
11101118``` pascal
11111119procedure AddResourceDirectiveToPascalSource(const Filename: string);
11121120var
11131121 ExpandedFilename: String;
11141122 CodeBuf: TCodeBuffer;
11151123begin
11161124 // 确保修剪文件名并包含完整路径
11171125 ExpandedFilename:=CleanAndExpandFilename(Filename);
11181126
11191127 // 将源代码编辑器中的更改保存到 codetools
11201128 LazarusIDE.SaveSourceEditorChangesToCodeCache(-1);
11211129
11221130 // 加载文件
11231131 CodeBuf:=CodeToolBoss.LoadFile(ExpandedFilename,true,false);
11241132
11251133 // 添加资源指令
11261134 if not CodeToolBoss.AddResourceDirective(CodeBuf,'example.res') then
11271135 LazarusIDE.DoJumpToCodeToolBossError;
11281136end;
11291137```
11301138
11311139codetools 还提供 FindResourceDirective 和 RemoveDirective 等函数。
11321140
11331141## 获取单元和包含文件的搜索路径
11341142
11351143IDE 中有许多不同的搜索路径来自项目,包,fpc 和 lazarus 目录,并且有许多类型的路径:在解析宏之前或之后,有或没有继承的搜索路径,作为相对路径或绝对路径。目录中的所有文件共享同一组搜索路径。您可以通过询问 codetools 来完全解析每个目录的搜索路径:
11361144
11371145``` pascal
11381146uses CodeToolManager;
11391147...
11401148
11411149Dir:=''; // 空目录用于新文件,并且具有与项目目录相同的设置
11421150
11431151// 获取包含文件的搜索路径:
11441152Path:=CodeToolBoss.GetIncludePathForDirectory(Dir);
11451153
11461154// 获取单元的搜索路径:
11471155// 此搜索路径将传递给编译器。
11481156// 它包含包输出目录,但不包含包源目录。
11491157Path:=CodeToolBoss.GetUnitPathForDirectory(Dir);
11501158
11511159// 只能为 IDE 提供额外的单元搜索路径(不传递给编译器)
11521160Path:=CodeToolBoss.GetSrcPathForDirectory(Dir);
11531161
11541162// 完整的搜索路径还包含单元的所有包源路径:
11551163Path:=CodeToolBoss.GetCompleteSrcPathForDirectory(Dir);
11561164```
11571165
11581166# 源代码编辑
11591167
11601168## 激活源代码编辑器
11611169
11621170``` pascal
11631171uses SrcEditorIntf;
11641172...
11651173Editor:=SourceEditorManagerIntf.ActiveEditor;
11661174if Editor=nil then exit;
11671175Filename:=Editor.FileName;
11681176ScreenPos:=Editor.CursorScreenXY;
11691177TextPos:=Editor.CursorTextXY;
11701178```
11711179
11721180# SynEdit
11731181
11741182## 获取 TSynEdit 的设置
11751183
11761184当您使用 TSynEdit 进行对话时,如果要使用与源代码编辑器相同的字体和设置,请使用:
11771185
11781186``` pascal
11791187uses SrcEditorIntf;
11801188...
11811189SourceEditorManagerIntf.GetEditorControlSettings(ASynEdit);
11821190```
11831191
11841192## 获取 SynEdit 的高亮设置
11851193
11861194如果您有一个带有高亮的 TSynEdit 的对话框,并且您希望使用与源代码编辑器高亮相同的颜色来使用此语言:
11871195
11881196使
11891197
11901198``` pascal
11911199uses SrcEditorIntf;
11921200...
11931201SourceEditorManagerIntf.GetHighlighterSettings(ASynHighlighter);
11941202```
11951203
11961204请参阅示例:[SQLStringsPropertyEditorDlg](http://svn.freepascal.org/svn/lazarus/trunk/components/sqldb/sqlstringspropertyeditordlg.pas) 单元中的 TSQLStringsPropertyEditorDlg.Create。
11971205
11981206# 帮助
11991207
12001208## 添加源的帮助
12011209
12021210首先创建一个 THelpDatabase:
12031211
12041212``` pascal
12051213HelpDB := TFPDocHTMLHelpDatabase(
12061214 HelpDatabases.CreateHelpDatabase('ANameOfYourChoiceForTheDatabase',
12071215 TFPDocHTMLHelpDatabase,true));
12081216HelpDB.DefaultBaseURL := 'http://your.help.org/';
12091217
12101218FPDocNode := THelpNode.CreateURL(HelpDB,
12111219 'Package1 - A new package',
12121220 'file://index.html');
12131221HelpDB.TOCNode := THelpNode.Create(HelpDB,FPDocNode);// 一次作为 TOC
12141222DirectoryItem := THelpDBISourceDirectory.Create(FPDocNode,'$(PkgDir)/lcl',
12151223 '*.pp;*.pas',false);// 一次作为正常页面
12161224HelpDB.RegisterItem(DirectoryItem);
12171225```
12181226
12191227## 在消息窗口中添加行
12201228
12211229``` pascal
12221230unit IDEMsgIntf;
12231231...
12241232var Dir: String;
12251233begin
12261234 Dir:=GetCurrentDir;
12271235 IDEMessagesWindow.BeginBlock;
12281236 IDEMessagesWindow.AddMsg('unit1.pas(30,4) Error: Identifier not found "a"',Dir,0);
12291237 IDEMessagesWindow.EndBlock;
12301238end;
12311239```
12321240
12331241# IDE 选项框架
12341242
12351243## 打开特定框架中的选项
12361244
12371245``` pascal
12381246uses LazIDEIntf;
12391247...
12401248LazarusIDE.DoOpenIDEOptions(TYourIDEOptionsFrame);
12411249```
12421250
12431251# 其它
12441252
12451253## 添加宏
12461254
12471255您可以添加自己的 IDE 宏:
12481256
12491257``` pascal
12501258uses MacroIntf, MacroDefIntf;
12511259
12521260procedure Register;
12531261begin
12541262 // 注册具有固定值的宏:
12551263 IDEMacros.Add(TTransferMacro.Create('MyMacro1','Value','Description',nil,[]));
12561264end;
12571265
12581266// 使用动态值注册宏需要一个对象的方法
12591267procedure TForm1.Init;
12601268begin
12611269 IDEMacros.Add(TTransferMacro.Create('MyMacro','Value','Description',@OnResolveMyMacro,[]));
12621270end;
12631271
12641272function TForm1.OnResolveMyMacro(const s: string; const Data: PtrInt;
12651273 var Abort: boolean): string;
12661274// s 是参数。例如 $MyMacro(parameter)
12671275// 数据是查询实例。可以是零。
12681276// 如果有错误设置 Abort 为 true。
12691277// 结果字符串可以包含宏。例如 Result:='$(FPCVer)/$(TargetOS)';
12701278begin
12711279 Result:='MyValue';
12721280end;
12731281```
12741282
12751283## 调试 IDE
12761284
12771285- 像往常一样编译 IDE,例如通过 Tools/Build Lazarus。确保设置调试标志,如 -g 或 -gw2。最好是使用配置文件“Debug IDE”,其中包含许多用于调试的标志。
12781286- 打开 ide \\ lazarus.lpi 项目。您无法直接编译此项目。
12791287- 根据需要设置断点等运行项目。
12801288
12811289## 另请参见
12821290
12831291- [[Creating IDE Help]]
12841292- [[Help protocol]]
12851293- [[How To Write Lazarus Component]]
12861294
12871295---
12881296*From the Free Pascal wiki, page "Extending the IDE/zh CN", 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