Sign in Join
Wiki copytemporary

Extending the IDE/es: what changed

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

OldNewLine
11# Extendiendo el IDE
22
33## Visión general
44
55El IDE de Lazarus soporta varios tipos de plugins:
66
77Componentes
88Estos son los elementos que se encuentrar en la Paleta de Componentes. Por ejemplo, TButton (que se encuentra en la solapa Standard) que se utiliza para crear Buttons.
99
1010Component Editors
1111Cuando haces doble click sobre un componente en el Diseñador, se invoka un editor de componente. El editor de componente puede además añadir un elemento extra al menú emergente (accedido cuando haces click en el pulsador derecho en un componente dentro del Diseñador).
1212
1313Property Editors
1414Cada fila en la sección de la rejilla (grid) del Inspector de Objetos utiliza un editor de propiedades que permite establecer o alterar el valor de su propiedad.
1515
1616Experts
1717Experts abarca todos los demás tipos de plugin. Pueden registrar nuevos elementos de menú, registrar atajos (short cuts), o extender otras características del IDE.
1818
1919Hay dos maneras posibles de añadir tus propios plugins al IDE de Lazarus:
2020
21211. Escribir un paquete, instalarlo y registrar tu plugin(s) en el procedimiento 'Register' procedure de una unit.
22222. Extender el cógigo de Lazarus, y enviar tu svn diff a la lista de correo de Lazarus.
2323
2424## Paquetes y Dependencias MakeFile
2525
2626Los siguientes pasos son necesarios para añadir nuevas dependencias de paquete.
2727
2828- Crear/Actualizar el MakeFile para el paquete vía Editor de Paquete / Más ... / Crear Makefile.
2929- Corregir todas las dependencias. Ver tools/updatemakefiles.lpi
3030
3131# Elementos del Menú
3232
3333Puedes añadir nuevos elementos al menú, ocultar o mover los existentes y añadir sub menús y secciones. Puedes registrar TMainMenu/TPopupMenu para tus propios formularios de forma que otros paquetes puedan extender más tu formulario. La unidad **MenuIntf** del paquete IDEIntf contiene todos todos los registros para menús y algunos elementos menú estandar del propio IDE.
3434
3535## Añadiendo un elemento al menú
3636
3737Un simple elemento de menú tal como 'View Object Inspector' se llama **TIDEMenuCommand**. Puedes crear uno con **RegisterIDEMenuCommand**, que tiene dos fomas con un montón de parámetros:
3838
3939``` pascal
4040
4141function RegisterIDEMenuCommand(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;
4848function RegisterIDEMenuCommand(const Path, Name, Caption: string;
4949 const OnClickMethod: TNotifyEvent = nil;
5050 const OnClickProc: TNotifyProcedure = nil;
5151 const Command: TIDECommand = nil;
5252 const ResourceName: String = ''
5353 ): TIDEMenuCommand; overload;
5454```
5555
5656La diferencia entre los dos consiste solamente en como se especifica la sección padre del menú. Puedes dar la sección del menú directamente o bien indirectamente a través de su trayecto. Algunas secciones estandar las puedes encontrar en la unidad *MenuIntf* Por ejemplo, la sección **mnuTools**, la cual es el menú *Tools* de la barra principal del IDE. Contiene una secciónon **itmSecondaryTools**, que es la sección recomendada para utilidades de terceros.
5757
5858Lo siguiente registra un nuevo mandato de menú con el nombre 'MyTool', el caption 'Arranca mi utilidad' y cuando es clickeada ejecuta el procedimiento *StartMyTool*:
5959
6060``` pascal
6161procedure StartMyTool;
6262begin
6363 ...ejecutada cuando el elemento del menú es clickeado...
6464end;
6565
6666procedure Register;
6767begin
6868 RegisterIDEMenuCommand(itmSecondaryTools, 'MyTool','Aranca mi utilidad',nil,@StartMyTool);
6969end;
7070```
7171
7272If you want to call a method instead of a procedure use the **OnClickMethod** parameter.
7373
7474Este elemento de menú no tiene un atajo. En caso de necesitar uno debes crear un **TIDECommand** y pasarlo en el parámetro **Command**. Por ejemplo:
7575
7676``` pascal
7777uses ... IDECommands, MenuIntf;
7878...
7979var
8080 Key: TIDEShortCut;
8181 Cat: TIDECommandCategory;
8282 CmdMyTool: TIDECommand;
8383begin
8484 // register IDE shortcut and menu item
8585 Key := IDEShortCut(VK_UNKNOWN,[],VK_UNKNOWN,[]);
8686 Cat:=IDECommandList.FindCategoryByName(CommandCategoryToolMenuName);
8787 CmdMyTool := RegisterIDECommand(Cat,'Start my tool', 'Starts my tool to do some stuff', Key, nil, @StartMyTool);
8888 RegisterIDEMenuCommand(itmSecondaryTools, 'MyTool', 'Start my tool', nil, nil, CmdMyTool);
8989end;
9090```
9191
9292# Atajos (Shortcuts)
9393
9494Todos los atajos (teclas que invocan alguna acción) se encuentran registradas en el IDECommandList. Este es un ejemplo sobre como encontrar todos los mandatos que reaccionan a la pulsación de Ctrl-D o la combinación de teclas pulsadas que comiencen por Ctrl-D:
9595
9696``` pascal
9797uses
9898 Classes, SysUtils, LCLProc, IDECommands;
9999
100100procedure ListCtrlD;
101101// Lista todos los idecommands con el atajo Ctrl-D
102102var
103103 i: integer;
104104 Cmd: TIDECommand;
105105 Commands: TFPList;
106106begin
107107 Commands:=IDECommandList.FindCommandsByShortCut(IDEShortCut(VK_D,[],VK_UNKNOWN,[])); // VK = Virtual Key
108108 try
109109 for i:=0 to Commands.Count-1 do begin
110110 Cmd:=TIDECommand(Commands[i]);
111111 writeln('Cmd: ',Cmd.Name,
112112 ' A=',dbgs(Cmd.ShortcutA.Shift1),'-',Cmd.ShortcutA.Key1,
113113 ',',dbgs(Cmd.ShortcutA.Shift2),'-',Cmd.ShortcutA.Key2,
114114 ' B=',dbgs(Cmd.ShortcutB.Shift1),'-',Cmd.ShortcutB.Key1,
115115 ',',dbgs(Cmd.ShortcutB.Shift2),'-',Cmd.ShortcutB.Key2
116116 );
117117 end;
118118 finally
119119 Commands.Free;
120120 end;
121121end;
122122```
123123
124124# Config files
125125
126126## Cargar/Salvar configuraciones
127127
128128Todos los ficheros de configuración del IDE se encuentran almacenados en un directorio como ficheros xml. Los paquetes también también pueden añadir sus propios ficheros en dicho directorio. El [[pcp|primary config path]] se puede leer con:
129129
130130``` pascal
131131uses LazIDEIntf;
132132...
133133 Directory := LazarusIDE.GetPrimaryConfigPath;
134134```
135135
136136Los paquetes pueden crear su propios ficheros xml con:
137137
138138``` pascal
139139uses
140140 ..., LCLProc, BaseIDEIntf, LazConfigStorage;
141141
142142const
143143 Version = 1;
144144var
145145 Config: TConfigStorage;
146146 SomeValue: String;
147147 SomeInteger: Integer;
148148 SomeBoolean: Boolean;
149149 FileVersion: LongInt;
150150begin
151151 SomeValue:='Default';
152152 SomeInteger:=3;
153153 SomeBoolean:=true;
154154
155155 // Salva configuraciones.
156156 try
157157 Config:=GetIDEConfigStorage('mysettings.xml',false);
158158 try
159159 // Almacena el número de versión de forma que las extensiones futuras puedan manejar ficheros de configuración antiguos.
160160 Config.SetDeleteValue('Path/To/The/Version',Version,0);
161161 // Almacena la variable de cadena "SomeValue".
162162 // Si SomeValue tiene el valor por defecto entonces la entrada no se almacena,
163163 // de forma que únicamente se almacena las diferencias al valor por defecto.
164164 // Así el xml se mantiene pequeño y su valor por defecto puede cambiar en el futuro.
165165 Config.SetDeleteValue('Path/To/Some/Value',SomeValue,'Default');
166166 Config.SetDeleteValue('Path/To/Some/Integer',SomeInteger,3);
167167 Config.SetDeleteValue('Path/To/Some/Boolean',SomeBoolean,true);
168168 // there are more overloads for SetDeleteValue, find out with Ctrl+Space
169169 finally
170170 Config.Free;
171171 end;
172172
173173 except
174174 on E: Exception do begin
175175 DebugLn(['Saving mysettings.xml failed: ',E.Message]);
176176 end;
177177 end;
178178
179179 // load settings
180180 try
181181 Config:=GetIDEConfigStorage('mysettings.xml',true);
182182 try
183183 // read the version of the config
184184 FileVersion:=Config.GetValue('Path/To/The/Version',0);
185185 // read a string variable "SomeValue". If the entry does not exist, use
186186 // the Default
187187 SomeValue:=Config.GetValue('Path/To/Some/Value','Default');
188188 SomeInteger:=Config.GetValue('Path/To/Some/Integer',3);
189189 SomeBoolean:=Config.GetValue('Path/To/Some/Boolean',true);
190190 finally
191191 Config.Free;
192192 end;
193193 except
194194 on E: Exception do begin
195195 DebugLn(['Loading mysettings.xml failed: ',E.Message]);
196196 end;
197197 end;
198198end;
199199```
200200
201201Notes:
202202
203203- Every IDE plugin should use its own config file. Especially you must not use the standard IDE option files like [[editoroptions.xml]] or [[environmentoptions.xml]].
204204- GetIDEConfigStorage when loading checks if the file exists and if not it will copy the template from the secondary config directory.
205205- Since 0.9.31 you can use this function to load a file outside the primary config directory.
206206
207207# Components
208208
209209## Extending existing components
210210
211211Source: [1](http://lazarus.freepascal.org/index.php/topic,17733.msg98425.html#msg98425) It is straightforward to customise existing LCL components, e.g. if you want to add properties.
212212
213213Add the properties you need with appropriate setter and getter methods and storage fields.
214214
215215Then instantiate them 'by hand', giving an owner component (to handle later destruction), and set Parent and possibly Top and Left and any other defaults your component needs when initialized.
216216
217217When you are satisfied that your customised component is debugged, add a RegisterComponent() call to stick it on the IDE Component Palette and save you having to do the setup code 'by hand' (look at any component's source to see how to do this).
218218
219219Here is a simple example:
220220
221221``` pascal
222222unit Unit1;
223223
224224{$mode objfpc}{$H+}
225225
226226interface
227227
228228uses
229229 Classes, SysUtils, Forms, StdCtrls;
230230
231231type
232232 TEdX = class(TEdit)
233233 private
234234 FNewIntProp: integer;
235235 FNewStrProp: string;
236236 procedure SetNewIntProp(AValue: integer);
237237 procedure SetNewStrProp(AValue: string);
238238 public
239239 constructor Create(theComponent: TComponent); override;
240240 property NewIntProp: integer read FNewIntProp write SetNewIntProp;
241241 property NewStrProp: string read FNewStrProp write SetNewStrProp;
242242 end;
243243
244244 TForm1 = class(TForm)
245245 procedure FormCreate(Sender: TObject);
246246 private
247247 edX: TEdX;
248248 public
249249 end;
250250
251251var
252252 Form1: TForm1;
253253
254254implementation
255255
256256{ TForm1 }
257257
258258procedure TForm1.FormCreate(Sender: TObject);
259259begin
260260 edX:= TEdX.Create(Self);
261261 edX.Parent:= Self;
262262 edX.Caption:= IntToStr(edX.NewIntProp);
263263 Caption:= edX.NewStrProp;
264264end;
265265
266266{$R *.lfm}
267267
268268{ TEdX }
269269
270270procedure TEdX.SetNewIntProp(AValue: integer);
271271begin
272272 if FNewIntProp=AValue then Exit;
273273 FNewIntProp:=AValue;
274274 // add custom code here
275275end;
276276
277277procedure TEdX.SetNewStrProp(AValue: string);
278278begin
279279 if FNewStrProp=AValue then Exit;
280280 FNewStrProp:=AValue;
281281 // add custom code here
282282end;
283283
284284constructor TEdX.Create(theComponent: TComponent);
285285begin
286286 inherited Create(theComponent);
287287 FNewStrProp:= 'new string property value';
288288 FNewIntProp:= 99;
289289end;
290290
291291end.
292292```
293293
294294## Writing components
295295
296296*Main article: [[How To Write Lazarus Component]]*
297297
298298You can create new components via the package editor.
299299
300300Create or open a package, click on **add**, click on **New Component**, fill in the items: Ancestor Type = TButton, New class name = TMyButton, palette page = Misc, Unit file name = mybutton.pas (this file will be created), unit name MyButton and click **ok**.
301301
302302### Giving a new component an icon for the component palette
303303
304304Create an image file of the format .bmp, .xpm or .png with the same name as the component class. For example *tmybutton.png* and save it in the package source directory. The image can be created by any graphic program (e.g. gimp) and should be no bigger than 24x24 pixel. Then convert the image to a resource file with the lazres tool, which can be found in the lazarus/tools directory:
305305
306306``` bash
307307~/lazarus/tools/lazres mybutton.lrs tmybutton.png
308308# note: Laz trunk/1.4+? uses .res resource files instead of .lrs files:
309309~/lazarus/tools/lazres mybutton.res tmybutton.png
310310```
311311
312312This creates an pascal include file, which is used in the initialization section of mybutton.pas:
313313
314314``` pascal
315315initialization
316316 {$I mybutton.lrs}
317317 // or in newer Lazarus version - to docheck syntax
318318 {$R mybutton.res}
319319```
320320
321321Install the package.
322322
323323### Hiding a component in the component palette
324324
325325Package IDEIntf, unit componentreg:
326326
327-`IDEComponentPalette.FindComponent('TButton').Visible:=false;`
327+``` pascal
328+IDEComponentPalette.FindComponent('TButton').Visible:=false;
329+```
328330
329331## Writing component editors
330332
331333A component editor handles things like double clicking on a component in a designer or adding menu items when right clicking on a component. Writing a component editor is easy. See the unit componenteditors.pas of the package IDEIntf for lots of examples. For instance to show an editor when double clicking see TCheckListBoxComponentEditor.
332334
333335## Writing property editors
334336
335337Each type of property (integer, string, TFont, ...) in the Object Inspector needs a property editor. If your component has a property *Password* of type string, then you can define a property editor for your specific component class, with a property named *Password* of type string. The unit propedits.pp of the package IDEIntf contains many of the standard property editors used by the IDE itself. For example the TStringPropertyEditor is the default property editor for all strings, while TComponentNamePropertyEditor is more specific and handles only TComponent.Name. See the unit for plenty of examples.
336338
337339### Hiding a property in the Object Inspector
338340
339341There is a special property editor for hiding:
340342
341343` RegisterPropertyEditor(TypeInfo(TAnchorSide), TControl, 'AnchorSideLeft', THiddenPropertyEditor);`
342344
343345# Forms
344346
345347The IDE allows to easily create descendants of forms and frames. These forms can have new published components and new published methods. But you when you add new published properties, they are not accessible via the Object Inspector. They work only at runtime. The methods in the IDE are fake, they can not be executed. The IDE can create the components, because their classes are registered in the component palette. Your new properties only exist in your source code. The IDE can not fake them yet. That's why you have to register the new class. That means:
346348
347349- create a design time package (or extend an existing one)
348350- your form must be in a unit of this package
349351
350352``` pascal
351353...
352354interface
353355
354356uses FormEditingIntf, Forms;
355357
356358type
357359 TYourForm = class(TForm)
358360 private
359361 FYourProperty: integer;
360362 published
361363 property YourProperty: integer read FYourProperty write FYourProperty;
362364 end;
363365
364366procedure Register;
365367
366368implementation
367369
368370procedure Register;
369371begin
370372 FormEditingHook.RegisterDesignerBaseClass(TYourForm);
371373end;
372374...
373375```
374376
375377- check the "Register" in the package editor for this unit.
376378- Install the package in the IDE
377379
378380# Designer
379381
380382## Writing a designer mediator
381383
382384The standard designer allows to visually edit LCL controls, while all others are shown as icons(like TOpenDialog or TDataSource). To visually edit non LCL control, you need to create a **designer mediator**. This can be used to design webpages, UML diagrams or other widgetsets like [[fpGUI]]. There is a complete example in examples/designnonlcl/.
383385
384386- Install the example package examples/designnonlcl/notlcldesigner.lpk and restart the IDE. This will register the designer mediator for TMyWidget components and add the new components TMyButton, TMyGroupBox to the component palette.
385387- Open the the example project examples/designnonlcl/project/NonLCL1.lpi.
386388- Open the unit1.pas and show the designer form (F12). You should see the components as red rectangles, which can be selected, moved and resized like LCL controls.
387389
388390## Create a new unique component name
389391
390392``` pascal
391393uses FormEditingIntf;
392394
393395...
394396
395397NewName:=FormEditingHook.CreateUniqueComponentName(AComponent);
396398
397399// Or if you need to create the name before creating the component:
398400
399401NewName:=FormEditingHook.CreateUniqueComponentName(ComponentClassName,OwnerComponent);
400402// ComponentClassName will be used as prefix, without a leading T.
401403// OwnerComponent is the new owner of the new component.
402404```
403405
404406## Select a component in the designer/object inspector
405407
406408``` pascal
407409uses propedits;
408410..
409411GlobalDesignHook.SelectOnlyThis(AComponent);
410412```
411413
412414## Get unit, designer, form of a file
413415
414416``` pascal
415417uses ProjectIntf, LazIDEIntf, ComponentEditors;
416418...
417419// open file
418420if LazarusIDE.DoOpenEditorFile(Filename,-1,-1,[ofAddToRecent])<>mrOk then exit;
419421// get file interface
420422aFile:=LazarusIDE.ActiveProject.FindFile(Filename,[]);
421423// get designer
422424aDesigner:=TComponentEditorDesigner(LazarusIDE.GetDesignerWithProjectFile(AFile,true));
423425if aDesigner=nil then
424426 exit; // this unit has no resource (form, frame, datamodule, etc.)
425427// get form
426428aForm:=aDesigner.Form;
427429```
428430
429431## Save unit, designer form
430432
431433``` pascal
432434uses LazIDEIntf;
433435...
434436if LazarusIDE.DoSaveEditorFile(Filename,[])<>mrOk then exit;
435437```
436438
437439# Event handlers
438440
439441There are several events in the IDE, for which plugins can add their own handlers.
440442
441443## Designer events
442444
443445In propedits.pp there is a "GlobalDesignHook" object, which maintains several events for designing. Each event calls a list of handlers. The default handlers are added by the IDE. You can add your own handlers with the AddHandlerXXX and RemoveHandlerXXX methods. They will be called before the default handlers.
444446
445447Examples:
446448
447449- Adding your handler (this is normally done in the constructor of your object):
448450
449-` GlobalDesignHook.AddHandlerPersistentAdded(@YourOnPersistentAdded);`
451+```text
452+ GlobalDesignHook.AddHandlerPersistentAdded(@YourOnPersistentAdded);
453+```
450454
451455- Removing your handler:
452456
453-` GlobalDesignHook.RemoveHandlerPersistentAdded(@YourOnPersistentAdded);`
457+```text
458+ GlobalDesignHook.RemoveHandlerPersistentAdded(@YourOnPersistentAdded);
459+```
454460
455461- You can remove all handlers at once. For example, it is a good idea to add this line in the destructor of your object:
456462
457-` GlobalDesignHook.RemoveAllHandlersForObject(Self);`
463+```text
464+ GlobalDesignHook.RemoveAllHandlersForObject(Self);
465+```
458466
459467The handlers of GlobalDesignHook:
460468
461469- Lookup root
462470 - ChangeLookupRoot - Called when the "LookupRoot" changed. The "LookupRoot" is the owner object of the currently selected components. Normally this is a TForm.
463471- Methods
464472 - CreateMethod
465473 - GetMethodName
466474 - GetMethods
467475 - MethodExists
468476 - RenameMethod
469477 - ShowMethod
470478 - MethodFromAncestor
471479 - ChainCall
472480- Components
473481 - GetComponent
474482 - GetComponentName
475483 - GetComponentNames
476484 - GetRootClassName
477485 - AddClicked - Called when the user selected a component class and clicked on the designer to add a new component. You can change the component class and the parent.
478486 - ComponentRenamed - Called when a component was renamed
479487- TPersistent objects
480488 - PersistentAdded - Called when a new TPersistent was added to the LookupRoot
481489 - PersistentDeleting - Called before a TPersistent is freed.
482490 - DeletePersistent - Called by the IDE to delete a TPersistent.
483491 - GetSelectedPersistents - Called when getting the current selection of TPersistent.
484492 - SetSelectedPersistents - Called when setting the current selection of TPersistent.
485493 - GetObject
486494 - GetObjectName
487495 - GetObjectNames
488496- Modifing
489497 - Modified
490498 - Revert
491499 - RefreshPropertyValues
492500- Selection
493501 - SetSelection
494502 - GetSelection
495503
496504### Examples for designer events
497505
498506#### Example: When dropping a new component move control to a child
499507
500508``` pascal
501509...
502510type
503511 TYourDesignerExtension = class
504512 private
505513 function AddClicked(ADesigner: TIDesigner;
506514 MouseDownComponent: TComponent; Button: TMouseButton;
507515 Shift: TShiftState; X, Y: Integer;
508516 var AComponentClass: TComponentClass;
509517 var NewParent: TComponent): boolean of object;
510518 public
511519 constructor Create;
512520 destructor Destroy; override;
513521 end;
514522
515523...
516524constructor TYourDesignerExtension.Create;
517525begin
518526 // register your handler
519527 GlobalDesignHook.AddHandlerAddClicked(@AddClicked);
520528end;
521529
522530destructor TYourDesignerExtension.Destroy;
523531begin
524532 // remove your handler:
525533 GlobalDesignHook.RemoveHandlerAddClicked(@AddClicked);
526534end;
527535
528536function TYourDesignerExtension.AddClicked(ADesigner: TIDesigner;
529537 MouseDownComponent: TComponent; Button: TMouseButton;
530538 Shift: TShiftState; X, Y: Integer;
531539 var AComponentClass: TComponentClass;
532540 var NewParent: TComponent): boolean of object;
533541begin
534542 // in this example TYourControl is a custom control with a ChildControl.
535543 // Whenever the user drops a control on the TYourControl instead of adding
536544 // the new control to the TYourControl, the new control is added as child
537545 // of ChildControl.
538546 // created
539547 if MouseDownComponent is TYourControl then
540548 NewParent:=TYourControl(MouseDownComponent).ChildControl;
541549 Result:=true;
542550end;
543551```
544552
545553### Disabling the designer mouse handler
546554
547555Normally the designer catches all mouse events of a component. If your custom control should handle the mouse events handle you can either set the **csDesignInteractive** **ControlStyle** or you can fine control it via the message *CM_DESIGNHITTEST* in your control:
548556
549557``` pascal
550558type
551559 TYourControl = class(TCustomControl)
552560 protected
553561 procedure CMDesignHitTest(var Message: TLMessage); message CM_DESIGNHITTEST;
554562 end;
555563...
556564procedure TYourControl.CMDesignHitTest(var Message: TLMessage);
557565var
558566 p: TSmallPoint;
559567 aShiftState: TShiftState;
560568begin
561569 aShiftState:=KeysToShiftState(PtrUInt(Message.WParam));
562570 p:=TSmallPoint(longint(Message.LParam));
563571 debugln(['TForm1.CMDesignHitTest ShiftState=',dbgs(aShiftState),' x=',p.x,' y=',p.y]);
564572 if SkipDesignerMouseHandler then
565573 Message.Result:=1; // now the designer calls the normal MouseUp, MouseMove and MouseDown methods.
566574end;
567575```
568576
569577## Getting notified when a designer form is modified
570578
571579Every designed LCL form has a Designer of type TIDesigner. The IDE creates designers of type TComponentEditorDesigner defined in the IDEIntf unit componenteditors. For example:
572580
573581``` pascal
574582procedure TYourAddOn.OnDesignerModified(Sender: TObject);
575583var
576584 IDEDesigner: TComponentEditorDesigner;
577585begin
578586 IDEDesigner:=TComponentEditorDesigner(Sender);
579587 ...
580588end;
581589
582590procedure TYourAddOn.ConnectDesignerForm(Form1: TCustomForm);
583591var
584592 IDEDesigner: TComponentEditorDesigner;
585593begin
586594 IDEDesigner:=TComponentEditorDesigner(Form1.Designer);
587595 IDEDesigner.AddHandlerModified(@OnDesignerModified);
588596end;
589597```
590598
591599## Project events
592600
593601These events are defined in unit LazIDEIntf.
594602
595603- **LazarusIDE.AddHandlerOnProjectClose**: called before a project is closed
596604- **LazarusIDE.AddHandlerOnProjectOpened**: called after the project was completely opened (for example all required packages were loaded, units were opened in the source editor)
597605- **LazarusIDE.AddHandlerOnSavingAll**: called before IDE saves everything
598606- **LazarusIDE.AddHandlerOnSavedAll**: called after IDE saved everything
599607- **LazarusIDE.AddHandlerOnProjectBuilding**: called before IDE builds the project
600608- **LazarusIDE.AddHandlerOnProjectDependenciesCompiling**: called before IDE compiles package dependencies of project
601609- **LazarusIDE.AddHandlerOnProjectDependenciesCompiled**: called after IDE compiled package dependencies of project
602610- **LazarusIDE.AddHandlerOnProjectBuildingFinished**: called after IDE built the project (successful or not) (since 1.5)
603611
604612## Other IDE events
605613
606614uses LazIDEIntf;
607615
608616Call these in the Register procedure of your package:
609617
610618- **LazarusIDE.AddHandlerOnIDERestoreWindows**: called when IDE is restores its windows (before opening the first project)
611619- **LazarusIDE.AddHandlerOnIDEClose**: called when IDE is shutting down (after closequery, so no more interactivity)
612620- **LazarusIDE.AddHandlerOnQuickSyntaxCheck**: called when the menu item or the shortcut for Quick syntax check is executed
613621- **LazarusIDE.AddHandlerOnLazarusBuilding**: // called before IDE builds Lazarus IDE (since 1.5)
614622- **LazarusIDE.AddHandlerOnLazarusBuildingFinished**: // called after IDE builds Lazarus IDE (since 1.5)
615623- **LazarusIDE.AddHandlerGetFPCFrontEndParams**: // called when the IDE gets the parameters of the 'fpc' front end tool (since 1.5)
616624- **LazarusIDE.AddHandlerGetFPCFrontEndPath**: // called when the IDE gets the path of the 'fpc' front end tool (since 1.5)
617625- **LazarusIDE.AddHandlerOnUpdateIDEComponentPalette**: ?
618626- **LazarusIDE.AddHandlerOnUpdateComponentPageControl**: ?
619627- **LazarusIDE.AddHandlerOnShowDesignerFormOfSource**: // called after showing a designer form for code editor (AEditor can be nil!) (since 1.5)
620628- **LazarusIDE.AddHandlerOnShowSourceOfActiveDesignerForm**: // called after showing a code of designer form (since 1.5)
621629- **LazarusIDE.AddHandlerOnChangeToolStatus**: //called when IDEToolStatus has changed (e.g. itNone-\>itBuilder etc.) (since 1.5)
622630
623631Call these in the initialization section of one of your units:
624632
625633- **AddBootHandler**
626634 - AddBootHandler(**libhTransferMacrosCreated**,@YourProc): called after IDEMacros were created (since 1.3)
627635 - AddBootHandler(**libhEnvironmentOptionsLoaded**,@YourProc): called after environment options were loaded (since 1.3)
628636
629637# Project
630638
631639## Current Project
632640
633641The current main project can be obtained by LazarusIDE.ActiveProject. (unit LazIDEIntf)
634642
635643## All units of current project
636644
637645Note that the term "units of project" is ambiguous.
638646
639647- The project inspector shows the list of the .lpi file. The project might not use all these units on all platforms and maybe the developer forgot to add all used units.
640648- Units from used packages are not project units.
641649
642650### All units of the project inspector
643651
644652To iterate through all pascal units listed in the project inspector you can use for example:
645653
646654``` pascal
647655uses
648656 LCLProc, FileUtil, LazIDEIntf, ProjectIntf;
649657
650658procedure ListProjectUnits;
651659var
652660 LazProject: TLazProject;
653661 i: Integer;
654662 LazFile: TLazProjectFile;
655663begin
656664 LazProject:=LazarusIDE.ActiveProject;
657665 if LazProject<>nil then
658666 for i:=0 to LazProject.FileCount-1 do
659667 begin
660668 LazFile:=LazProject.Files[i];
661669 if LazFile.IsPartOfProject
662670 and FilenameIsPascalUnit(LazFile.Filename)
663671 then
664672 debugln(LazFile.Filename);
665673 end;
666674end;
667675```
668676
669677### All used units of project
670678
671679To find all currently used units of a project/package you can use the following. Note that the IDE needs to parse all units, so it can take some time.
672680
673681``` pascal
674682uses
675683 LazLoggerBase, LazIDEIntf, ProjectIntf;
676684
677685procedure ListProjectUnits;
678686var
679687 LazProject: TLazProject;
680688 i: Integer;
681689begin
682690 LazProject:=LazarusIDE.ActiveProject;
683691 if LazProject<>nil then
684692 begin
685693 Units:=LazarusIDE.FindUnitsOfOwner(LazProject,[fuooListed,fuooUsed]); // add fuooPackages to include units from packages
686694 try
687695 for i:=0 to Units.Count-1 do
688696 debugln('Filename=',Units[i]);
689697 finally
690698 Units.Free;
691699 end;
692700 end;
693701end;
694702```
695703
696704## The .lpr, .lpi and .lps file of a project
697705
698706``` pascal
699707uses
700708 LCLProc, FileUtil, ProjectIntf, LazIDEIntf;
701709var
702710 LazProject: TLazProject;
703711begin
704712 LazProject:=LazarusIDE.ActiveProject;
705713 // every project has a .lpi file:
706714 DebugLn(['Project'' lpi file: ',LazProject.ProjectInfoFile]);
707715
708716 // if the project session information is stored in a separate .lps file:
709717 if LazProject.SessionStorage<>pssNone then
710718 DebugLn(['Project'' lps file: ',LazProject.ProjectSessionFile]);
711719
712720 // If the project has a .lpr file it is the main source file:
713721 if (LazProject.MainFile<>nil)
714722 and (CompareFileExt(LazProject.MainFile.Filename,'lpr')=0) then
715723 DebugLn(['Project has lpr file: ',LazProject.MainFile.Filename]);
716724end;
717725```
718726
719727## The executable / target file name of a project
720728
721729There is a macro \$(TargetFile), which can be used in paths and external tools. You can query the macro in code:
722730
723731``` pascal
724732uses MacroIntf;
725733
726734function MyGetProjectTargetFile: string;
727735begin
728736 Result:='$(TargetFile)';
729737 if not IDEMacros.SubstituteMacros(Result) then
730738 raise Exception.Create('unable to retrieve target file of project');
731739end;
732740```
733741
734742See here for more macros: [[IDE Macros in paths and filenames]].
735743
736744## Add your own project type
737745
738746You can add items to the 'New ...' dialog:
739747
740748- See the unit ProjectIntf of the package IDEIntf.
741749- See the [[Project Templates]]
742750
743751## Add your own file type
744752
745753You can add items to the 'New ...' dialog:
746754
747755- See the unit ProjectIntf of the package IDEIntf.
748756- Choose a base class TFileDescPascalUnit for normal units or TFileDescPascalUnitWithResource for a new form/datamodule.
749757
750758### Add a new file type
751759
752760``` pascal
753761uses ProjectIntf;
754762...
755763 { TFileDescText }
756764
757765 TFileDescMyText = class(TProjectFileDescriptor)
758766 public
759767 constructor Create; override;
760768 function GetLocalizedName: string; override;
761769 function GetLocalizedDescription: string; override;
762770 end;
763771...
764772
765773procedure Register;
766774
767775implementation
768776
769777procedure Register;
770778begin
771779 RegisterProjectFileDescriptor(TFileDescMyText.Create,FileDescGroupName);
772780end;
773781
774782{ TFileDescMyText }
775783
776784constructor TFileDescMyText.Create;
777785begin
778786 inherited Create;
779787 Name:='MyText'; // do not translate this
780788 DefaultFilename:='text.txt';
781789 AddToProject:=false;
782790end;
783791
784792function TFileDescText.GetLocalizedName: string;
785793begin
786794 Result:='My Text'; // replace this with a resourcestring
787795end;
788796
789797function TFileDescText.GetLocalizedDescription: string;
790798begin
791799 Result:='An empty text file';
792800end;
793801```
794802
795803### Add a new form type
796804
797805``` pascal
798806uses ProjectIntf;
799807
800808...
801809 TFileDescPascalUnitWithMyForm = class(TFileDescPascalUnitWithResource)
802810 public
803811 constructor Create; override;
804812 function GetInterfaceUsesSection: string; override;
805813 function GetLocalizedName: string; override;
806814 function GetLocalizedDescription: string; override;
807815 end;
808816...
809817
810818procedure Register;
811819
812820implementation
813821
814822procedure Register;
815823begin
816824 RegisterProjectFileDescriptor(TFileDescPascalUnitWithMyForm.Create,FileDescGroupName);
817825end;
818826
819827{ TFileDescPascalUnitWithMyForm }
820828
821829constructor TFileDescPascalUnitWithMyForm.Create;
822830begin
823831 inherited Create;
824832 Name:='MyForm'; // do not translate this
825833 ResourceClass:=TMyForm;
826834 UseCreateFormStatements:=true;
827835end;
828836
829837function TFileDescPascalUnitWithMyForm.GetInterfaceUsesSection: string;
830838begin
831839 Result:='Classes, SysUtils, MyWidgetSet';
832840end;
833841
834842function TFileDescPascalUnitWithForm.GetLocalizedName: string;
835843begin
836844 Result:='MyForm'; // replace this with a resourcestring
837845end;
838846
839847function TFileDescPascalUnitWithForm.GetLocalizedDescription: string;
840848begin
841849 Result:='Create a new MyForm from example package NotLCLDesigner';
842850end;
843851```
844852
845853# Packages
846854
847855You can perform various actions with [[Lazarus Packages|Packages]]:
848856
849857## Search in all packages
850858
851859Iterate all packages loaded in the IDE (since 0.9.29).
852860
853861``` pascal
854862uses PackageIntf;
855863...
856864for i:=0 to PackageEditingInterface.GetPackageCount-1 do
857865 writeln(PackageEditingInterface.GetPackages(i).Name);
858866```
859867
860868## Search a package with a name
861869
862870``` pascal
863871uses PackageIntf;
864872...
865873var
866874 Pkg: TIDEPackage;
867875begin
868876 Pkg:=PackageEditingInterface.FindPackageWithName('LCL');
869877 if Pkg<>nil then
870878 ...
871879end;
872880```
873881
874882Note: FindPackageWithName does not open the package editor. For that use DoOpenPackageWithName.
875883
876884## Obtener el nombre de fichero .lpk de un paquete instalado
877885
878886``` pascal
879887uses PackageIntf;
880888...
881889var
882890 Pkg: TIDEPackage;
883891begin
884892 Pkg:=PackageEditingInterface.FindPackageWithName('LCL');
885893 if Pkg<>nil then
886894 LPKFilename:=Pkg.Filename;
887895end;
888896```
889897
890898## Instalar paquetes
891899
892900**Note**: Instalar únicamente paquetes con plugins IDE. Instalar otros paquetes puede hacer el IDE inestable.
893901
894902``` pascal
895903uses PackageIntf, contnrs;
896904...
897905 PkgList:=TObjectList.create(true);
898906 try
899907 Pkg:=TLazPackageID.Create;
900908 Pkg.Name:='Cody';
901909 PkgList.Add(Pkg);
902910 // Chequear si el IDE puede encontrar cody.lpk y todas las dependencias.
903911 // El IDE will muestra algunas advertencias/confirmaciones si algo parece extraño.
904912 if not PackageEditingInterface.CheckInstallPackageList(PkgList,[]) then
905913 exit;
906914 // in this example we have checked already, so skip the warnings
907915 // and rebuild the IDE
908916 if PackageEditingInterface.InstallPackages(PkgList,[piiifSkipChecks,piiifRebuildIDE])<>mrOK then
909917 exit;
910918 finally
911919 PkgList.Free;
912920 end;
913921```
914922
915923## Abrir un fichero de paquete (lpk)
916924
917925``` pascal
918926uses PackageIntf, FileUtil;
919927...
920928var
921929 pkg: TIDEPackage;
922930begin
923931 if PackageEditingInterface.DoOpenPackageFile(LPKFilename,[pofAddToRecent],false)<>mrOk then
924932 exit;
925933 Pkg:=PackageEditingInterface.FindPackageWithName(ExtractFilenameOnly(LPKFilename));
926934 ...
927935end;
928936```
929937
930938> **Warning:** El IDE cierra automáticamentes paquetes no utilizados on idle. Nunca mantener referencias a un TIDEPackage.
931939
932940## Find the package(s) of a unit
933941
934942You have the file name of a unit, e.g. '/home/user/unit.pas', and you want to know to which package(s) and project(s) it belongs use this:
935943
936944``` pascal
937945uses Classes, PackageIntf, ProjectIntf;
938946...
939947var
940948 Owners: TFPList;
941949 i: Integer;
942950 o: TObject;
943951begin
944952 Owners:=PackageEditingInterface.GetPossibleOwnersOfUnit('/full/path/of/unit.pas',[]);
945953 if Owners=nil then begin
946954 // unit is not directly associated with a project/package
947955 // maybe the unit was for some reason not added, but is reachable
948956 // search in all unit paths of all projects/packages
949957 // Beware: This can lead to false hits
950958 Owners:=PackageEditingInterface.GetPossibleOwnersOfUnit('/full/path/of/unit.pas',
951959 [piosfExcludeOwned,piosfIncludeSourceDirectories]);
952960 end;
953961 if Owners=nil then exit;
954962 try
955963 for i:=0 to Owners.Count-1 do begin
956964 o:=TObject(Owners[i]);
957965 if o is TIDEPackage then begin
958966 writeln('Owner is package ',TIDEPackage(o).Name);
959967 end else if o is TLazProject then begin
960968 writeln('Owner is project ',TLazProject(o).ProjectInfoFile);
961969 end;
962970 end;
963971 finally
964972 Owners.Free;
965973 end;
966974```
967975
968976# Ventanas
969977
970978Hay básicamente cuatro tipos de ventandas del IDE:
971979
972980- La barra principal del IDE bar que es Application.MainForm. Siempre está presente.
973981- Ventanas flotantes/acoplables tales como el editor del código fuente, the Object Inspectors and Messages.
974982- Fomas modales, tales como los diálogos de búsqueda, opciones y preguntas.
975983- Sugerencias y formas de completado.
976984
977985## Añadiendo una nueva ventana de acoplado en el IDE
978986
979987Que es una ventana del IDE acoplable: Ventanas tales como el Editor de Código Fuente o el Inspector de Objetos son ventanas flotantes que se pueden acoplar si se instala un paquete de acoplamiento, y su estado, posición y tamaño se almacena y restaura en el siguiente inicio del IDE. En orden a restaurar una ventana el IDE necesita un creador como se definie en la unidad **IDEWindowIntf** del paquete IDEIntf. Cada ventana acoplable debe tener un único nombre. No usar por tanto nombres genéricos como 'FileBrowser' porque haría que entre fácilmente en conflicto con otros paquetes. Y no usar nombres cortos como 'XYZ' porque el creador es responsable de todas las formas que comiencen con dicho nombre.
980988
981989### Como registrar una ventana acoplable del IDE
982990
983991Recuerda utilizar un nombre largo única que sea un identificador pascal válido. Tus ventanas pueden tener cualquier caption que necesites.
984992
985993``` pascal
986994uses SysUtils, IDEWindowIntf;
987995...
988996var MyIDEWindow: TMyIDEWindow = nil;
989997
990998procedure CreateMyIDEWindow(Sender: TObject; aFormName: string; var AForm: TCustomForm; DoDisableAutoSizing: boolean);
991999begin
9921000 // check the name
9931001 if CompareText(aFormName,MyIDEWindowName)<>0 then exit;
9941002 // create the form if not already done and disable autosizing
9951003 IDEWindowCreators.CreateForm(MyIDEWindow,TMyIDEWindowm,DoDisableAutosizing,Application);
9961004 ... init the window ...
9971005 AForm:=MyIDEWindow;
9981006end;
9991007
10001008procedure Register;
10011009begin
10021010 IDEWindowCreators.Add('MyIDEWindow',@CreateMyIDEWindow,nil,'100','50%','+300','+20%');
10031011 // the default boundsrect of the form is:
10041012 // Left=100, Top=50% of Screen.Height, Width=300, Height=20% of Screen.Height
10051013 // when the IDE needs an instance of this window it calls the procedure CreateMyIDEWindow.
10061014end;
10071015```
10081016
10091017### Showing an IDE window
10101018
10111019**Do not use Show**. Use:
10121020
10131021``` pascal
10141022IDEWindowCreators.ShowForm(MyIDEWindow,false);
10151023```
10161024
10171025This will work with docking. The docking system might wrap the form into a docking site. The BringToFront parameter tells the docking system to make the form and all its parent sites visible and bring the top level site to the front.
10181026
10191027### Notes about IDEWindowCreators and SimpleLayoutStorage
10201028
10211029The IDEWindowCreators.SimpleLayoutStorage simply stores the BoundsRect and WindowState of all forms that were once opened. It is used as fallback if no dockmaster is installed. It stores the state even if a DockMaster is installed, so that when the dockmaster is uninstalled the forms bounds are restored.
10221030
10231031The IDEWindowCreators is used by all dockable forms to register themselves and to show forms. When showing a form the Creator checks if a IDEDockMaster is installed and will delegate the showing to it. If no IDEDockMaster is installed it simply shows the form. The IDEDockMaster can use the information in the IDEWindowCreators to create forms by names and get an idea where to place a form when showing it for the first time. For more details see the packages AnchorDockingDsgn and EasyDockMgDsgn.
10241032
10251033# CodeTools
10261034
10271035The CodeTools is a package providing a vast amount of functions to parse, search and change pascal sources and some basic functions for other languages as well. You can use them without the IDE too. It is recommended that you read first about the CodeTools in general before using them in the IDE: [[Codetools]].
10281036
10291037Before calling any of the CodeTools functions in the IDE you should commit the current changes of the source editor to the CodeTools buffers:
10301038
10311039``` pascal
10321040uses LazIDEIntf;
10331041...
10341042 // save changes in source editor to codetools
10351043 LazarusIDE.SaveSourceEditorChangesToCodeCache(-1); // -1: commit all source editors
10361044```
10371045
10381046## Adding a resource directive to a file
10391047
10401048This adds a {\$R example.res} to a pascal unit:
10411049
10421050``` pascal
10431051procedure AddResourceDirectiveToPascalSource(const Filename: string);
10441052var
10451053 ExpandedFilename: String;
10461054 CodeBuf: TCodeBuffer;
10471055begin
10481056 // make sure the filename is trimmed and contains a full path
10491057 ExpandedFilename:=CleanAndExpandFilename(Filename);
10501058
10511059 // save changes in source editor to codetools
10521060 LazarusIDE.SaveSourceEditorChangesToCodeCache(-1);
10531061
10541062 // load the file
10551063 CodeBuf:=CodeToolBoss.LoadFile(ExpandedFilename,true,false);
10561064
10571065 // add the resource directive
10581066 if not CodeToolBoss.AddResourceDirective(CodeBuf,'example.res') then
10591067 LazarusIDE.DoJumpToCodeToolBossError;
10601068end;
10611069```
10621070
10631071The codetools provides also functions like FindResourceDirective and RemoveDirective.
10641072
10651073## Getting the search paths for units and include files
10661074
10671075There are many different search paths in the IDE from projects, packages, the fpc and lazarus directory and there are many types of paths: before or after resolving macros, with or without inherited search paths, as relative or absolute paths. All files in a directory share the same set of search paths. You can get the search paths for each directory fully resolved by asking the codetools:
10681076
10691077``` pascal
10701078uses CodeToolManager;
10711079...
10721080
10731081Dir:=''; // the empty directory is for new files and has the same settings as the project directory
10741082
10751083// Getting the search paths for include files:
10761084Path:=CodeToolBoss.GetIncludePathForDirectory(Dir);
10771085
10781086// Getting the search paths for units:
10791087// This search path is passed to the compiler.
10801088// It contains the package output directories, but not the package source directories.
10811089Path:=CodeToolBoss.GetUnitPathForDirectory(Dir);
10821090
10831091// There can be additional unit search paths for the IDE only (not passed to the compiler)
10841092Path:=CodeToolBoss.GetSrcPathForDirectory(Dir);
10851093
10861094// The complete search path contains also all package source paths for units:
10871095Path:=CodeToolBoss.GetCompleteSrcPathForDirectory(Dir);
10881096```
10891097
10901098# Source Editor
10911099
10921100## Active source editor
10931101
10941102``` pascal
10951103uses SrcEditorIntf;
10961104...
10971105Editor:=SourceEditorManagerIntf.ActiveEditor;
10981106if Editor=nil then exit;
10991107Filename:=Editor.FileName;
11001108ScreenPos:=Editor.CursorScreenXY;
11011109TextPos:=Editor.CursorTextXY;
11021110```
11031111
11041112# SynEdit
11051113
11061114## Getting the settings for a TSynEdit
11071115
11081116When you have a dialog using a TSynEdit and you want to use the same font and settings like the source editor use:
11091117
11101118``` pascal
11111119uses SrcEditorIntf;
11121120...
11131121SourceEditorManagerIntf.GetEditorControlSettings(ASynEdit);
11141122```
11151123
11161124## Getting the settings for a SynEdit highlighter
11171125
11181126When you have a dialog using a TSynEdit with a highlighter and you want to use the same colors like the source editor highlighter for this language use:
11191127
11201128``` pascal
11211129uses SrcEditorIntf;
11221130...
11231131SourceEditorManagerIntf.GetHighlighterSettings(ASynHighlighter);
11241132```
11251133
11261134See for an example: TSQLStringsPropertyEditorDlg.Create in the unit [SQLStringsPropertyEditorDlg](http://svn.freepascal.org/svn/lazarus/trunk/components/sqldb/sqlstringspropertyeditordlg.pas).
11271135
11281136# Help
11291137
11301138## Adding help for sources
11311139
11321140First create a THelpDatabase:
11331141
11341142``` pascal
11351143HelpDB := TFPDocHTMLHelpDatabase(
11361144 HelpDatabases.CreateHelpDatabase('ANameOfYourChoiceForTheDatabase',
11371145 TFPDocHTMLHelpDatabase,true));
11381146HelpDB.DefaultBaseURL := 'http://your.help.org/';
11391147
11401148FPDocNode := THelpNode.CreateURL(HelpDB,
11411149 'Package1 - A new package',
11421150 'file://index.html');
11431151HelpDB.TOCNode := THelpNode.Create(HelpDB,FPDocNode);// once as TOC
11441152DirectoryItem := THelpDBISourceDirectory.Create(FPDocNode,'$(PkgDir)/lcl',
11451153 '*.pp;*.pas',false);// and once as normal page
11461154HelpDB.RegisterItem(DirectoryItem);
11471155```
11481156
11491157## Adding lines to the messages window
11501158
11511159``` pascal
11521160unit IDEMsgIntf;
11531161...
11541162var Dir: String;
11551163begin
11561164 Dir:=GetCurrentDir;
11571165 IDEMessagesWindow.BeginBlock;
11581166 IDEMessagesWindow.AddMsg('unit1.pas(30,4) Error: Identifier not found "a"',Dir,0);
11591167 IDEMessagesWindow.EndBlock;
11601168end;
11611169```
11621170
11631171# Miscellaneous
11641172
11651173## Adding a macro
11661174
11671175You can add your own IDE macros:
11681176
11691177``` pascal
11701178uses MacroIntf, MacroDefIntf;
11711179
11721180procedure Register;
11731181begin
11741182 // registering a Macro with a fixed value:
11751183 IDEMacros.Add(TTransferMacro.Create('MyMacro1','Value','Description',nil,[]));
11761184end;
11771185
11781186// registering a Macro with a dynamic value requires a method of an object
11791187procedure TForm1.Init;
11801188begin
11811189 IDEMacros.Add(TTransferMacro.Create('MyMacro','Value','Description',@OnResolveMyMacro,[]));
11821190end;
11831191
11841192function TForm1.OnResolveMyMacro(const s: string; const Data: PtrInt;
11851193 var Abort: boolean): string;
11861194// s is the parameter. For example $MyMacro(parameter)
11871195// Data is the querying instance. Can be nil.
11881196// If there is an error set Abort to true.
11891197// The result string can contain macros. For example Result:='$(FPCVer)/$(TargetOS)';
11901198begin
11911199 Result:='MyValue';
11921200end;
11931201```
11941202
11951203## Depurando el IDE
11961204
11971205- Compila el IDE como habitualmente e.g. via Tools/Build de Lazarus. Asegúrate de establecer los flags de depuración tales como -g o -gw2. Lo mejor es utilizar el profile "Debug IDE" que contiene algunos flags útiles para depuración.
11981206- Abre el proyecto ide\lazarus.lpi. No se puede compilar directamente este proyecto.
11991207- Establece los puntos de ruptura (breakpoints) acorde a tus necesidades etc y ejecuta el proyecto.
12001208
12011209## See also
12021210
12031211- [[Creating IDE Help]]
12041212- [[Help protocol]]
12051213- [[How To Write Lazarus Component]]
12061214
12071215---
12081216*From the Free Pascal wiki, page "Extending the IDE/es", 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