Vous êtes sur la page 1sur 23

Construction d'une application

15. Construction d'une application

Il est bien loin le temps où réaliser un programme consistait essentiellement à créer un


fichier exécutable auquel on rajoutait un petit fichier "LISEZ.MOI.TXT" dans lequel on
indiquait rapidement comment utiliser le programme.

Aujourd'hui, si cette partie demeure essentielle, la construction d'une application ne se


borne pas à cela et il faut penser à réaliser, en sus, un certain nombre de fonctionnalités qui
assureront la prise en compte réelle de l'application par ses utilisateurs.
Ces fonctionnalités annexes sont très diverses et dépendent de la fonction première de
l'application. Néanmoins quelques constantes apparaissent et sont, aujourd'hui,
incontournables. Il ne saurait être question de livrer une application professionnelle qui ne
posséderait pas ces fonctions. Une application doit :
- Posséder un module d'impression ( quelles applications n'éditent pas divers
résultats ? ). Dans la mesure du possible, pour les éditions personnalisées, celles
réalisées sur les postes clients, doivent être "wysiwyg"
- Posséder une aide en ligne complète et ergonomique.
- Pouvoir être installées facilement. Or les applications modernes mettent en œuvre,
en plus de l'exécutable, divers pilotes, .DLL, fichiers d'aide etc. Cette installation ne
peut donc pas être réalisée à la main et il faut prévoir une procédure automatisée
prenant en compte les caractéristiques de la machine hôte.
- Pouvoir être configurée.

Installation Éditions

Application et
modules
applicatifs

Configuration Aide en ligne

Page XV.1
Construction d'une application

15.1 : Initialisation et paramétrage d'une


application
Il est de plus en plus nécessaire de disposer de dispositifs qui permettent de maintenir
diverses informations indispensables au bon fonctionnement de l'application ( recueils
d'information sur le système, mots de passe, personnalisation de l'application, sauvegarde
d'informations recueillies, etc. ).

Plusieurs dispositifs peuvent être mis en œuvre, à commencer par la simple écriture de
ces informations dans un fichier externe. Mais deux sont prévus explicitement par les standards
de programmation Windows :
- L'utilisation de fichiers d'initialisation ( d'extension '.ini' ).
- L'inscription de ces informations dans la base de registres du système.

 Si l'utilisation de la base de registres est prônée aujourd'hui au détriment de


l'utilisation de fichiers 'ini' ( privilégiée sous Windows 3.x ), les deux mécanismes cohabitent
aujourd'hui et présentent chacun des avantages et inconvénients qu'il est intéressant de
comparer.
- Les fichiers 'ini' sont es fichiers externes au format texte, pouvant être édités
et modifiés par le simple bloc notes de Windows. De ce fait ils sont
aisément modifiables, ce qui peut sembler être un inconvénient mais se
révèle être un avantage lorsque l'application est bloquée à cause d'un
paramètre contenu dans le fichier.
- Les fichiers 'ini' ne peuvent plus aujourd'hui avoir d'effet néfaste sur le
fonctionnement du système.
- La base de registres permet de stocker un grand nombre d'informations de
tout types. Ce stockage se fait d'une manière "hermétique" et il faut disposer
d'utilitaires spécifiques ( et d'une certaine compétence technique ) pour
pouvoir modifier son contenu.
- Une insertion mal contrôlée dans la base de registres peut "véroler" celle-ci
et donc perturber voire bloquer le comportement de tout le système.
Il semble donc qu'il faille continuer à privilégier l'utilisation des fichiers 'ini'
quand ceux-ci ne doivent contenir que des informations peu sensibles ne
servant qu'au bon fonctionnement de l'application. Il faut préférer l'insertion
dans la base de registres dès lors qu'il s'agit de stocker des informations plus
sensibles ( mots de passe, identification, numéro de licences, etc. ).

15. 11 Gestion des fichiers ".ini" :


15.111 / Généralités sur les fichiers '.ini'

Windows 3.11 a généralisé l'utilisation de fichiers "texte" d'extension ".ini" qui sont des
fichiers de configuration faciles à manipuler.

 Le fait qu'un fichier ".ini" soit au format texte facilite sa modification. Il est en
effet possible de l'éditer à l'aide de n'importe quel éditeur de texte afin de
modifier manuellement un paramétrage malencontreux qui empêche le bon
fonctionnement de l'application.

Un fichier ".ini" est composé de sections débutant par un mot clé marqué entre crochet.
Au sein d'une section, chaque ligne ( clé ) correspond à une initialisation.

Page XV.2
Construction d'une application

La syntaxe est la suivante :

parametre=valeur d'initialisation
// il n'y a pas d'espace au niveau du '='

 Une ligne commençant par un ' ;' est une ligne de commentaire. Elle
n'est donc pas prise en compte par l'application.

 Par tradition on a tendance à créer les fichiers 'ini' dans le répertoire de


Windows ( voire à utiliser les fichiers WIN.INI et SYSTEM.INI ). Si cela
s'explique par le fait que c'est plus simple à réaliser lorsqu'on fait appel
aux fonctions du SDK, cela entraîne une certaine anarchie au sein de ce
répertoire. Il est préférable que le fichier 'ini' soit créé dans le répertoire
de l'application utilisatrice.

Exemple :

; lignes copiées à partir du fichier DELPHI.INI

[Gallery]
BaseDir=I:\DELPHI\GALLERY
GalleryProjects=1
GalleryForms=1

[Experts]
ExptDemo=I:\DELPHI\BIN\EXPTDEMO.DLL

15.112 / Gestion des fichiers '.ini' par la classe TIniFile :

Il est possible d'accéder aux différents fichiers ".ini" via un ensemble de fonctions du
SDK de Windows. Mais ces fonctions ne sont pas particulièrement aisées à manipuler et
nécessitent la mises en place de tampons et l'utilisation de variables de type pointeur.

C++ Builder encapsule complètement et efficacement ces fonctions en proposant une


classe particulière appelée TInifile.
C'est grâce à un objet créé à partir de cette classe que l'on peut créer un fichier ".ini", le
lire ou le modifier ( par contre on ne peut pas le supprimer : il faut pour cela utiliser les
fonctions spéciales de gestions des fichiers).

La procédure à adopter est la suivante :


- Déclarer une variable au type TInifile ;
- Créer explicitement cette variable.
- Accéder aux différentes méthodes de l'objet pour réaliser les opérations souhaitées.
- Détruire l'objet, lorsque l'on en n'a plus besoin, afin de libérer la mémoire.

 Bien entendu, comme on l'a déjà fait en d'autres circonstances, cet objet
n'est pas accessible via l'inspecteur d'objet et tout accès ne peut être réalisé
que par programmation.

Page XV.3
Construction d'une application

Principales méthodes :

DeleteKey ( ) Supprime une clé au sein d'une section


EraseSection ( ) Efface une section entière d'un fichier .INI.
ReadBool ( ) Lit une valeur booléenne
ReadInteger ( ) Lit une valeur entière
ReadString ( ) Lit une chaîne de caractères
ReadSection ( ) Lit une section entière
WriteBool ( ) Écrit une valeur booléenne dans le fichier
WriteInteger ( ) Écrit une valeur entière
WriteString ( ) Écrit une chaîne de caractères.

 On utilise les opérateurs new et delete, ainsi que le constructeur ( TIniFile )


et le destructeur de la classe pour créer et détruire un composant TIniFile.

 Dans chaque fonction de lecture ou d'écriture, il faut indiquer la


section concernée et le paramètre cible. Il est possible d'indiquer des
valeurs par défaut.

 Les méthodes Write.... écrivent un paramètre de type adéquat


dans le fichier '.ini' à la section spécifiée. Si le paramètre existait déjà il est
modifié, sinon il est créé.

Exemple :

Dans le fichier ".h" associé à la feuille indiquer :

#include <inifiles.hpp> // tout en haut du fichier


......
public: // Déclarations de l'utilisateur
__fastcall TForm1( TComponent* Owner );
TIniFile *ObjIni ;
// Pointeur sur un objet de type TIniFile
};

void __fastcall TForm1::FormCreate(TObject *Sender)


{
AnsiString FichierIni ;
int Desc ;

FichierIni = ExtractFilePath ( Application ->ExeName );


FichierIni = FichierIni + "Essai.ini" ;

if ( ! FileExists( FichierIni ) )
{
Desc = FileCreate( FichierIni );
// Création du fichier
if ( Desc < 0 )
ShowMessage ( "Création du fichier Essai.ini
impossible" ) ;
else // Le fichier est créé : on l'initialise
{

ObjIni = new TIniFile ( FichierIni );


// Création de l'objet de type TIniFile
ObjIni -> WriteString ( "A savoir", "Auteurs",
"Ma compagnie à moi" ) ;

Page XV.4
Construction d'une application

ObjIni ->WriteString ("Options","Organisme" ,


"ESAT" ) ;
}
}
else
// Le fichier existe, on le lit pour initialiser
l'application
{
ObjIni = new TIniFile ( FichierIni );
EOrganisme -> Text = ObjIni -> ReadString ( "Options",
"Organisme", "ESAT");
EAuteurs -> Text = ObjIni -> ReadString ( "A savoir",
"Auteurs", "" ) ;
}
}

// Ecriture dans le fichier ini

void __fastcall TForm1::Button1Click(TObject *Sender)


{
AnsiString FichierIni ;

FichierIni = ExtractFilePath (Application ->ExeName );


FichierIni = FichierIni + "Essai.ini" ;
ObjIni = new TIniFile ( FichierIni );
// Création de l'objet de type TIniFile
ObjIni -> WriteString ( "A savoir", "Auteurs",
EAuteurs -> Text ) ;
ObjIni -> WriteString ( "Options", "Organisme",
EOrganisme -> Text ) ;
}

15.12 : Utilisation de la base de registres


La prolifération de fichiers '.ini', et / ou l'utilisation non maîtrisée des fichiers '.ini'
système ( Win.ini et System.ini en particulier ) ont provoqué de nombreux problèmes qui ont
nuit à la "réputation" des ce type de fichier. Ce qui a conduit Microsoft à chercher à centraliser
toutes les données de configuration dans une base spécialisée, la base de registres ( registry en
anglais ).

 La base de registres existait déjà sous Windows 3.1 mais n'était utilisée que par les
programme OLE.

 Les informations de la base de registre sont stockées dans deux fichiers du répertoire
Windows ( System.dat et User.dat ).

 On peut utiliser l'utilitaire Regedit.exe pour visualiser et même éditer le contenu de la


base de registres. Mais il est déconseillé de le faire si l'on n'a pas les compétences
nécessaire car toute modification inconsidérée peut entraîner le blocage des applications
voire même du système ( Même si Windows maintient des fichiers de sauvegardes (
System.da0 et User.da0 ).

15.121 / Constitution de la base de registres :


La base de registres utilise des "clés" ( KEY ) pour enregistrer les différents paramètres.

Page XV.5
Construction d'une application

Chaque clé prend alors une valeur d'initialisation. Cette valeur peut être de type chaîne
de caractères, entier, booléen, réel, date ou "binaire" ( succession de 0 et de 1 n'ayant de
sens que pour l'application qui a généré cette valeur ).

Ces clés, très nombreuses, sont stockées sous forme d'une arborescence, les clés étant de
plus en plus précise au fur et à mesure que l'on "descend" dans l'arborescence.

L'arborescence est constituée de 6 "sections" intitulées :

Section Utilisation
HKEY_CLASSES_ROOT
HKEY_LOCAL_MACHINE Windows y stocke les informations sur la
configuration matérielle.
HKEY_CURRENTS_CONFIG
HKEY_CURRENT_USER Stocke les informations sur les programmes
installés sur la machine.
Cette section est elle-même divisée en
plusieurs sections dont l'une s'appelle
software.
Microsoft recommande de diviser cette section
en plusieurs sous-sections de la manière
suivante :
Software\Compagnie\Logiciel\Version
HKEY_USERS
HKEY_DYN_DATA

15.122 / Utilisation de l'objet TRegistry :


De la même manière que les fichiers ".ini" sont gérés par un objet TIniFile, la base de
registres est gérée, par une application C++ Builder, par un objet de la classe
TRegistry qu'il faut créer explicitement pour la circonstance.

Pour avoir accès à la base de registres il faut :


- Créer un objet de la classe TRegistry ;
- Spécifier une section racine ( par défaut : HKEY_CURRENT_USER ).
- Ouvrir la base de registres par la méthode OpenKey ( ) .

A partir de là il faut utiliser une des méthodes de la classe TRegistry en fonction de ses
besoins :

Openkey ( ) Ouvre une clé dans la section définie dans la propriété RootKey.
Si la clé n'existe pas elle est créée.
CreateKey ( ) Crée une nouvelle clé.
CloseKey ( ) Met fin à l'accès à la clé courante. La base est alors remise à
jour.
KayExists ( ) Détermine si une clé existe.
GetKeyInfo ( ) Retourne diverses infos sur la clé courante.
GetKeyNames ( ) Copie toutes les sous-clés de la clé courante.
GetDataType ( ) Retourne le type de la variable ValueName
Read ... ( ) Lisent le contenu d'une variable du type spécifié.
Write ... ( ) Écrivent dans la base de registre, une valeur du type spécifié.

DeleteKey ( ) Supprime une clé.


DeleteValue ( ) Supprime une valeur
ValueExists ( ) Renvoie true si la valeur existe.

Page XV.6
Construction d'une application

Exemple :

bool Res ;
AnsiString EditorFont ;
int FontSize ;
TRegistry *MonReg = new TRegistry ( ) ;

MonReg -> RootKey = HKEY_CURRENT_USER ;


Res = MonReg -> OpenKey
("Software\\Mesproduits\\MonAppli\\2.1\\Editor",false);
// Le test de Res permet de tester la création de la clé
.....
EditorFont = MonReg -> ReadString ( "Editor Font" ) ;
Fontsize = monReg -> ReadInteger ( "Font size" ) ;
....

15.2 : Création d'une aide contextuelle


Toute application actuelle se doit d'être accompagnée d'un ensemble de produits aidant
les différents types d'utilisateurs dans la prise en compte et l'utilisation au quotidien de
l'application.
Ces produits sont constitués essentiellement :
- D'une documentation papier plus ou moins "copieuse" ;
- D'une aide en ligne en mesure d'apporter toutes les informations nécessaires à un
utilisateur lorsqu'il est en train d'utiliser l'application.

 Il peut aussi y avoir d'autres produits ( tels des assistants ou des présentations
plus ou moins dynamiques du produit , mais cela est beaucoup plus complexe à
réaliser et n'est pas encore une "recommandation" incontournable ).

Ils doivent apporter une aide dans toutes les phases d'utilisation de l'application :
- Installation, configuration et désinstallation de l'application ;
- Utilisation courante ;
- Administration de l'application.

 Dans une application complexe, la réalisation de l'ensemble des produits d'aide


doit être confiée à une équipe spécialisée tant le travail à accomplir peut se révéler important.

 Si l'on pense souvent à réaliser des produits d'aide à l'utilisation d'une


application, on oublie fréquemment de faire évoluer ceux-ci en parallèle avec les évolutions
de l'application.

15.21 : Réalisation d'une aide en ligne

Page XV.7
Construction d'une application

L'aspect "documentation papier" n'entrant pas dans le cadre de ce cours, on se


concentrera sur les aspects programmation induits par la création d'une aide en ligne.

Il existe, à l'heure actuelle, deux manières pour réaliser cette fonctionnalités :


- Une méthode "standardisée" mais en passe de devenir obsolète : la génération puis
l'appel en cours d'exécution de fichiers d'aide au format ".hlp".
- Une méthode émergente, mais non encore standardisée, consistant à créer des
fichiers au format ".html" - comme ceux utilisés sur les sites Internet - et à les
afficher en cas de besoin.

 Si l'utilisation de fichier ".hlp" est encore promue par Microsoft il


ne fait aucun doute que, dans les années à venir, ce sera
l'utilisation de fichiers ".html" qui sera privilégiée. Beaucoup plus
souple cette méthode est aussi plus intéressante par la
possibilité qu'elle offre de créer des sites internet "d'aide" à
l'utilisation d'un produit.

15.22 : Création et mise en place d'une aide au format ".hlp"


Toute les applications professionnelles doivent être livrées, aujourd'hui encore, avec un
fichier d'aide répondant aux spécifications Windows.
Ce fichier, d'extension '.hlp' est construit et compilé grâce à des utilitaires spécifiques
pour pouvoir être lu par Windows, soit directement soit via l'application. Dans ce dernier cas,
il est souhaitable que l'appel du fichier d'aide amène à l'écran la rubrique appropriée au
contexte d'utilisation de l'application ( au lieu de présenter la feuille d'accueil de l'aide ). On
parle alors d'aide contextuelle.

Pour arriver à cela, il faut que le programmeur réalise des liens entre les différents
modules de son application et les rubriques de l'aide lorsqu'il met au point le code.

15.221 / Structure d'un fichier d'aide '.hlp' :


Un fichier d'aide est, à l'origine, constitué par un ( ou plusieurs ) fichier "texte" au
format '.rtf ' ( Rich Text Format ), c'est à dire un format qui utilise certaines
conventions typographique pour indiquer :
- La couleur d'affichage de certaines parties du texte,
- La police utilisée ainsi que sa taille,
- Les emplacements ou seront incorporées des images,
- Les retraits de paragraphe, etc. .

Le format 'rtf' permet en outre de créer des liens "hypertexte" permettant la navigation
non structurée entre diverses partie du texte : le fait de définir un mot clé comme étant
un "point chaud" ( = activable ) fait que, lorsque l'utilisateur place la souris sur ce mot,
la forme du curseur change : le fait de cliquer provoque l'affichage d'un autre texte
(contenu d'une autre rubrique ).

 Un texte "point chaud" est souligné. Une image, ou une partie d'image,
peut aussi être un point chaud.

Page XV.8
Construction d'une application

L'ensemble des fichiers '.rtf' constituant un fichier d'aide est regroupé au sein d'un
projet. Un fichier 'projet, d'extension '.prj', est alors constitué : c'est un fichier texte à la
structure particulière permettant de fédérer les divers fichiers '.rtf', d'indiquer les images
à incorporer, les liens à établir avec une application , etc.

15.222 / Création d'un fichier d'aide :


A l'origine il fallait connaître toutes les codes spécifiques au format '.rtf' et la structure
exacte du fichier 'projet' pour pouvoir se lancer dans la construction d'un fichier d'aide.
En utilisant un traitement de texte reconnaissant le format '.rtf' ( comme Word ) on
pouvait alors mener la chose à bien.

Aujourd'hui les choses sont beaucoup plus simples car il existe de nombreux utilitaires
permettant la création directe de fichiers au format '.rtf' tout en créant automatiquement
le fichier 'projet' adéquat. Dans ce domaine les produits les plus onéreux ne sont pas
toujours les plus efficaces et les plus simples d'emploi et on trouve en shareware
français des produits très faciles d'emploi ( écrits en Visual Basic .... ou en Delphi ).

Il est donc vivement conseillé d'utiliser ce type de produit.

Une fois le projet réalisé, il faut le compiler afin de créer le fichier '.hlp' souhaité. Il
faut pour cela utiliser un compilateur spécial fourni gratuitement par Microsoft : le
compilateur HC ( Help Compilator ) et ses successeurs ( HC31 ou mieux HCP ).

 La compilation se fait en mode DOS est peut être très longue si le projet est
important.

 HCP utilise la mémoire étendue. De ce fait il est adapté aux projets ambitieux.

Les générateurs de fichiers d'aide permettent de définir un numéro d'identification


spécifique pour chaque rubrique d'aide du fichier ( cet identificateur est appelé
'identifiant de contexte' ou 'context number' ).
Le créateur du fichier d'aide doit veiller à ce que les numéros utilisés soient uniques au
sein du projet.

 Les environnements C++ Builder et Delphi fournissent, sur le CD, un utilitaire


permettant l'édition de fichiers RTF puis la génération d'un fichier d'aide au
format '.hlp'.

15.223 / Prise en compte du fichier d'aide par l'application :


Une fois le fichier d'aide réalisé, il peut être pris en compte par l'application, lors de son
exécution. Pour cela il faut :

1. Indiquer à l'application, le lieu où le fichier est stocké. Cela se fait grâce au menu
'Options de Projet' onglet Application. Il suffit de renseigner la zone de saisie
'Fichier d'aide :'.

2. Invoquer le fichier d'aide à partir d'un bouton ou d'un item de menu.

Pour cela :

Page XV.9
Construction d'une application

- Initialiser la propriété Helpfile de l'objet Application en indiquant le chemin


d'accès au fichier d'aide ( cela peut se faire dans l'événement OnCreate de la
feuille principale ).
- Lancer le fichier d'aide au moyen de la méthode HelpCommand ( ) :

void __fastcall TForm1::FormCreate(TObject *Sender)


{
Application -> HelpCommand (HELP_CONTENTS, 0);
}

15.224 / Mise en place d'une aide contextuelle :


Il est de plus en plus souhaitable que l'utilisateur dispose d'une aide adaptée à son
contexte d'exécution. Le fait d'appeler l'aide affiche alors la rubrique adéquate.

Pour réaliser une telle aide il faut alors utiliser la méthode HelpContext ( ) ou la
méthode HelpJump ( ).

HelpContext ( ) utilise les numéros d'identification des différentes rubriques de l'aide.


HelpJump ( ) utilise les noms de ces rubriques.

void __fastcall TForm1.Button2Click(TObject *Sender);


{
Application -> HelpContext ( 100 ) ;
};

void __fastcall TForm1::Aide2Click(TObject *Sender)


{
Application -> HelpJump ( "RubriqueContextuelle" ) ;
}
/* Cette dernière fonctionnalité ne fonctionne pas
toujours, les numéros de rubriques générés par certains
éditeurs n'étant pas compatibles avec la syntaxe C++
Builder*/

 Dans les deux cas il faut que le créateur du fichier d'aide fournisse les
renseignements adéquats ( noms et / ou numéros des rubriques du
fichier ) pour pouvoir constituer une aide contextuelle efficace.

15.23 : Création d'un système d'aide HTML


Il est de plus en plus préférable de mettre en place un système d'aide basé sur le langage
HTML pour réaliser une aide en ligne.
Dans ces conditions il faudra :
- Disposer d'un éditeur HTML afin de créer l'ensemble des pages HTML constituant
le système d'aide ;
- Faire afficher ces pages à partir de l'application lorsque l'utilisateur en fera la
demande.

Page XV.10
Construction d'une application

Pour cette dernière phase deux possibilités sont offertes au programmeur :

- Soit utiliser le navigateur Internet présent sur la machine. Mais il faut alors savoir
quel est le navigateur installé ( ou alors il faut fournir lors de l'installation le
navigateur que l'on souhaite faire utiliser ).

Le fait que le navigateur soit un programme "externe" à l'application fait que son
lancement et son rafraîchissement ( affichage des diverses pages de l'aide ) se révèle
assez délicat et nécessite l'utilisation de primitives de l'API Windows proches du
système.

- Soit utiliser le composant navigateur fourni avec C++ Builder .


Cette dernière solution se révèle la plus pratique même si le navigateur fourni par
l'environnement de développement n'a pas toutes les capacités des navigateurs du
commerce.

15.231 / Lancement du navigateur de la machine :


Le lancement du navigateur présent sur la machine se fait en invoquant la fonction
ShellExecute ( ) de l'API Windows.

 Penser à inclure l'en tête <shellapi.h> dans le fichier en-tête associé.

On a ainsi les primitives générales suivantes :

void __fastcall TForm1::Index1Click(TObject *Sender)


{
AnsiString Chemin ;

Chemin = ExtractFilePath( Application -> ExeName )


+ "Html\\" ;
/* Les fichiers Html de l'aide sont stockés dans un
sous-répertoire Html du répertoire de l'application */

Navigateur ( Chemin + "\Accueil_index.html" );


/* On utilise une fonction d'appel afin d'être en mesure
d'appeler plusieurs fichiers html en fonction des
besoins */
}

void TForm1::Navigateur ( AnsiString Lien )


{
char *pLien ;
/* Il faut utiliser un pointeur sur une chaîne AZT
car les fonctions de l'API Windows ne reconnaissent
pas les AnsiString */

pLien = Lien . c_str ( );


// Initialisation du pointeur

if ( ShellExecute ( Handle, "Open", "iexplore.exe" ,


pLien , "." , SW_SHOW ) < HINSTANCE ( 3 ))
/* Voir le prototype de la fonction dans l'aide en
ligne */
{
if ( ShellExecute ( Handle, "Open", "netscape.exe",
pLien , "." , SW_SHOW ) < HINSTANCE ( 3 ))

Page XV.11
Construction d'une application

ShowMessage ( "Il n'y a pas de navigateur


d'installé sur la machine." ) ;

}
}

 Le problème majeur auquel on est confronté lorsque l'on utilise le navigateur


de la machine vient du fait que si l'on souhaite appeler, à partir d'une autre
partie de l'application, le navigateur pour afficher une autre fiche d'aide, le
navigateur est de nouveau chargé en mémoire. Cette multiplication des
instances devient rapidement pénalisante pour le système.
Il est possible de palier à cet inconvénient mais cela suppose l'utilisation de
Messages Windows qui sont d'une programmation délicate.

15.232 / Utilisation du composant navigateur livré avec C++ Builder :


Il est possible d'utiliser le composant Navigateur fournit par C++ Builder mais ce
dernier, qui est en fait un composant Active X, n'a pas les mêmes performances que les
navigateurs du commerce. Il peut cependant être utilisé pour des affichages simples.

De plus, si l'on souhaite réellement fournir à l'utilisateur les fonctionnalités


traditionnelles proposées traditionnellement par les navigateurs, il faut réaliser, par
programmation les fonctionnalités suivantes : précédent, suivant, arrêt, réactualiser.
Cela nécessite la mise en place de différentes listes chargées de tracer les différentes
actions de l'utilisateur ( affichages successifs des différentes feuilles HTML ).

 Il est cependant possible de construire une fois pour toute une fiche
autonome qui réalisera ces fonctions et qui pourra ensuite être utilisée dans
les différents projets qui le souhaitent.

 Les composants "Navigateurs" évoluent rapidement. De fait celui utilisé par


Delphi 5 est, une fois n'est pas coutume, différent de celui utilisé par C++
Builder 4.

15.3 : Impressions
15.31 : Généralités

15.311 / La problématique de l'impression :


L'impression s'est longtemps résumé à celle de listings utilisant, au mieux de leurs
capacités, les imprimantes matricielles plus ou moins rapides de l'époque. Au mieux,
l'utilisation de caractères semi graphiques permettait de réaliser un minimum de mise en
page. La difficulté tait renforcée par le fait que chaque imprimante avait un
comportement particulier.

 En standard, le langage C, et le langage C++ qui lui succède, ne sont conçu


que pour réaliser ce type d'impression.

Page XV.12
Construction d'une application

La généralisation de l'informatique personnelle, et celles des interfaces graphiques, a


fait naître le besoin de pouvoir réaliser des impressions élaborées permettant d'obtenir
des documents similaires à ceux qui étaient affichés à l'écran ( mode "wysiwyg" ).

Des environnements comme Windows ont permis de répondre à ce besoin en ajoutant


une couche "logique" aux impressions : Le programmeur, en manipulant certaines
primitives, indique la structure du document à imprimer. Ces primitives sont ensuite
interprétées par un "moteur" d'impression interne au système qui ensuite donne les
ordres d'impression adéquats à l'imprimante "physique" connectée à la machine.

Pour ce qui concerne le programmeur l'impression de documents sur une imprimante,


ce traduit donc par la manipulation de l'ensemble des fonctions de GDI.
C'est en effet GDI qui va prendre en compte les commandes qui lui sont adressées par
les différentes instructions du programme, qui va "construire" en mémoire la page à
imprimer, puis va piloter le flot de données résultant vers la sortie d'imprimante, en
initiant et en maintenant un dialogue avec le pilote de périphérique concerné ( le pilote
de l'imprimante choisie par l'utilisateur ).

Ce système permet de réaliser des impressions quelle que soit l'imprimante utilisée pour
l'impression ( c'est GDI qui se charge de réaliser les adaptations nécessaires ). GDI se
comporte donc comme une imprimante virtuelle générique.

 Il faut signaler que GDI est un pilote générique


de construction de page. Qu'importe quelle est la destination exacte de la
page ainsi construite. De fait il suffit de dire à GDI de réaliser un affichage et
il le fera aussi facilement que si on lui demande de réaliser une impression :
pour lui c'est la même chose, seul le pilote de périphérique incriminé diffère.
En d'autres termes, la grande majorité des notions qui vont être étudiées
dans le chapitre qui suit, l'impression sur une imprimante, pourra sans peine
être transposée à la construction et à l'affichage d'images à l'écran : ce sont
les mêmes méthodes qui sont utilisées.
Ce qui explique que, via GDI, on peut réaliser "simplement" des
prévisualisations de documents avant impression.

 GDI utilise, pour construire ses pages, une unité de mesure


spécifique à Microsoft, le twips. Cette unité permet de définir les dimensions
et les coordonnées des "objets" devant être imprimés.
1 twip = 1/1440 inch soit 1/567 de centimètre.
Le problème vient du fait que le nombre de twips par pixel dépend du
matériel utilisé. Il va falloir prendre en compte cette limitation lors de la
programmation des impressions ( ou des affichages à l'écran ).

15.312 / Dialogue avec GDI :

Quelle que soit la manière dont on réalise les impressions, il est nécessaire, avant
d'entamer celles-ci, de donner quelques indications à GDI :
- Quelle est l'imprimante utilisée pour l'impression ;
- Type d'impression ( toutes les pages, certains pages, une ou plusieurs copies, etc. ).
- Etc...

Page XV.13
Construction d'une application

En d'autres termes il faut configurer l'imprimante puis lancer le travail d'impression.


Cela est réalisé par deux composants appartenant à l'onglet "Dialogues" de C++
Builder:
- TPrintDialog qui permet de lancer l'impression après avoir spécifié quelques une
de ses caractéristiques.
- TPrinterSetupDialog qui permet de réaliser la configuration des imprimantes
reconnues par le système, même s'il n'y a pas d'impression à réaliser.

Comme tous les composants "dialogues", ces deux composants sont en fait des
interfaces avec des bibliothèques de dialogues standards de Windows ( stockées dans
COMMDLG.DLL ). Autrement dit, quel que soit l'environnement de développement, la
boite de dialogue qui s'affiche en cours d'exécution est identique.

 Il est possible d'accéder aux fonctionnalités de configuration à partir d'un


composant TPrintDialog en cours d'exécution en appuyant sur le bouton
"Configurer".

Comme tous les composants de l'onglet "Dialogues", ceux-ci sont des composants
invisibles qui s'activent, en programmation grâce à la méthode Execute ( ).

if ( PrintDialog -> Execute ( ) )


// si l'impression est bien entamée
...... < réalisation des actions à réaliser >

15.313 / Possibilités d'impression fournies par C++ Builder


Même si tous les ordres d'impressions passent par GDI, C++ Builder propose – au
moins – trois manières de réaliser des impressions.
1 – Utilisation de la méthode Print ( ) ;
2 – Utilisation de l'objet TPrinter ;
3 - Utilisation de l'ensemble de composants QReport.

15.32 : Utilisation de la méthode Print ( )


La classe TCustonForm, ancêtre de toutes les feuilles des projets C++ Builder,
implémente la méthode Print ( ) qui peut être invoquée sans autre formalité.

Cette méthode réalise d'une manière transparente ( c'est à dire via un dialogue avec GDI
entièrement géré par la méthode ) la copie "écran" de la fenêtre qui l'a invoquée.

void __fastcall TForm1::Button1Click(TObject *Sender)


{
if ( PrintDialog -> Execute ( ))
Print ( ) ;
}

Si cette possibilité est de loin la plus simple à mettre en œuvre elle est aussi la plus
limitée : les cas où l'on a besoin de réaliser une copie de la fenêtre active sont relativement
rares.

Page XV.14
Construction d'une application

 Les nouvelles versions de C++ Builder font que la méthode Print ( ) tient
compte de la résolution de l'imprimante. On obtient donc une impression de taille acceptable
même si l'imprimante utilisée a une résolution élevée. Dans les premières versions des
environnements Borland, l'impression d'une feuille de 600 x 480 pixels se traduisait par
l'impression d'une "vignette" de moins de 2 cm de coté ( pour une imprimante de résolution
720 ppi ).
En fait cela est possible en initialisant la propriété PrintScale de l'objet Form
concerné.

15.33: Utilisation de l'objet TPrinter


Printer est un objet "interne" qui permet de gérer les impressions sous Windows ( en fait
il sert d'interface avec GDI en tout ce qui concerne les impressions ).

Comme tout objet qui se respecte, Printer dispose d'un ensemble de propriétés et de
méthodes accessibles en programmation. Depuis quelques versions la classe TPrinter est
documentée dans l'aide en ligne ( ce qui n'était pas vrai à l'origine ) même si la lecture des
rubriques révèle quelques surprises. On peut donc manipuler l'objet Printer sans trop de
problèmes et il donne alors satisfaction dans de nombreux cas.

 En fait l'objet Printer encapsule l'accès aux primitives de GDI nécessaires pour
réaliser une impression. Il faut savoir que des utilitaires comme Quick Report
invoquent, en s'appuyant sur les scripts générés en phase de conception, un
objet de type Printer pour assurer le dialogue avec GDI. La génération de script
facilite ce dialogue ( une partie des ordres sont générés "à la souris" ) mais cela
se traduit par une plus grande lenteur d'exécution et une plus grande
consommation de ressources systèmes. Invoquer directement Printer se révèle
certes plus fastidieux mais est plus efficace en termes de performances.

15.331 / Création d'un objet de type TPrinter :


Avant toute chose, inclure une directive permettant d'accéder à la classe TPrinter.

#include <Printers.hpp> // pour l'objet Printer

Exceptionnellement un objet de type TPrinter est créé en utilisant une méthode


spécifique de la classe : la méthode Printer ( ).

PPrinter = Printer ( ) ;

15.332 / Principales propriétés et méthodes


En fait une seule propriété est réellement utilisée dans l'objet Printer : La propriété
Canvas.
Cette propriété, qui est un objet de classe TCanvas, est celle qui faudra utiliser pour
"dessiner" la feuille à imprimer via ses principales "sous-propriétés" et "sous-
méthodes":

Propriétés de TCanvas :
Brush Permet de définir les modes de remplissage des objets.
Pen Permet de définir les types et épaisseurs des traits.

Page XV.15
Construction d'une application

Font Permet de déterminer les caractéristiques des fontes utilisées pour


imprimer les différents textes.
PenPos Permet de déterminer la position courante, en twips, du crayon.
Méthodes de TCanvas :
Draw Permet d'imprimer des images ( attention au format de l'image imprimée )
LineTo Trace des segments de lignes d'un point courant à un point passé en
coordonnées.
Rectangle Trace un rectangle dont les cotés ont les coordonnées spécifiées.
TextOut Permet d'afficher un texte, dans la fonte courante, à la position spécifiée.

L'impression via la propriété Canvas se fait alors comme dans l'exemple :

Printer -> Canvas -> Font -> Name = "Arial" ;


PPrinter -> Canvas -> Font -> Style =
PPrinter -> Canvas -> Font -> Style << fsBold ;
/* La syntaxe alambiquée de cette instruction est due à
certaines spécificités du C/C++ ( comme pour la boite
MessageDLG ) */
PPrinter -> Canvas -> Font -> Size = 14 ;
PPrinter -> Canvas -> Pen -> Color = clBlack ;
PPrinter -> Canvas -> Pen -> Width = 1 ;
PPrinter -> Canvas -> Pen -> Style = psSolid ;
PPrinter -> Canvas -> Brush -> Style = bsClear ;
PPrinter -> Canvas -> Brush -> Color = clWhite ;
PPrinter -> Canvas -> Rectangle ( 50,500,5750,7800 ) ;
PPrinter -> Canvas ->
TextOut (2000 , 300 , "ESSAI D'IMPRESSION" ) ;
etc...

Il est évident que cela devient rapidement fastidieux si l'impression à réaliser est
importante. Néanmoins, en utilisant quelques méthodes bien choisies on arrive
rapidement à obtenir des résultats très corrects : impressions de cadres de tous types,
utilisation des fontes diverses avec enrichissements variés, impressions de graphiques
et d'images, etc.
Surtout, les impressions sont réalisées très rapidement, car le nombre d'intermédiaire est
très réduit : on s'adresse directement à GDI.

 Les scripts utilisés par QuickReport ( vu plus loin ) servent justement à


décrire les différents positionnements des objets à imprimer sans que
l'utilisateur de cet utilitaire ait à se préoccuper de calculer précisément le
positionnement exact de ces derniers.

L'objet Printer implémente quelques méthodes permettant de gérer le document à


imprimer.

Méthodes :
BeginDoc Lance le travail d'impression
EndDoc Met fin au travail d'impression.
En fait EndDoc achève le travail en mémoire de l'objet Printer.
L'impression du document commence à ce moment.
NewPage Force Printer à changer de page.

15.332 / Problèmes à régler :


Page XV.16
Construction d'une application

L'impression via l'objet Printer se révèle à l'usage ( par utilisation massive de copier /
coller ) assez rapide à maîtriser. Il est vrai que de nombreux essais sont nécessaires pour
positionner correctement les différents objets en utilisant des coordonnées exprimées en
twips.

L'exemple précédent imprimait un rectangle occupant à peu près la surface d'une page
A4. Une telle page à donc une largeur approximative de 5800 twips pour une hauteur de
7800 twips..... pour une résolution imprimante de 720 ppi. Car c'est là que le problème
apparaît : l'affichage dépend de la résolution de l'imprimante. Il sera d'une taille deux
fois plus importante si la résolution courante de l'imprimante utilisée est de 360 ppi.

Il faut donc, en programmation, mettre en œuvre un dispositif capable de corriger cet


état de chose.
Il faut pour cela procéder en trois étapes :

1. Connaître la résolution de l'imprimante courante.


Pour cela il faut appeler des fonctions de l'API Windows, sachant que la
résolution en X peut différer de la résolution en Y.

// Permet de connaître la résolution en X et en Y de


l'imprimante en cours
PPIX = GetDeviceCaps ( PPrinter -> Handle , LOGPIXELSX );
PPIY = GetDeviceCaps ( PPrinter -> Handle , LOGPIXELSY );

2. Déterminer un coefficient multiplicateur pour mettre à l'échelle toutes les


coordonnées de la page.

EchX = PPIX / 720 ;


EchY = PPIY / 720 ;
/* Les coordonnées utilisées dans la suite
correspondent à une imprimante de résolution
de 720 ppi. Si l'imprimante utilise des
résolutions X et Y de 720 ppi, les
coefficients multiplicateurs sont égaux à 1
*/
Printer -> BeginDoc ( ) ;

3. Pondérer toutes les coordonnées utilisées dans les différentes méthodes par les
coefficients ainsi déterminés.

Rectangle ( floor( 50 * EchX ), floor ( 500 * EchY ),


floor ( 5750 * EchX ) , floor ( 7800 * EchY ) ) ;
TextOut (floor ( 2000 * EchX ), floor ( 300 * EchY ),
"ESSAI D'IMPRESSION" ) ;

{ Il faut utiliser la fonction floor ( ) car il se


peut que le coefficient utilisé induise des nombres
réels et les différentes méthodes n'autorisent que
des coordonnées entières }

Par exemple si la résolution de l'imprimante est de 360 ppi, les coefficients


correcteurs seront égaux à 0.5. de ce fait toutes les coordonnées seront divisées
par 2, et le résultat final sera équivalent à celui obtenu avec une imprimante de
résolution 720 ppi utilisant des coefficients égaux à 1.

15.333 / Impressions de graphiques


Page XV.17
Construction d'une application

Si l'on souhaite imprimer une image ou une partie de l'écran ( ce qui permet
d'outrepasser les limites de la méthode Print ( ) ), il faut utiliser les propriétés Draw ( )
et StretchDraw ( ) de la propriété Canvas.

 Draw ( ) est cependant difficile à utiliser car on se heurte de nouveau aux


problèmes d'échelles citées plus haut. De fait, si on souhaite imprimer une image dont les
dimensions sont exprimées en pixels ( ex : 200 x 200, ce qui est suffisant pour l'affichage à
l'écran ) celles-ci seront transformées en twips.... et on imprimera une vignette. StretchDraw
( ) pallie avec cet inconvénient.. mais nécessite plusieurs essais d'impression avant d'obtenir
un résultat satisfaisant.

{
Graphics::TBitmap *ImageForm ;
/* Le :: est utilisé pour ôter l'ambiguïté avec la classe
Bitmap de l'API Windows */

// Structures de type rectangle


TRect RectSour , RectDest , RectImpr;

MonPrinter = Printer ( ) ;

/* Initialisation des tailles des rectangles avec les


tailles des parties d'écran à imprimer */
RectSour . Left = .... ;
RectSour . Top = .... ;
RectSour . Right = .... ;
RectSour . Bottom = ..... ;

RectDest . Left = 0 ;
RectDest . Top = 0 ;
RectDest . Right = .... ;
RectDest . Bottom = .... ;

RectImpr . Left = 1000 ;


RectImpr . Top = 1000 ;
RectImpr . Right =
( RectImpr . Left ) + .... ) ;
RectImpr . Bottom =
( RectImpr . Top ) + .....);

ImageForm = GetFormImage ( ) ;
// Capture d'une image de la dimension de la feuille active

Image -> Width = Chart -> Width ;


Image -> Height = Chart -> Height ;
Image -> Canvas -> CopyRect
( RectDest , ImageForm -> Canvas , RectSour ) ;

if ( PrintDialog -> Execute ( )) ;


{
MonPrinter -> BeginDoc ( ) ;
MonPrinter -> Canvas -> StretchDraw
( RectImpr , Image -> Picture -> Graphic ) ;
MonPrinter -> EndDoc ( ) ;

}
delete MonPrinter ;

15.34 : Utilisation de l'ensemble de composants QuickReport

Page XV.18
Construction d'une application

15.431 / Présentation :
Depuis quelques versions, les produits Borland ( Delphi et C++Builder ) sont fournis
avec un ensemble de composants permettant de réaliser des impressions élaborées :
rapport d'entreprises avec en têtes, compteurs de page, logos, connexions à des bases de
données, états de différents types, etc.

QuickReport est un utilitaire conçu au départ par une société tierce. Il semble qu'il ait
été racheté depuis par Borland car seule cette société continue à le proposer. Il est
explicitement destiné à être utilisé dans des applications ayant de gros besoins
d'impressions ( applications orientées "données" en particulier ) et est très utile dans ces
cas par sa capacité à gérer aisément les résultats de requêtes SQL.

QuickReport fonctionne via des scripts qui sont générés automatiquement lors de la
phase de conception des états d'impression. Il y a un script par type d'état à générer.

Ses autres caractéristiques sont les suivantes :


- Permet de réaliser la prévisualisation avant impression.
- Le module Quick Report s'intègre à l'exécutable ( qui grossit d'environ 200 ko ).
De fait il n'a pas besoin de DLL externes ( mais il ne faut pas oublier, lors de la diffusion de
l'application, les différents scripts de réalisation des états ).

 Quick Report est un exemple typique , mais "light", d'une catégorie


d'utilitaire apparue avec la généralisation des impressions "graphiques" ( c'est à
dire tout type d'impression autre que de simples listings peu élaborés ). On les
appelle "générateurs d'états" et ils sont vendus en général de manière
indépendante des environnements de développement. Un des plus connus,
concurrent direct de Quick Report, s'appelle Crystal Report.
Ces produits fonctionnent de deux manières : soient ils s'intègrent à
l'exécutable, comme Quick Report, soient ils sont complètement indépendants
et ne proposent qu'un ensemble de composants servant d'interface entre le
programme exécutable et le programme de génération d'états : l'invocation de
ces composants lance l'exécutable d'impression qui agit alors de manière
autonome.

Tout atelier de développement qui se respecte doit savoir manipuler de tels utilitaires.
Mais cette solution se révèle lourde à mettre en œuvre et à diffuser lorsque les besoins
en impressions sont relativement limités.

15.432 / Composition type d'un état :


Un état, surtout s'il est orienté "édition de données" est généralement constitué :
-D'un titre ( une seule fois sur la première page );
-D'une numérotation de pages ;
-D'un en-tête et d'un pied de page ( contenant des informations que l'on retrouve sur
toutes les pages imprimées ).
-D'en tête de colonnes ;
-....

Tous ces composants seront conçus dans des bandeaux qu'il suffira de positionner sur la
feuille "modèle" et qui seront appelés à chaque fois que l'on en aura besoin en cours
d'impression. Un bandeau est donc un modèle d'une partie de page à imprimer. Ils sera
éditer avec les données "courantes" correspondantes.

15.433 / Le composant QuickRep :

Page XV.19
Construction d'une application

Pour réaliser une impression avec QuickReport il faut :


- Créer et initialiser une nouvelle fiche qui ne sera jamais affichée.
- Déposer un composant QuickRep qui permet de contrôler l'édition. Ce composant,
comportant une grille de placement, occupe la quasi totalité de la feuille.

Ce composant maître comporte un grand nombre de propriétés dont les principales sont:

Bands Indique quels types de bandes vont être utilisées.


DataSet Nom de la Table ( ou Query ) d'où proviennent les
données.
DisplayPrintDialog Indique s'il faut afficher la boite de dialogue de lancement
d'impression.
Options Différentes options
Page Permet de paramétrer le format de la page à imprimer.
PrinterSetting Caractéristiques d'impression.
ReportTitle Titre apparaissant dans le gestionnaire d'impression
ShowProgress Affiche une jauge de progression de l'impression.
Units Unité de mesure
Zoom Utilisé pour la prévisualisation à 'écran.

De même il comporte quelques méthodes :

Newpage ( ) : Force un saut de page ;


Preview ( ) : Force l'affichage de la fenêtre de prévisualisation ;
Print ( ) : Force l'impression.

15.434 / Le composant QRBand :


Ce composant permet de générer les "patrons" des différents objets qui seront
imprimées :
-En-tête et pied de page ;
-Libellés des colonnes ;
-Enregistrement type ;
-Titre.

Chaque bande est un objet TQRBand. L'ordre de conception / création de ces bandes n'a
aucune importance. L'impression se fera en fonction du type de la bande.

Les principales propriétés de ce composant sont :

BandType Permet de déterminer le type de bande ( 10 types différents ).


Frame Contour de la bande
HasChild Indique sui une bande enfant est associée à la bande ( voir plus
loin ).

Par exemple pour créer un état comportant un titre, un en-tête et un pied de page,
des libellés de colonnes et des données sous forme d'enregistrement il faut 5
composants QRBand de types différents ( types : rbTitle, rbPageHeader,
rbPageFooter rbColumnHeader, rbDetail ).

Page XV.20
Construction d'une application

Il faut poser, initialiser et nommer chaque composant QRBand. Ces composants


s'étendent automatiquement à la largeur du composant QuickRep.

 Le fait de déposer un composant QRBand et d'initialiser le type de bande


fait que la propriété Bands du composant QuickRep est mise à jour.

15.435 / Les composants de composition des modèles :


Plusieurs composants permettent de spécifier la manière dont sera réalisée, bande par
bande, ( positionnement et type de données à imprimer ).

La plupart de ces composants reprennent les caractéristiques générales de composants


déjà étudiés ( de type Label, Memo, Image, etc... ). Seul manque, évidemment, le
composant dérivé de Edit.

15.436 / Méthode générale de génération d'état :


Une fois la feuille "invisible" créée.

1- Déposer un composant QuickRep et initialiser la propriété Dataset ( si affichage


de données issues d'une table ou d'une requête ).

2- Déposer autant de composants QRBand qu'il y aura de type d'objets à imprimer.

3- Déposer, sur chaque type de bande les composants permettant de constituer les
modèles d'objets. Le cas échéant connecter les composants aux champs des tables ou requêtes à
afficher ( en initialisant les propriétés DataSet et DataField ).

 Il faut déposer autant de composant QRDBText qu'il y a de champ


d'enregistrement à imprimer.

4- Dans la feuille principale déposer un bouton pour lancer l'impression et un autre, le


cas échéant, pour réaliser la prévisualisation. Créer les gestionnaires d'événements adéquats :

if ( PDQRep -> Execute ( ) )


FQReport -> QuickRep -> Print ( ) ;
et :
FQReport -> QuickRep -> Preview ( ) ;

15.437 / Édition des contenus de tables liées :


Un des avantages apporté par l'utilisation de Quick Report vient du fait qu'il propose de
nombreux composants permettant l'éditions d'états complexes, tels ceux que l'on
rencontre dès lors qu'il s'agit d'éditer des résultats issus d'une base de données
relationnelle.
Il n'est pas question ici d'étudier en détail toutes les possibilités offertes par Quick
Report ( ce qui veut dire que la maîtrise de ce produit passe par une phase
d'apprentissage qu'il ne faudra pas sous-estimer ) mais l'on peut déjà, simplement,
réaliser un état regroupant des données issus es deux tables liées ( une table "maître" et
une table "esclave" ).
Pour cela il faut utiliser un composant spécifique, le composant TQRSubDetail, qui se
dépose sur le composant TQuickRep comme les autres, et sur lequel, comme sur un

Page XV.21
Construction d'une application

composant TQRBand, on peut déposer divers composants d'interface et d'accès aux


sources de données.

Il suffit de lier les deux tables, comme cela a été fait précédemment ( voir chapitre
"tables liées" ), pour que, à l'impression, on ait un état comportant des ensembles
successifs de bandes suivantes :
- Une bande contenant les informations de l'enregistrement courant provenant de la
table maître.
- Une bande contenant les informations issues de la table liée, fonction des valeurs
courantes de la table maître.

On constate que :
- Il y a autant d'ensemble de bandes que d'enregistrement contenus dans la table
maître.
- Chaque bande maître est suivie d'un nombre variable de bandes "filles" pour une
bande "maître" ( fonction du lien 1  n existant entre les deux tables ).

15.5 : Utilisation d'InstallShield


Install Shield est un utilitaire, fourni avec les différents produits Borland, permettant de
faciliter l'installation de produits logiciels sur des cibles dont on ne connaît pas, a priori
l'arborescence.

 Seule une version allégée d'Install Shield, appelée Install Shield Express, est
fournie avec l'environnement de développement. Une version professionnelle, plus puissante,
peut être acquise en sus.
Les versions du produit évoluent rapidement et sont de plus en plus faciles à
utiliser.

On utilise Install Shield une fois que le produit est achevé, avec génération d'un
exécutable stable ainsi que les différents types de fichiers qu'il est susceptible d'avoir à utiliser :
- bibliothèques DLL;
- exécutables annexes ( BDE et/ou générateur d'états par exemple ) ;
- fichiers de données ;
- fichiers d'aide ;
- fichiers d'initialisation ;
- etc.

La génération du script d'installation ( d'extension .iwz ) se fait, à l'intérieur d'Install


Shield, sous forme d'un projet. L'utilisateur est guidé pas à pas pour réaliser son projet jusqu'à
la génération des médias d'installation. Ce script génère un programme d'installation hautement
personnalisé.

 Le programme d'installation peut générer ou modifier des clés dans la base


de registre du système cible.

Une fois les choix initiaux réalisés ( nouveau projet ou ouverture d'un projet existant, et
détermination éventuelle d'un répertoire de stockage ), le projet se présente sous la forme d'une
check-list qu'il s'agit de renseigner en fonction de vos besoins :

- Aspect de la fenêtre de l'utilitaire d'installation.

Page XV.22
Construction d'une application

- Inclusion de différents modules annexes ( BDE, pilotes SQL ou ODBC, VCL, etc.).
Une attention particulière doit être apportée à cette phase car il faut déterminer les
types de composants qu'il faudra inclure au produit ( y compris les composants
Quick Report, Internet, etc. le cas échéant ).
- Génération des images des disquettes d'installation ( ou CD ).
- Test de la procédure d'installation.
- Génération des médias d'installation.

Page XV.23