Extending the IDE/de

From Free Pascal wiki
Jump to navigationJump to search

Deutsch (de) English (en) español (es) français (fr) 日本語 (ja) русский (ru) slovenčina (sk) 中文(中国大陆) (zh_CN)

Erweitern der IDE

Überblick

Die IDE unterstützt verschiedene Erweiterungen:

Komponenten
Komponenten werden in der Palette installiert. Z.B. TButton erzeugt Buttons.
Komponenten-Editoren
Komponenteneditoren 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.
Eigenschafts-Editoren
Stellen die Editierfähigkeiten im Objektinspektor zur Verfügung.
Experten
Das sind alle anderen Typen von Editoren. Sie registrieren neue Menüpunkte, Tastenkürzel oder erweitern andere Merkmale der IDE.


Es gibt 2 Möglichkeiten, Ihre eigenen Plugins in Lazarus zu integrieren:

  1. Erstellen Sie ein Package, installieren Sie es und registrieren Sie das Plugin mit der Prozedur 'Register' in einer Unit.
  2. Erweitern Sie den Lazarus Code und senden Sie Ihr SVN diff an die Lazarus-Mailing-Liste.

Menüpunkte

Sie 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.

Einen Menüpunkt hinzufügen

Ein 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:

function RegisterIDEMenuCommand(Parent: TIDEMenuSection;
                                const Name, Caption: string;
                                const OnClickMethod: TNotifyEvent = nil;
                                const OnClickProc: TNotifyProcedure = nil;
                                const Command: TIDECommand = nil;
                                const ResourceName: String = ''
                                ): TIDEMenuCommand; overload;
function RegisterIDEMenuCommand(const Path, Name, Caption: string;
                                const OnClickMethod: TNotifyEvent = nil;
                                const OnClickProc: TNotifyProcedure = nil;
                                const Command: TIDECommand = nil;
                                const ResourceName: String = ''
                                ): TIDEMenuCommand; overload;

Der 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".

Das 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:

procedure StartMyTool;
begin
  ...wird ausgeführt, wenn der Menüpunkt angeklickt wird...
end;

procedure Register;
begin
  RegisterIDEMenuCommand(itmSecondaryTools, 'MyTool','Start my tool',nil,@StartMyTool);
end;

Falls Sie statt der Prozedur eine Methode aufrufen wollen, dann verwenden Sie den OnClickMethod Parameter.

Dieser 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:

uses ... IDECommands, MenuIntf;
...
var
  Key: TIDEShortCut;
  Cat: TIDECommandCategory;
  CmdMyTool: TIDECommand;
begin
  // register IDE shortcut and menu item
  Key := IDEShortCut(VK_UNKNOWN,[],VK_UNKNOWN,[]);
  Cat := IDECommandList.FindCategoryByName(CommandCategoryToolMenuName);
  CmdMyTool := RegisterIDECommand(Cat,'Start my tool', 'Starts my tool to do some stuff', Key, nil, @StartMyTool);
  RegisterIDEMenuCommand(itmSecondaryTools, 'MyTool', 'Start my tool', nil, nil, CmdMyTool);
end;

Konfigurationsdateien

Laden/Speichern von Einstellungen

Alle 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:

uses LazIDEIntf;
...
  Directory := LazarusIDE.GetPrimaryConfigPath;

Packages erzeugen ihre eigenen xml-Dateien mit:

uses
  ..., LCLProc, BaseIDEIntf, LazConfigStorage;

const
  Version = 1;
var
  Config: TConfigStorage;
  SomeValue: String;
  SomeInteger: Integer;
  SomeBoolean: Boolean;
  FileVersion: LongInt;
begin
  SomeValue:='Default';
  SomeInteger:=3;
  SomeBoolean:=true;

  // speichere die Einstellungen
  try
    Config:=GetIDEConfigStorage('mysettings.xml',false);
    try
      // store the version number so future extensions can handle old config files
      Config.SetDeleteValue('Path/To/The/Version',Version,0);
      // store string variable "SomeValue"
      // if SomeValue has the default value the entry is not stored,
      // so only the differences to the default are stored.
      // This way the xml is kept short and defaults may change in future.
      Config.SetDeleteValue('Path/To/Some/Value',SomeValue,'Default');
      Config.SetDeleteValue('Path/To/Some/Integer',SomeInteger,3);
      Config.SetDeleteValue('Path/To/Some/Boolean',SomeBoolean,true);
      // there are more overloads for SetDeleteValue, find out with Ctrl+Space
    finally
      Config.Free;
    end;

  except
    on E: Exception do begin
      DebugLn(['Saving mysettings.xml failed: ',E.Message]);
    end;
  end;

  // lade die Einstellungen
  try
    Config:=GetIDEConfigStorage('mysettings.xml',true);
    try
      // read the version of the config
      FileVersion:=Config.GetValue('Path/To/The/Version',0);
      // read a string variable "SomeValue". If the entry does not exist, use
      // the Default
      SomeValue:=Config.GetValue('Path/To/Some/Value','Default');
      SomeInteger:=Config.GetValue('Path/To/Some/Integer',3);
      SomeBoolean:=Config.GetValue('Path/To/Some/Boolean',true);
    finally
      Config.Free;
    end;
  except
    on E: Exception do begin
      DebugLn(['Loading mysettings.xml failed: ',E.Message]);
    end;
  end;
end;

Komponenten

Komponenten schreiben

Sie 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:

  • Speichern: Hier können Sie Ihre Komponente oder Ihr Package unter einen Namen Ihrer Wahl speichern.
  • 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.
  • Einstellungen: In diesem Dialog können Sie neben der Beschreibung Ihrer Komponente und ihrer Versionierung auch den Package-Typ einstellen sowie Sprachregelungen treffen.
  • Installieren: Wenn Ihre Komponente fertig erstellt ist, können Sie sie über diesen Knopf in die IDE einbinden.
  • Compilereinstellungen: Hier lässt sich festlegen, mit welchen Optionen und Compiler-Argumenten Ihr Package kompiliert werden soll.

Hinweis: Detailierte Informationen zum Package-Editor finden Sie hier.

Beispiel: Eine von TButton abgeleitete Komponente erstellen:

  1. Öffnen Sie den Package-Editor wie oben geschrieben
  2. Klicken Sie auf "Hinzufügen --> Neue Komponente"
  3. 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
  4. Klicken Sie auf Ok - und schon können Sie in der Unit meinbutton.pas den TButton an Ihre Bedürfnisse anpassen.

Einer neuen Komponente ein Icon für die Komponentenpalette geben

Zum 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:

 ~/lazarus/tools/lazres mybutton.lrs tmybutton.png

Das erzeugt eine Pascal Include Datei, die im Initialisierungs-Abschnitt von mybutton.pas verwendet wird:

 initialization
   {$I mybutton.lrs}

Installieren Sie das Package.

Eine Komponente aus der Palette verstecken

Package IDEIntf, unit componentreg:

IDEComponentPalette.FindComponent('TButton').Visible:=false;

Komponenten-Editoren schreiben

Ein 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.

Eigenschafts-Editoren schreiben

Jeder 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.

Designer

Einen Designer-Mediator schreiben

Der 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/.

  • 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.
  • Öffnen Sie das Beispielsprojekt examples/designnonlcl/project/NonLCL1.lpi.
  • Ö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.

Einen neuen einzigartigen Komponentennamen erzeugen

uses FormEditingIntf;

...

NewName:=FormEditingHook.CreateUniqueComponentName(AComponent);

// Or if you need to create the name before creating the component:

NewName:=FormEditingHook.CreateUniqueComponentName(ComponentClassName,OwnerComponent);
// ComponentClassName will be used as prefix, without a leading T.
// OwnerComponent is the new owner of the new component.

Eine Komponente im Designer/Objektinspektor auswählen

uses propedits;
..
GlobalDesignHook.SelectOnlyThis(AComponent);

Ereignis-Handler

Es gibt einige Ereignisse in der IDE, für die Plugins ihre eigenen Handler hinzufügen können.

Designerereignisse

In 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.

Beispiele:

 Einfügen Ihres Handlers (das geschieht normalerweise im Konstruktor Ihres Objekts):
   GlobalDesignHook.AddHandlerComponentAdded(@YourOnComponentAdded);
Entfernen Ihrer Handlers: GlobalDesignHook.RemoveHandlerComponentAdded(@YourOnComponentAdded);
Sie können alle Handler auf einmal entfernen. Zum Beispiel, ist es eine gute Idee, diese Zeile im Destruktor des Objekts anzufügen: GlobalDesignHook.RemoveAllHandlersForObject(Self);

Die Handler von GlobalDesignHook:

 // lookup root
 ChangeLookupRoot
   Called when the "LookupRoot" changed.
   The "LookupRoot" is the owner object of the currently selected components.
   Normally this is a TForm.
// methods CreateMethod GetMethodName GetMethods MethodExists RenameMethod ShowMethod Called MethodFromAncestor ChainCall
// components GetComponent GetComponentName GetComponentNames GetRootClassName ComponentRenamed Called when a component was renamed ComponentAdded Called when a new component was added to the LookupRoot ComponentDeleting Called before a component is freed. DeleteComponent Called by the IDE to delete a component. GetSelectedComponents Get the current selection of components.
// persistent objects GetObject GetObjectName GetObjectNames
// modifing Modified Revert RefreshPropertyValues

Benachrichtigt werden, wenn ein Formular im Designer modifiziert wurde

Jedes 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:

procedure TYourAddOn.OnDesignerModified(Sender: TObject);
var
  IDEDesigner: TComponentEditorDesigner;
begin
  IDEDesigner:=TComponentEditorDesigner(Sender);
  ...
end;

procedure TYourAddOn.ConnectDesignerForm(Form1: TCustomForm);
var
  IDEDesigner: TComponentEditorDesigner;
begin
  IDEDesigner:=TComponentEditorDesigner(Form1.Designer);
  IDEDesigner.AddHandlerModified(@OnDesignerModified);
end;

Projektereignisse

Diese Ereignisse sind definiert in der Unit LazIDEIntf.


  • LazarusIDE.AddHandlerOnProjectClose: wird aufgerufen bevor ein Projekt geschlossen wird
  • 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)
  • LazarusIDE.AddHandlerOnSavingAll: wird aufgerufen bevor die IDE alles speichert
  • LazarusIDE.AddHandlerOnSavedAll: wird aufgerufen nachdem die IDE alles gespeichert hat
  • LazarusIDE.AddHandlerOnProjectBuilding: wird aufgerufen bevor die IDE das Projekt erstellt
  • LazarusIDE.AddHandlerOnProjectDependenciesCompiling: wird aufgerufen bevor die IDE die Packageabhängigkeiten eines Projekts kompiliert
  • LazarusIDE.AddHandlerOnProjectDependenciesCompiled: wird aufgerufen nachdem die IDE die Packageabhängigkeiten eines Projekts kompiliert hat

Andere IDE Ereignisse

  • LazarusIDE.AddHandlerOnIDERestoreWindows: wird aufgerufen, wenn die IDE ihre Fernster wiederherstellt (bevor das erste Projekt geöffnet wird)
  • LazarusIDE.AddHandlerOnIDEClose: wird aufgerufen, wenn die IDE beendet wird (nach closequery, also keine Interaktivität mehr)
  • LazarusIDE.AddHandlerOnQuickSyntaxCheck: wird aufgerufen, wenn der Menüpunkt oder das Tastenkürzel für die Schnelle Syntaxüberprüfung aussgeführt wird

Projekt

Aktuelles Projekt

Das aktuelle Hauptprojekt erhalten Sie mit LazarusIDE.ActiveProject. (unit LazIDEIntf)

Alle Units des aktuellen Projekts

Um alle Pascal-Units des aktuellen Hauptprojektes der IDE zu durchlaufen benutzen Sie zum Beispiel:

uses LCLProc, FileUtil, LazIDEIntf, ProjectIntf;

procedure ListProjectUnits;
var
  LazProject: TLazProject;
  i: Integer;
  LazFile: TLazProjectFile;
begin
  LazProject:=LazarusIDE.ActiveProject;
  if LazProject<>nil then
    for i:=0 to LazProject.FileCount-1 do
    begin
      LazFile:=LazProject.Files[i];
      if LazFile.IsPartOfProject
      and FilenameIsPascalUnit(LazFile.Filename)
      then
        debugln(LazFile.Filename);
    end;
end;

Die .lpr, .lpi und .lps Datei eines Projekts

uses LCLProc, FileUtil, ProjectIntf, LazIDEIntf;
var
  LazProject: TLazProject;
begin
  LazProject:=LazarusIDE.ActiveProject;
  // jedes Projekt hat eine .lpi Datei:
  DebugLn(['Project'' lpi file: ',LazProject.ProjectInfoFile]);

  // if the project session information is stored in a separate .lps file:
  if LazProject.SessionStorage<>pssNone then
    DebugLn(['Project'' lps file: ',LazProject.ProjectSessionFile]);

  // If the project has a .lpr file it is the main source file:
  if (LazProject.MainFile<>nil)
  and (CompareFileExt(LazProject.MainFile.Filename,'lpr')=0) then
    DebugLn(['Project has lpr file: ',LazProject.MainFile.Filename]);
end;

Der Name der ausführbaren Ziel-Datei eines Projekts

Es gibt ein Makro $(TargetFile), das in Pfaden und externen Werkzeugen verwendet werden kann. Beispiel:

uses MacroIntf;

function MyGetProjectTargetFile: string;
begin
  Result:='$(TargetFile)';
  if not IDEMacros.SubstituteMacros(Result) then
    raise Exception.Create('unable to retrieve target file of project');
end;

Für weitere Makros siehe: IDE Makros in Pfaden und Dateinamen.

Hinzufügen Ihres eigenen Projekttyps

Sie können Menüpunkte zum Dialog 'Neu ...' hinzufügen:

Hinzufügen Ihres eigenen Dateityps

Sie können Einträge hinzufügen zum Dialog 'Neu ...':

  • Siehe die Unit ProjectIntf aus dem Package IDEIntf.
  • Wählen Sie eine Basisklasse TFileDescPascalUnit für normale Units oder TFileDescPascalUnitWithResource für ein neues Formular/Datenmodul.

Hinzufügen eines neuen Dateityps

Dieses Beispiel entstammt der ide/mainintf.pas Datei und registriert eine einfache Textdatei:


uses ProjectIntf;
...
  { TFileDescText }

  TFileDescMyText = class(TProjectFileDescriptor)
  public
    constructor Create; override;
    function GetLocalizedName: string; override;
    function GetLocalizedDescription: string; override;
  end;
...

procedure Register;

implementation

procedure Register;
begin
  RegisterProjectFileDescriptor(TFileDescMyText.Create,FileDescGroupName);
end;

{ TFileDescMyText }

constructor TFileDescMyText.Create;
begin
  inherited Create;
  Name:='MyText'; // do not translate this
  DefaultFilename:='text.txt';
  AddToProject:=false;
end;

function TFileDescText.GetLocalizedName: string;
begin
  Result:='My Text'; // replace this with a resourcestring
end;

function TFileDescText.GetLocalizedDescription: string;
begin
  Result:='An empty text file';
end;

Hinzufügen eines neuen Formulartyps

Diese Beispiel ist aus 'ide/mainintf.pas' und registriert das normale Formular:


uses ProjectIntf;

...
  TFileDescPascalUnitWithMyForm = class(TFileDescPascalUnitWithResource)
  public
    constructor Create; override;
    function GetInterfaceUsesSection: string; override;
    function GetLocalizedName: string; override;
    function GetLocalizedDescription: string; override;
  end;
...

procedure Register;

implementation

procedure Register;
begin
  RegisterProjectFileDescriptor(TFileDescPascalUnitWithMyForm.Create,FileDescGroupName);
end;

{ TFileDescPascalUnitWithMyForm }

constructor TFileDescPascalUnitWithMyForm.Create;
begin
  inherited Create;
  Name:='MyForm'; // do not translate this
  ResourceClass:=TMyForm;
  UseCreateFormStatements:=true;
end;

function TFileDescPascalUnitWithMyForm.GetInterfaceUsesSection: string;
begin
  Result:='Classes, SysUtils, MyWidgetSet';
end;

function TFileDescPascalUnitWithForm.GetLocalizedName: string;
begin
  Result:='MyForm'; // replace this with a resourcestring
end;

function TFileDescPascalUnitWithForm.GetLocalizedDescription: string;
begin
  Result:='Create a new MyForm from example package NotLCLDesigner';
end;

Packages

Suche in allen Packages

Durchsuche alle Packages die in der IDE geladen sind (seit Version 0.9.29):

uses PackageIntf;
...
for i:=0 to PackageEditingInterface.GetPackageCount-1 do
  writeln(PackageEditingInterface.GetPackages(i).Name);

Suche ein Package mit einem bestimmten Namen

uses PackageIntf;
...
var
  Pkg: TIDEPackage;
begin
  Pkg:=PackageEditingInterface.FindPackageWithName('LCL');
  if Pkg<>nil then 
    ...
end;

Anmerkung: 'FindPackageWithName' öffnet nicht den Package-Editor. Benutzen Sie dazu 'DoOpenPackageWithName'.

Installieren von Packages

Anmerkung: Installieren Sie nur Packages mit IDE-Plugins. Andere Packages zu installieren, kann die IDE instabil machen.

uses PackageIntf, contnrs;

  PkgList:=TObjectList.create(true);
  try
    Pkg:=TLazPackageID.Create;
    Pkg.Name:='Cody';
    PkgList.Add(Pkg);
    // überprüft, ob die IDE die Datei 'cody.lpk' und alle Abhängigkeiten finden kann
    // Die IDE gibt einige Warnungen/Bestätigungen aus, falls ihr irgendetwas seltsam vorkommt.
    if not PackageEditingInterface.CheckInstallPackageList(PkgList,[]) then
      exit;
    // in diesem Beispiel haben wir bereits überprüft, deshalb Warnungen überspringen
    // und die IDE neu erstellen
    if PackageEditingInterface.InstallPackages(PkgList,[piiifSkipChecks,piiifRebuildIDE])<>mrOK then
      exit;
  finally
    PkgList.Free;
  end;

Fenster

Grundsätzlich gibt es vier Typen von IDE Fenstern:

  • die IDE Hauptleiste ist in Application.MainForm. Sie ist immer präsent.
  • schwebende/andockbare Fenster (wie die Quelltext-Editoren, der Objektinspektor und die Meldungen)
  • die modalen Formulare, wie der Suchen-Dialog, Einstellungen-Dialog und Rückfragen.
  • Hints und Vervollständigungs-Formulare

Hinzufügen eines neuen andockbaren IDE-Fensters

Was 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.

Wie registriert man ein andockbares IDE-Fenster

Vergessen Sie nicht, einen langen, uniquen Namen zu verwenden, der ein gültiger Pascal-Bezeichner ist. Ihr Fenster kann einen beliebigen Titel haben.

uses SysUtils, IDEWindowIntf;
...
var MyIDEWindow: TMyIDEWindow = nil; 

procedure CreateMyIDEWindow(Sender: TObject; aFormName: string; var AForm: TCustomForm; DoDisableAutoSizing: boolean);
begin
  // check the name
  if CompareText(aFormName,MyIDEWindowName)<>0 then exit;
  // create the form if not already done and disable autosizing
  IDEWindowCreators.CreateForm(MyIDEWindow,TMyIDEWindowm,DoDisableAutosizing,Application);
  ... init the window ...
  AForm:=MyIDEWindow;
end;

procedure Register;
begin
  IDEWindowCreators.Add('MyIDEWindow',@CreateMyIDEWindow,nil,'100','50%','+300','+20%');
  // the default boundsrect of the form is:
  // Left=100, Top=50% of Screen.Height, Width=300, Height=20% of Screen.Height
  // when the IDE needs an instance of this window it calls the procedure CreateMyIDEWindow.
end;

Anzeigen eines IDE-Fensters

Benutzen Sie nicht Show. Nehmen Sie stattdessen:

IDEWindowCreators.ShowForm(MyIDEWindow,false);

Das 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.

Anmerkungen über IDEWindowCreators und SimpleLayoutStorage

Das 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.

Die 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.

CodeTools in der IDE

Die 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 (deutsch).

Bevor Sie irgendeine der Codetools-Funktionen in der IDE aufrufen, sollten Sie die letzten Änderungen im Quelltexteditor in den Codetools-Puffern speichern:

uses LazIDEIntf;
...
  // save changes in source editor to codetools
  LazarusIDE.SaveSourceEditorChangesToCodeCache(-1); // -1: commit all source editors

Hinzufügen einer resource Direktive zu einer Datei

Dies fügt eine {$R example.res} Direktive zu einer Pascal Unit hinzu:

procedure AddResourceDirectiveToPascalSource(const Filename: string);
var
  ExpandedFilename: String;
  CodeBuf: TCodeBuffer;
begin
  // make sure the filename is trimmed and contains a full path
  ExpandedFilename:=CleanAndExpandFilename(Filename);
  
  // save changes in source editor to codetools
  LazarusIDE.SaveSourceEditorChangesToCodeCache(-1);

  // die Datei laden
  CodeBuf:=CodeToolBoss.LoadFile(ExpandedFilename,true,false);

  // die resource Direktive hinzufügen
  if not CodeToolBoss.AddResourceDirective(CodeBuf,'example.res') then
    LazarusIDE.DoJumpToCodeToolBossError;
end;

Die Codetools stellen auch Funktionen wie FindResourceDirective und RemoveDirective zur Verfügung.

Die Suchpfade für Units und Include-Dateien ermitteln

In 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:

uses CodeToolManager;
...

Dir:=''; // das leere Verzeichnis ist für neue Dateien und hat die selben Einstellungen wie das Projektverzeichnis

// ermittelt die Suchpfade für Include-Dateien:
Path:=CodeToolBoss.GetIncludePathForDirectory(Dir);

// ermittelt die Suchpfade für Units:
// Dieser Suchpfad wird an den Compiler übergeben.
// Er enthält die Package-Ausgabe-Verzeichnisse, aber nicht die Package-Quell-Verzeichnisse.
Path:=CodeToolBoss.GetUnitPathForDirectory(Dir);

// zusätzliche Unit-Suchpfade nur für die IDE können auftreten (werden nicht an den Compiler übergeben)
Path:=CodeToolBoss.GetSrcPathForDirectory(Dir);

// der vollständige Suchpfad enthält auch alle Package-Quell-Pfade für Units:
Path:=CodeToolBoss.GetCompleteSrcPathForDirectory(Dir);

Quelltext-Editor

Aktiver Quelltext-Editor

uses SrcEditorIntf;
...
Editor:=SourceEditorManagerIntf.ActiveEditor;
if Editor=nil then exit;
Filename:=Editor.FileName;
ScreenPos:=Editor.CursorScreenXY;
TextPos:=Editor.CursorTextXY;

SynEdit

Die Einstellungen für einen TSynEdit holen

Wenn Sie einen TSynEdit in einem Dialog haben und Sie wollen die selbe Schriftart und die selben Einstellungen wie im Quelltext-Editor verwenden::

uses SrcEditorIntf;
...
SourceEditorManagerIntf.GetEditorControlSettings(ASynEdit);

Die Einstellungen für einen SynEdit-Highlighter holen

Wenn 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:

uses SrcEditorIntf;
...
SourceEditorManagerIntf.GetHighlighterSettings(ASynHighlighter);

Siehe für ein Beispiel auch: TSQLStringsPropertyEditorDlg.Create in der Unit SQLStringsPropertyEditorDlg.

Hilfe

Hilfe für die Quellen hinzufügen

Erzeugen sie zuerst eine THelpDatabase:

HelpDB := TFPDocHTMLHelpDatabase(
  HelpDatabases.CreateHelpDatabase('EinNameIhrerWahlFürDieDatenbank',
                                    TFPDocHTMLHelpDatabase,true));
  HelpDB.DefaultBaseURL := 'http://ihre.hilfe.org/';

  FPDocNode := THelpNode.CreateURL(HelpDB,
                                   'Package1 - A new package',
                                   'file://index.html');
  HelpDB.TOCNode := THelpNode.Create(HelpDB,FPDocNode);// einmal als Inhaltsverzeichnis
  DirectoryItem := THelpDBISourceDirectory.Create(FPDocNode,'$(PkgDir)/lcl',
                                   '*.pp;*.pas',false);// und einmal als normale Seite
  HelpDB.RegisterItem(DirectoryItem);

Zeilen zum Nachrichtenfenster hinzufügen

unit IDEMsgIntf;
...
var Dir: String;
begin
  Dir:=GetCurrentDir;
  IDEMessagesWindow.BeginBlock;
  IDEMessagesWindow.AddMsg('unit1.pas(30,4) Error: Identifier not found "a"',Dir,0);
  IDEMessagesWindow.EndBlock;
end;

Überblick über die verschiedenen Elemente der Hilfe

Hilfe für die IDE erzeugen