Professional Documents
Culture Documents
de composants
Borland®
™
Delphi 7
pour Windows™
Reportez-vous au fichier DEPLOY situé dans le répertoire racine de votre produit Delphi 7 pour obtenir la liste
complète des fichiers que vous pouvez distribuer conformément aux termes du contrat de licence de Delphi.
Les applications mentionnées dans ce manuel sont brevetées ou en attente de brevet. Ce document ne donne
aucun droit sur ces brevets. Reportez-vous au CD du produit ou à la boîte de dialogue A propos.
COPYRIGHT © 1983–2002 Borland Software Corporation. Tous droits réservés. Tous les produits Borland sont
des marques commerciales ou des marques déposées de Borland Software Corporation aux Etats-Unis ou dans
les autres pays. Toutes les autres marques sont la propriété de leurs fabricants respectifs.
D7–CWG–0802
Table des matières
Chapitre 1 Ancêtres, descendants et hiérarchies
des classes . . . . . . . . . . . . . . . . . . . . . 2-3
Présentation générale de la création Contrôle des accès . . . . . . . . . . . . . . . . . 2-4
d’un composant 1-1 Masquer les détails d’implémentation . . . . 2-5
Bibliothèque de classes. . . . . . . . . . . . . . 1-1 Définition de l’interface avec le concepteur
Composants et classes. . . . . . . . . . . . . . . 1-2 des composants . . . . . . . . . . . . . . . . 2-6
Création de composants . . . . . . . . . . . . . 1-3 Définition de l’interface d’exécution . . . . . 2-6
Modification de contrôles existants . . . . . 1-3 Définition de l’interface de conception. . . . 2-7
Création de contrôles fenêtrés . . . . . . . . 1-4 Répartition des méthodes . . . . . . . . . . . . . 2-8
Création de contrôles graphiques . . . . . . 1-4 Méthodes statiques . . . . . . . . . . . . . . . 2-8
Sous-classement de contrôles Windows. . . 1-5 Exemple de méthodes statiques . . . . . . 2-8
Création de composants non visuels . . . . 1-5 Méthodes virtuelles . . . . . . . . . . . . . . . 2-9
Contenu d’un composant ?. . . . . . . . . . . . 1-5 Redéfinition des méthodes . . . . . . . . . 2-9
Suppression des dépendances . . . . . . . . 1-6 Méthodes dynamiques . . . . . . . . . . . . 2-10
Définition des propriétés, méthodes Membres abstraits d’une classe . . . . . . . . . 2-10
et événements . . . . . . . . . . . . . . . . . 1-6 Classes et pointeurs . . . . . . . . . . . . . . . 2-10
Propriétés . . . . . . . . . . . . . . . . . . 1-6
Méthodes . . . . . . . . . . . . . . . . . . 1-7 Chapitre 3
Evénements . . . . . . . . . . . . . . . . . 1-7 Création de propriétés 3-1
Encapsulation des graphiques . . . . . . . . 1-8
Pourquoi créer des propriétés ?. . . . . . . . . . 3-1
Recensement des composants . . . . . . . . 1-9
Types de propriétés. . . . . . . . . . . . . . . . . 3-2
Création d’un nouveau composant . . . . . . . 1-9
Publication des propriétés héritées . . . . . . . . 3-3
Création d’un composant avec
Définition des propriétés . . . . . . . . . . . . . 3-4
l’expert composant . . . . . . . . . . . . . . 1-10
Déclarations des propriétés . . . . . . . . . . 3-4
Création manuelle d’un composant . . . . . 1-12
Stockage interne des données . . . . . . . . . 3-4
Création d’un fichier unité . . . . . . . . 1-12
Accès direct . . . . . . . . . . . . . . . . . . . 3-5
Dérivation du composant . . . . . . . . . 1-13
Méthodes d’accès . . . . . . . . . . . . . . . . 3-5
Recensement du composant. . . . . . . . 1-13
Méthode read . . . . . . . . . . . . . . . . 3-7
Création de bitmaps pour les composants . 1-14
Méthode write . . . . . . . . . . . . . . . . 3-7
Installation d’un composant
Valeurs par défaut d’une propriété . . . . . . 3-8
dans la palette de composants . . . . . . . . . 1-16
Spécification d’aucune valeur par défaut 3-8
Emplacement des fichiers du composant . . 1-17
Création de propriétés tableau . . . . . . . . . . 3-9
Test des composants non installés. . . . . . . . 1-17
Création de propriétés
Test des composants installés . . . . . . . . . . 1-19
pour sous-composants . . . . . . . . . . . . . 3-10
Création des propriétés pour interfaces . . . . 3-11
Chapitre 2 Stockage et chargement des propriétés . . . . 3-12
Programmation orientée objet Utilisation du mécanisme de stockage
et écriture des composants 2-1 et de chargement . . . . . . . . . . . . . . 3-12
Définition de nouvelles classes . . . . . . . . . 2-1 Spécification des valeurs par défaut . . . . 3-13
Dérivation de nouvelles classes . . . . . . . 2-2 Détermination du stockage . . . . . . . . . 3-14
Modification des valeurs par défaut Initialisation après chargement . . . . . . . 3-14
d’une classe pour éviter les répétitions 2-2 Stockage et chargement
Ajout de nouvelles capacités des propriétés
à une classe . . . . . . . . . . . . . . . . 2-3 non publiées . . . . . . . . . . . . . . . . . 3-15
Déclaration d’une nouvelle classe Création de méthodes pour le stockage et le
de composant . . . . . . . . . . . . . . . . . 2-3 chargement de valeurs de propriétés . 3-15
i
Redéfinition de la méthode Chapitre 6
DefineProperties . . . . . . . . . . . . . 3-16
Graphiques et composants 6-1
Présentation des graphiques . . . . . . . . . . . 6-1
Chapitre 4 Utilisation du canevas . . . . . . . . . . . . . . . 6-3
Création d’événements 4-1 Travail sur les images . . . . . . . . . . . . . . . 6-3
Qu’est-ce qu’un événement ? . . . . . . . . . . 4-1 Utilisation d’une image, d’un graphique
Les événements sont des pointeurs ou d’un canevas . . . . . . . . . . . . . . . . 6-4
de méthodes. . . . . . . . . . . . . . . . . . 4-2 Chargement et stockage des graphiques . . . 6-4
Les événements sont des propriétés . . . . . 4-2 Gestion des palettes. . . . . . . . . . . . . . . 6-5
Les types d’événements sont des types Spécification d’une palette
de pointeurs de méthodes. . . . . . . . . . 4-3 pour un contrôle . . . . . . . . . . . . . . 6-6
Les types gestionnaire d’événement Bitmaps hors écran . . . . . . . . . . . . . . . . . 6-6
sont des procédures . . . . . . . . . . . 4-3 Création et gestion des bitmaps hors écran . 6-6
Les gestionnaires d’événements Copie des images bitmap . . . . . . . . . . . 6-7
sont facultatifs . . . . . . . . . . . . . . . . 4-4 Réponse aux changements . . . . . . . . . . . . 6-7
Implémentation des événements standard . . . 4-5
Identification des événements standard. . . 4-5 Chapitre 7
Evénements standard Gestion des messages
pour tous les contrôles . . . . . . . . . . 4-5
Evénements standard pour les contrôles
et des notifications système 7-1
Compréhension du système de gestion
standard . . . . . . . . . . . . . . . . . . 4-5
des messages. . . . . . . . . . . . . . . . . . . . 7-1
Rendre visibles des événements . . . . . . . 4-6
Que contient un message Windows ? . . . . 7-2
Changement de la gestion
Répartition des messages . . . . . . . . . . . 7-3
des événements standard . . . . . . . . . . 4-6
Suivi du flux des messages . . . . . . . . 7-3
Définition de vos propres événements . . . . . 4-7
Modification de la gestion des messages . . . . 7-4
Déclenchement de l’événement . . . . . . . 4-7
Surcharge de la méthode du gestionnaire . . 7-4
Deux sortes d’événements. . . . . . . . . 4-8
Utilisation des paramètres d’un message . . 7-4
Définition du type de gestionnaire . . . . . 4-8
Interception des messages . . . . . . . . . . . 7-5
Notifications simples . . . . . . . . . . . . 4-8
Création de nouveaux gestionnaires
Gestionnaires d’événements spécifiques. 4-8
de messages . . . . . . . . . . . . . . . . . . . . 7-6
Renvoi d’informations
Définition de vos propres messages . . . . . 7-6
à partir du gestionnaire . . . . . . . . . 4-9
Déclaration d’un identificateur
Déclaration de l’événement . . . . . . . . . . 4-9
de message . . . . . . . . . . . . . . . . . 7-6
Les noms d’événement débutent
Déclaration d’un type enregistrement
par “On” . . . . . . . . . . . . . . . . . . 4-9
de message . . . . . . . . . . . . . . . . . 7-6
Appel de l’événement . . . . . . . . . . . . . 4-9
Déclaration d’une nouvelle méthode
de gestion d’un message . . . . . . . . . . . 7-7
Chapitre 5 Envoi des messages . . . . . . . . . . . . . . . 7-8
Création de méthodes 5-1 Diffusion d’un message à tous
Eviter les interdépendances . . . . . . . . . . . 5-1 les contrôles d’une fiche . . . . . . . . . . 7-8
Noms des méthodes. . . . . . . . . . . . . . . . 5-2 Appel direct du gestionnaire
Protection des méthodes . . . . . . . . . . . . . 5-3 de message d’un contrôle. . . . . . . . . 7-9
Méthodes qui doivent être publiques . . . . 5-3 Envoi d’un message à l’aide de la file
Méthodes qui doivent être protégées . . . . 5-3 d’attente des messages Windows . . . 7-10
Méthodes abstraites . . . . . . . . . . . . . . 5-4 Envoi d’un message qui ne s’exécute
Rendre virtuelles des méthodes . . . . . . . . . 5-4 pas immédiatement . . . . . . . . . . . 7-10
Déclaration des méthodes . . . . . . . . . . . . 5-4 Réponse aux notifications du système
à l’aide de CLX . . . . . . . . . . . . . . . . . 7-10
Réponse aux signaux . . . . . . . . . . . . . 7-11
ii
Affectation de gestionnaires de signaux Chapitre 9
personnalisés . . . . . . . . . . . . . . . 7-12
Réponse aux événements système . . . . . . 7-12
Modification d’un composant
Evénements couramment utilisés . . . . 7-13 existant 9-1
Surcharge de la méthode EventFilter . . 7-15 Création et recensement du composant . . . . . 9-1
Génération des événements Qt . . . . . . 7-16 Modification de la classe composant. . . . . . . 9-2
Redéfinition du constructeur . . . . . . . . . 9-2
Chapitre 8 Spécification de la nouvelle valeur
Accessibilité des composants par défaut de la propriété . . . . . . . . . . 9-3
iii
Fourniture d’un événement OnChange . . 11-13 Chapitre 13
Exclusion des cellules vides . . . . . . . . 11-13
Transformation d’une boîte de dialogue
Chapitre 12 en composant 13-1
Définition de l’interface du composant . . . . 13-2
Contrôles orientés données 12-1 Création et recensement du composant . . . . 13-2
Création d’un contrôle pour scruter Création de l’interface du composant . . . . . 13-3
les données . . . . . . . . . . . . . . . . . . . . 12-2 Inclusion de l’unité de la fiche . . . . . . . 13-3
Création et recensement du composant . . . 12-2 Ajout des propriétés de l’interface . . . . . 13-4
Fonctionnement du contrôle en lecture Ajout de la méthode Execute . . . . . . . . 13-5
seulement . . . . . . . . . . . . . . . . . . . 12-3 Test du composant . . . . . . . . . . . . . . . . 13-6
Ajout de la propriété ReadOnly . . . . . 12-4
Autorisation des mises à jour Chapitre 14
nécessaires . . . . . . . . . . . . . . . . . 12-4 Extensions de l’EDI 14-1
Ajout du lien aux données . . . . . . . . . . 12-5 Présentation de l’API Tools . . . . . . . . . . . 14-2
Déclaration du champ de classe . . . . . 12-6 Conception d’une classe expert . . . . . . . . . 14-3
Déclaration des propriétés d’accès . . . . 12-6 Implémentation des interfaces de l’expert . 14-4
Exemple de déclaration des propriétés Installation du paquet de l’expert. . . . . . 14-5
d’accès . . . . . . . . . . . . . . . . . . . 12-6 Accès aux services de l’API Tools . . . . . . . 14-5
Initialisation du lien de données . . . . . 12-7 Utilisation d’objets natifs de l’EDI . . . . . 14-6
Réponse aux changements de données . . . 12-8 Utilisation de l’interface INTAServices . 14-6
Création d’un contrôle de modification Ajout d’une image à la liste d’images . 14-7
de données . . . . . . . . . . . . . . . . . . . . 12-9 Ajout d’une action à la liste d’actions . 14-7
Modification de la valeur par défaut Suppression de boutons
de FReadOnly . . . . . . . . . . . . . . . . . 12-9 de barres d’outils . . . . . . . . . . . . 14-8
Gestion des messages liés à la souris Débogage d’un expert . . . . . . . . . . . . 14-9
ou au clavier. . . . . . . . . . . . . . . . . 12-10 Numéros de version de l’interface . . . . 14-10
Réponse aux messages indiquant Utilisation des fichiers et des éditeurs . . . . .14-11
la manipulation de la souris. . . . . . 12-10 Utilisation des interfaces de module . . . .14-11
Réponse aux messages indiquant Utilisation des interfaces d’éditeur . . . . 14-12
la manipulation du clavier. . . . . . . 12-11 Création de fiches et de projets . . . . . . . . 14-12
Mise à jour de la classe lien de données Création de modules . . . . . . . . . . . . 14-13
sur un champ . . . . . . . . . . . . . . . . 12-12 Notification d’un expert
Modification de la méthode Change . . . 12-13 des événements de l’EDI. . . . . . . . . . . 14-16
Mise à jour de l’ensemble de données . . 12-13
Index I-1
iv
Chapitre
Bibliothèque de classes
Les composants de Delphi résident dans une bibliothèque de composants qui
comprend la bibliothèque des composants visuels (Visual Component Library,
VCL) et la bibliothèque des composants multiplates-formes (Component Library
for Cross Platform, CLX). La Figure 1.1 présente la relation qui existe entre les
classes sélectionnées qui composent la hiérarchie VCL. La hiérarchie CLX est
similaire à celle de la hiérarchie VCL, mais les contrôles Windows sont appelés
des widgets (par exemple, TWinControl est appelé TWidgetControl), et il existe
d’autres différences. Pour plus de détails sur les hiérarchies de classes et les
relations d’héritage entre classes, voir Chapitre 2, “Programmation orientée objet
et écriture des composants”. Pour un aperçu des différences entre les hiérarchies,
voir “WinCLX ou VisualCLX” au Chapitre 15 du Guide du développeur et
Composants et classes
Comme les composants sont des classes, les créateurs de composants manipulent
les objets à un niveau différent de celui des développeurs d’applications.
La création de nouveaux composants nécessite de dériver de nouvelles classes.
Brièvement, il existe deux différences principales entre la création des
composants et leur utilisation dans des applications. Pour la création de
composants,
• Vous avez accès à des parties de la classe qui sont inaccessibles aux
programmeurs d’applications.
• Vous ajoutez de nouvelles parties (des propriétés, par exemple) aux
composants.
A cause de ces différences, il faut prendre en compte un plus grand nombre de
conventions, et réfléchir à la manière dont les développeurs d’applications vont
utiliser les composants.
Création de composants
Un composant peut quasiment constituer tout élément de programme
manipulable à la conception. La création d’un composant consiste à dériver une
nouvelle classe à partir d’une classe existante. Vous pouvez dériver un nouveau
composant de plusieurs façons :
• Modification de contrôles existants
• Création de contrôles fenêtrés
• Création de contrôles graphiques
• Sous-classement de contrôles Windows
• Création de composants non visuels
Le Tableau 1.1 présente les différents types de composants et les classes que vous
utiliserez comme point de départ pour chacun d’eux.
Vous pouvez aussi dériver des classes qui ne sont pas des composants et qui
ne peuvent pas être manipulées dans une fiche comme TRegIniFile et TFont.
propriétés des boîtes liste mais ne les rend pas toutes publiques. En dérivant un
composant à partir de l’une des classes abstraites telles que TCustomListBox, vous
rendez publiques uniquement les propriétés que vous souhaitez mettre à
disposition dans votre composant et vous laissez les autres protégées.
Le Chapitre 3, “Création de propriétés”, explique la publication des propriétés
héritées. Le Chapitre 9, “Modification d’un composant existant”, et le Chapitre 11,
“Personnalisation d’une grille”, montrent des exemples de modification de
contrôles existants.
Propriétés
Les propriétés donnent au développeur d’applications l’illusion de définir ou
de lire la valeur d’une variable, tout en permettant au concepteur de composants
de dissimuler la structure de données sous-jacente ou de définir un traitement
spécial lorsque la valeur est accédée.
Méthodes
Les méthodes de classes sont des fonctions et procédures qui opèrent sur une
classe plutôt que sur des instances particulières de cette classe. Par exemple, les
méthodes constructeur de composants (Create) sont toutes des méthodes de
classes. Les méthodes de composants sont des procédures et fonctions qui
opèrent sur les instances des composants elles-mêmes. Les développeurs
d’applications utilisent des méthodes pour que les composants effectuent des
actions particulières ou renvoient des valeurs non contenues par des propriétés.
Comme elles nécessitent une exécution de code, les méthodes ne sont disponibles
qu’au moment de l’exécution. Elles sont utiles pour plusieurs raisons :
• Les méthodes encapsulent la fonctionnalité d’un composant dans l’objet même
où résident les données.
• Les méthodes peuvent cacher des procédures compliquées sous une interface
simple et cohérente. Un développeur d’applications peut appeler la méthode
AlignControls d’un composant sans savoir comment elle fonctionne ni si elle
diffère de la méthode AlignControls d’un autre composant.
• Les méthodes permettent de mettre à jour plusieurs propriétés avec un seul
appel.
Le Chapitre 5, “Création de méthodes”, explique comment ajouter des méthodes
à vos composants.
Evénements
Un événement est une propriété spéciale qui appelle du code, pendant
l’exécution, en réponse à une saisie ou à une autre opération. Les événements
permettent aux développeurs d’associer des blocs de code spécifiques à des
3 Lorsque vous avez rempli les champs de l’expert composant, effectuez l’une
des opérations suivantes :
• Cliquez sur Installer. Pour placer un composant dans un paquet nouveau
ou non, cliquez sur Composant|Installer et spécifiez le paquet dans la boîte
de dialogue qui apparaît. Voir “Test des composants non installés” à la
page 1-17.
4 Cliquez sur OK. L’EDI crée une nouvelle unité.
Attention Si vous dérivez un composant d’une classe dont le nom commence par
“custom” (comme TCustomControl), ne tentez pas de le placer sur une fiche
avant d’avoir surchargé toute méthode abstraite du composant initial. Delphi
ne peut pas créer d’instance d’une classe ayant des propriétés ou des
méthodes abstraites.
Pour voir le code source de votre unité, cliquez sur Voir l’unité. Si l’expert
composant est déjà fermé, ouvrez le fichier unité dans l’éditeur de code en
sélectionnant Fichier|Ouvrir. Delphi crée une nouvelle unité contenant la
déclaration de classe et la procédure Register, et ajoute une clause uses qui
comprend toutes les unités Delphi standard.
L’unité ressemble à cela :
unit MyControl;
interface
uses
Windows, Messages, SysUtils, Types, Classes, Controls;
type
TMyControl = class(TCustomControl)
private
{ Déclarations privées }
protected
{ Déclarations protégées }
public
{ Déclarations publiques }
published
{ Déclarations publiées }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents(’Samples’, [TMyControl]); //Dans CLX, utilisez une autre page
end;
end.
Remarque Aux endroits où les applications CLX utilisent des unités distinctes, celles-ci sont
remplacées par des unités de même nom précédées d’un Q ; par exemple,
QControls remplace Controls. Dans le cas d’une dérivation à partir de
TCustomControl dans l’unité QControls, la seule différence est la clause uses qui
ressemble à ceci :
uses
SysUtils, Types, Classes, QGraphics, QControls, QForms, QDialogs, QStdCtrls;
Dérivation du composant
Chaque composant est une classe dérivée de TComponent, de l’un de ses
descendants plus spécialisés (tels que TControl ou TGraphicControl) ou d’une
classe composant existante. “Création de composants” à la page 1-3 indique les
classes à dériver pour obtenir les différentes sortes de composants.
La dérivation des classes est expliquée plus en détail dans la section “Définition
de nouvelles classes” à la page 2-1.
Pour dériver un composant, ajoutez une déclaration de type objet à la partie
interface de l’unité qui contiendra le composant.
Une classe composant simple est un composant non visuel descendant
directement de TComponent.
Pour créer une classe composant simple, ajoutez la déclaration de classe suivante
à la partie interface de votre unité composant :
type
TNewComponent = class(TComponent)
end;
Pour l’instant, le nouveau composant ne fait rien de plus que TComponent. C’est
juste un squelette sur lequel vous allez bâtir votre nouveau composant.
La dérivation des classes est expliquée plus en détail dans “Définition de
nouvelles classes” à la page 2-1.
Recensement du composant
Le recensement est une opération simple qui indique à l’EDI les composants
à ajouter à la bibliothèque des composants et les pages de la palette sur
lesquelles ils doivent apparaître. Pour une présentation plus détaillée du
processus de recensement, voir Chapitre 8, “Accessibilité des composants
au moment de la conception”.
Pour recenser un composant :
1 Ajoutez une procédure nommée Register à la partie interface de l’unité du
composant. Register n’a pas de paramètres, la déclaration est donc très simple :
procedure Register;
Si vous ajoutez un composant à une unité qui contient déjà des composants,
elle doit déjà avoir la procédure Register déclarée, afin que vous ne soyez pas
obligé de changer la déclaration.
Remarque Bien que Delphi soit un langage qui ne tient pas compte de la distinction
minuscules/majuscules, la procédure Register en tient compte et doit être
orthographiée avec un R majuscule.
2 Ecrivez la procédure Register dans la partie implémentation de l’unité, en
appelant RegisterComponents pour chaque composant que vous voulez recenser.
RegisterComponents est une procédure qui prend deux paramètres : le nom
d’une page de palette de composants et un ensemble de types de composants.
Si vous ajoutez un composant à un recensement existant, vous pouvez soit
ajouter le nouveau composant à l’ensemble dans l’instruction existante, soit
ajouter une nouvelle instruction qui appelle RegisterComponents.
Pour recenser un composant appelé TMyControl et le placer sur la page Exemples
de la palette, vous devrez ajouter la procédure Register suivante à l’unité
contenant la déclaration de TMyControl :
procedure Register;
begin
RegisterComponents(’Samples’, [TNewControl]);
end;
Cette procédure Register place TMyControl sur la page Exemples de la palette des
composants.
Une fois le composant recensé, vous pouvez le compiler dans un paquet
(voir Chapitre 8, “Accessibilité des composants au moment de la conception”)
et l’installer sur la palette des composants.
Une classe est d’abord un type. Comme programmeur, vous travaillez sans arrêt
avec les types et les instances, même si vous ne parlez pas en ces termes. Par
exemple, vous créez des variables d’un certain type, par exemple Integer. Les
classes sont habituellement plus complexes que de simples types de données,
mais elles fonctionnent de la même façon. En affectant différentes valeurs aux
instances d’un même type, vous effectuez différentes tâches.
Par exemple, il est courant de créer une fiche contenant deux boutons appelés
OK et Annuler. Chacun correspond à une instance de la classe TButton, mais, en
attribuant une valeur différente à leurs propriétés Caption et différents
gestionnaires à leurs événements OnClick, vous faites se comporter différemment
les deux instances.
Modification des valeurs par défaut d’une classe pour éviter les répétitions
Dans tout programme, les répétitions superflues sont à proscrire. Si vous vous
surprenez à répéter les mêmes lignes de code, vous serez sans doute amené à les
placer à part dans une sous-routine ou fonction, ou encore à construire une
bibliothèque de routines utilisables par un autre programme. Le même
raisonnement s’applique aux composants. Si vous modifiez fréquemment les
mêmes propriétés ou si vous appelez les mêmes méthodes, vous créerez sans
doute un nouveau composant qui effectue ces tâches par défaut.
Par exemple, supposons qu’à chaque création d’une nouvelle application, vous
ajoutez une boîte de dialogue accomplissant une fonction déterminée. Bien qu’il
soit simple de recréer à chaque fois cette boîte de dialogue, c’est superflu. Vous
pouvez concevoir la boîte de dialogue une fois pour toute, définir ses propriétés
puis installer le composant enveloppe associé dans la palette des composants. En
faisant du dialogue un composant réutilisable, non seulement vous éliminez une
tâche répétitive mais renforcez la standardisation et minimisez les erreurs qui
peuvent être occasionnées par chaque nouvelle création de la boîte de dialogue.
Le Chapitre 9, “Modification d’un composant existant”, montre un exemple qui
modifie les propriétés par défaut d’un composant.
Remarque Si vous voulez ne modifier que les propriétés publiées d’un composant existant
ou enregistrer des gestionnaires d’événement spécifiques à un composant ou à
un groupe de composants, vous pourrez accomplir ceci plus facilement en créant
un modèle de composant.
Déclarez les membres en private si vous voulez qu’ils ne soient disponibles que
dans la classe où ils ont été définis. Déclarez-les en protected si vous voulez
qu’ils ne soient disponibles que dans cette classe et ses descendants.
Souvenez-vous que si un membre est disponible n’importe où dans un fichier
unité, il est disponible partout dans ce fichier. Ainsi, si vous définissez deux
classes dans la même unité, elles pourront accéder à l’une ou l’autre des
méthodes privées. Et si vous dérivez une classe dans une unité différente de son
ancêtre, toutes les classes de la nouvelle unité pourront accéder aux méthodes
protégées de l’ancêtre.
var
TestForm: TTestForm;
implementation
procedure TTestForm.FormCreate(Sender: TObject);
begin
SecretForm.FSecretCode := 13; { le compilateur s’arrête avec
"Identificateur de champ attendu" }
end;
end. { fin de l’unité }
Bien qu’un programme utilisant l’unité HideInfo puisse utiliser les classes de type
TSecretForm, il ne peut accéder au champ FSecretCode dans aucune de ces classes.
Remarque Les noms et les emplacements de certaines unités sont différents pour les
applications CLX. Par exemple, l’unité Controls est QControls dans une
application CLX.
Méthodes statiques
Toutes les méthodes sont statiques à moins que vous ne les déclariez
spécifiquement autrement. Les méthodes statiques fonctionnent comme des
procédures ou des fonctions normales. Le compilateur détermine l’adresse exacte
de la méthode et la lie au moment de la compilation.
Le premier avantage des méthodes statiques est qu’elles sont réparties très
rapidement. Comme le compilateur peut déterminer l’adresse exacte de la
méthode, il la lie directement. Les méthodes virtuelles et dynamiques, au
contraire, utilisent des moyens indirects pour donner l’adresse de leurs méthodes
lors de l’exécution, ce qui prend davantage de temps.
Une méthode statique ne change pas lorsqu’elle est héritée d’une classe
descendante. Si vous déclarez une classe comprenant une méthode statique, puis
dérivez une nouvelle classe à partir de celle-ci, la classe dérivée partage
exactement la même méthode à la même adresse. Cela signifie que vous ne
pouvez pas redéfinir des méthodes statiques. Une méthode statique réalise
toujours la même chose quelle que soit la classe qui y est appelée. Si vous
déclarez une méthode dans une classe dérivée ayant le même nom qu’une
méthode statique dans la classe ancêtre, la nouvelle méthode remplace
simplement celle héritée dans la classe dérivée.
Méthodes virtuelles
Les méthodes virtuelles emploient un mécanisme de répartition plus compliqué
et plus souple que les méthodes statiques. Une méthode virtuelle peut être
redéfinie dans des classes descendantes, mais est toujours appelée dans la classe
ancêtre. L’adresse d’une méthode virtuelle n’est pas déterminée lors de la
compilation ; à la place, l’objet où la méthode est définie donne l’adresse lors de
l’exécution.
Pour qu’une méthode soit virtuelle, ajoutez la directive virtual après la
déclaration de la méthode. La directive virtual crée une entrée dans le tableau de
méthode virtuelle, de l’objet, ou VMT, qui contient les adresses de toutes les
méthodes virtuelles d’un type objet.
Lorsque vous dérivez une nouvelle classe d’une classe existante, la nouvelle
classe a son propre VMT, qui comprend toutes les entrées provenant du VMT de
l’ancêtre plus toutes les méthodes virtuelles supplémentaires déclarées dans la
nouvelle classe.
Méthodes dynamiques
Les méthodes dynamiques sont des méthodes virtuelles avec un mécanisme de
répartition légèrement différent. Comme les méthodes dynamiques n’ont pas
d’entrées dans le tableau de méthode virtuelle de l’objet, elles peuvent réduire la
taille de la mémoire consommée par les objets. Cependant les méthodes de
répartition dynamiques sont quelque peu plus lentes que les méthodes de
répartition virtuelles normales. Si une méthode est fréquemment appelée, ou si
son exécution nécessite un temps court, vous devrez probablement la déclarer
virtuelle plutôt que dynamique.
Les objets doivent stocker les adresses de leurs méthodes dynamiques. Mais
plutôt que de recevoir les entrées dans le tableau de méthode virtuelle, les
méthodes dynamiques sont indiquées séparément. La liste des méthodes
dynamiques contient des entrées uniquement pour les méthodes introduites ou
redéfinies par une classe particulière. (le tableau de méthode virtuelle, à
l’inverse, comprend toutes les méthodes virtuelles de l’objet, à la fois héritées et
introduites). Les méthodes dynamiques héritées sont réparties en cherchant
chaque liste de méthode dynamique de l’ancêtre, en allant en arrière dans
l’arborescence de l’héritage.
Pour rendre une méthode dynamique, ajoutez la directive dynamic après la
déclaration de méthode.
Classes et pointeurs
Chaque classe (et par conséquent chaque composant) est en fait un pointeur. Le
compilateur déréférence automatiquement les pointeurs de classe à votre place,
aussi n’avez-vous généralement pas besoin de vous poser ces questions. Le statut
des classes en tant que pointeurs devient important lorsque vous passez une
classe comme paramètre. En général, vous transmettrez les classes par valeur
plutôt que par référence. Car les classes sont déjà des pointeurs, c’est-à-dire des
références ; transmettre une classe par référence serait transmettre une référence à
une référence.
Création de propriétés
Chapitre3
3
Les propriétés sont la partie la plus visible des composants. Le développeur
d’applications a la possibilité de les voir et de les manipuler au moment de la
conception et dispose d’un retour immédiat au fur et à mesure que réagissent les
composants dans le concepteur de fiches. Des propriétés bien conçues simplifient
l’utilisation de vos composants par d’autres programmeurs et en facilitent la
maintenance.
Pour utiliser de façon optimale les propriétés de vos composants, vous devez
connaître les points suivants :
• Pourquoi créer des propriétés ?
• Types de propriétés
• Publication des propriétés héritées
• Définition des propriétés
• Création de propriétés tableau
• Stockage et chargement des propriétés
fournit valeurs. L’inspecteur d’objets valide les affectations des valeurs aux
propriétés dès qu’elles sont effectuées.
• Les propriétés peuvent masquer les détails de l’implémentation. Par exemple,
des données stockées de façon interne sous une forme cryptée peuvent
apparaître non cryptées en tant que la valeur d’une propriété ; bien que
la valeur puisse être un simple nombre, le composant peut rechercher cette
valeur dans une base de données ou effectuer des calculs complexes afin de
la récupérer. Les propriétés permettent d’associer des opérations complexes
à une simple affectation ; ce qui apparaît comme l’affectation d’un champ
correspond en fait à un appel de méthode et cette dernière peut accomplir
à peu près n’importe quelle tâche.
• Les propriétés peuvent être virtuelles. Ce qui paraît être une seule propriété
pour le développeur d’applications peut être implémenté de manière
différente dans des composants différents.
Un exemple simple est la propriété Top que tous les contrôles possèdent.
L’attribution d’une nouvelle valeur à Top n’a pas pour seul effet de modifier une
valeur mémorisée ; elle provoque aussi le déplacement et le réaffichage du
contrôle. Les effets de la définition d’une propriété ne se limitent pas
nécessairement à un composant unique ; par exemple, donner la valeur True
à la propriété Down d’un turbobouton a pour effet d’attribuer la valeur False
à la propriété Down de tous les autres turboboutons du même groupe.
Types de propriétés
Une propriété peut avoir un type quelconque. Les divers types sont affichés
de manière différente dans l’inspecteur d’objets, ce qui valide l’affectation des
propriétés effectuées au moment de la conception.
Accès direct
L’accès direct est le moyen le plus simple d’accéder aux données d’une propriété.
Autrement dit, les parties read et write de la déclaration d’une propriété
spécifient que l’affectation ou la lecture de la valeur de la propriété s’effectue
directement dans le champ de stockage interne sans appel à une méthode
d’accès. L’accès direct est utile lorsque vous voulez rendre une propriété
accessible dans l’inspecteur d’objets, mais que vous ne voulez pas que le
changement de sa valeur déclenche un processus immédiatement.
En général, vous définirez un accès direct pour la partie read d’une déclaration
de propriété et utiliserez une méthode d’accès pour la partie write. Cela permet
de mettre à jour l’état du composant lorsque la valeur de la propriété change.
La déclaration de type composant suivante montre une propriété qui utilise
l’accès direct pour les parties read et write.
type
TSampleComponent = class(TComponent)
private { le stockage interne est privé }
FMyProperty: Boolean; { déclare la donnée membre pour contenir la valeur }
published { rend la propriété disponible à la conception }
property MyProperty: Boolean read FMyProperty write FMyProperty;
end;
Méthodes d’accès
Vous pouvez spécifier une méthode d’accès plutôt qu’un champ dans les parties
read et write d’une déclaration de propriété. Les méthodes d’accès doivent être
protected, et sont habituellement déclarées comme virtual ; cela autorise les
composants descendants à surcharger l’implémentation de la propriété.
Evitez de rendre publiques les méthodes d’accès. Les conserver protected vous
prémunit contre toute modification accidentelle d’une propriété par un
développeur d’applications qui appellerait ces méthodes.
Voici une classe qui déclare trois propriétés en utilisant le spécificateur d’index,
qui autorise aux trois propriétés d’avoir les mêmes méthodes d’accès en lecture
et en écriture :
type
TSampleCalendar = class(TCustomGrid)
public
property Day: Integer index 3 read GetDateElement write SetDateElement;
property Month: Integer index 2 read GetDateElement write SetDateElement;
property Year: Integer index 1 read GetDateElement write SetDateElement;
private
function GetDateElement(Index: Integer): Integer; { notez le paramètre Index }
procedure SetDateElement(Index: Integer; Value: Integer);
ƒ
Comme chaque élément de la date (day, month et year) est un int et comme la
définition de chacun requiert le codage de la date lorsqu’elle est définie, le code
évite la duplication en partageant les méthodes de lecture et d’écriture pour les
trois propriétés. Vous n’avez besoin que d’une seule méthode pour lire un
élément date et une autre pour écrire l’élément date.
Voici la méthode read qui obtient l’élément date :
function TSampleCalendar.GetDateElement(Index: Integer): Integer;
var
AYear, AMonth, ADay: Word;
begin
DecodeDate(FDate, AYear, AMonth, ADay); { éclate la date encodée en éléments }
case Index of
1: Result := AYear;
2: Result := AMonth;
3: Result := ADay;
else Result := -1;
end;
end;
Voici la méthode write qui définit l’élément date approprié :
procedure TSampleCalendar.SetDateElement(Index: Integer; Value: Integer);
var
AYear, AMonth, ADay: Word;
begin
if Value > 0 then { tous les éléments doivent être positifs }
begin
DecodeDate(FDate, AYear, AMonth, ADay); { récupère les éléments courants de la date }
case Index of { définit le nouvel élément selon l’index }
1: AYear := Value;
2: AMonth := Value;
3: ADay := Value;
else Exit;
end;
FDate := EncodeDate(AYear, AMonth, ADay); { encode la date modifiée }
Refresh; { mise à jour du calendrier visible }
end;
end;
Méthode read
La méthode read d’une propriété est une fonction qui n’accepte aucun paramètre
(sauf pour ce qui est mentionné ci-après) et renvoie une valeur du même type
que la propriété. Par convention, le nom de la fonction est Get suivi du nom de
la propriété. Par exemple, la méthode read pour une propriété intitulée Count
serait GetCount. La méthode read manipule les données internes afin de générer
une valeur de la propriété respectant le type demandé.
Les seules exceptions à la règle “aucun paramètre” sont les propriétés tableau et
les propriétés qui utilisent un spécificateur d’index (voir “Création de propriétés
tableau” à la page 3-9), pour lesquelles cet index est transmis comme paramètre.
Utilisez des spécificateurs d’index pour créer une méthode read unique partagée
par plusieurs propriétés. Pour plus d’informations sur les spécificateurs d’index,
voir le Guide du langage Delphi.)
Si vous ne déclarez aucune méthode read, la propriété fonctionne uniquement en
écriture. Les propriétés fonctionnant en écriture uniquement sont très rares.
Méthode write
La méthode write d’une propriété est une procédure acceptant un seul paramètre
(sauf pour ce qui est mentionné ci-après) du même type que la propriété. Le
paramètre peut être transmis par référence ou par valeur et peut porter le nom
de votre choix. Par convention, le nom de la méthode write est Set suivi du nom
de la propriété. Par exemple, la méthode write d’une propriété intitulée Count
serait SetCount. La valeur transmise en paramètre devient la nouvelle valeur de
la propriété ; la méthode write doit accomplir les manipulations nécessaires pour
placer les données concernées à l’emplacement de stockage interne de la
propriété.
Les seules exceptions à la règle “paramètre unique” sont les propriétés tableau et
les propriétés qui utilisent un spécificateur d’index, pour lesquelles cet index est
transmis comme second paramètre. Utilisez des spécificateurs d’index pour créer
une méthode read unique partagée par plusieurs propriétés. Pour plus
d’informations sur les spécificateurs d’index, voir le Guide du langage Delphi.)
Si vous ne déclarez aucune méthode write, la propriété fonctionne uniquement
en lecture.
Les méthodes write testent normalement si une nouvelle valeur diffère de la
valeur actuelle avant de modifier la propriété. Par exemple, voici une méthode
write simple d’une propriété de type entier appelée Count stockant sa valeur
courante dans un champ appelé FCount.
procedure TMyComponent.SetCount(Value: Integer);
begin
if Value <> FCount then
begin
FCount := Value;
Update;
end;
end;
begin
FTimer := TTimer.Create(self);
FTimer.Name := ’Timer’; bit facultatif, rend le résultat plus agréable
FTimer.SetSubComponent(True);
FTimer.FreeNotification(self);
end;
end;
end;
end;
Remarquez que le setter de la propriété a appelé la méthode FreeNotification du
composant défini comme valeur de la propriété. Cet appel garantit que le
composant servant de valeur à la propriété envoie une notification au moment
où il est sur le point d’être détruit. Il envoie cette notification en appelant la
méthode Notification. Vous gérez cet appel en surchargeant la méthode
Notification, comme suit :
procedure TDemoComponent.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (AComponent = FTimer) then
FTimer := nil;
end;
Détermination du stockage
Vous pouvez choisir si Delphi stocke ou non chacune des propriétés de vos
composants. Par défaut, sont stockées toutes les propriétés de la partie published
de la déclaration de classe. Vous pouvez choisir de ne pas stocker une propriété
ou de désigner une fonction qui décidera, de manière dynamique, du stockage
de la propriété.
Pour contrôler le stockage par Delphi d’une propriété, ajoutez la directive stored
à la déclaration de propriété, suivie par true, false ou le nom d’une fonction
booléenne.
Le code suivant montre un composant avec la déclaration de trois nouvelles
propriétés. La première est toujours stockée, la deuxième ne l’est jamais et la
troisième est stockée selon la valeur d’une fonction booléenne :
type
TSampleComponent = class(TComponent)
protected
function StoreIt: Boolean;
public
ƒ
published
property Important: Integer stored True; { toujours stockée }
property Unimportant: Integer stored False; { jamais stockée }
property Sometimes: Integer stored StoreIt; { dépend de la valeur de la fonction }
end;
procedure TDatabase.Loaded;
begin
inherited Loaded; { appelle d’abord la méthode héritée }
try
if FStreamedConnected then Open { rétablit les connexions }
else CheckSessionName(False);
except
if csDesigning in ComponentState then { lors de la conception... }
Application.HandleException(Self) { permet à Delphi de gérer l’exception }
else raise; { sinon, redéclenche }
end;
end;
• Créer deux méthodes de type TStreamProc, une pour stocker et une pour
charger la valeur de propriété. TStreamProc accepte un flux comme argument
et vous pouvez utiliser les méthodes du flux afin d’écrire et lire les valeurs de
propriétés.
Prenons pour exemple une propriété représentant un composant créé à
l’exécution. Delphi sait comment écrire cette valeur, mais ne le fait pas
automatiquement car le composant n’est pas créé dans le concepteur de fiches.
Puisque le système de flux peut dès à présent charger et enregistrer des
composants, vous pouvez utiliser la première approche. Les méthodes suivantes
chargent et stockent le composant créé dynamiquement qui représente la valeur
d’une propriété appelée MyCompProperty :
procedure TSampleComponent.LoadCompProperty(Reader: TReader);
begin
if Reader.ReadBoolean then
MyCompProperty := Reader.ReadComponent(nil);
end;
procedure TSampleComponent.StoreCompProperty(Writer: TWriter);
begin
Writer.WriteBoolean(MyCompProperty <> nil);
if MyCompProperty <> nil then
Writer.WriteComponent(MyCompProperty);
end;
Création d’événements
Chapitre4
4
Un événement est un lien entre une occurrence du système (une action
de l’utilisateur ou un changement de focalisation, par exemple) et le fragment
de code qui assure effectivement la réponse. Le code de réponse est le
gestionnaire de l’événement, dont l’écriture est presque toujours du ressort du
développeur de l’application. Grâce aux événements, les développeurs peuvent
personnaliser le comportement des composants sans avoir besoin de modifier
les classes elles-mêmes. Cela s’appelle la délégation.
Les événements associés aux actions utilisateur les plus usuelles (par exemple,
les actions de la souris) sont intégrés dans les composants standard, mais vous
pouvez aussi définir de nouveaux événements. Pour être capable de créer des
événements dans un composant, vous devez avoir compris ce qui suit :
• Qu’est-ce qu’un événement ?
• Implémentation des événements standard
• Définition de vos propres événements
Les événements étant implémentés en tant que propriétés, il vaut mieux avoir
bien compris le Chapitre 3, “Création de propriétés”, avant de créer ou de
modifier les événements d’un composant.
Remarque Pour répondre aux frappes de touches spéciales (comme la touche Alt), vous
devez répondre au message WM_GETDLGCODE ou CM_WANTSPECIALKEYS
de Windows. Voir Chapitre 7, “Gestion des messages et des notifications
système”, pour plus d’informations sur l’écriture de gestionnaires de messages.
de composant et si votre code agit sur cet état, vous devez d’abord effectuer ces
changements d’état avant d’autoriser le code de l’utilisateur à y répondre.
Supposons que vous écrivez un composant et que vous souhaitez modifier la
façon dont il répond aux clics de souris. Au lieu d’associer un gestionnaire à
l’événement OnClick, comme le ferait le développeur d’applications, redéfinissez
la méthode protégée Click :
procedure click override { déclaration forward }
ƒ
procedure TMyControl.Click;
begin
inherited Click; { exécute la gestion standard, y compris l’appel au gestionnaire }
ƒ { vos modifications s’insèrent ici }
end;
Déclenchement de l’événement
Vous avez besoin de savoir ce qui a déclenché l’événement. Pour certains
événements, la réponse est évidente. Par exemple, un événement associé à
l’enfoncement du bouton de souris se produit lorsque l’utilisateur clique avec
le bouton gauche de la souris provoquant l’envoi par Windows d’un message
WM_LBUTTONDOWN à l’application. La réception de ce message provoque
l’appel de la méthode MouseDown d’un composant qui à son tour appelle le code
que l’utilisateur a associé à l’événement OnMouseDown.
Néanmoins, certains événements sont liés de façon moins évidente à des
occurrences externes moins spécifiques. Par exemple, une barre de défilement
dispose d’un événement OnChange qui peut être déclenché par plusieurs
occurrences, telles des frappes de touche, des clics de souris, ou des
modifications dans d’autres contrôles. Lorsque vous définissez vos événements,
assurez-vous que les occurrences appellent tous les événements appropriés.
Remarque Pour les applications CLX, voir “Réponse aux notifications du système à l’aide
de CLX” à la page 7-10.
Notifications simples
Un événement de type notification ne fait qu’indiquer qu’un événement
particulier s’est produit sans fournir aucune information sur le moment et
l’endroit où il s’est produit. Les notifications utilisent le type TNotifyEvent, qui
véhiculent un paramètre unique correspondant à l’émetteur de l’événement. Les
seuls éléments “connus” du gestionnaire associé à une notification sont donc le
type d’événement et le composant impliqué. Par exemple, les événements clic de
souris sont des notifications. Lorsque vous écrivez un gestionnaire pour un
événement de ce type, vous ne récupérez que deux informations : le fait qu’un
clic s’est produit et le composant impliqué.
Une notification est un processus à sens unique. Il n’existe aucun mécanisme
pour renvoyer une information en retour ou pour inhiber la gestion d’une
notification.
Déclaration de l’événement
Une fois déterminé le type de votre gestionnaire d’événement, vous pouvez
déclarer le pointeur de méthode et la propriété pour l’événement. N’oubliez pas
d’attribuer un nom à l’événement qui soit à la fois significatif et descriptif pour
que l’utilisateur puisse comprendre son rôle. Dans la mesure du possible,
choisissez des noms de propriétés qui ressemblent à ceux de composants déjà
définis.
Appel de l’événement
Il est préférable de centraliser tous les appels à un événement. Autrement dit,
créez une méthode virtuelle dans votre composant qui appelle le gestionnaire
d’événement de l’application (s’il a été défini) et qui fournit une gestion par
défaut.
Création de méthodes
Chapitre5
5
Les méthodes des composants sont des procédures et des fonctions intégrées
dans la structure d’une classe. Il n’existe pratiquement aucune restriction sur
ce que peuvent réaliser les méthodes d’un composant, mais Delphi n’en respecte
pas moins un certain nombre de standards qu’il est préférable de suivre.
Ce sont :
• Eviter les interdépendances
• Noms des méthodes
• Protection des méthodes
• Rendre virtuelles des méthodes
• Déclaration des méthodes
En général, les composants ne doivent pas contenir beaucoup de méthodes
et vous devez chercher à minimiser le nombre des méthodes appelées par une
application. Il est préférable d’encapsuler sous la forme de propriétés des
caractéristiques qu’il serait tentant d’implémenter sous forme de méthodes.
Les propriétés fournissent une interface qui s’inscrit parfaitement dans Delphi et
sont accessibles au moment de la conception.
Méthodes abstraites
Une méthode est parfois déclarée abstract dans un composant Delphi. Dans la
bibliothèque de composants, les méthodes abstraites se produisent habituellement
dans les classes dont les noms commencent par “custom”, comme dans
TCustomGrid TCustomGrid. De telles classes sont elles-mêmes abstraites, au sens
où elles ne servent qu’à la dérivation de classes descendantes.
Bien que vous puissiez créer un objet instance d’une classe contenant un membre
abstrait, ce n’est pas recommandé. L’appel du membre abstrait entraîne une
exception EAbstractError.
La directive abstract est utilisée pour indiquer des parties de classes qui doivent
être surfacées et définies dans des composants descendants ; cela force les
écrivains de composants à redéclarer le membre abstrait dans des classes
descendantes avant que des instances actuelles de la classe puissent être créées.
public
function CalculateArea: Integer; virtual; { déclare la méthode public virtual }
end;
ƒ
implementation
ƒ
procedure TSampleComponent.MakeBigger; { implémente la première méthode }
begin
Height := Height + 5;
Width := Width + 5;
end;
function TSampleComponent.CalculateArea: Integer; { implémente la deuxième méthode }
begin
Result := Width * Height;
end;
Graphiques et composants
Chapitre6
6
Windows fournit une puissante interface GDI (Graphics Device Interface) servant
à dessiner des graphiques indépendamment des périphériques.
Malheureusement, GDI impose au programmeur des contraintes supplémentaires
telles que la gestion des ressources graphiques. Delphi prend en charge toutes
ces tâches GDI ingrates, vous laisse vous concentrer sur le travail productif, vous
épargnant les recherches de handles perdus ou de ressources non restituées.
De même que toute partie de l’API Windows, vous pouvez appeler les fonctions
GDI directement depuis votre application Delphi Toutefois, vous vous rendrez
vite compte que l’utilisation de l’encapsulation Delphi des fonctions graphiques
est un moyen plus efficace et plus rapide de créer des graphiques.
Remarque Les fonctions GDI sont particulières à Windows et ne s’appliquent pas aux
applications CLX. Mais, des composants CLX utilisent la bibliothèque Qt.
Les rubriques de cette section comprennent :
• Présentation des graphiques
• Utilisation du canevas
• Travail sur les images
• Bitmaps hors écran
• Réponse aux changements
Utilisation du canevas
La classe canevas encapsule les contrôles graphiques à plusieurs niveaux, allant
des fonctions de haut niveau (pour dessiner des lignes, des formes et du texte)
aux propriétés de niveau intermédiaire pour manipuler les fonctionnalités de
dessin du canevas ; et dans la bibliothèque de composants, offre un accès de bas
niveau au GDI Windows.
Le Tableau 6.1 résume les possibilités du canevas.
Pour plus d’informations sur les classes canevas, leurs méthodes et leurs
propriétés, reportez-vous à l’aide en ligne.
Les trois sujets suivants sont nécessaires à la compréhension du travail sur les
images dans Delphi :
• Utilisation d’une image, d’un graphique ou d’un canevas
• Chargement et stockage des graphiques
• Gestion des palettes
Pour charger une image dans un objet image à partir d’un fichier, appelez la
méthode LoadFromFile de l’objet image. Pour enregistrer une image dans un
fichier à partir d’un objet image, appelez la méthode SaveToFile de l’objet image.
LoadFromFile et SaveToFile acceptent le nom d’un fichier comme seul paramètre.
LoadFromFile utilise l’extension du fichier pour déterminer le type d’objet
graphique créé ou chargé. SaveToFile utilise le type de fichier approprié au type
d’objet graphique enregistré.
Pour charger un bitmap dans l’objet image d’un contrôle image, par exemple,
vous devez transmettre le nom du fichier bitmap à la méthode LoadFromFile de
l’objet image :
procedure TForm1.LoadBitmapClick(Sender: TObject);
begin
Image1.Picture.LoadFromFile(’RANDOM.BMP’);
end;
L’objet image reconnaît .bmp comme extension par défaut des fichiers bitmap,
elle crée donc le graphique en tant que TBitmap, avant d’appeler la méthode
LoadFromFile du graphique. Puisque le graphique est un bitmap, l’image est
chargée depuis le fichier en tant que bitmap.
plutôt construire un objet bitmap puis dessiner sur son canevas avant de copier
la totalité de l’image sur le canevas affiché.
La méthode Paint d’un contrôle graphique est un exemple d’utilisation typique
d’un bitmap hors écran. Comme avec tout objet temporaire, l’objet bitmap doit
être protégé par un bloc try..finally :
type
TFancyControl = class(TGraphicControl)
protected
procedure Paint; override; { surcharge la méthode Paint }
end;
procedure TFancyControl.Paint;
var
Bitmap: TBitmap; { variable temporaire pour le bitmap hors écran }
begin
Bitmap := TBitmap.Create; { construit l’objet bitmap }
try
{ dessine sur le bitmap }
{ copie le résultat dans le canevas du contrôle }
finally
Bitmap.Free; { détruit l’objet bitmap }
end;
end;
des messages qu’il répartit selon le message en appelant une méthode choisie
dans un ensemble de méthodes spécifiques. Un gestionnaire par défaut est
appelé si aucune méthode n’est définie pour le message.
Le diagramme suivant illustre le fonctionnement du système de répartition
de message :
Evénement MainWndProc WndProc Dispatch Gestionnaire
Windows ne sont pas utilisés sous Linux. A la place, CLX utilise un moyen
ne dépendant pas de la plate-forme pour répondre aux notifications système.
Dans CLX, l’équivalent des messages Windows est un système de signaux
à partir de la couche widget sous-jacente. Alors que dans la VCL, les messages
Windows proviennent soit du système d’exploitation, soit des contrôles Windows
natifs que la VCL enveloppe, la couche widget utilisée par CLX fait une
distinction entre les deux. Si la notification provient d’un widget, on l’appelle un
signal. Si la notification provient du système d’exploitation, on l’appelle un
événement système. La couche widget communique les événements système
à vos composants CLX sous forme d’un signal de type événement.
Remarque Les méthodes de chaque objet intercepteur sont déclarées dans l’unité Qt.
Les méthodes sont présentées linéairement dans des routines globales avec des
noms qui reflètent l’objet intercepteur auquel elles appartiennent. Par exemple,
toutes les méthodes de l’objet intercepteur associé au widget application
(QApplication) commencent par ‘QApplication_hook.’ Cette dé-hiérarchisation est
nécessaire pour que l’objet CLX Delphi puisse accéder aux méthodes depuis
l’objet intercepteur C++.
Tableau 7.1 Méthodes protégées de TWidgetControl pour la réponse aux notifications système
Méthode Description
BeginAutoDrag Appelée quand l’utilisateur clique sur le bouton gauche de la souris si le
contrôle a un DragMode de dmAutomatic.
Click Appelée quand l’utilisateur relâche le bouton de la souris au-dessus du
contrôle.
DblClick Appelée quand l’utilisateur double-clique avec la souris au-dessus du
contrôle.
DoMouseWheel Appelée quand l’utilisateur quand l’utilisateur tourne la molette de la
souris.
DragOver Appelée quand l’utilisateur fait glisser le curseur de la souris au-dessus
du contrôle.
KeyDown Appelée quand l’utilisateur appuie sur une touche alors que le contrôle
détient la focalisation.
KeyPress Appelée après KeyDown si KeyDown ne gère pas la frappe de touche.
KeyString Appelée quand l’utilisateur entre une frappe de touche et que le système
utilise un jeu de caractères multi-octets.
KeyUp Appelée quand l’utilisateur relâche une touche alors que le contrôle
détient la focalisation.
MouseDown Appelée quand l’utilisateur clique sur le bouton de la souris au-dessus
du contrôle.
MouseMove Appelée quand l’utilisateur déplace le curseur de la souris au-dessus du
contrôle.
MouseUp Appelée quand l’utilisateur relâche le bouton de la souris au-dessus du
contrôle.
PaintRequest Appelée quand système a besoin de redessiner le contrôle.
WidgetDestroyed Appelée lorsqu’un widget sous-jacent à un contrôle est détruit.
Dans la surcharge, appelez la méthode héritée pour que les processus par défaut
répondent aux signaux.
Remarque Outre les méthodes qui répondent aux événements système, les contrôles
incluent un certain nombre de méthodes similaires provenant de TControl ou de
TWidgetControl pour notifier au contrôle divers événements. Bien qu’elles ne
répondent pas aux événements système, elles effectuent les mêmes tâches que la
plupart des messages Windows envoyés aux contrôles VCL. Le Tableau 7.1
contient la liste de ces méthodes.
Tableau 7.2 Méthodes protégées de TWidgetControl pour répondre aux événements des contrôles
Méthode Description
BoundsChanged Appelée quand le contrôle est redimensionné.
ColorChanged Appelée quand la couleur du contrôle change.
CursorChanged Appelée quand le curseur change de forme. Le curseur de la souris
adopte cette forme lorsqu’il est au-dessus de ce widget.
EnabledChanged Appelée lorsqu’une application change l’état activé d’une fenêtre ou
d’un contrôle.
FontChanged Appelée quand l’ensemble des ressources de polices change.
PaletteChanged Appelée quand la palette du widget change.
ShowHintChanged Appelée quand les conseils d’aide d’un contrôle sont affichés ou cachés.
StyleChanged Appelée quand les styles de l’interface graphique utilisateur de la fenêtre
ou du contrôle changent.
TabStopChanged Appelée quand l’ordre de tabulation de la fiche change.
TextChanged Appelée quand le texte du contrôle change.
VisibleChanged Appelée quand un contrôle est caché ou rendu visible.
La rubrique associée au composant doit avoir une note de bas de page “K”
(qui indique les mots clé de recherche) comprenant le nom de la classe du
composant. Par exemple, la note de bas de page des mots clés pour le
composant TMemo contient “TMemo”.
La rubrique associée au composant doit également comprendre une note de
bas de page $ qui indique le titre de la rubrique. Le titre apparaît dans la
boîte de dialogue des rubriques, la boîte de dialogue Signet et la fenêtre
Historique.
2 Chaque composant doit inclure les rubriques de navigation secondaires
suivantes :
• Une rubrique de hiérarchie offrant des liens vers chaque ancêtre
du composant appartenant à sa hiérarchie.
• Une liste de toutes les propriétés disponibles dans le composant,
avec des liens vers les entrées décrivant ces propriétés.
• Une liste de tous les événements disponibles dans le composant,
avec des liens vers les entrées décrivant ces événements.
• Une liste de toutes les méthodes disponibles dans le composant,
avec des liens vers les entrées décrivant ces méthodes.
Les liens vers les classes d’objets, les propriétés ou les événements dans le
système d’aide de Delphi peuvent être réalisés à l’aide de Alinks. Alink opère
la liaison vers une classe d’objet en utilisant le nom de classe de l’objet suivi
d’un caractère de soulignement et de la chaîne “object”. Par exemple, pour
réaliser un lien vers l’objet TCustomPanel, utilisez le code suivant :
!AL(TCustomPanel_object,1)
Pour réaliser un lien vers une propriété, une méthode ou un événement, faites
précéder son nom par celui de l’objet qui l’implémente et par un caractère de
soulignement. Par exemple, pour réaliser un lien vers la propriété Text
implémentée par TControl, utilisez le code suivant :
!AL(TControl_Text,1)
Pour voir un exemple de rubriques de navigation secondaires, affichez l’aide
d’un composant quelconque et cliquez sur les liens étiquetés hiérarchie,
propriétés, méthodes ou événements.
3 Chaque propriété, événement ou méthode déclaré à l’intérieur du composant
doit avoir une rubrique.
Une rubrique décrivant une propriété, un événement ou une méthode doit
indiquer la déclaration de l’élément et décrire son rôle. Les développeurs
d’applications accéderont à cette rubrique en sélectionnant l’élément dans
l’inspecteur d’objets et en appuyant sur F1, ou en plaçant le curseur dans
l’éditeur de code sur le nom de l’élément et en appuyant sur F1. Pour avoir
un exemple de rubrique associée à une propriété, sélectionnez un élément
quelconque dans l’inspecteur d’objets et appuyez sur F1.
Tableau 8.2 Méthodes pour lire et écrire les valeurs des propriétés
Type de propriété Méthode Get Méthode Set
Virgule flottante GetFloatValue SetFloatValue
Pointeur de méthode (événement) GetMethodValue SetMethodValue
Type ordinal GetOrdValue SetOrdValue
Chaîne GetStrValue SetStrValue
Lorsque vous redéfinissez une méthode GetValue, appelez l’une des méthodes
“Get”. Lorsque vous redéfinissez SetValue, appelez l’une des méthodes “Set”.
Les propriétés Color sont plus polyvalentes que la plupart des autres propriétés,
l’utilisateur dispose de plusieurs moyens pour sélectionner une couleur dans
l’inspecteur d’objets : il peut taper une valeur, sélectionner dans une liste ou faire
appel à l’éditeur personnalisé. C’est pourquoi la méthode GetAttributes de
TColorProperty, inclut plusieurs attributs dans la valeur qu’elle renvoie :
function TColorProperty.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paDialog, paValueList, paRevertable];
end;
Catégories de propriétés
Dans l’IDE, l’inspecteur d’objets vous permet de masquer et d’afficher
sélectivement des propriétés basées sur les catégories de propriété. Les propriétés
des nouveaux composants personnalisés peuvent rentrer dans ce schéma en
recensant des propriétés par catégories. Faites ceci lors du recensement du
composant en appelant RegisterPropertyInCategory ou RegisterPropertiesInCategory.
Utilisez RegisterPropertyInCategory pour recenser une seule propriété. Utilisez
RegisterPropertiesInCategory pour recenser plusieurs propriétés dans un seul appel
de fonction. Ces fonctions sont définies dans l’unité DesignIntf.
Notez qu’il n’est pas obligatoire de recenser des propriétés ni que toutes les
propriétés d’un composant personnalisé soient recensées lorsque quelques-unes le
sont. Toute propriété non explicitement associée à une catégorie est incluse dans
la catégorie TMiscellaneousCategory. De telles propriétés sont affichées ou
masquées dans l’inspecteur d’objets selon cette catégorisation par défaut.
En plus de ces deux fonctions de recensement de propriétés, il existe une
fonction IsPropertyInCategory. Cette fonction est utile pour la création d’utilitaires
de localisation, dans laquelle vous devez déterminer si une propriété est recensée
dans une catégorie de propriété donnée.
Redéfinition du constructeur
Lorsque vous placez un composant dans une fiche au moment de la conception
ou lorsqu’une application en cours d’exécution construit un composant, le
Déclaration de la propriété
Généralement, pour déclarer une propriété, vous déclarez un champ privé pour
stocker les données de la propriété puis vous spécifiez les méthodes pour lire et
écrire sa valeur. Souvent, la méthode pour lire la valeur n’est pas nécessaire car
un simple pointage sur la valeur stockée suffit.
S’agissant de notre contrôle forme, vous aurez à déclarer un champ contenant la
forme courante, puis à déclarer une propriété qui lit ce champ et l’écrit via un
appel de méthode.
Ajoutez les déclarations suivantes dans TSampleShape :
type
TSampleShape = class(TGraphicControl)
private
FShape: TSampleShapeType; { champ pour contenir la valeur de la propriété }
procedure SetShape(Value: TSampleShapeType);
published
property Shape: TSampleShapeType read FShape write SetShape;
end;
Il ne vous reste plus qu’à ajouter l’implémentation de SetShape.
Pour changer les valeurs initiales des propriétés du composant, vous devez
redéfinir le constructeur afin qu’il affecte les valeurs voulues. Le constructeur
doit être virtuel.
Souvenez-vous que vous devez ajouter le constructeur à la partie public de la
déclaration de la classe du composant, puis écrire le nouveau constructeur dans
la partie implémentation de l’unité du composant. La première instruction du
nouveau constructeur doit toujours être un appel au constructeur hérité. Ensuite,
ajoutez l’unité StdCtrls à la clause uses.
type
TSampleCalendar = class(TCustomGrid
public
constructor Create(AOwner: TComponent); override;
ƒ
end;
ƒ
constructor TSampleCalendar.Create(AOwner: TComponent);
begin
inherited Create(AOwner); { appelle le constructeur hérité }
ColCount := 7; { toujours 7 jours/semaine }
RowCount := 7; { toujours 6 semaines plus les titres }
FixedCols := 0; { aucun libellé de ligne }
FixedRows := 1; { une ligne pour les noms de jour }
ScrollBars := ssNone; { pas de défilement nécessaire }
Options := Options - [goRangeSelect] + [goDrawFocusSelected]; {désactive la sélection
d’intervalle }
end;
Le calendrier a dorénavant sept colonnes et sept lignes, avec la ligne de titre fixe
(ou qui ne défile pas).
Pour remplir le contenu des cellules de la grille, vous devez redéfinir la méthode
DrawCell.
Les cellules de titre de la ligne fixe sont ce qu’il y a de plus facile à remplir. La
bibliothèque d’exécution contient un tableau avec l’intitulé raccourci des jours et
il vous faut donc insérer l’intitulé approprié à chaque colonne :
type
TSampleCalendar = class(TCustomGrid)
protected
procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
override;
end;
ƒ
procedure TSampleCalendar.DrawCell(ACol, ARow: Longint; ARect: TRect;
AState: TGridDrawState);
begin
if ARow = 0 then
Canvas.TextOut(ARect.Left, ARect.Top, ShortDayNames[ACol + 1]);
{ utilise les chaînes RTL }
end;
Suivi de la date
Pour que le contrôle calendrier soit utile, les utilisateurs ainsi que les
applications doivent disposer d’un moyen de définir la date, le mois et l’année.
Delphi stocke les dates et les heures dans des variables de type TDateTime.
TDateTime est une représentation numérique encodée des dates et des heures
particulièrement pratique pour être manipulée par un programme mais peu
commode à interpréter par un utilisateur.
Vous pouvez donc stocker la date du calendrier sous une forme encodée et
fournir un accès direct à cette valeur lors de l’exécution, mais vous pouvez aussi
fournir les propriétés Day, Month et Year que l’utilisateur du composant peut
définir lors de la conception.
Le suivi de la date dans le calendrier comprend les traitements suivants :
• Stockage interne de la date
• Accès au jour, au mois et à l’année
• Génération des numéros de jours
• Sélection du jour en cours
TSampleCalendar = class(TCustomGrid)
private
FDate: TDateTime;
ƒ
2 Initialisez le champ date dans le constructeur :
constructor TSampleCalendar.Create(AOwner: TComponent);
begin
inherited Create(AOwner); { existait déjà }
ƒ { d’autres initialisations ici }
FDate := Date; { prend la date active du RTL }
end;
3 Déclarez une propriété à l’exécution pour accéder à la date encodée.
Vous aurez besoin d’une méthode pour définir la date car sa définition
entraîne la mise à jour de l’image sur l’écran du contrôle :
type
TSampleCalendar = class(TCustomGrid)
private
procedure SetCalendarDate(Value: TDateTime);
public
property CalendarDate: TDateTime read FDate write SetCalendarDate;
ƒ
procedure TSampleCalendar.SetCalendarDate(Value: TDateTime);
begin
FDate := Value; { définit la nouvelle valeur date }
Refresh; { met à jour l’image à l’écran }
end;
ƒ
2 Déclarez et écrivez les méthodes d’implémentation, définissant les différents
éléments pour chaque valeur d’index :
type
TSampleCalendar = class(TCustomGrid)
private
function GetDateElement(Index: Integer): Integer; { notez le paramètre Index }
procedure SetDateElement(Index: Integer; Value: Integer);
ƒ
function TSampleCalendar.GetDateElement(Index: Integer): Integer;
var
AYear, AMonth, ADay: Word;
begin
DecodeDate(FDate, AYear, AMonth, ADay); { éclate la date encodée en éléments }
case Index of
1: Result := AYear;
2: Result := AMonth;
3: Result := ADay;
else Result := -1;
end;
end;
procedure TSampleCalendar.SetDateElement(Index: Integer; Value: Integer);
var
AYear, AMonth, ADay: Word;
begin
if Value > 0 then { tous les éléments doivent être positifs }
begin
DecodeDate(FDate, AYear, AMonth, ADay);{ récupère les éléments courants de la date }
case Index of { définit le nouvel élément selon l’index }
1: AYear := Value;
2: AMonth := Value;
3: ADay := Value;
else Exit;
end;
FDate := EncodeDate(AYear, AMonth, ADay); { encode la date modifiée }
Refresh; { mise à jour du calendrier visible }
end;
end;
Vous pouvez maintenant définir le jour, le mois et l’année du calendrier lors de
la conception à partir de l’inspecteur d’objets, ou à l’exécution à partir du code.
Bien que vous n’ayez pas encore ajouté le code pour dessiner les dates dans les
cellules, vous disposez maintenant de toutes les données nécessaires.
begin
ƒ
FDate := EncodeDate(AYear, AMonth, ADay); { encode la date modifiée }
UpdateCalendar; { appelait précédemment Refresh }
end;
end;
3 Ajoutez une méthode au calendrier renvoyant le numéro du jour à partir des
coordonnées ligne/colonne d’une cellule qui lui sont transmises :
function TSampleCalendar.DayNum(ACol, ARow: Integer): Integer;
begin
Result := FMonthOffset + ACol + (ARow - 1) * 7; { calcule le jour pour cette cellule }
if (Result < 1) or (Result > MonthDays[IsLeapYear(Year), Month]) then
Result := -1; { renvoie -1 si incorrect }
end;
Pensez à ajouter la déclaration de DayNum à la déclaration de type du
composant.
4 Vous pouvez désormais calculer l’endroit où s’affichent les dates, et mettre à
jour DrawCell pour remplir les cellules :
procedure TCalendar.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
var
TheText: string;
TempDay: Integer;
begin
if ARow = 0 then { s’il s’agit de la ligne de titre ...}
TheText := ShortDayNames[ACol + 1] { utilise le nom du jour }
else begin
TheText := ’’; { cellule vide par défaut }
TempDay := DayNum(ACol, ARow); { récupère le numéro pour cette cellule }
if TempDay <> -1 then TheText := IntToStr(TempDay); { utilise ce numéro s’il est
valide }
end;
with ARect, Canvas do
TextRect(ARect, Left + (Right - Left - TextWidth(TheText)) div 2,
Top + (Bottom - Top - TextHeight(TheText)) div 2, TheText);
end;
Si maintenant vous réinstallez le composant calendrier et le placez dans une
fiche, les informations correspondant au mois en cours apparaîtront.
Déplacement de la sélection
Le comportement reçu en héritage d’une grille gère le déplacement de la
sélection en réponse aux touches de direction enfoncées ou aux clics de souris.
Pour modifier le jour sélectionné, vous devez modifier le comportement
implicite.
Pour gérer les déplacements à l’intérieur du calendrier, vous devez redéfinir la
méthode Click de la grille.
Lorsque vous redéfinissez une méthode telle que Click, en dépendance étroite
avec les interactions de l’utilisateur, vous devez pratiquement toujours inclure un
appel à la méthode reçue en héritage pour ne pas perdre le comportement
standard.
Le code suivant est une méthode Click surchargée pour la grille calendrier.
N’oubliez pas d’ajouter la déclaration de Click à TSampleCalendar, en incluant
après la directive override.
procedure TSampleCalendar.Click;
var
TempDay: Integer;
begin
inherited Click; { n’oubliez pas d’appeler la méthode héritée ! }
TempDay := DayNum(Col, Row); { récupère le numéro du jour de la cellule cliquée }
if TempDay <> -1 then Day := TempDay; { change le jour s’il est valide }
end;
end;
Vous avez maintenant un lien de données complet. Il vous reste à indiquer au
contrôle les données qu’il doit lire dans le champ lié. La section suivante vous
explique comment procéder.
procedure Register;
implementation
procedure Register;
begin
RegisterComponents(’Samples’, [TAboutBoxDlg]);
end;
end.
Remarque Les noms et les emplacements de certaines unités sont différents pour les
applications CLX. Par exemple, l’unité Controls est QControls dans les
applications CLX.
Pour l’instant, le nouveau composant possède uniquement les fonctionnalités
intégrées à TComponent. C’est le composant non visuel le plus simple. Dans la
section suivante, vous allez créer l’interface entre le composant et la boîte de
dialogue.
Test du composant
Une fois le composant boîte de dialogue installé, vous pouvez l’utiliser comme
n’importe quelle autre boîte de dialogue commune, en le plaçant sur une fiche
et en l’exécutant. Un moyen rapide de vérifier le fonctionnement de la boîte A
propos de consiste à ajouter un bouton de commande dans une fiche et à
exécuter la boîte de dialogue lorsque l’utilisateur clique sur ce bouton.
Par exemple, si vous avez créé une boîte de dialogue A propos de, et si vous
l’avez ajouté à la palette des composants, vous pouvez tester son fonctionnement
en suivant les étapes ci-dessous :
1 Créez un nouveau projet.
2 Placez un composant A propos de dans la fiche principale.
3 Placez un bouton de commande dans la fiche.
4 Double-cliquez sur le bouton de commande pour créer un gestionnaire
d’événements vide.
14
Extensions de l’EDI
Chapitre14
Vous pouvez étendre et personnaliser l’EDI avec vos propres éléments de menu,
boutons de barres d’outils, experts création de fiches dynamiques et davantage
en utilisant l’API Open Tools (souvent abrégée en API Tools). L’API Tools est un
ensemble d’une centaine d’interfaces qui interagissent et contrôlent l’EDI, y
compris le menu principal, les barres d’outils, les listes principales d’actions et
d’images, les tampons internes de l’éditeur de code source, les macros et liaisons
clavier, les fiches et leurs composants dans l’éditeur de fiches, le débogueur et le
processus en cours de débogage, l’achèvement de code, la vue des messages et la
liste de tâches.
Pour utiliser l’API Tools, il suffit d’écrire des classes qui implémentent certaines
interfaces et d’appeler les services proposés par d’autres interfaces. Votre code
API Tools doit être compilé et chargé dans l’EDI lors de la conception sous la
forme d’un paquet de conception ou d’une DLL. Ainsi l’écriture d’une extension
API Tools ressemble à la conception d’un éditeur de propriété ou de composant.
Avant d’aborder ce chapitre, vous devez vous être familiarisé avec l’utilisation
des paquets (Chapitre 16, “Utilisation des paquets et des composants”, du Guide
du développeur) et le recensement des composants (Chapitre 8, “Accessibilité des
composants au moment de la conception”).
Ce chapitre traite les sujets suivants :
• Présentation de l’API Tools
• Conception d’une classe expert
• Accès aux services de l’API Tools
• Utilisation des fichiers et des éditeurs
• Création de fiches et de projets
• Notification d’un expert des événements de l’EDI
Il existe trois types d’interfaces que vous devez implémenter : les experts, les
notificateurs et les créateurs :
• Comme indiqué plus haut dans cette section, une classe expert implémente
l’interface IOTAWizard et éventuellement des interfaces dérivées.
• Un notificateur est un autre type d’interface de l’API Tools. L’EDI utilise des
notificateurs pour prévenir votre expert quand il se produit quelque chose qui
le concerne. Si vous écrivez une classe qui implémente l’interface de
notification, recensez le notificateur dans l’API Tools et l’EDI appelle votre
objet notificateur quand l’utilisateur ouvre un fichier, modifie le code source,
change une fiche, démarre une session de débogage, etc. Les notificateurs sont
décrits en détail dans la section “Notification d’un expert des événements de
l’EDI” à la page 14-16.
• Un créateur est un autre type d’interface à implémenter. L’API Tools utilise
des créateurs pour créer de nouvelles unités, des fiches, des projets ou
d’autres fichiers ou pour ouvrir des fichiers existants. Pour plus
d’informations, voir la section “Création de fiches et de projets” à la
page 14-12.
Les modules et les éditeurs sont d’autres interfaces importantes. Une interface
module représente une unité ouverte ayant un ou plusieurs fichiers. Une
interface éditeur représente un fichier ouvert. Différentes interfaces éditeur vous
donnent accès aux différents aspects de l’EDI : l’éditeur de code source pour les
fichiers source, le concepteur de fiche pour les fichiers fiche et les ressources de
projet pour les fichiers ressource. Pour plus d’informations, voir la section
“Utilisation des fichiers et des éditeurs” à la page 14-11.
Les sections suivantes vous guident dans les étapes de la conception d’un expert.
Reportez-vous à l’aide en ligne pour des détails complets sur chaque interface.
La seule différence entre ces experts est la manière dont l’utilisateur fait appel à
l’expert :
• Un expert menu est ajouté au menu Aide de l’EDI. Quand l’utilisateur
sélectionne l’élément de menu, l’EDI appelle la fonction Execute de l’expert.
Les experts normaux étant beaucoup plus flexibles, on n’utilise généralement
les experts menu uniquement pour le prototypage ou la mise au point.
• Les experts fiche et projet sont également appelés experts du référentiel car ils
sont placés dans le référentiel d’objets. L’utilisateur accède à ces experts dans
la boîte de dialogue Nouveaux éléments. L’utilisateur peut également voir ces
experts dans le référentiel d’objets (en choisissant la commande Outils|
Référentiel). L’utilisateur peut cocher la case Nouvelle fiche d’un expert fiche,
ce qui indique à l’EDI d’appeler l’expert fiche quand l’utilisateur choisit la
commande Fichier|Nouvelle fiche. L’utilisateur peut également cocher la case
Fiche principale. Celle-ci indique à l’EDI d’utiliser l’expert fiche pour la fiche
par défaut d’une nouvelle application. Pour un expert projet, l’utilisateur peut
cocher la case Nouveau projet. Dans ce cas, quand l’utilisateur choisit la
commande Fichier|Nouvelle application, l’EDI appelle l’expert projet
sélectionné.
• Le quatrième type d’expert correspond aux situations ne rentrant pas dans les
autres catégories. A la base, un expert ne fait rien automatiquement ou de
lui-même. Vous devez donc définir comment l’expert est appelé.
L’API Tools ne définit aucune restriction sur les experts, par exemple imposer
qu’un expert projet crée effectivement un projet. Vous pouvez tout aussi bien
concevoir un expert projet qui crée une fiche qu’un expert fiche qui crée un
projet (du moins si c’est vraiment ce que vous voulez).
qu’il a créé mais il ne doit pas supprimer l’image qu’il a ajouté à la liste
d’images. La suppression d’une image perturberait l’indice de toutes les images
ajoutées après cet expert.
L’expert utilise réellement les objets TMainMenu, TActionList, TImageList et
TToolBar de l’EDI, vous pouvez donc écrire du code de la même manière que
dans une application normale. Cela signifie également que vous avez de
nombreuses opportunités de bloquer l’EDI ou de désactiver des caractéristiques
importantes, par exemple en supprimant le menu Fichier.
NewAction.ActionList := Services.ActionList;
NewAction.Caption := GetMenuText();
NewAction.Hint := ’Affiche une boîte de dialogue inutile’;
NewAction.ImageIndex := ImageIndex;
NewAction.OnUpdate := action_update;
NewAction.OnExecute := action_execute;
L’élément de menu initialise sa propriété Action avec l’action qui vient d’être
créée. Le problème dans la création d’un élément de menu, c’est de savoir où
l’insérer. L’exemple suivant recherche le menu Voir et insère le nouvel élément
de menu comme premier élément du menu Voir. En général, il n’est pas
judicieux de se baser sur une position absolue : en effet, vous ne savez jamais
quand un autre expert va s’ajouter au menu. De plus, les versions ultérieures de
Delphi peuvent également réorganiser les menus. Il est préférable de rechercher
dans le menu un élément de nom donné. Dans un souci de clarté l’approche
simpliste est indiqué ci-dessous.
for I := 0 to Services.MainMenu.Items.Count - 1 do
begin
with Services.MainMenu.Items[I] do
begin
if CompareText(Name, ’ViewsMenu’) = 0 then
begin
NewItem := TMenuItem.Create(nil);
NewItem.Action := NewAction;
Insert(0, NewItem);
end;
end;
end;
Une fois l’action ajoutée à la liste d’actions de l’EDI, l’utilisateur peut voir
l’action quand il personnalise les barres d’outils. L’utilisateur peut sélectionner
l’action et l’ajouter à une barre d’outils. Cela peut poser un problème quand
votre expert est déchargé : tous les boutons de barre d’outils se retrouvent avec
des pointeurs flottants sur une action et un gestionnaire d’événement OnClick
inexistants. Pour éviter des violations d’accès, votre expert doit trouver tous les
boutons d’outils faisant référence à ses actions et les supprimer.
begin
Btn := ToolBar.Buttons[I];
if Btn.Action = Action then
begin
{ Retire "Btn" de "ToolBar" }
ToolBar.Perform(CM_CONTROLCHANGE, WPARAM(Btn), 0);
Btn.Free;
end;
end;
end;
destructor MyWizard.Destroy;
var
Services: INTAServices;
Btn: TToolButton;
begin
Supports(BorlandIDEServices, INTAServices, Services);
{ Vérifier toutes les barres d’outils et retirer tous les boutons utilisant cette action.
}
remove_action(NewAction, Services.ToolBar[sCustomToolBar]);
remove_action(NewAction, Services.ToolBar[sDesktopToolBar]);
remove_action(NewAction, Services.ToolBar[sStandardToolBar]);
remove_action(NewAction, Services.ToolBar[sDebugToolBar]);
remove_action(NewAction, Services.ToolBar[sViewToolBar]);
remove_action(NewAction, Services.ToolBar[sInternetToolBar]);
NewItem.Free;
NewAction.Free;
end;
Comme vous pouvez le voir dans cet exemple simple, votre expert peut interagir
avec l’EDI de manière très flexible. Cependant, avec la flexibilité vient également
la responsabilité. Vous pouvez facilement produire des pointeurs flottants ou
d’autres violations d’accès. La section suivante donne quelques conseils pour
diagnostiquer ce type de problème.
du compilateur pour vous assurer que vous avez activé le débogage ; vérifiez
que vous avez chargé le bon paquet ; et revérifiez les modules de processus pour
être sûr et certain que vous avez bien chargé le fichier .bpl souhaité.
En procédant ainsi, vous ne pouvez pas déboguer dans le code VCL, CLX ou
RTL mais pour l’expert même vous disposez de toutes les fonctions de
débogage, ce qui devrait suffire pour trouver le problème.
Création de modules
Généralement, un expert fiche ou projet crée un ou plusieurs nouveaux fichiers.
En fait, au lieu de fichiers réels, mieux vaut créer des modules sans nom et non
enregistrés. Lorsque l’utilisateur les enregistre, l’EDI lui demande le nom de
fichier. Un expert utilise un objet créateur pour créer de tels modules.
Une classe créateur implémente une interface de création qui hérite de
IOTACreator. L’expert transmet l’objet créateur à la méthode CreateModule du
service de module, et l’EDI rappelle l’objet créateur pour obtenir les paramètres
nécessaires à la création du module.
Ainsi, un expert fiche qui crée une nouvelle fiche implémente généralement
GetExisting pour renvoyer false et GetUnnamed pour renvoyer true. Cela crée un
module sans nom (l’utilisateur doit donc spécifier un nom avant de pouvoir
enregistrer le fichier) et sans fichier existant correspondant (l’utilisateur doit donc
enregistrer le fichier même s’il ne l’a pas modifié). D’autres méthodes du
créateur indiquent à l’EDI le type de fichier créé (un projet, une unité ou une
fiche), spécifient le contenu du fichier ou renvoient le nom de la fiche, le nom de
l’ancêtre ou d’autres informations importantes. D’autres rappels permettent à un
expert d’ajouter des modules à un projet qui vient d’être créé, ou d’ajouter des
composants à une fiche qui vient d’être créée.
Pour créer un nouveau fichier, ce qui est généralement nécessaire avec un expert
fiche ou projet, il faut spécifier le contenu du nouveau fichier. Pour ce faire,
écrivez une nouvelle classe implémentant l’interface IOTAFile. Si votre expert se
contente du contenu de fichier par défaut, vous pouvez renvoyer nil depuis
toute fonction qui renvoie IOTAFile.
Par exemple, votre société peut utiliser un bloc de commentaire standardisé
devant apparaître au début de chaque fichier source. Vous pouvez obtenir ceci
avec un modèle statique du référentiel d’objets, mais il faut alors modifier
manuellement le bloc de commentaire pour indiquer l’auteur et la date de
création. Vous pouvez utiliser à la place un créateur pour remplir
dynamiquement le bloc de commentaire lors de la création du fichier.
Il faut tout d’abord écrire un expert qui crée de nouvelles fiches et unités. La
plupart des fonctions d’un créateur renvoient zéro, des chaînes vides ou d’autres
valeurs par défaut, ce qui indique à l’API Tools d’utiliser le comportement par
défaut pour créer une nouvelle unité ou une fiche. Redéfinissez GetCreatorType
pour indiquer à l’API Tools le type de module à créer : une unité ou une fiche.
Pour créer une unité, renvoyez sUnit. Pour créer une fiche, renvoyez sForm.
Pour simplifier le code, utilisez une seule classe utilisant le type de créateur
comme argument du constructeur. Enregistrez le type du créateur dans une
donnée membre afin que GetCreatorType puisse renvoyer sa valeur. Implémentez
NewImplSource et NewIntfSource pour renvoyer le contenu souhaité dans le fichier.
TCreator = class(TInterfacedObject, IOTAModuleCreator)
public
constructor Create(const CreatorType: string);
{ IOTAModuleCreator }
function GetAncestorName: string;
Result := Group.ActiveProject;
Exit;
end;
end;
end;
Le créateur renvoie nil depuis NewFormSource pour générer un fichier fiche par
défaut. Les méthodes intéressantes sont NewImplSource et NewIntfSource qui
créent une instance de IOTAFile renvoyant le contenu du fichier.
La classe TFile implémente l’interface IOTAFile. Elle renvoie -1 comme âge du
fichier (cela signifie que le fichier n’existe pas) et renvoie le contenu du fichier
dans une chaîne. Pour garder la classe TFile simple, le créateur génère la chaîne,
la classe TFile se contenant de la transmettre.
TFile = class(TInterfacedObject, IOTAFile)
public
constructor Create(const Source: string);
function GetSource: string;
function GetAge: TDateTime;
private
FSource: string;
end;
constructor TFile.Create(const Source: string);
begin
FSource := Source;
end;
function TFile.GetSource: string;
begin
Result := FSource;
end;
function TFile.GetAge: TDateTime;
begin
Result := TDateTime(-1);
end;
Vous pouvez stocker le texte du contenu du fichier dans une ressource afin d’en
simplifier la modification, mais dans un souci de simplicité, dans cet exemple le
texte est codé directement dans l’expert. L’exemple suivant génère le code source
en supposant l’existence d’une fiche. Vous pouvez facilement gérer le cas encore
plus simple d’une unité de base. Testez FormIdent et, si elle est vide, créez une
unité de base, sinon créez une unité de fiche. Le squelette de base du code est le
même que celui par défaut de l’EDI (avec bien entendu l’ajout des commentaires
au début), mais vous pouvez le modifier à votre guise.
function TCreator.NewImplSource(
const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;
var
FormSource: string;
begin
FormSource :=
’{ ----------------------------------------------------------------- ’ + #13#10 +
’%s - description’+ #13#10 +
Index I-1
partie publiée 2-7 contrôles
partie publique 2-6 changement 1-3
propriétés comme 3-3 fenêtrés 1-4
transmission comme paramètres 2-10 forme 10-8
classes ancêtres 2-4 graphiques 6-4, 10-1–10-10
classes dérivées 2-4 création 1-4, 10-3
redéfinition des méthodes 2-9 dessin 10-3, 10-8–10-10
clic, événements 4-2, 4-8 événements 6-7
Click, méthode 4-2, 7-14 palettes et 6-5–6-6
redéfinition 4-7, 11-12 personnalisés 1-5
closures 4-9 pour modifier les données 12-9–12-14
CLX pour scruter les données 12-2–12-8
notifications système 7-10–7-16 réception de la focalisation 1-4
signaux 7-11–7-12 redessin 10-8, 10-9, 11-4, 11-5
CM_EXIT, message 12-13 redimensionnement 6-7, 11-4
CMExit, méthode 12-13 contrôles de redimensionnement
code 5-4 graphiques 6-7
ColorChanged, méthode 7-15 contrôles graphiques 1-4, 6-4, 10-1–10-10
composant, expert 1-10 comparés aux bitmaps 10-3
composants 1-1, 2-1, 3-3 création 1-4, 10-3
abstraites 1-3 dessin 10-3, 10-8–10-10
aide en ligne 8-4 enregistrement des ressources système 1-4
ajout à l’unité existante 1-13 événements 6-7
ajout à la palette de composants 8-1 contrôles mémo 3-9
ajout aux unités 1-13 modification 9-1
bitmaps 1-14 contrôles orientés données 12-1
bitmaps de palette 1-14 création 12-2–12-14
changement 9-1–9-4 destruction 12-7
classes dérivées 1-3, 1-13, 10-2 pour modifier les données 12-9–12-14
création 1-2, 1-9 pour scruter les données 12-2–12-8
dépendances 1-6 réponse aux changements 12-8
déplacement 1-16 contrôles personnalisés 1-5
double-clic 8-16, 8-18–8-19 bibliothèques 1-5
initialisation 3-14, 10-7, 12-7 contrôles préexistants 1-5
installation 8-20 conventions d’attribution de nom
interfaces 2-4, 13-2 champs 4-3
conception 2-7 événements 4-9
exécution 2-6 méthodes 5-2
menus contextuels 8-16, 8-17–8-18 propriétés 3-7
non visuels 1-5, 1-13, 13-3 types d’enregistrement de message 7-7
orientés données 12-1 CopyMode, propriété 6-3
paquets 8-20 CopyRect, méthode 6-3, 6-7
personnalisation 1-3, 3-2, 4-1 crayons 10-6
pour modifier les données 12-9–12-14 changement 10-8
pour scruter les données 12-2–12-8 créateurs 14-3, 14-12–14-16
recensement 1-13, 8-2 CursorChanged, méthode 7-15
répondre aux événements 4-6, 4-8, 4-10, 12-8
ressources, libération 13-5 D
test 1-17, 1-19, 13-6–13-7
DataChange, méthode 12-12
composants non visuels 1-5, 1-13, 13-3
DataField, propriété 12-6
constructeurs 1-18, 3-13, 5-3, 11-4, 11-5, 12-7
DataSource (propriété), contrôles orientés
objets ayant un propriétaire et 10-6, 10-7
données 12-6
redéfinition 9-2
Day, propriété 11-6
Contains, liste (paquets) 8-20
DblClick, méthode 7-14
contextes de périphériques 1-8, 6-2
.dcr, fichiers 1-14
Index I-3
réponse aux événements de l’EDI 14-16 GetAttributes, méthode 8-11
types 14-4 GetFloatValue, méthode 8-9
experts fiche 14-4 GetMethodValue, méthode 8-9
experts menu 14-4 GetOrdValue, méthode 8-9
experts projet 14-4 GetPalette, méthode 6-6
experts référentiel d’objets 14-4 GetProperties, méthode 8-11
GetStrValue, méthode 8-9
F GetValue, méthode 8-9
glisser-déplacer, événements 10-2
fenêtre
Graphic, propriété 6-4
classe 1-5
graphiques 6-1–6-8
contrôles 1-4
chargement 6-4, 6-5
gestion de message 11-4
complexes 6-6
handles 1-4, 1-6
conteneurs 6-4
procédures 7-3
enregistrement 6-4
fiches, en composants 13-1
fonctions, appel 6-2
fichiers, graphiques 6-4
indépendants 6-3
FillRect, méthode 6-3
méthodes 6-3, 6-5, 6-7
finally, mot réservé 6-7, 13-5
copie d’images 6-7
FloodFill, méthode 6-3
palettes 6-6
focalisation 1-4
outils de dessin 6-2, 6-8, 10-6
focalisation de saisie 1-4
changement 10-8
fonctions 1-7
redessiner les images 6-7
API Windows 1-4, 6-1
redimensionnement 6-7
attribution de nom 5-2
stockage 6-4
événements et 4-3
graphiques (méthodes), palettes 6-6
graphiques 6-2
grilles 11-1, 11-3, 11-5, 11-12
lecture des propriétés 3-7, 8-9, 8-11
fonctions membres
paramètres de propriété 3-7
H
Font, propriété 6-3 Handle, propriété 1-4, 1-6, 6-3
FontChanged, méthode 7-15 HandleException, méthode 7-3
formes géométriques, dessin 10-10 héritage de classe 2-8
FReadOnly 12-9 héritées
méthodes 4-7
G propriétés 10-2, 11-3
publication 3-3
GDI, applications 1-8, 6-1 hérités
gestion de message 7-4–7-5 événements 4-5
gestionnaires d’événements 1-8, 4-2, 4-9, 12-8 hiérarchie (classes) 2-4
affichage de l’éditeur de code 8-19 HookEvents, méthode 7-12
déclarations 4-6, 4-9, 11-13 hors écran, bitmaps 6-6–6-7
méthodes 4-3, 4-5, 4-6
par défaut, redéfinition 4-10 I
paramètres 4-3, 4-8, 4-9, 4-10
notification, événements 4-8 icônes 6-4
pointeurs 4-2, 4-3, 4-9 ajout aux composants 1-14
transmission de paramètres par référence 4-10 identificateurs
types 4-3–4-4, 4-8–4-9 champs de classe 4-3
vides 4-10 événements 4-9
gestionnaires de messages 7-2, 7-3, 11-4, 11-5 méthodes 5-2
création 7-6–7-8 paramètres de propriété 3-7
déclarations 7-6, 7-8 types d’enregistrement de message 7-7
méthodes, surcharge 7-7 images 6-3, 6-3–6-6
par défaut 7-3 dessin 10-8
redéfinition 7-4 redessiner 6-7
réduction du scintillement 6-6
Index I-5
messages de frappes de touches 4-6, 12-10 O
messages définis par l’utilisateur 7-6, 7-8
messages liés à la souris 12-10 objets
messages souris 7-2, 12-10 ayant un propriétaire 10-5–10-8
métafichiers 6-4 initialisation 10-7
méthodes 1-7, 5-1, 11-11 instanciation 4-2
appel 4-6, 5-3, 10-4 temporaires 6-7
attribution de nom 5-2 objets ayant un propriétaire 10-5–10-8
déclaration 5-4 initialisation 10-7
dynamiques 2-10 OnChange, événement 6-7, 10-8, 11-13, 12-13
public 5-3 OnClick, événement 4-2, 4-3, 4-5
statiques 2-8 OnCreate, événement 1-17
virtuelles 2-9 OnDataChange, événement 12-8, 12-12
dessin 10-9, 10-10 OnDblClick, événement 4-5
gestion des messages 7-2, 7-3, 7-5 OnDragDrop, événement 4-5
gestionnaires d’événements 4-3, 4-5, 4-6 OnDragOver, événement 4-5
redéfinition 4-6 OnEndDrag, événement 4-5
graphiques 6-3, 6-5, 6-7 OnEnter, événement 4-5
palettes 6-6 OnExit, événement 12-14
héritées 4-7 OnKeyDown, événement 4-5, 7-13, 12-11
initialisation 3-14 OnKeyPress, événement 4-5, 7-13
propriétés et 3-5–3-7, 5-1, 5-2, 10-4 OnKeyString, événement 7-13
protected 5-3 OnKeyUp, événement 4-5, 7-13
public 5-3 OnMouseDown, événement 4-5, 7-13, 12-10
redéfinition 2-9, 7-4, 7-5, 7-7, 11-12 OnMouseMove, événement 4-5, 7-13
répartition 2-8 OnMouseUp, événement 4-5, 7-13
virtuelles 2-9, 5-4 opérations avec effet 6-7
méthodes dynamiques 2-10 optimisation des ressources système 1-4
méthodes statiques 2-8 outils de dessin 6-2, 6-8, 10-6
modèles de composants 2-2 changement 10-8
Modified, méthode 12-13 outils natifs de l’API 14-6–14-10
modules 1-12 override, directive 2-9, 7-4
API Tools 14-3, 14-11–14-12 Owner, propriété 1-18
mois, renvoyer actuel 11-8
Month, propriété 11-6 P
mots clés 8-5
Paint, méthode 6-7, 10-9, 10-10
protected 4-6
PaintRequest, méthode 7-14
MouseDown, méthode 7-14, 12-10
palette des composants
MouseMove, méthode 7-14
ajout de bitmaps personnalisés 1-14
MouseUp, méthode 7-14
ajout de composants 8-1
MoveTo, méthode 6-3
déplacement des composants 1-16
Msg, paramètre 7-3
PaletteChanged, méthode 6-6, 7-15
MyEvent_ID, type 7-16
palettes 6-5–6-6
comportement par défaut 6-6
N spécification 6-6
nombres 3-2 paquets 8-20
valeurs de propriété 3-13 composants 8-20
notificateurs 14-3 liste Contains 8-20
API Tools 14-16–14-20 liste Requires 8-20
écriture 14-19 par défaut
notification, événements 4-8 classe ancêtre 2-4
notifications système 7-10–7-16 gestionnaires
notifications système Linux 7-10–7-16 événements 4-10
Nouveau, commande 1-12 message 7-3
Nouvelle unité, commande 1-12 redéfinition 4-10
Index I-7
rectangles, dessin 10-10 TCustomControl 1-4
redéfinition des méthodes 2-9, 7-4, 7-5, 11-12 TCustomGrid 11-1, 11-3
redessin des contrôles 10-8, 10-9, 11-4, 11-5 TCustomListBox 1-4
redessiner les images 6-7 TDateTime, type 11-6
redimensionnement des contrôles 11-4 TDefaultEditor 8-17
Register, procédure 1-13, 8-2 temporaires, objets 6-7
RegisterComponents, procédure 1-14, 8-2 TEnumProperty, type 8-8
RegisterPropertyEditor, procédure 8-12 test
Requires, liste (paquets) 8-20 composants 1-17, 1-19, 13-6–13-7
.res, fichiers 1-16 valeurs 3-7
ressources 1-8, 6-1 TextChanged, méthode 7-15
en mémoire cache 6-2 TextHeight, méthode 6-3
libération 13-5 TextOut, méthode 6-3
système, optimisation 1-4 TextRect, méthode 6-3
ressources en mémoire cache 6-2 TextWidth, méthode 6-3
ressources système, préservation 1-4 TFieldDataLink 12-5
Result, paramètre 7-7 TFloatProperty, type 8-8
RTTI 2-7 TFontNameProperty, type 8-8
TFontProperty, type 8-8
S TGraphic 6-4
TGraphicControl 1-4, 10-2
SaveToFile (méthode), graphiques 6-5
THandleComponent 7-12
SelectCell, méthode 11-14, 12-4
TIcon 6-4
Self, paramètre 1-18
TiledDraw, méthode 6-7
SendMessage, méthode 7-10
TIntegerProperty, type 8-7, 8-9
services, API Tools 14-2, 14-5–14-12
TKeyPressEvent, type 4-4
SetFloatValue, méthode 8-9
TLabel 1-4
SetMethodValue, méthode 8-9
TListBox 1-4
SetOrdValue, méthode 8-9
TMessage 7-5, 7-7
SetStrValue, méthode 8-9
TMetafile 6-4
SetValue, méthode 8-9
TMethod, type 7-12
ShowHintChanged, méthode 7-15
TMethodProperty, type 8-8
signaux, réponse aux signaux (CLX) 7-11–7-12
TNotifyEvent 4-8
simple, types 3-2
TObject 2-4
sous-classement des contrôles Windows 1-5
ToolsAPI, unité 14-2
sous-composants, propriétés 3-10
TOrdinalProperty, type 8-7
stored, directive 3-14
TPicture, type 6-4
StretchDraw, méthode 6-3, 6-7
TPropertyAttributes 8-11
StyleChanged, méthode 7-15
TPropertyEditor, classe 8-7
systèmes d’aide 8-4
transfert d’enregistrements 13-2
fichiers 8-4
try, mot réservé 6-7, 13-5
mots clés 8-5
TSetElementProperty, type 8-8
TSetProperty, type 8-8
T TStringProperty, type 8-8
tableaux 3-3, 3-9 TWinControl 1-4, 4-5
TabStopChanged, méthode 7-15 types
Tapplication, événements système 7-13 définis par l’utilisateur 10-3
TBitmap 6-4 enregistrement de message 7-7
TCalendar 11-1 propriétés 3-2, 3-9, 8-9
TCharProperty, type 8-8 types définis par l’utilisateur 10-3
TClassProperty, type 8-8 types énumérés 3-2, 10-3
TColorProperty, type 8-8
TComponent 1-5 U
TComponentProperty, type 8-8
unités, ajout de composants 1-13
TControl 1-4, 4-5, 4-6
UpdateCalendar, méthode 12-4
Index I-9
I-10 Guide du concepteur de composants