I. Introduction▲
Lorsque vous créez un nouveau projet avec Lazarus, que ce soit par le menu « Projet / Nouveau projet… » ou par le menu « Fichier / Nouveau… », vous pouvez faire votre choix parmi plusieurs types de projets : application graphique standard, application console, bibliothèque, etc. Il s'agit de modèles standard de projet, dans lesquels sont prédéfinies une série d'options de compilation, d'unités déclarées par défaut et une interface minimale vierge.
Il est possible d'aller plus loin et de créer vous-même un modèle de projet personnalisé contenant plus d’éléments prédéfinis, afin de gagner du temps en début de développement. Cette possibilité n'a évidemment de sens que si vous êtes amené(e) à utiliser les mêmes éléments dans plusieurs projets.
La création d'un modèle de projet n'est pas très compliquée, il est même possible de partir d'un projet existant. Dans ce tutoriel, nous allons prendre comme exemple un modèle d'application de test possédant une fenêtre de débogage masquable, dans laquelle des informations peuvent être affichées pendant l'exécution.
II. Création du projet qui servira de modèle▲
II-A. Partie interface▲
Créez un nouveau projet de type « Application ».
Les propriétés de la fiche principale resteront telles quelles.
L'élément prédéfini dans le modèle sera la fenêtre de débogage : créez-la via le menu « Fichier / Nouvelle fiche » ou via le second bouton de la barre d'outils.
Dimensionnez cette seconde fiche selon vos souhaits, nommez-la par exemple frmDebug (propriété Name) et donnez-lui le titre que vous voulez (propriété Caption).
Déposez-y un composant de type TMemo, que vous nommez par exemple mmoDebug (propriété Name). Réglez son alignement sur alClient (propriété Align), forcez-le en lecture seule (propriété ReadOnly) et effacez son contenu (propriété Lines, clic sur les trois points puis « Effacer »).
Retournez à la fiche principale et déposez-y un composant de type TMainMenu, c'est-à -dire une barre de menu. Nous considérons donc que les applications qui seront créées d'après ce modèle possèderont un menu principal ; tout ce que nous allons faire sera de créer un sous-menu permettant d'afficher ou de masquer la fenêtre de débogage. Double-cliquez sur le composant afin d'ouvrir l'assistant de création de menu.
Créez un menu, appelez-le par exemple mnuWindow (propriété Name) et donnez-lui comme libellé « &Window » ou « &Fenêtre » (propriété Caption). Affublez-le d'un sous-menu mnuWindowDebug (propriété Name), avec le libellé de votre choix (propriété Caption), et cochez sa propriété AutoCheck afin d'afficher une case à cocher à côté du libellé :
II-B. Partie métier▲
Occupons-nous de l'affichage ou du masquage de la fenêtre de débogage.
Tout d'abord, ajoutez l'unité ufrmDebug à la clause uses de l'unité principale.
Ensuite, créez le gestionnaire d'événement OnClick du menu mnuWindowDebug. Son contenu est tout simple :
procedure
TForm1.mnuWindowDebugClick(Sender : TObject);
(* Shows or hides the debug window *)
begin
frmDebug.Visible := mnuWindowDebug.Checked;
end
;
Ainsi, en fonction de l'état de la propriété Checked du menu, la fenêtre de débogage sera affichée ou masquée (étant entendu qu'au démarrage de l'application, la fenêtre sera invisible).
Prenons soin d'empêcher que la fenêtre frmDebug soit directement fermée, en créant un gestionnaire pour l'événement OnCloseQuery :
procedure
TfrmDebug.FormCloseQuery(Sender : TObject; var
CanClose : boolean
);
(* Prevents the window from being closed *)
begin
CanClose := false
;
end
;
De cette manière, le menu système de la fenêtre permettra que celle-ci soit redimensionnée, minimisée ou maximisée, mais pas fermée. Pour la masquer, il faudra passer par le menu de la fenêtre principale de l'application.
III. Enregistrement du projet▲
Enregistrez votre projet, mais pas n'importe où :
L'endroit où Lazarus s'attend à trouver les modèles de projets est le sous-dossier .lazarus/templates de votre dossier personnel.
C'est donc aussi à cet endroit que vous devez copier un projet existant si vous désirez en faire un modèle de projet.
Attention que sous Linux et macOS, les dossiers dont le nom commence par un point sont invisibles par défaut ; il vous faudra peut-être activer l'affichage des fichiers cachés dans le dialogue d'enregistrement.
Enregistrez le projet sous le nom debugtemplate (par exemple) dans un nouveau sous-dossier du même nom sous le dossier .lazarus/templates. Laissez le nom Unit1 par défaut pour la fiche principale et donnez un nom à l'unité de la seconde fiche (ufrmDebug, pour rester cohérent avec le nom donné à la fiche).
IV. Transformation du projet en modèle▲
Faisons le point :
- nous avons créé un projet debugtemplate contenant une fiche principale Form1 (nom laissé par défaut) et une seconde fiche frmDebug ;
- la fiche Form1 contient un menu principal MainMenu1 (nom laissé par défaut), qui lui-même contient un menu mnuWindow avec un élément mnuWindowDebug dont nous avons défini le gestionnaire d'événement OnClick ;
- la fiche frmDebug contient un composant TMemo appelé mmoDebug et le gestionnaire d'événement OnCloseQuery.
Pourquoi avons-nous laissé inchangés les noms de la fiche principale et du menu principal ? Parce que ces noms seront définis au moment de la création du projet basé sur notre modèle. Nous allons même en faire des variables du modèle.
À ce stade, que nous ayons créé un projet exprès (comme nous venons de le faire) ou bien recopié un projet existant dans le sous-dossier .lazarus/templates, les actions qui vont suivre sont identiques.
IV-A. Création du fichier project.ini▲
Dans le dossier du modèle, créez un fichier texte appelé project.ini (ce nom est obligatoire). Ce fichier contient les informations nécessaires à Lazarus pour créer un projet basé sur le modèle. Voici son contenu :
[Variables]
MAINUNIT
=
New filename for the Unit1.pas file
MAINFORM
=
Main form name
MAINMENU
=
Main menu name
[Project]
Name
=
Custom debug application
Author
=
Alcatiz
Description
=
GUI application with a debug window
Dans la première section [Variables], nous définissons trois variables pour le modèle :
- MAINUNIT, le nom de l'unité principale ;
- MAINFORM, le nom de la fiche principale ;
- MAINMENU, le nom du menu principal.
Ce qui est inscrit après le signe « = » est le commentaire associé à la variable.
Dans la section [Project] se trouvent des métainformations sur le modèle :
- Name, le libellé du modèle qui sera affiché par Lazarus ;
- Author, votre nom en tant qu'auteur du modèle ;
- Description, une brève description du modèle.
IV-B. Implémentation des variables du modèle▲
À présent vient une étape légèrement fastidieuse : implémenter les variables dans tous les fichiers composant le projet. Il est possible d'automatiser ce processus à l'aide d'une petite application batch ou shell, mais nous allons tout détailler.
IV-B-1. Renommage des fichiers▲
Important : tous les noms de variables doivent être précédés et suivis d'un double caractère de soulignement.
Ainsi, si une variable MAVARIABLE a été définie dans le fichier project.ini, elle doit être implémentée sous la forme __MAVARIABLE__ dans les noms de fichiers ou dans le contenu des fichiers.
Il en va de même pour les types : le type de la variable MAVARIABLE doit être implémenté sous la forme T__MAVARIABLE__.
Renommez tout d'abord les fichiers Unit1.pas et Unit1.lfm en __MAINUNIT__.pas et __MAINUNIT__.lfm.
Renommez ensuite tous les fichiers debugtemplate.* en __PROJNAME__.*. La variable PROJNAME est une variable définie par défaut qui représente le nom du nouveau projet lorsque celui-ci sera enregistré.
Ne touchez pas aux fichiers ufrmDebug.pas et ufrmDebug.lfm, ils garderont ces noms dans le nouveau projet.
IV-B-2. Implémentation des variables dans les fichiers▲
Il s'agit à présent d'ouvrir chaque fichier composant le projet et d'y implémenter les variables du modèle.
Le fichier __MAINUNIT__.pas :
- toutes les occurrences de Form1 doivent être remplacées par __MAINFORM__ ;
- toutes les occurrences de TForm1 doivent être remplacées par T__MAINFORM__ ;
- MainMenu1 doit être remplacé par __MAINMENU__.
Voici le résultat :
unit
__MAINUNIT__;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, Menus, ufrmDebug;
type
{ T__MAINFORM__ }
T__MAINFORM__ = class
(TForm)
mnuWindow : TMenuItem;
mnuWindowDebug : TMenuItem;
__MAINMENU__ : TMainMenu;
procedure
mnuWindowDebugClick(Sender : TObject);
private
public
end
;
var
__MAINFORM__ : T__MAINFORM__;
implementation
{$R *.lfm}
{ T__MAINFORM__ }
procedure
T__MAINFORM__.mnuWindowDebugClick(Sender : TObject);
(* Shows or hides the debug window *)
begin
frmDebug.Visible := mnuWindowDebug.Checked;
end
;
end
.
Le fichier __MAINUNIT__.lfm :
- toutes les occurrences de Form1 doivent être remplacées par __MAINFORM__ ;
- TForm1 doit être remplacé par T__MAINFORM__ ;
- toutes les occurrences de MainMenu1 doivent être remplacées par __MAINMENU__.
Voici le résultat :
object __MAINFORM__: T__MAINFORM__
Left = 354
Height = 235
Top = 153
Width = 313
Caption = '__MAINFORM__'
DesignTimePPI = 94
Menu = __MAINMENU__
LCLVersion = '2.0.4.0'
object __MAINMENU__: TMainMenu
left = 6
object mnuWindow: TMenuItem
Caption = '&Window'
object mnuWindowDebug: TMenuItem
AutoCheck = True
Caption = '&Show log'
OnClick = mnuWindowDebugClick
end
end
end
end
Le fichier __PROJNAME__.lpr :
- l'identificateur du programme doit être remplacé par __PROJNAME__ ;
- dans la clause uses, Unit1 doit être remplacée par __MAINUNIT__ ;
- Form1 doit être remplacée par __MAINFORM__ ;
- TForm1 doit être remplacé par T__MAINFORM__.
Voici le résultat :
program
__PROJNAME__;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, __MAINUNIT__, ufrmDebug;
{$R *.res}
begin
RequireDerivedFormResource := True
;
Application.Scaled := True
;
Application.Initialize;
Application.CreateForm(T__MAINFORM__, __MAINFORM__);
Application.CreateForm(TfrmDebug, frmDebug);
Application.Run;
end
.
Le fichier __PROJNAME__.lpi :
- toutes les occurrences de debugtemplate doivent être remplacées par __PROJNAME__ ;
- à l'exception des balises <Unit1> et </Unit1>, toutes les occurrences de Unit1 doivent être remplacées par __MAINUNIT__ ;
- Form1 doit être remplacée par __MAINFORM__.
Voici le résultat :
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version
Value
=
"11"
/>
<General>
<SessionStorage
Value
=
"InProjectDir"
/>
<MainUnit
Value
=
"0"
/>
<Title
Value
=
"__PROJNAME__"
/>
<Scaled
Value
=
"True"
/>
<ResourceType
Value
=
"res"
/>
<UseXPManifest
Value
=
"True"
/>
<XPManifest>
<DpiAware
Value
=
"True"
/>
</XPManifest>
<Icon
Value
=
"0"
/>
</General>
<BuildModes
Count
=
"1"
>
<Item1
Name
=
"Default"
Default
=
"True"
/>
</BuildModes>
<PublishOptions>
<Version
Value
=
"2"
/>
<UseFileFilters
Value
=
"True"
/>
</PublishOptions>
<RunParams>
<FormatVersion
Value
=
"2"
/>
<Modes
Count
=
"0"
/>
</RunParams>
<RequiredPackages
Count
=
"1"
>
<Item1>
<PackageName
Value
=
"LCL"
/>
</Item1>
</RequiredPackages>
<Units
Count
=
"3"
>
<Unit0>
<Filename
Value
=
"__PROJNAME__.lpr"
/>
<IsPartOfProject
Value
=
"True"
/>
</Unit0>
<Unit1>
<Filename
Value
=
"__MAINUNIT__.pas"
/>
<IsPartOfProject
Value
=
"True"
/>
<ComponentName
Value
=
"__MAINFORM__"
/>
<HasResources
Value
=
"True"
/>
<ResourceBaseClass
Value
=
"Form"
/>
<UnitName
Value
=
"__MAINUNIT__"
/>
</Unit1>
<Unit2>
<Filename
Value
=
"ufrmdebug.pas"
/>
<IsPartOfProject
Value
=
"True"
/>
<ComponentName
Value
=
"frmDebug"
/>
<HasResources
Value
=
"True"
/>
<ResourceBaseClass
Value
=
"Form"
/>
<UnitName
Value
=
"ufrmDebug"
/>
</Unit2>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version
Value
=
"11"
/>
<Target>
<Filename
Value
=
"__PROJNAME__"
/>
</Target>
<SearchPaths>
<IncludeFiles
Value
=
"$(ProjOutDir)"
/>
<UnitOutputDirectory
Value
=
"lib/$(TargetCPU)-$(TargetOS)"
/>
</SearchPaths>
<Linking>
<Options>
<Win32>
<GraphicApplication
Value
=
"True"
/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
<Debugging>
<Exceptions
Count
=
"3"
>
<Item1>
<Name
Value
=
"EAbort"
/>
</Item1>
<Item2>
<Name
Value
=
"ECodetoolError"
/>
</Item2>
<Item3>
<Name
Value
=
"EFOpenError"
/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>
Le fichier __PROJNAME__.lps :
- debugtemplate doit être remplacé par __PROJNAME__ ;
- à l'exception des balises <Unit1> et </Unit1>, toutes les occurrences de Unit1 doivent être remplacées par __MAINUNIT__ ;
- Form1 doit être remplacée par __MAINFORM__.
Et voici le résultat :
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectSession>
<Version
Value
=
"11"
/>
<BuildModes
Active
=
"Default"
/>
<Units
Count
=
"3"
>
<Unit0>
<Filename
Value
=
"__PROJNAME__.lpr"
/>
<IsPartOfProject
Value
=
"True"
/>
<EditorIndex
Value
=
"-1"
/>
<UsageCount
Value
=
"25"
/>
</Unit0>
<Unit1>
<Filename
Value
=
"__MAINUNIT__.pas"
/>
<IsPartOfProject
Value
=
"True"
/>
<ComponentName
Value
=
"__MAINFORM__"
/>
<HasResources
Value
=
"True"
/>
<ResourceBaseClass
Value
=
"Form"
/>
<UnitName
Value
=
"__MAINUNIT__"
/>
<CursorPos
X
=
"34"
Y
=
"41"
/>
<UsageCount
Value
=
"25"
/>
<Loaded
Value
=
"True"
/>
<LoadedDesigner
Value
=
"True"
/>
</Unit1>
<Unit2>
<Filename
Value
=
"ufrmdebug.pas"
/>
<IsPartOfProject
Value
=
"True"
/>
<ComponentName
Value
=
"frmDebug"
/>
<HasResources
Value
=
"True"
/>
<ResourceBaseClass
Value
=
"Form"
/>
<UnitName
Value
=
"ufrmDebug"
/>
<IsVisibleTab
Value
=
"True"
/>
<EditorIndex
Value
=
"1"
/>
<CursorPos
X
=
"44"
Y
=
"33"
/>
<UsageCount
Value
=
"25"
/>
<Loaded
Value
=
"True"
/>
<LoadedDesigner
Value
=
"True"
/>
</Unit2>
</Units>
<JumpHistory
Count
=
"4"
HistoryIndex
=
"3"
>
<Position1>
<Filename
Value
=
"__MAINUNIT__.pas"
/>
<Caret
Line
=
"41"
Column
=
"34"
/>
</Position1>
<Position2>
<Filename
Value
=
"__MAINUNIT__.pas"
/>
<Caret
Line
=
"42"
Column
=
"34"
/>
</Position2>
<Position3>
<Filename
Value
=
"__MAINUNIT__.pas"
/>
<Caret
Line
=
"41"
Column
=
"34"
/>
</Position3>
<Position4>
<Filename
Value
=
"ufrmdebug.pas"
/>
</Position4>
</JumpHistory>
<RunParams>
<FormatVersion
Value
=
"2"
/>
<Modes
Count
=
"0"
ActiveMode
=
""
/>
</RunParams>
</ProjectSession>
</CONFIG>
V. Utilisation du modèle▲
Notre modèle de projet étant finalisé, il est temps de tester son utilisation. Créez un nouveau projet, le nouveau modèle apparaît à présent dans la liste :
Vous voyez comment le contenu des clés Name et Description du fichier project.ini est utilisé par Lazarus.
Sélectionnez le nouveau modèle puis cliquez sur « OK ». Lazarus vous demande la valeur des différentes variables que nous avons implémentées :
- le nom du projet (PROJNAME)Â ;
- le nom de l'unité principale (MAINUNIT) ;
- le nom de la fiche principale (MAINFORM)Â ;
- le nom du menu principal (MAINMENU)Â ;
- ainsi que le répertoire du projet, qui est à créer.
Une fois que tous les champs sont complétés, cliquez sur « OK ». Vous disposez d'un nouveau projet possédant déjà une fenêtre de débogage ainsi qu'un menu principal :
Le gain de temps est évident !
VI. Remerciements▲
Je remercie Gilles Vasseur pour sa relecture technique et Claude Leloup pour ses corrections.