Introduction▲
Jusqu'à présent, Delphi nous permettait le développement d'objets par la programmation. Avec Delphi 7 Entreprise ou Architecte (avec lesquels ModelMaker est livré, la version Professionnelle de Delphi pouvant également utiliser ModelMaker à condition de le commander séparément), nous allons pouvoir construire des objets par des diagrammes. C'est un changement de niveau majeur. Nous pouvons enfin voir dessinée à l'écran cette caractéristique fondamentale de l'objet : l'encapsulation et nous pouvons faire ressortir visuellement les liaisons entre objets. Au lieu de dizaines de lignes détaillant chaque classe dans le code, nous voyons des rectangles entourant les noms des classes.
Cela n'a l'air de rien, mais en fait cela change tout, car nous pouvons nous concentrer désormais sur l'essentiel.
À partir de ce qu'en UML on appelle le diagramme de classe, ModelMaker construira automatiquement le code détaillé dans Delphi 7.
- Etant donné la richesse du sujet, nous centrons ce tutoriel sur l'utilisation de base de ModelMaker.
- Dans un second tutoriel nous aborderons le développement de classes métiers (Objets de gestion).
I. Paramétrage de ModelMaker▲
Nous nous plaçons d'emblée dans le cas où l'outil donne sa puissance d'intégration maximale avec Delphi 7.
Dans le menu de Delphi 7, après avoir créé une nouvelle application CLX que nous sauvegardons, nous cliquons sur ModelMaker|Run ModelMaker pour lancer ModelMaker. Dans le menu de ModelMaker, cliquons sur Options|Environment options. Pour mettre en œuvre le two-way avec Delphi 7, cochons les cases comme ci-dessous.
Dans Delphi 7
Dans ModelMaker
Une fenêtre de précaution s'affiche lorsque nous cochons Auto Refresh from IDE. Cette fenêtre nous prévient qu'avec le two-way, il n'y a ni maître ni esclave :
Si nous modifions le code Delphi alors ModelMaker prendra en compte automatiquement ces modifications et inversement. Toutefois, ModelMaker nous avertira s'il détecte des changements dans le code source Delphi, car il applique un contrôle plus strict sur les modifications apportées directement dans le code.
Donc un code écrit en Delphi peut ne pas remonter correctement dans ModelMaker dans 0,01% des cas d'après la documentation, spécialement dans 2 cas :
- si le code est incorrect : début et fin de commentaires mal balancés par exemple, procédures de classes non définies dans la classe qui sont des situations temporaires qui existent en cours de saisie de code.
- si vous utilisez des directives de compilation conditionnelles qui s'intercalent dans le balancement des begin … end (en fait l'IDE de Delphi lui-même ne fait pas mieux, car dans ce cas, Ctrl+Maj+flèche haut/bas ne fait pas passer alternativement de la déclaration de la procédure de classe à son implémentation). Donc,
on n'écrira pas :
procedure
TSample.Action;
{$IFDEF DEMO}
var
S: string
;
begin
S := ‘Demo';
ShowMessage(S);
{$ELSE}
begin
{$ENDIF}
end
;
mais on
écrira :
procedure
TSample.Action;
{$IFDEF DEMO}
var
S: string
;
{$ENDIF}
begin
{$IFDEF DEMO}
S := ‘Demo';
ShowMessage(S);
{$ENDIF}
end
;
Nous avons pris le temps de détailler ceci pour bien faire prendre conscience que si ces points ne sont pas respectés, il y a effectivement le risque de ne plus retrouver le code que l'on vient de passer ¾ d'heure à saisir.
On ne conduit pas une Ferrari comme une 2 CV. Ceux qui veulent une conduite plus pépère, ne doivent pas activer l'Auto Refresh from IDE et peuvent, par exemple, tout saisir (diagrammes et détail du code) dans l'environnement de ModelMaker.
Pour ma part, j'apprécie trop l'environnement de Delphi et travaille avec l'Auto Refresh from IDE activé :
La saisie des diagrammes est faite dans ModelMaker et la saisie du code dans l'IDE de Delphi, tout en prenant soin de respecter les points ci-dessus et ceux indiqués dans la documentation de ModelMaker (chapitre sur l'Import). De plus, je prends la précaution suivante : puisque la traduction n'est faite qu'au moment du basculement d'un environnement dans l'autre, toujours faire une compilation dans Delphi avant de revenir dans ModelMaker. Avec un peu de pratique, cela se passe très bien. Et autant prendre de bonnes habitudes tout de suite.
II. Création de classes dans ModelMaker▲
Pour nous exercer, nous allons créer un petit composant sympa. Basé sur un TEdit, ce composant sera utilisé uniquement pour afficher une somme en euro. Mais en double-cliquant dessus, on passera alternativement aux francs et à l'euro.
Dans ModelMaker, par File|New from Default, créons un nouveau modèle ModelMaker.
Note : Nous associons un projet au sens de Delphi à un modèle au sens de ModelMaker.
Nous apercevons alors une hiérarchie de classes. (Faites F3 si vous ne la voyez pas).
Note : Sur les images de cet article, vous voyez un TInstantObject qui n'est probablement pas affiché sur votre écran. Veuillez ne pas en tenir compte. L'explication vous en sera donnée dans le tutoriel suivant.
L'icône de ces classes est en pointillé. Cela veut dire que ces classes sont définies dans des fichiers sources externes au projet. Ce que nous voulons, c'est créer un TEditMonetaire descendant de TEdit. TEdit est lui-même descendant indirect de TComponent. Nous n'avons pas besoin de recréer toute la hiérarchie : il nous suffit de raccrocher TEditMonetaire à son ancêtre direct TEdit. Donc, après avoir mis TComponent en surbrillance, nous appuyons sur Inser et ajoutons un TEdit.
TEdit n'est ici qu'un simple emplacement à partir duquel nous allons faire descendre TEditMonetaire. Pour indiquer que c'est un simple point d'ancrage, double-cliquons sur TEdit et cochons Place Holder.
Maintenant, après avoir mis TEdit en surbrillance, nous appuyons sur Inser et ajoutons un TEditMonetaire.
Nous avons créé notre classe, ou tout du moins le rectangle qui la représente.
La hiérarchie peut être visualisée dans le diagramme de classes (Appuyez sur F5). Nous allons reconstruire le diagramme pour qu'il prenne en compte nos classes. Par clic droit dans le diagramme, nous choisissons Clear diagram|Yes, puis clic droit et Wizards|Visualization wizard. Cliquez sur la double flèche pour prendre toutes les classes, puis Next|Finish. Vous pouvez réarranger le diagramme. La partie qui nous intéresse est celle-ci :
Par rapport à TEdit, notre composant aura les particularités suivantes :
- il n'affiche que des valeurs numériques, au format monétaire
- le double-clic sur le composant effectue une conversion de monnaie.
Ceci implique que nous intervenions sur l'événement OnDblClick. Nous souhaitons également offrir au programmeur une propriété Monnaie qui permette de lire ou de modifier par programme la monnaie d'affichage en cours.
Le plus simple est d'intervenir sur les propriétés et événements hérités de TEdit.
Pour que celles-ci soient montées dans le modèle (pour l'instant TEdit n'est qu'un rectangle), il nous suffit d'aller chercher ces propriétés dans le fichier source où elles sont déclarées. Cliquons sur l'icône Import source file, entourée ici de rouge : Comme nous avons choisi de développer une application CLX (et non VCL), nous cliquons sur <no source alias>. Avant de choisir l'unité, cochons Select Classes and Events types pour pouvoir choisir la classe. Affichons le répertoire CLX des sources de Delphi, l'unité QStdCtrls.
Note : Pour s'assurer que l'auto génération du code n'ira pas modifier les sources de Delphi, il est prudent de cliquer droit dans l'explorateur Windows sur le sous-répertoire Delphi7\Source puis sur Propriétés, et de cocher Lecture seule pour interdire toute modification sur tous les fichiers.
Revenons à l'affichage des classes en appuyant sur F3. Vérifions que si nous cliquons sur TEdit, nous voyons maintenant apparaître la liste des propriétés et méthodes dans le rectangle en bas (pour tout avoir, cliquer sur All). Revenons à notre composant en cliquant sur le rectangle TEditMonetaire en haut. Pour ajouter la propriété Monetaire, cliquez sur P+.
Tapez Monetaire (sans accent), choisissez le type Char, cliquez sur Read Access|Field et terminez par Ok.
Enfin, nous voulons que le composant démarre toujours avec Monetaire = '€'. Nous allons donc surcharger Create : nous cliquons droit dans le rectangle en bas pour choisir Wizards|Method Override Wizard…. Nous mettons en surbrillance Create override et cliquons sur Ok.
Le rectangle du bas doit maintenant se présenter ainsi
Bien que par la suite nous saisirons le code dans l'IDE de Delphi, voyons ici comment il est également possible de le saisir dans ModelMaker. Par F6 nous activons l'implémentation de code dans ModelMaker. Nous cliquons sur le rectangle du bas sur Create. A droite s'affiche alors la section générée par l'héritage : inherited Create; C'est ModelMaker qui a les droits d'écriture sur cette section.
Pour ajouter notre ligne, nous devons ajouter une section sur laquelle nous aurons les droits d'écriture.
Cliquons sur l'icône Add section et saisissons à droite le code Monetaire := '€';
Note : La saisie du caractère Euro par AltGr+E active dans ModelMaker le raccourci clavier Alt+Ctrl+E. Il est possible de désactiver ce raccourci ou de copier/coller le caractère Euro à partir d'un traitement de texte.
A ce stade, nous pouvons également afficher les propriétés dans le diagramme de classes. Cliquons droit dans le rectangle TEditMonetaire du diagramme de classe à droite, et choisissons Symbol properties. Mettons Member filter|Member list style à Auto Member list et cochons Fields, Properties et Events.
Fermons par Ok. Nous voyons alors les propriétés dans le diagramme de classe
Sauvegardons le modèle sous le nom ProjectModelMakerIntro.mpb
Nous pourrions fermer ModelMaker et Delphi : tout notre travail est sauvegardé dans ce fichier.
III. Génération et mise au point du code dans Delphi▲
Le projet Delphi ProjectModelMakerIntro.dpr et le projet ModelMaker ProjectModelMakerIntro.mpb étant ouverts nous allons procéder à la génération de code. Pour cela, affichons les Unités dans ModelMaker par F4. La fenêtre en haut à droite nous indique que TEditMonetaire n'est pas assignée à une unité. En effet, notre classe n'existe à ce stade que dans le projet ModelMaker, pas encore dans une unité Delphi. Nous allons donc indiquer à ModelMaker dans quelle unité Delphi mettre cette classe. Puisque nous créons un nouveau composant, nous allons créer une nouvelle unit. Après cliqué dans la fenêtre en haut à gauche, appuyons sur la touche Inser. Nous donnons comme nom d'unité UnitEditMonetaire.pas et double cliquons sur TEditMonetaire. Après validation par Ok, la fenêtre en haut à gauche indique le lien entre la classe et sa nouvelle unité.
Note : Avant d'activer la génération nous devons tenir compte du fait que, par défaut, ModelMaker est orienté VCL et non CLX. Il nous faut donc adapter les uses à CLX. Pour cela nous allons modifier la unit par défaut :
- Dans le répertoire bin de ModelMaker, recopions Defunit.pas en DefunitVCL.pas
- Avec un éditeur, modifions la clauses uses de Defunit.pas qui devient :
uses SysUtils, Types, Classes, QGraphics, QControls, QForms, QDialogs, QStdCtrls;
Pour faire entrer cette unité dans le cycle de génération automatique, cliquez en haut sur le cadenas ouvert (celui de gauche), puis sur l'éclair de génération.
Ayant mis la unit en surbrillance, cliquez sur le triangle d'activation de la régénération automatique.
La fenêtre en haut à gauche prend alors l'allure suivante :
Allons dans Delphi par le menu de ModelMaker Delphi|Locate in Delphi ou par Ctrl+F11. L'unité a été automatiquement générée et ajoutée au projet. |
unit
UnitEditMonetaire;
interface
uses
SysUtils, Types, Classes, QGraphics, QControls, QForms, QDialogs,
QStdCtrls;
type
TEditMonetaire = class
(TEdit)
private
FMonetaire: Char
;
procedure
SetMonetaire(Value: Char
);
public
constructor
Create(aOwner: TComponent); override
;
property
Monetaire: Char
read
FMonetaire write
SetMonetaire;
end
;
procedure
Register
;
implementation
procedure
Register
;
begin
end
;
{
******************************** TEditMonetaire ********************************
}
constructor
TEditMonetaire.Create(aOwner: TComponent);
begin
inherited
Create(aOwner);
Alignment := taRightJustify;
ShowHint := True
;
Monetaire := '€'
;
end
;
procedure
TEditMonetaire.SetMonetaire(Value: Char
);
begin
end
;
end
.
Nous retrouvons la définition de notre classe, ainsi que la ligne de code Monetaire := '€'; que nous avions saisie dans ModelMaker.
Sauvegardez le projet Delphi.
Nous allons maintenant compléter notre classe en travaillant dans l'IDE de Delphi.
Nous voulons que le double-clic change de monnaie : ajoutons ces 2 lignes
protected
procedure
DblClick; override
avant le end; de la définition de TEditMonetaire dans l'unité dans Delphi.
Maj+Ctrl+C pour générer l'implémentation que nous complétons par inherited DblClick; ce qui donne
procedure
TEditMonetaire.DblClick;
begin
inherited
DblClick;
end
;
Nous avons donc modifié le code dans Delphi.
Sauvegardons dans Delphi. La mise à jour du modèle est alors faite en arrière plan dans ModelMaker.
À son tour, cette mise à jour du modèle est immédiatement répercutée dans Delphi.
À cause de cet aller-retour entre les deux IDE, vous ne devez sauvegarder que du code valide. Pour cela, il est vivement conseillé de compiler l'unité avant de la sauvegarder.
Allons maintenant dans ModelMaker (par Alt+TAB) : la méthode DblClick a bien été ajoutée au modèle. Revenons dans Delphi pour compléter la méthode :
procedure
TEditMonetaire.DblClick;
begin
if
Monnaie = '€'
then
Monnaie := 'F'
else
Monnaie := '€'
;
inherited
DblClick;
end
;
Note : c'est à dessein que notre ligne précède inherited : ainsi le double-clic atterrira sur la zone mise à jour.
Nous allons maintenant modifier l'apparence de notre contrôle selon que l'affichage est en euros ou en francs.
Dans Delphi, nous complétons le code ainsi :
procedure
TEditMonetaire.SetMonetaire(Value: Char
);
const
EUROFRANCS = 6
.55957
;
begin
if
FMonnaie = '€'
then
begin
FMonnaie := 'F'
;
Font.Style := Font.Style - [fsBold] + [fsItalic];
try
Text := Format('%n'
, [StrToFloat(Text) * EUROFRANCS]);
except
Text := ''
;
end
;
Hint := 'Francs'
;
end
else
begin
FMonnaie := '€'
;
Font.Style := Font.Style + [fsBold] - [fsItalic];
try
Text := Format('%n'
, [StrToFloat(Text) / EUROFRANCS]);
except
Text := ''
;
end
;
Hint := 'Euros'
;
end
;
end
;
et nous sauvegardons.
Vous pouvez aller dans ModelMaker et afficher le code (F6 et clic sur SetMonetaire) : le code est présent.
Note : si vous modifiez le code dans ModelMaker, il vous suffit de sauvegarder le modèle pour voir vos modifications dans Delphi. En vous habituant à voir votre code dans Delphi et dans ModelMaker, vous prendrez confiance dans ce double accès qui vous est offert : c'est génial!
Vous n'êtes d'ailleurs pas obligé d'ouvrir les deux environnements pour faire des modifications.
Si vous travaillez dans Delphi uniquement, la prochaine fois que vous ouvrirez ModelMaker, celui-ci va comparer les dates des fichiers. Si le fichier source Delphi est plus récent que le modèle, il vous affiche une fenêtre de Messages. En double-cliquant sur le nom de la unit dans cette fenêtre, il vous est proposé de re-importer :
IV. Création et enregistrement du composant▲
Vérifions que le code compile bien dans Delphi.
Pour ajouter les indications d'enregistrement, nous allons dans ModelMaker. Par F4, nous affichons les Units. Nous cliquons droit sur UnitEditMonetaire et choisissons Edit unit. Ceci nous permet d'indiquer la page où le composant doit être enregistré :
Le code de l'unité est alors automatiquement complété :
procedure
Register
;
begin
RegisterComponents('ExemplesCLX'
, [TEditMonetaire]);
end
;
Nous pouvons alors installer le composant dans la palette (voir la documentation de Delphi).
Vous pouvez tester le composant : il n'accepte que des nombres et lorsque l'utilisateur final double-clic sur le composant, la somme est convertie et la police et le Hint sont modifiés. (Bien entendu, un composant professionnel devra avoir d'autres caractéristiques, notamment traiter les effets de bord de double-conversion).
Note : Nous avons utilisé ModelMaker pour développer un composant. Mais l'utilisation de ModelMaker n'est pas limitée aux composants : nous le verrons dans les autres tutoriels.
V. Reverse engineering▲
Nous avons vu que nous pouvions faire évoluer notre code dans Delphi, ModelMaker étant fermé. A la prochaine réouverture de ModelMaker, celui-ci est capable d'intégrer les modifications dans son modèle. Cette capacité peut être étendue à un projet complet : ModelMaker est capable de créer le modèle d'un code existant. C'est ce qu'on appelle la rétro conception (reverse engineering).
Supposons que notre composant ait été développé directement en Delphi, sans passer par ModelMaker. A titre d'exemple, nous allons faire la rétro conception de notre projet.
Ouvrons notre projet dans Delphi, puis ModelMaker à partir du menu de Delphi.
Nous introduisons le projet dans un nouveau modèle très simplement par le menu de Delphi ModelMaker|Convert project to Model. Vous pouvez constater que tout est présent dans notre nouveau modèle. Nous devons cependant aménager la présentation du diagramme de classe : pour cela, cliquons sur l'icône Diagrams (ou F5). Puis sur l'icône Add Class diagram tout à gauche. Dans l'espace de droite, cliquons droit, pour choisir Wizards|Visualization Wizard (ou Ctrl+W). La liste des classes du modèle s'affiche. Sélectionnons TEdit et TEditMonetaire et validons. Le diagramme présente les deux classes avec leur relation d'héritage. Pour compléter l'affichage, sélectionnons TEditMonetaire en cliquant dessus dans le diagramme. Activons les Symbol properties par clic droit (ou Ctrl+E) puis Symbol Style|Member filter|Member list style|Auto Member list et cochons Fields, Properties et Events.
Nous retrouvons le diagramme initial.
Note : Lors de la création du modèle, le cycle de génération automatique est désactivé (cadenas fermé).
Par précaution, vous ne l'activerez que si vous disposez par ailleurs d'une copie du source importé.
La démarche de rétro conception pourra être utilisée avec profit, notamment :
- pour les codes que vous avez à maintenir (en premier lieu ceux que vous avez déjà écrits)
- pour les codes que l'on vous envoie, ou que vous trouvez sur Internet.
Le grand intérêt de la rétro conception est de vous permettre de visualiser l'architecture statique de l'application. Vous disposez d'un support pour développer votre réflexion à un meilleur niveau.
VI. Conclusion▲
Dans ce tutoriel, nous avons traité un cas simple d'utilisation de ModelMaker : il s'agissait de nous familiariser avec ce nouvel outil intégré à Delphi 7. C'est dans les situations réelles complexes que vous apprécierez toute la puissance de simplification que ModelMaker vous apportera.
Pour aller plus loin, nous vous invitons à lire le tutoriel suivant sur le développement de classes métiers (Objets de gestion)