Sign in Join
Wiki copytemporary

Extending the IDE/de: what changed

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

OldNewLine
11# Erweitern der IDE
22
33## Überblick
44
55Die IDE unterstützt verschiedene Erweiterungen:
66
77Komponenten
88Komponenten werden in der Palette installiert. Z.B. TButton erzeugt Buttons.
99
1010Komponenten-Editoren
1111Komponenteneditoren werden benutzt, wenn Sie auf eine Komponente im Designer doppelklicken oder um einige extra Items im Popupmenü des Designers hinzuzufügen, indem man auf eine Komponente rechtsklickt.
1212
1313Eigenschafts-Editoren
1414Stellen die Editierfähigkeiten im Objektinspektor zur Verfügung.
1515
1616Experten
1717Das sind alle anderen Typen von Editoren. Sie registrieren neue Menüpunkte, Tastenkürzel oder erweitern andere Merkmale der IDE.
1818
1919Es gibt 2 Möglichkeiten, Ihre eigenen Plugins in Lazarus zu integrieren:
2020
21211. Erstellen Sie ein Package, installieren Sie es und registrieren Sie das Plugin mit der Prozedur 'Register' in einer Unit.
22222. Erweitern Sie den Lazarus Code und senden Sie Ihr SVN diff an die Lazarus-Mailing-Liste.
2323
2424# Menüpunkte
2525
2626Sie können neue Menüpunkte anfügen, bestehende Menüpunkte verstecken oder verschieben und Untermenüs oder Abschnitte hinzufügen. Für Ihre eigenen Formulare können Sie das TMainMenu/TPopupMenu registrieren, sodass andere Packages darauf zugreifen und Ihr Formular erweitern können. Die Unit **MenuIntf** des IDEIntf-Packages enthält die gesamte Registrierung für Menüs und viele Standard-Menüpunkte der IDE selbst.
2727
2828## Einen Menüpunkt hinzufügen
2929
3030Ein einzelner Menüpunkt wie 'View Object Inspector' wird **TIDEMenuCommand** genannt. Sie können einen erzeugen mit dem Befehl **RegisterIDEMenuCommand**, der in zwei Formen mit Unmengen von Parametern vorkommen kann:
3131
3232``` pascal
3333function RegisterIDEMenuCommand(Parent: TIDEMenuSection;
3434 const Name, Caption: string;
3535 const OnClickMethod: TNotifyEvent = nil;
3636 const OnClickProc: TNotifyProcedure = nil;
3737 const Command: TIDECommand = nil;
3838 const ResourceName: String = ''
3939 ): TIDEMenuCommand; overload;
4040function RegisterIDEMenuCommand(const Path, Name, Caption: string;
4141 const OnClickMethod: TNotifyEvent = nil;
4242 const OnClickProc: TNotifyProcedure = nil;
4343 const Command: TIDECommand = nil;
4444 const ResourceName: String = ''
4545 ): TIDEMenuCommand; overload;
4646```
4747
4848Der Unterschied zwischen diesen beiden Formen liegt nur darin, wie Sie die 'parent menu section' angeben. Geben Sie diesen Menüabschnitt direkt an oder oder indirekt mittels eines Pfades. Viele Standardmenüs finden Sie in der Unit *MenuIntf*. Zum Beispiel den Abschnitt **mnuTools**, der das Menü *Tools* aus dem IDE-Hauptmenü liefert. Es enthält einen Abschnitt **itmSecondaryTools**, das ist der empfohlene Abschnitt für "Third party tools".
4949
5050Das folgende Beispiel registriert einen neuen Menübefehl mit dem Namen 'MyTool', der Beschriftung 'Start my tool' und führt beim Klicken die Prozedur *StartMyTool* aus:
5151
5252``` pascal
5353procedure StartMyTool;
5454begin
5555 ...wird ausgeführt, wenn der Menüpunkt angeklickt wird...
5656end;
5757
5858procedure Register;
5959begin
6060 RegisterIDEMenuCommand(itmSecondaryTools, 'MyTool','Start my tool',nil,@StartMyTool);
6161end;
6262```
6363
6464Falls Sie statt der Prozedur eine Methode aufrufen wollen, dann verwenden Sie den **OnClickMethod** Parameter.
6565
6666Dieser Menüpunkt hat kein Tastenkürzel. Wenn Sie ein Tastenkürzel brauchen, dann erzeugen Sie einen **TIDECommand** und übergeben das Kürzel im **Command** Parameter. Zum Beispiel:
6767
6868``` pascal
6969uses ... IDECommands, MenuIntf;
7070...
7171var
7272 Key: TIDEShortCut;
7373 Cat: TIDECommandCategory;
7474 CmdMyTool: TIDECommand;
7575begin
7676 // register IDE shortcut and menu item
7777 Key := IDEShortCut(VK_UNKNOWN,[],VK_UNKNOWN,[]);
7878 Cat := IDECommandList.FindCategoryByName(CommandCategoryToolMenuName);
7979 CmdMyTool := RegisterIDECommand(Cat,'Start my tool', 'Starts my tool to do some stuff', Key, nil, @StartMyTool);
8080 RegisterIDEMenuCommand(itmSecondaryTools, 'MyTool', 'Start my tool', nil, nil, CmdMyTool);
8181end;
8282```
8383
8484# Konfigurationsdateien
8585
8686## Laden/Speichern von Einstellungen
8787
8888Alle Konfigurationsdateien der IDE werden in einem einzigen Verzeichnis als xml-Dateien gespeichert. Auch Packages können dort ihre eigenen Dateien ablegen. Das primäre Konfigurationsverzeichnis kann ermittelt werden mit:
8989
9090``` pascal
9191uses LazIDEIntf;
9292...
9393 Directory := LazarusIDE.GetPrimaryConfigPath;
9494```
9595
9696Packages erzeugen ihre eigenen xml-Dateien mit:
9797
9898``` pascal
9999uses
100100 ..., LCLProc, BaseIDEIntf, LazConfigStorage;
101101
102102const
103103 Version = 1;
104104var
105105 Config: TConfigStorage;
106106 SomeValue: String;
107107 SomeInteger: Integer;
108108 SomeBoolean: Boolean;
109109 FileVersion: LongInt;
110110begin
111111 SomeValue:='Default';
112112 SomeInteger:=3;
113113 SomeBoolean:=true;
114114
115115 // speichere die Einstellungen
116116 try
117117 Config:=GetIDEConfigStorage('mysettings.xml',false);
118118 try
119119 // store the version number so future extensions can handle old config files
120120 Config.SetDeleteValue('Path/To/The/Version',Version,0);
121121 // store string variable "SomeValue"
122122 // if SomeValue has the default value the entry is not stored,
123123 // so only the differences to the default are stored.
124124 // This way the xml is kept short and defaults may change in future.
125125 Config.SetDeleteValue('Path/To/Some/Value',SomeValue,'Default');
126126 Config.SetDeleteValue('Path/To/Some/Integer',SomeInteger,3);
127127 Config.SetDeleteValue('Path/To/Some/Boolean',SomeBoolean,true);
128128 // there are more overloads for SetDeleteValue, find out with Ctrl+Space
129129 finally
130130 Config.Free;
131131 end;
132132
133133 except
134134 on E: Exception do begin
135135 DebugLn(['Saving mysettings.xml failed: ',E.Message]);
136136 end;
137137 end;
138138
139139 // lade die Einstellungen
140140 try
141141 Config:=GetIDEConfigStorage('mysettings.xml',true);
142142 try
143143 // read the version of the config
144144 FileVersion:=Config.GetValue('Path/To/The/Version',0);
145145 // read a string variable "SomeValue". If the entry does not exist, use
146146 // the Default
147147 SomeValue:=Config.GetValue('Path/To/Some/Value','Default');
148148 SomeInteger:=Config.GetValue('Path/To/Some/Integer',3);
149149 SomeBoolean:=Config.GetValue('Path/To/Some/Boolean',true);
150150 finally
151151 Config.Free;
152152 end;
153153 except
154154 on E: Exception do begin
155155 DebugLn(['Loading mysettings.xml failed: ',E.Message]);
156156 end;
157157 end;
158158end;
159159```
160160
161161# Komponenten
162162
163163## Komponenten schreiben
164164
165165Sie können mit dem Lazarus Package-Editor eine neue, eigene Komponente erstellen. Sie erreichen den Editor über die Menüführung "Datei --\> Neu --\> Package, Standard Package". Es öffnet sich ein Fenster mit dem Datei- und Komponentenbaum Ihres Packages. Über die dort angezeigten Schaltflächen können Sie Ihr Package einrichten:
166166
167167- **Speichern:** Hier können Sie Ihre Komponente oder Ihr Package unter einen Namen Ihrer Wahl speichern.
168168- **Hinzufügen:** Hier erscheint ein Fenster mit mehreren Tabs. Die wichtisten im Überblick: Im Tab *Neue Datei* können Sie zum Beispiel Units und Formulardateien für Ihr Projekt erstellen. Eine bereits vorhandene Unit können Sie im Reiter *Neue Unit* einbinden. Wenn Sie Ihre Komponente auf eine bereits existierende Komponente aufbauen wollen, können Sie diese im Tab *Neue Komponente* auswählen.
169169- **Einstellungen:** In diesem Dialog können Sie neben der Beschreibung Ihrer Komponente und ihrer Versionierung auch den Package-Typ einstellen sowie Sprachregelungen treffen.
170170- **Installieren:** Wenn Ihre Komponente fertig erstellt ist, können Sie sie über diesen Knopf in die IDE einbinden.
171171- **Compilereinstellungen:** Hier lässt sich festlegen, mit welchen Optionen und Compiler-Argumenten Ihr Package kompiliert werden soll.
172172
173173**Hinweis**: Detailierte Informationen zum Package-Editor finden Sie [[IDE Window: Package Editor/de|hier.]]
174174
175175*Beispiel: Eine von TButton abgeleitete Komponente erstellen:*
176176
1771771. Öffnen Sie den Package-Editor wie oben geschrieben
1781782. Klicken Sie auf "Hinzufügen --\> Neue Komponente"
1791793. Wählen Sie als Basisklasse "TButton", und füllen die Felder wie folgt aus: Neuer Klassenname: TMeinButton, Palettenseite: Misc, Unit Dateiname: meinbutton.pas (diese Datei wird erstellt), Unit Name: MeinButton
1801804. Klicken Sie auf Ok - und schon können Sie in der Unit meinbutton.pas den TButton an Ihre Bedürfnisse anpassen.
181181
182182### Einer neuen Komponente ein Icon für die Komponentenpalette geben
183183
184184Zum Beispiel wollen wir TMyButton ein Icon geben. Erzeugen sie eine Bilddatei im Format .bmp, .xpm oder .png mit dem selben Namen wie die Komponentenklasse, z.B. *tmybutton.png* und speichern sie diese im Package-Quelltextverzeichnis. Das Bild kann mit einem beliebigen Grafikprogramm (z.B. Gimp) erzeugt werden und sollte nicht größer sein als 24x24 Pixel. Konvertieren Sie das Bild in eine .lrs Datei mit dem 'lazres' Werkzeug, das Sie im Verzeichnis 'lazarus/tools' finden:
185185
186-` ~/lazarus/tools/lazres mybutton.lrs tmybutton.png`
186+```text
187+ ~/lazarus/tools/lazres mybutton.lrs tmybutton.png
188+```
187189
188190Das erzeugt eine Pascal Include Datei, die im Initialisierungs-Abschnitt von mybutton.pas verwendet wird:
189191
190-` initialization`\
191-`   {$I mybutton.lrs}`
192+```text
193+ initialization
194+ {$I mybutton.lrs}
195+```
192196
193197Installieren Sie das Package.
194198
195199### Eine Komponente aus der Palette verstecken
196200
197201Package IDEIntf, unit componentreg:
198202
199-`IDEComponentPalette.FindComponent('TButton').Visible:=false;`
203+``` pascal
204+IDEComponentPalette.FindComponent('TButton').Visible:=false;
205+```
200206
201207## Komponenten-Editoren schreiben
202208
203209Ein Komponenten-Editor verarbeitet Dinge wie einen Doppelklick auf eine Komponente im Designer oder das Hinzufügen von Menüpunkten bei einem Rechtsklick auf eine Komponente. Einen Komponenten-Editor zu schreiben ist einfach. Siehe die Unit *componenteditors.pas* vom Package *IDEIntf* für zahlreiche Beispiele. Um beispielweise beim Doppelklick einen Editor anzuzeigen, siehe: TCheckListBoxComponentEditor.
204210
205211## Eigenschafts-Editoren schreiben
206212
207213Jeder Eigenschaftstyp (integer, string, TFont, ...) im Objektinspektor benötigt einen Eigenschafts-Editor. Wenn Ihre Komponente eine Eigenschaft 'Password' vom Typ *string* hat, können Sie einen Eigenschafts-Editor definieren für Ihre besondere Komponenten-Klasse, mit genau diesem Typ. Die Unit *propedits.pp* aus dem Package *IDEIntf* enthält viele der Standard-Eigenschafts-Editoren, die von der IDE selbst verwendet werden. Zum Beispiel ist der *TStringPropertyEditor* der vorgegebene Editor für alle Strings, während *TComponentNamePropertyEditor* spezieller ist und nur *TComponent.Name* bearbeitet.
208214
209215# Designer
210216
211217## Einen Designer-Mediator schreiben
212218
213219Der Standard-Designer erlaubt es, die Steuerelemente der LCL visuell zu bearbeiten, wo hingegen alle anderen nur als Symbole angezeigt werden. Um Steuerelemente (die nicht aus der LCL stammen) ebenfalls visuell bearbeiten zu können, sollten Sie einen **Designer-Mediator** erzeugen. Dieser kann dazu verwendet werden, Webseiten zu entwerfen, UML Diagramme oder andere Widgetsets wie [[fpGUI]]. Es gibt ein ausführliches Beispiel unter: in examples/designnonlcl/.
214220
215221- Installieren Sie das Beispielspackage examples/designnonlcl/notlcldesigner.lpk und starten Sie die IDE neu. Dadurch werden der Designer-Mediator für TMyWidget-Komponenten registriert und die neuen Komponenten TMyButton, TMyGroupBox zur Komponentenpalette hinzugefügt.
216222- Öffnen Sie das Beispielsprojekt examples/designnonlcl/project/NonLCL1.lpi.
217223- Öffnen Sie die unit1.pas und zeigen Sie das Formular im Designer an (mit F12). Sie sollten jetzt die Komponenten als rote Rechtecke dargestellt sehen, die Sie genau so wie LCL-Steuerelemente auswählen, verschieben oder in der Größe verändern können.
218224
219225## Einen neuen einzigartigen Komponentennamen erzeugen
220226
221227``` pascal
222228uses FormEditingIntf;
223229
224230...
225231
226232NewName:=FormEditingHook.CreateUniqueComponentName(AComponent);
227233
228234// Or if you need to create the name before creating the component:
229235
230236NewName:=FormEditingHook.CreateUniqueComponentName(ComponentClassName,OwnerComponent);
231237// ComponentClassName will be used as prefix, without a leading T.
232238// OwnerComponent is the new owner of the new component.
233239```
234240
235241## Eine Komponente im Designer/Objektinspektor auswählen
236242
237243``` pascal
238244uses propedits;
239245..
240246GlobalDesignHook.SelectOnlyThis(AComponent);
241247```
242248
243249# Ereignis-Handler
244250
245251Es gibt einige Ereignisse in der IDE, für die Plugins ihre eigenen Handler hinzufügen können.
246252
247253## Designerereignisse
248254
249255In propedits.pp gibt es ein "GlobalDesignHook" Objekt, das verschiedene Ereignisse zum Entwurf verwaltet. Jedes Ereignis ruft eine List von Handlern auf. Die Vorgabe-Handler werden von der IDE angefügt. Sie können eigene Handler mit den Methoden *AddHandlerXXX* und *RemoveHandlerXXX* anfügen. Diese werden aufgerufen vor den Vorgabe-Handlern.
250256
251257Beispiele:
252258
253-` Einfügen Ihres Handlers (das geschieht normalerweise im Konstruktor Ihres Objekts):`\
254-`   GlobalDesignHook.AddHandlerComponentAdded(@YourOnComponentAdded);`\
255-`  Entfernen Ihrer Handlers:`\
256-`   GlobalDesignHook.RemoveHandlerComponentAdded(@YourOnComponentAdded);`\
257-`  Sie können alle Handler auf einmal entfernen. Zum Beispiel, ist es eine gute Idee,`\
258-` diese Zeile im Destruktor des Objekts anzufügen:`\
259-`   GlobalDesignHook.RemoveAllHandlersForObject(Self);`
259+```text
260+ Einfügen Ihres Handlers (das geschieht normalerweise im Konstruktor Ihres Objekts):
261+ GlobalDesignHook.AddHandlerComponentAdded(@YourOnComponentAdded);
262+ Entfernen Ihrer Handlers:
263+ GlobalDesignHook.RemoveHandlerComponentAdded(@YourOnComponentAdded);
264+ Sie können alle Handler auf einmal entfernen. Zum Beispiel, ist es eine gute Idee,
265+ diese Zeile im Destruktor des Objekts anzufügen:
266+ GlobalDesignHook.RemoveAllHandlersForObject(Self);
267+```
260268
261269Die Handler von GlobalDesignHook:
262270
263-` // lookup root`\
264-` ChangeLookupRoot`\
265-`   Called when the "LookupRoot" changed.`\
266-`   The "LookupRoot" is the owner object of the currently selected components.`\
267-`   Normally this is a TForm.`\
268-`  // methods`\
269-` CreateMethod`\
270-` GetMethodName`\
271-` GetMethods`\
272-` MethodExists`\
273-` RenameMethod`\
274-` ShowMethod`\
275-`   Called`\
276-` MethodFromAncestor`\
277-` ChainCall`\
278-`  // components`\
279-` GetComponent`\
280-` GetComponentName`\
281-` GetComponentNames`\
282-` GetRootClassName`\
283-` ComponentRenamed`\
284-`   Called when a component was renamed`\
285-` ComponentAdded`\
286-`   Called when a new component was added to the LookupRoot`\
287-` ComponentDeleting`\
288-`   Called before a component is freed.`\
289-` DeleteComponent`\
290-`   Called by the IDE to delete a component.`\
291-` GetSelectedComponents`\
292-`   Get the current selection of components.`\
293-`  // persistent objects`\
294-` GetObject`\
295-` GetObjectName`\
296-` GetObjectNames`\
297-`  // modifing`\
298-` Modified`\
299-` Revert`\
300-` RefreshPropertyValues`
271+``` pascal
272+ // lookup root
273+ ChangeLookupRoot
274+ Called when the "LookupRoot" changed.
275+ The "LookupRoot" is the owner object of the currently selected components.
276+ Normally this is a TForm.
277+ // methods
278+ CreateMethod
279+ GetMethodName
280+ GetMethods
281+ MethodExists
282+ RenameMethod
283+ ShowMethod
284+ Called
285+ MethodFromAncestor
286+ ChainCall
287+ // components
288+ GetComponent
289+ GetComponentName
290+ GetComponentNames
291+ GetRootClassName
292+ ComponentRenamed
293+ Called when a component was renamed
294+ ComponentAdded
295+ Called when a new component was added to the LookupRoot
296+ ComponentDeleting
297+ Called before a component is freed.
298+ DeleteComponent
299+ Called by the IDE to delete a component.
300+ GetSelectedComponents
301+ Get the current selection of components.
302+ // persistent objects
303+ GetObject
304+ GetObjectName
305+ GetObjectNames
306+ // modifing
307+ Modified
308+ Revert
309+ RefreshPropertyValues
310+```
301311
302312## Benachrichtigt werden, wenn ein Formular im Designer modifiziert wurde
303313
304314Jedes LCL-Formular hat einen Designer des Typs TIDesigner. Die IDE erzeugt Designer der Type TComponentEditorDesigner, die in der IDEIntf Unit componenteditors definiert ist. Ein Beispiel:
305315
306316``` pascal
307317procedure TYourAddOn.OnDesignerModified(Sender: TObject);
308318var
309319 IDEDesigner: TComponentEditorDesigner;
310320begin
311321 IDEDesigner:=TComponentEditorDesigner(Sender);
312322 ...
313323end;
314324
315325procedure TYourAddOn.ConnectDesignerForm(Form1: TCustomForm);
316326var
317327 IDEDesigner: TComponentEditorDesigner;
318328begin
319329 IDEDesigner:=TComponentEditorDesigner(Form1.Designer);
320330 IDEDesigner.AddHandlerModified(@OnDesignerModified);
321331end;
322332```
323333
324334## Projektereignisse
325335
326336Diese Ereignisse sind definiert in der Unit LazIDEIntf.
327337
328338- **LazarusIDE.AddHandlerOnProjectClose**: wird aufgerufen bevor ein Projekt geschlossen wird
329339- **LazarusIDE.AddHandlerOnProjectOpened**: wird aufgerufen nachdem das Projekt vollständig geöffnet wurde (wenn beispielsweise alle erforderlichen Packages geladen und die Units im Quelltext-Editor geöffnet wurden)
330340- **LazarusIDE.AddHandlerOnSavingAll**: wird aufgerufen bevor die IDE alles speichert
331341- **LazarusIDE.AddHandlerOnSavedAll**: wird aufgerufen nachdem die IDE alles gespeichert hat
332342- **LazarusIDE.AddHandlerOnProjectBuilding**: wird aufgerufen bevor die IDE das Projekt erstellt
333343- **LazarusIDE.AddHandlerOnProjectDependenciesCompiling**: wird aufgerufen bevor die IDE die Packageabhängigkeiten eines Projekts kompiliert
334344- **LazarusIDE.AddHandlerOnProjectDependenciesCompiled**: wird aufgerufen nachdem die IDE die Packageabhängigkeiten eines Projekts kompiliert hat
335345
336346## Andere IDE Ereignisse
337347
338348- **LazarusIDE.AddHandlerOnIDERestoreWindows**: wird aufgerufen, wenn die IDE ihre Fernster wiederherstellt (bevor das erste Projekt geöffnet wird)
339349- **LazarusIDE.AddHandlerOnIDEClose**: wird aufgerufen, wenn die IDE beendet wird (nach closequery, also keine Interaktivität mehr)
340350- **LazarusIDE.AddHandlerOnQuickSyntaxCheck**: wird aufgerufen, wenn der Menüpunkt oder das Tastenkürzel für die Schnelle Syntaxüberprüfung aussgeführt wird
341351
342352# Projekt
343353
344354## Aktuelles Projekt
345355
346356Das aktuelle Hauptprojekt erhalten Sie mit LazarusIDE.ActiveProject. (unit LazIDEIntf)
347357
348358## Alle Units des aktuellen Projekts
349359
350360Um alle Pascal-Units des aktuellen Hauptprojektes der IDE zu durchlaufen benutzen Sie zum Beispiel:
351361
352362``` pascal
353363uses LCLProc, FileUtil, LazIDEIntf, ProjectIntf;
354364
355365procedure ListProjectUnits;
356366var
357367 LazProject: TLazProject;
358368 i: Integer;
359369 LazFile: TLazProjectFile;
360370begin
361371 LazProject:=LazarusIDE.ActiveProject;
362372 if LazProject<>nil then
363373 for i:=0 to LazProject.FileCount-1 do
364374 begin
365375 LazFile:=LazProject.Files[i];
366376 if LazFile.IsPartOfProject
367377 and FilenameIsPascalUnit(LazFile.Filename)
368378 then
369379 debugln(LazFile.Filename);
370380 end;
371381end;
372382```
373383
374384## Die .lpr, .lpi und .lps Datei eines Projekts
375385
376386``` pascal
377387uses LCLProc, FileUtil, ProjectIntf, LazIDEIntf;
378388var
379389 LazProject: TLazProject;
380390begin
381391 LazProject:=LazarusIDE.ActiveProject;
382392 // jedes Projekt hat eine .lpi Datei:
383393 DebugLn(['Project'' lpi file: ',LazProject.ProjectInfoFile]);
384394
385395 // if the project session information is stored in a separate .lps file:
386396 if LazProject.SessionStorage<>pssNone then
387397 DebugLn(['Project'' lps file: ',LazProject.ProjectSessionFile]);
388398
389399 // If the project has a .lpr file it is the main source file:
390400 if (LazProject.MainFile<>nil)
391401 and (CompareFileExt(LazProject.MainFile.Filename,'lpr')=0) then
392402 DebugLn(['Project has lpr file: ',LazProject.MainFile.Filename]);
393403end;
394404```
395405
396406## Der Name der ausführbaren Ziel-Datei eines Projekts
397407
398408Es gibt ein Makro \$(TargetFile), das in Pfaden und externen Werkzeugen verwendet werden kann. Beispiel:
399409
400410``` pascal
401411uses MacroIntf;
402412
403413function MyGetProjectTargetFile: string;
404414begin
405415 Result:='$(TargetFile)';
406416 if not IDEMacros.SubstituteMacros(Result) then
407417 raise Exception.Create('unable to retrieve target file of project');
408418end;
409419```
410420
411421Für weitere Makros siehe: [[IDE Macros in paths and filenames/de|IDE Makros in Pfaden und Dateinamen]].
412422
413423## Hinzufügen Ihres eigenen Projekttyps
414424
415425Sie können Menüpunkte zum Dialog 'Neu ...' hinzufügen:
416426
417427- Siehe die Unit ProjectIntf aus dem Package IDEIntf.
418428- Siehe die [[Project Templates]]
419429
420430## Hinzufügen Ihres eigenen Dateityps
421431
422432Sie können Einträge hinzufügen zum Dialog 'Neu ...':
423433
424434- Siehe die Unit ProjectIntf aus dem Package IDEIntf.
425435- Wählen Sie eine Basisklasse TFileDescPascalUnit für normale Units oder TFileDescPascalUnitWithResource für ein neues Formular/Datenmodul.
426436
427437### Hinzufügen eines neuen Dateityps
428438
429439Dieses Beispiel entstammt der ide/mainintf.pas Datei und registriert eine einfache Textdatei:
430440
431441``` pascal
432442uses ProjectIntf;
433443...
434444 { TFileDescText }
435445
436446 TFileDescMyText = class(TProjectFileDescriptor)
437447 public
438448 constructor Create; override;
439449 function GetLocalizedName: string; override;
440450 function GetLocalizedDescription: string; override;
441451 end;
442452...
443453
444454procedure Register;
445455
446456implementation
447457
448458procedure Register;
449459begin
450460 RegisterProjectFileDescriptor(TFileDescMyText.Create,FileDescGroupName);
451461end;
452462
453463{ TFileDescMyText }
454464
455465constructor TFileDescMyText.Create;
456466begin
457467 inherited Create;
458468 Name:='MyText'; // do not translate this
459469 DefaultFilename:='text.txt';
460470 AddToProject:=false;
461471end;
462472
463473function TFileDescText.GetLocalizedName: string;
464474begin
465475 Result:='My Text'; // replace this with a resourcestring
466476end;
467477
468478function TFileDescText.GetLocalizedDescription: string;
469479begin
470480 Result:='An empty text file';
471481end;
472482```
473483
474484### Hinzufügen eines neuen Formulartyps
475485
476486Diese Beispiel ist aus 'ide/mainintf.pas' und registriert das normale Formular:
477487
478488``` pascal
479489uses ProjectIntf;
480490
481491...
482492 TFileDescPascalUnitWithMyForm = class(TFileDescPascalUnitWithResource)
483493 public
484494 constructor Create; override;
485495 function GetInterfaceUsesSection: string; override;
486496 function GetLocalizedName: string; override;
487497 function GetLocalizedDescription: string; override;
488498 end;
489499...
490500
491501procedure Register;
492502
493503implementation
494504
495505procedure Register;
496506begin
497507 RegisterProjectFileDescriptor(TFileDescPascalUnitWithMyForm.Create,FileDescGroupName);
498508end;
499509
500510{ TFileDescPascalUnitWithMyForm }
501511
502512constructor TFileDescPascalUnitWithMyForm.Create;
503513begin
504514 inherited Create;
505515 Name:='MyForm'; // do not translate this
506516 ResourceClass:=TMyForm;
507517 UseCreateFormStatements:=true;
508518end;
509519
510520function TFileDescPascalUnitWithMyForm.GetInterfaceUsesSection: string;
511521begin
512522 Result:='Classes, SysUtils, MyWidgetSet';
513523end;
514524
515525function TFileDescPascalUnitWithForm.GetLocalizedName: string;
516526begin
517527 Result:='MyForm'; // replace this with a resourcestring
518528end;
519529
520530function TFileDescPascalUnitWithForm.GetLocalizedDescription: string;
521531begin
522532 Result:='Create a new MyForm from example package NotLCLDesigner';
523533end;
524534```
525535
526536# Packages
527537
528538## Suche in allen Packages
529539
530540Durchsuche alle Packages die in der IDE geladen sind (seit Version 0.9.29):
531541
532542``` pascal
533543uses PackageIntf;
534544...
535545for i:=0 to PackageEditingInterface.GetPackageCount-1 do
536546 writeln(PackageEditingInterface.GetPackages(i).Name);
537547```
538548
539549## Suche ein Package mit einem bestimmten Namen
540550
541551``` pascal
542552uses PackageIntf;
543553...
544554var
545555 Pkg: TIDEPackage;
546556begin
547557 Pkg:=PackageEditingInterface.FindPackageWithName('LCL');
548558 if Pkg<>nil then
549559 ...
550560end;
551561```
552562
553563Anmerkung: 'FindPackageWithName' öffnet nicht den Package-Editor. Benutzen Sie dazu 'DoOpenPackageWithName'.
554564
555565## Installieren von Packages
556566
557567**Anmerkung**: Installieren Sie nur Packages mit IDE-Plugins. Andere Packages zu installieren, kann die IDE instabil machen.
558568
559569``` pascal
560570uses PackageIntf, contnrs;
561571
562572 PkgList:=TObjectList.create(true);
563573 try
564574 Pkg:=TLazPackageID.Create;
565575 Pkg.Name:='Cody';
566576 PkgList.Add(Pkg);
567577 // überprüft, ob die IDE die Datei 'cody.lpk' und alle Abhängigkeiten finden kann
568578 // Die IDE gibt einige Warnungen/Bestätigungen aus, falls ihr irgendetwas seltsam vorkommt.
569579 if not PackageEditingInterface.CheckInstallPackageList(PkgList,[]) then
570580 exit;
571581 // in diesem Beispiel haben wir bereits überprüft, deshalb Warnungen überspringen
572582 // und die IDE neu erstellen
573583 if PackageEditingInterface.InstallPackages(PkgList,[piiifSkipChecks,piiifRebuildIDE])<>mrOK then
574584 exit;
575585 finally
576586 PkgList.Free;
577587 end;
578588```
579589
580590# Fenster
581591
582592Grundsätzlich gibt es vier Typen von IDE Fenstern:
583593
584594- die IDE Hauptleiste ist in Application.MainForm. Sie ist immer präsent.
585595- schwebende/andockbare Fenster (wie die Quelltext-Editoren, der Objektinspektor und die Meldungen)
586596- die modalen Formulare, wie der Suchen-Dialog, Einstellungen-Dialog und Rückfragen.
587597- Hints und Vervollständigungs-Formulare
588598
589599## Hinzufügen eines neuen andockbaren IDE-Fensters
590600
591601Was ist ein andockbares IDE-Fenster: Fenster wie der Quelltext-Editor oder der Objektinspektor sind schwebende Fenster, die angedockt werden können, wenn das Package 'docking' installiert ist. Sein Status, seine Position und Größe werden gespeichert und beim nächsten Start der IDE wieder abgerufen. Um ein Fenster wiederherstellen zu können, braucht die IDE einen Creator wie er in der Unit **IDEWindowIntf** des Packages 'IDEIntf' definiert ist. Jedes andockbare Fenster benötigt einen einzigartigen Namen. Verwenden Sie keine allgemeinen Namen wie 'FileBrowser' weil dies sehr leicht zu Konflikten mit anderen Packages führen kann. Und verwenden Sie keine Kurznamen wie 'XYZ', weil der Creator verantwortlich ist für alle Formulare, die mit diesem Namen beginnen.
592602
593603### Wie registriert man ein andockbares IDE-Fenster
594604
595605Vergessen Sie nicht, einen langen, uniquen Namen zu verwenden, der ein gültiger Pascal-Bezeichner ist. Ihr Fenster kann einen beliebigen Titel haben.
596606
597607``` pascal
598608uses SysUtils, IDEWindowIntf;
599609...
600610var MyIDEWindow: TMyIDEWindow = nil;
601611
602612procedure CreateMyIDEWindow(Sender: TObject; aFormName: string; var AForm: TCustomForm; DoDisableAutoSizing: boolean);
603613begin
604614 // check the name
605615 if CompareText(aFormName,MyIDEWindowName)<>0 then exit;
606616 // create the form if not already done and disable autosizing
607617 IDEWindowCreators.CreateForm(MyIDEWindow,TMyIDEWindowm,DoDisableAutosizing,Application);
608618 ... init the window ...
609619 AForm:=MyIDEWindow;
610620end;
611621
612622procedure Register;
613623begin
614624 IDEWindowCreators.Add('MyIDEWindow',@CreateMyIDEWindow,nil,'100','50%','+300','+20%');
615625 // the default boundsrect of the form is:
616626 // Left=100, Top=50% of Screen.Height, Width=300, Height=20% of Screen.Height
617627 // when the IDE needs an instance of this window it calls the procedure CreateMyIDEWindow.
618628end;
619629```
620630
621631### Anzeigen eines IDE-Fensters
622632
623633**Benutzen Sie nicht Show**. Nehmen Sie stattdessen:
624634
625635``` pascal
626636IDEWindowCreators.ShowForm(MyIDEWindow,false);
627637```
628638
629639Das wird auch mit Docking funktionieren. Das Docking-System wird das Formular in eine Docking-Site einschließen. Der Parameter 'BringToFront' befiehlt dem Docking-System, dieses Formular und all seine Eltern-Sites sichtbar zu machen und die Site der obersten Ebene in den Vordergrund zu bringen.
630640
631641### Anmerkungen über IDEWindowCreators und SimpleLayoutStorage
632642
633643Das IDEWindowCreators.SimpleLayoutStorage speichert einfach das BoundsRect und den WindowState von allen Formularen, die einmal geöffnet wurden. Es stellt ein Fallback dar, falls kein Dockmaster installiert ist. Es speichert des Zustand sogar wenn ein DockMaster installiert ist, sodass auch beim Deinstallieren des Dockmasters die Formulargrößen wiederhergestellt werden können.
634644
635645Die IDEWindowCreators werden bei allen andockbaren Formularen eingesetzt, um sich selbst zu registrieren und die Formulare anzuzeigen. Beim Anzeigen eines Formulars überprüft der Creator ob ein IDEDockMaster installiert ist und überträgt ihm die Aufgabe des Anzeigens. Ist kein IDEDockMaster installiert wird das Formular einfach angezeigt. Der IDEDockMaster kann die Informationen in den IDEWindowCreators benutzen, um benannte Formulare zu erzeugen und um festzustellen, wo ein Formular beim ersten Anzeigen zu platzieren ist. Für weitere Details siehe die Packages **AnchorDockingDsgn** und **EasyDockMgDsgn**.
636646
637647# CodeTools in der IDE
638648
639649Die CodeTools sind ein Package das eine große Anzahl von Funktionen zum Parsen, Untersuchen und Ändern von Pascal-Quelltexten zur Verfügung stellt, daneben auch einige grundlegende Funktionen für andere Sprachen. Sie können sie auch ohne die IDE einsetzen. Es wird empfohlen, dass Sie zuerst über die CodeTools im Allgemeinen nachlesen, bevor Sie sie in der IDE benutzen: [[Codetools/de|CodeTools (deutsch)]].
640650
641651Bevor Sie irgendeine der Codetools-Funktionen in der IDE aufrufen, sollten Sie die letzten Änderungen im Quelltexteditor in den Codetools-Puffern speichern:
642652
643653``` pascal
644654uses LazIDEIntf;
645655...
646656 // save changes in source editor to codetools
647657 LazarusIDE.SaveSourceEditorChangesToCodeCache(-1); // -1: commit all source editors
648658```
649659
650660## Hinzufügen einer resource Direktive zu einer Datei
651661
652662Dies fügt eine {\$R example.res} Direktive zu einer Pascal Unit hinzu:
653663
654664``` pascal
655665procedure AddResourceDirectiveToPascalSource(const Filename: string);
656666var
657667 ExpandedFilename: String;
658668 CodeBuf: TCodeBuffer;
659669begin
660670 // make sure the filename is trimmed and contains a full path
661671 ExpandedFilename:=CleanAndExpandFilename(Filename);
662672
663673 // save changes in source editor to codetools
664674 LazarusIDE.SaveSourceEditorChangesToCodeCache(-1);
665675
666676 // die Datei laden
667677 CodeBuf:=CodeToolBoss.LoadFile(ExpandedFilename,true,false);
668678
669679 // die resource Direktive hinzufügen
670680 if not CodeToolBoss.AddResourceDirective(CodeBuf,'example.res') then
671681 LazarusIDE.DoJumpToCodeToolBossError;
672682end;
673683```
674684
675685Die Codetools stellen auch Funktionen wie FindResourceDirective und RemoveDirective zur Verfügung.
676686
677687## Die Suchpfade für Units und Include-Dateien ermitteln
678688
679689In der IDE gibt es viele unterschiedliche Suchpfade von Projekten, Packages, dem FPC und Lazarus Verzeichnis und es gibt viele Arten von Pfaden: vor und nach dem Auflösen von Makros, mit oder ohne geerbte Suchpfade, als relative oder absolute Pfade. Alle Dateien in einem Verzeichnis teilen sich den selben Bestand an Suchpfaden. Sie erhalten die Suchpfade für jedes Verzeichnis voll aufgelöst durch eine Abfrage der Codetools:
680690
681691``` pascal
682692uses CodeToolManager;
683693...
684694
685695Dir:=''; // das leere Verzeichnis ist für neue Dateien und hat die selben Einstellungen wie das Projektverzeichnis
686696
687697// ermittelt die Suchpfade für Include-Dateien:
688698Path:=CodeToolBoss.GetIncludePathForDirectory(Dir);
689699
690700// ermittelt die Suchpfade für Units:
691701// Dieser Suchpfad wird an den Compiler übergeben.
692702// Er enthält die Package-Ausgabe-Verzeichnisse, aber nicht die Package-Quell-Verzeichnisse.
693703Path:=CodeToolBoss.GetUnitPathForDirectory(Dir);
694704
695705// zusätzliche Unit-Suchpfade nur für die IDE können auftreten (werden nicht an den Compiler übergeben)
696706Path:=CodeToolBoss.GetSrcPathForDirectory(Dir);
697707
698708// der vollständige Suchpfad enthält auch alle Package-Quell-Pfade für Units:
699709Path:=CodeToolBoss.GetCompleteSrcPathForDirectory(Dir);
700710```
701711
702712# Quelltext-Editor
703713
704714## Aktiver Quelltext-Editor
705715
706716``` pascal
707717uses SrcEditorIntf;
708718...
709719Editor:=SourceEditorManagerIntf.ActiveEditor;
710720if Editor=nil then exit;
711721Filename:=Editor.FileName;
712722ScreenPos:=Editor.CursorScreenXY;
713723TextPos:=Editor.CursorTextXY;
714724```
715725
716726# SynEdit
717727
718728## Die Einstellungen für einen TSynEdit holen
719729
720730Wenn Sie einen TSynEdit in einem Dialog haben und Sie wollen die selbe Schriftart und die selben Einstellungen wie im Quelltext-Editor verwenden::
721731
722732``` pascal
723733uses SrcEditorIntf;
724734...
725735SourceEditorManagerIntf.GetEditorControlSettings(ASynEdit);
726736```
727737
728738## Die Einstellungen für einen SynEdit-Highlighter holen
729739
730740Wenn Sie einen Dialog haben, der einen TSynEdit mit einem Highlighter enthält, können Sie die selben Farben wie der Highlighter des Quelltext-Editors für diese Sprache verwenden:
731741
732742``` pascal
733743uses SrcEditorIntf;
734744...
735745SourceEditorManagerIntf.GetHighlighterSettings(ASynHighlighter);
736746```
737747
738748Siehe für ein Beispiel auch: TSQLStringsPropertyEditorDlg.Create in der Unit [SQLStringsPropertyEditorDlg](http://svn.freepascal.org/svn/lazarus/trunk/components/sqldb/sqlstringspropertyeditordlg.pas).
739749
740750# Hilfe
741751
742752## Hilfe für die Quellen hinzufügen
743753
744754Erzeugen sie zuerst eine THelpDatabase:
745755
746756``` pascal
747757HelpDB := TFPDocHTMLHelpDatabase(
748758 HelpDatabases.CreateHelpDatabase('EinNameIhrerWahlFürDieDatenbank',
749759 TFPDocHTMLHelpDatabase,true));
750760 HelpDB.DefaultBaseURL := 'http://ihre.hilfe.org/';
751761
752762 FPDocNode := THelpNode.CreateURL(HelpDB,
753763 'Package1 - A new package',
754764 'file://index.html');
755765 HelpDB.TOCNode := THelpNode.Create(HelpDB,FPDocNode);// einmal als Inhaltsverzeichnis
756766 DirectoryItem := THelpDBISourceDirectory.Create(FPDocNode,'$(PkgDir)/lcl',
757767 '*.pp;*.pas',false);// und einmal als normale Seite
758768 HelpDB.RegisterItem(DirectoryItem);
759769```
760770
761771## Zeilen zum Nachrichtenfenster hinzufügen
762772
763773``` pascal
764774unit IDEMsgIntf;
765775...
766776var Dir: String;
767777begin
768778 Dir:=GetCurrentDir;
769779 IDEMessagesWindow.BeginBlock;
770780 IDEMessagesWindow.AddMsg('unit1.pas(30,4) Error: Identifier not found "a"',Dir,0);
771781 IDEMessagesWindow.EndBlock;
772782end;
773783```
774784
775785## Überblick über die verschiedenen Elemente der Hilfe
776786
777787[[Creating IDE Help/de|Hilfe für die IDE erzeugen]]
778788
779789---
780790*From the Free Pascal wiki, page "Extending the IDE/de", 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