Académique Documents
Professionnel Documents
Culture Documents
Borland ®
C++Builder 6™
pour Windows ®
Reportez-vous au fichier DEPLOY situé dans le répertoire racine de votre produit C++Builder pour obtenir la liste
complète des fichiers que vous pouvez distribuer en accord avec les termes du contrat de licence de C++Builder.
Les applications mentionnées dans ce manuel sont brevetées ou en attente de brevet. Reportez-vous au CD du
produit ou à la boîte de dialogue A propos. Ce document ne donne aucun droit sur ces brevets.
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.
CPE1360WW21001 6E4R0102
02030405-9 8 7 6 5 4 3 2 1
PDF
Table des matières
Chapitre 1 Chapitre 4
Introduction 1-1 Utilisation de BaseCLX 4-1
Contenu de ce manuel . . . . . . . . . . . . . . 1-1 Utilisation des flux . . . . . . . . . . . . . . . . . 4-2
Conventions typographiques. . . . . . . . . . . 1-3 Utilisation des flux pour lire ou écrire
Support technique . . . . . . . . . . . . . . . . . 1-3 des données . . . . . . . . . . . . . . . . . . 4-2
Méthodes de flux pour la lecture
et l’écriture . . . . . . . . . . . . . . . . . 4-2
Partie I Lecture et écriture de composants. . . . . 4-3
Programmation C++Builder Copie de données d’un flux vers un autre . 4-3
Spécification de la position et de la taille
Chapitre 2 du flux . . . . . . . . . . . . . . . . . . . . . 4-4
Développement d’applications Déplacement sur une position
particulière . . . . . . . . . . . . . . . . . 4-4
avec C++Builder 2-1 Utilisation des propriétés de position
L’environnement de développement intégré. . 2-1
et de taille. . . . . . . . . . . . . . . . . . 4-4
Conception d’applications . . . . . . . . . . . . 2-2
Utilisation des fichiers . . . . . . . . . . . . . . . 4-5
Création des projets . . . . . . . . . . . . . . . . 2-3
Approches des E/S fichier . . . . . . . . . . . 4-5
Modification du code . . . . . . . . . . . . . . . 2-4
Utilisation de flux de fichier . . . . . . . . . . 4-6
Compilation des applications . . . . . . . . . . 2-4
Création et ouverture de fichiers
Débogage des applications . . . . . . . . . . . . 2-5
en utilisant des flux de fichier . . . . . . 4-6
Déploiement des applications . . . . . . . . . . 2-5
Utilisation du handle de fichier . . . . . . 4-7
Manipulation de fichiers . . . . . . . . . . . . 4-7
Chapitre 3 Suppression d’un fichier . . . . . . . . . . 4-8
Utilisation des bibliothèques Recherche d’un fichier . . . . . . . . . . . 4-8
de composants 3-1 Modification d’un nom de fichier . . . . 4-10
Présentation des bibliothèques de classes . . . 3-1 Routines date-heure de fichier . . . . . . 4-10
Propriétés, méthodes et événements . . . . 3-2 Copie d’un fichier . . . . . . . . . . . . . 4-10
Propriétés . . . . . . . . . . . . . . . . . . 3-2 Utilisation des fichiers ini et du registre. . . . 4-11
Méthodes . . . . . . . . . . . . . . . . . . 3-3 Utilisation de TIniFile et TMemIniFile . 4-11
Evénements . . . . . . . . . . . . . . . . . 3-3 Utilisation de TRegistryIniFile . . . . . . 4-13
Evénements utilisateur. . . . . . . . . . . 3-3 Utilisation de TRegistry. . . . . . . . . . 4-13
Evénements système . . . . . . . . . . . . 3-4 Utilisation des listes . . . . . . . . . . . . . . . 4-14
Objets, composants et contrôles . . . . . . . . . 3-4 Opérations de listes courantes. . . . . . . . 4-14
Branche TObject . . . . . . . . . . . . . . . . 3-6 Ajout d’éléments de liste . . . . . . . . . 4-15
Branche TPersistent . . . . . . . . . . . . . . 3-7 Suppression d’éléments de liste . . . . . 4-15
Branche TComponent . . . . . . . . . . . . . 3-7 Accès aux éléments de la liste . . . . . . 4-15
Branche TControl. . . . . . . . . . . . . . . . 3-9 Réorganisation d’éléments de liste . . . 4-16
Branche TWinControl/TWidgetControl . . . 3-10 Listes persistantes . . . . . . . . . . . . . . . 4-16
Utilisation des listes de chaînes. . . . . . . . . 4-17
Lecture et enregistrement
des listes de chaînes. . . . . . . . . . . . . 4-17
i
Création d’une nouvelle liste de chaînes . . 4-18 Recensez la famille de conversion
Listes de chaînes à court terme . . . . . . 4-18 et les autres unités . . . . . . . . . . . . 4-34
Listes de chaînes à long terme . . . . . . 4-18 Utilisation des nouvelles unités . . . . . 4-35
Manipulation des chaînes d’une liste . . . . 4-19 Création d’espaces de dessin . . . . . . . . . . 4-36
Comptage des chaînes d’une liste . . . . 4-20
Accès à une chaîne spécifique . . . . . . 4-20 Chapitre 5
Recherche d’éléments Utilisation des composants 5-1
dans une liste de chaînes . . . . . . . . 4-20 Initialisation des propriétés d’un composant . . 5-2
Parcours des chaînes d’une liste . . . . . 4-20 Initialisation des propriétés à la conception . 5-2
Ajout d’une chaîne à une liste . . . . . . 4-20 Utilisation des éditeurs de propriétés. . . 5-3
Déplacement d’une chaîne Initialisation des propriétés à l’exécution . . 5-3
dans une liste . . . . . . . . . . . . . . . 4-21 Appel de méthodes. . . . . . . . . . . . . . . . . 5-3
Suppression d’une chaîne d’une liste . . 4-21 Utilisation des événements
Association d’objets et des gestionnaires d’événements . . . . . . . 5-4
à une liste de chaînes . . . . . . . . . . 4-21 Génération d’un nouveau
Utilisation des chaînes . . . . . . . . . . . . . . 4-22 gestionnaire d’événement . . . . . . . . . . 5-4
Routines manipulant les caractères Génération du gestionnaire de l’événement
étendus . . . . . . . . . . . . . . . . . . . . 4-22 par défaut d’un composant . . . . . . . . . 5-4
Routines couramment utilisées Recherche de gestionnaires d’événements . . 5-5
pour les AnsiStrings . . . . . . . . . . . . . 4-23 Association d’un événement à un gestionnaire
Routines couramment utilisées d’événement existant . . . . . . . . . . . . . 5-5
pour les chaînes à zéro terminal . . . . . . 4-26 Utilisation du paramètre Sender. . . . . . 5-6
Impression . . . . . . . . . . . . . . . . . . . . . 4-27 Affichage et codage d’événements
Conversion de mesures . . . . . . . . . . . . . . 4-28 partagés . . . . . . . . . . . . . . . . . . . 5-6
Exécution des conversions . . . . . . . . . . 4-28 Association d’événements de menu
Exécution des conversions simples. . . . 4-28 à des gestionnaires d’événements . . . . . . 5-6
Exécution des conversions complexes . . 4-29 Suppression de gestionnaires d’événements 5-7
Ajout de nouveaux types de mesure . . . . 4-29 Composants multiplates-formes ou non
Création d’une famille de conversion multiplates-formes . . . . . . . . . . . . . . . . 5-7
simple et ajout d’unités . . . . . . . . . . . 4-29 Ajout de composants personnalisés
Déclaration des variables . . . . . . . . . 4-30 à la palette des composants . . . . . . . . 5-10
Recensement de la famille
de conversion . . . . . . . . . . . . . . . 4-30 Chapitre 6
Recensement des unités de mesure . . . 4-30 Manipulation des contrôles 6-1
Utilisation des nouvelles unités . . . . . 4-30 Implémentation du glisser-déplacer
Utilisation d’une fonction de conversion . . 4-31 dans les contrôles . . . . . . . . . . . . . . . . . 6-1
Déclaration des variables . . . . . . . . . 4-31 Début de l’opération glisser-déplacer . . . . 6-1
Recensement de la famille Acceptation des éléments à déplacer . . . . . 6-2
de conversion . . . . . . . . . . . . . . . 4-31 Déplacement des éléments. . . . . . . . . . . 6-3
Recensement de l’unité de base . . . . . 4-31 Fin de l’opération glisser-déplacer . . . . . . 6-3
Ecriture des méthodes de conversion Personnalisation du glisser-déplacer
à destination et à partir avec un objet déplacement . . . . . . . . . . 6-4
de l’unité de base . . . . . . . . . . . . . 4-32 Changement du pointeur de la souris . . . . 6-4
Recensement des autres unités . . . . . . 4-32 Implémentation du glisser-ancrer
Utilisation des nouvelles unités . . . . . 4-32 dans les contrôles . . . . . . . . . . . . . . . . . 6-4
Utilisation d’une classe pour gérer Transformation d’un contrôle fenêtré
les conversions . . . . . . . . . . . . . . . . 4-32 en un site d’ancrage. . . . . . . . . . . . . . 6-5
Création de la classe de conversion . . . 4-33 Transformation d’un contrôle
Déclaration des variables . . . . . . . . . 4-34 en un enfant ancrable . . . . . . . . . . . . . 6-5
ii
Contrôle de l’ancrage des contrôles enfant . 6-6 Création de paquets et de DLL . . . . . . . . . 7-10
Contrôle du désancrage Utilisation des paquets et des DLL . . . . . 7-11
des contrôles enfant . . . . . . . . . . . . . 6-6 Utilisation des DLL dans C++Builder . . . . . 7-12
Contrôle de la réponse des contrôles enfant Création de DLL dans C++Builder. . . . . . . 7-12
aux opérations glisser-ancrer . . . . . . . . 6-7 Création de DLL contenant
Manipulation du texte dans les contrôles . . . 6-7 des composants VCL et CLX . . . . . . . . . 7-13
Définition de l’alignement du texte . . . . . 6-7 Liaison de DLL . . . . . . . . . . . . . . . . . . 7-16
Ajout de barres de défilement Ecriture d’applications de bases de données . 7-16
en mode exécution . . . . . . . . . . . . . . 6-8 Distribution d’applications
Ajout de l’objet Clipboard . . . . . . . . . . 6-9 de bases de données . . . . . . . . . . . . 7-17
Sélection de texte. . . . . . . . . . . . . . . . 6-9 Création d’applications serveur Web. . . . . . 7-18
Sélection de la totalité d’un texte . . . . . . 6-9 Utilisation de WebBroker. . . . . . . . . . . 7-18
Couper, copier et coller du texte . . . . . . . 6-10 Création d’applications WebSnap . . . . . . 7-19
Effacement du texte sélectionné . . . . . . . 6-10 Utilisation d’InternetExpress . . . . . . . . 7-20
Désactivation des éléments de menu . . . . 6-10 Création d’applications services Web. . . . 7-20
Ajout d’un menu surgissant . . . . . . . . . 6-11 Ecriture d’applications en utilisant COM . . . 7-20
Gestion de l’événement OnPopup . . . . . . 6-12 Utilisation de COM et de DCOM . . . . . . 7-21
Ajout de graphiques à des contrôles . . . . . . 6-12 Utilisation de MTS et de COM+ . . . . . . 7-21
Spécification du style dessiné Utilisation de modules de données . . . . . . 7-22
par le propriétaire . . . . . . . . . . . . . . 6-13 Création et modification de modules
Ajout d’objets graphiques de données standard . . . . . . . . . . . . 7-23
à une liste de chaînes . . . . . . . . . . . . 6-14 Nom d’un module de données
Ajout d’images à une application . . . . 6-14 et de son fichier unité . . . . . . . . . . 7-23
Ajout d’images à une liste de chaînes . . 6-14 Placer et nommer les composants . . . . 7-24
Dessiner des éléments dessinés Utilisation des propriétés et événements
par le propriétaire . . . . . . . . . . . . 6-15 des composants dans un module
Dimensionnement des éléments dessinés de données . . . . . . . . . . . . . . . . 7-25
par le propriétaire . . . . . . . . . . . . . . 6-15 Création de règles de gestion
Dessin des éléments par le propriétaire. . . 6-16 dans un module de données . . . . . . 7-25
Accès à un module de données
Chapitre 7 depuis une fiche . . . . . . . . . . . . . . . 7-25
Création d’applications, de composants Ajout d’un module de données distant
à un projet serveur d’application . . . . . 7-26
et de bibliothèques 7-1 Utilisation du référentiel d’objets. . . . . . . . 7-27
Création d’applications . . . . . . . . . . . . . . 7-1
Partage d’éléments dans un projet . . . . . 7-27
Applications d’interface utilisateur
Ajout d’éléments au Référentiel d’objets. . 7-27
graphique . . . . . . . . . . . . . . . . . . . 7-1
Partage d’objets par une équipe
Modèles d’interfaces utilisateur . . . . . 7-2
de développement. . . . . . . . . . . . . . 7-27
Applications SDI . . . . . . . . . . . . . . 7-2
Utilisation d’un élément du référentiel
Applications MDI. . . . . . . . . . . . . . 7-2
d’objets dans un projet . . . . . . . . . . . 7-28
Définition des options de l’EDI, du projet
Copie d’un élément . . . . . . . . . . . . 7-28
et de la compilation . . . . . . . . . . . 7-3
Héritage d’un élément . . . . . . . . . . 7-28
Modèles de programmation . . . . . . . . . 7-3
Utilisation d’un élément . . . . . . . . . 7-28
Applications console . . . . . . . . . . . . . . 7-4
Utilisation de modèles de projet . . . . . . 7-29
Utilisation de la VCL et de la CLX
Modification d’éléments partagés. . . . . . 7-29
dans les applications console . . . . . . 7-4
Spécification d’un projet par défaut, d’une
Applications service . . . . . . . . . . . . . . 7-4
nouvelle fiche et de la fiche principale . . 7-29
Threads de service . . . . . . . . . . . . . 7-7
Activation de l’aide dans les applications . . . 7-30
Propriétés de nom d’un service . . . . . 7-9
Interfaces avec les systèmes d’aide . . . . . 7-30
Débogage d’applications service . . . . . 7-10
iii
Implémentation de ICustomHelpViewer . . 7-31 Transfert de paramètres supplémentaires
Communication avec le gestionnaire aux fiches . . . . . . . . . . . . . . . . . . . . 8-8
d’aide . . . . . . . . . . . . . . . . . . . . . 7-31 Récupération des données des fiches. . . . . 8-9
Demande d’informations Récupération de données
au gestionnaire d’aide . . . . . . . . . . . . 7-32 dans les fiches non modales . . . . . . . 8-9
Affichage de l’aide basée sur un mot clé . . 7-33 Récupération de données
Affichage des sommaires . . . . . . . . . . . 7-34 dans les fiches modales . . . . . . . . . 8-10
Implémentation de IExtendedHelpViewer . 7-34 Réutilisation des composants
Implémentation de IHelpSelector . . . . . . 7-35 et des groupes de composants . . . . . . . . 8-13
Recensement des objets du système d’aide. 7-36 Création et utilisation
Recensement des visualiseurs d’aide . . 7-36 des modèles de composants . . . . . . . . . . 8-13
Recensement des sélecteurs d’aide . . . . 7-36 Manipulation des cadres. . . . . . . . . . . . . 8-14
Utilisation de l’aide Création de cadres . . . . . . . . . . . . . . 8-14
dans une application VCL . . . . . . . . . . . 7-37 Ajout de cadres à la palette
Comment TApplication traite-il l’aide VCL 7-37 des composants . . . . . . . . . . . . . . . 8-15
Comment les contrôles VCL Utilisation et modification des cadres . . . 8-15
traitent-ils l’aide . . . . . . . . . . . . . . . 7-37 Partage des cadres . . . . . . . . . . . . . . 8-16
Utilisation de l’aide Développement de boîtes de dialogue. . . . . 8-17
dans une application CLX . . . . . . . . . . . 7-38 Utilisation des boîtes de dialogue
Comment TApplication d’ouverture . . . . . . . . . . . . . . . . . . 8-17
traite-il l’aide CLX . . . . . . . . . . . . . . 7-38 Organisation des actions pour les barres d’outils
Comment les contrôles CLX et les menus . . . . . . . . . . . . . . . . . . . 8-18
traitent-ils l’aide . . . . . . . . . . . . . . . 7-38 Qu’est-ce qu’une action ?. . . . . . . . . . . 8-20
Appel direct à un système d’aide . . . . . . . . 7-39 Définition des bandes d’actions . . . . . . . 8-21
Utilisation de IHelpSystem . . . . . . . . . . . . 7-39 Création des barres d’outils et des menus . 8-21
Personnalisation du système d’aide de l’EDI . 7-40 Ajout de couleurs, de motifs ou d’images
aux menus, boutons et barres d’outils 8-23
Chapitre 8 Ajout d’icônes aux menus
Conception de l’interface utilisateur et aux barres d’outils . . . . . . . . . . 8-23
Création de barres d’outils et de menus
des applications 8-1 personnalisables par l’utilisateur . . . 8-24
Contrôle du comportement de l’application . . 8-1
Cacher les éléments et les catégories
Manipulation de l’application . . . . . . . . 8-2
inutilisés dans les bandes d’actions . . 8-25
Gestion de l’écran . . . . . . . . . . . . . . . 8-2
Utilisation des listes d’actions. . . . . . . . . . 8-26
Paramétrage des fiches . . . . . . . . . . . . . . 8-2
Définition des listes d’actions . . . . . . . . 8-26
Utilisation de la fiche principale . . . . . . . 8-3
Que se passe-t-il lors du déclenchement
Cacher la fiche principale . . . . . . . . . . . 8-3
d’une action ? . . . . . . . . . . . . . . . . 8-27
Ajout de fiches . . . . . . . . . . . . . . . . . 8-3
Réponse par les événements . . . . . . . 8-27
Liaison de fiches . . . . . . . . . . . . . . 8-3
Comment les actions trouvent
Gestion de la disposition . . . . . . . . . . . 8-4
leurs cibles . . . . . . . . . . . . . . . . 8-29
Utilisation des fiches . . . . . . . . . . . . . . . 8-5
Actualisation des actions . . . . . . . . . . . 8-29
Contrôle du stockage en mémoire
Classes d’actions prédéfinies . . . . . . . . 8-30
des fiches . . . . . . . . . . . . . . . . . . . 8-5
Conception de composants action . . . . . 8-31
Affichage d’une fiche créée
Recensement d’actions . . . . . . . . . . . . 8-32
automatiquement . . . . . . . . . . . . . 8-6
Création et gestion de menus . . . . . . . . . . 8-32
Création dynamique de fiche . . . . . . . 8-6
Ouverture du concepteur de menus . . . . 8-33
Création de fiches non modales
Construction des menus . . . . . . . . . . . 8-34
comme fenêtres . . . . . . . . . . . . . . 8-7
Nom des menus . . . . . . . . . . . . . . 8-34
Création d’une instance de fiche
Nom des éléments de menu . . . . . . . 8-34
en utilisant une variable locale . . . . . 8-7
iv
Ajout, insertion et suppression Création de groupes de boutons outil . 8-52
d’éléments de menu . . . . . . . . . . . 8-35 Utilisation de boutons outil bascule . . 8-52
Ajout de lignes de séparation. . . . . . . 8-37 Ajout d’un composant barre multiple . . . 8-52
Spécification de touches accélératrices Définition de l’aspect
et de raccourcis clavier . . . . . . . . . . 8-37 de la barre multiple . . . . . . . . . . . 8-53
Création de sous-menus. . . . . . . . . . . . 8-37 Réponse aux clics . . . . . . . . . . . . . . . 8-53
Création de sous-menus par déplacement Affectation d’un menu
de menus existants . . . . . . . . . . . . 8-38 à un bouton outil . . . . . . . . . . . . 8-53
Déplacement d’éléments de menu . . . . 8-38 Ajout de barres d’outils cachées . . . . . . 8-54
Ajout d’images à des éléments de menu 8-39 Masquage et affichage d’une barre d’outils 8-54
Affichage du menu . . . . . . . . . . . . . 8-40
Edition des éléments de menu Chapitre 9
dans l’inspecteur d’objets . . . . . . . . . . 8-40 Types de contrôles 9-1
Utilisation du menu contextuel Contrôles texte . . . . . . . . . . . . . . . . . . . 9-1
du concepteur de menus . . . . . . . . . . 8-41 Contrôles de saisie . . . . . . . . . . . . . . . 9-2
Commandes du menu contextuel . . . . 8-41 Propriétés des contrôles de saisie . . . . . . . 9-3
Déplacement parmi les menus Contrôles de saisie mémo
à la conception . . . . . . . . . . . . . . 8-41 et texte formaté . . . . . . . . . . . . . . 9-3
Utilisation des modèles de menu . . . . . . 8-42 Contrôles de visualisation de texte
Enregistrement d’un menu comme modèle 8-43 (CLX seulement). . . . . . . . . . . . . . . . 9-4
Conventions de nom pour les éléments Libellés . . . . . . . . . . . . . . . . . . . . . . 9-4
et les gestionnaires d’événements Contrôles de saisies spécialisées . . . . . . . . . 9-5
des modèles de menu . . . . . . . . . . 8-44 Barres de défilement . . . . . . . . . . . . . . 9-5
Manipulation d’éléments de menu Barres graduées . . . . . . . . . . . . . . . . . 9-5
à l’exécution. . . . . . . . . . . . . . . . . . 8-45 Contrôles flèches haut-bas (VCL seulement) 9-6
Fusion de menus . . . . . . . . . . . . . . . . 8-45 Contrôles incrémenteur (CLX seulement) . . 9-6
Spécification du menu actif : Contrôles touche d’accès rapide
propriété Menu . . . . . . . . . . . . . . 8-45 (VCL seulement). . . . . . . . . . . . . . . . 9-7
Ordre des éléments de menu fusionnés : Contrôles séparateur . . . . . . . . . . . . . . 9-7
propriété GroupIndex . . . . . . . . . . 8-46 Boutons et contrôles similaires . . . . . . . . . . 9-7
Importation de fichiers ressource . . . . . . 8-46 Contrôles bouton . . . . . . . . . . . . . . . . 9-8
Conception de barres d’outils Boutons bitmap . . . . . . . . . . . . . . . . . 9-8
et de barres multiples . . . . . . . . . . . . . . 8-47 Turboboutons . . . . . . . . . . . . . . . . . . 9-9
Ajout d’une barre d’outils en utilisant Cases à cocher . . . . . . . . . . . . . . . . . . 9-9
un composant volet . . . . . . . . . . . . . 8-48 Boutons radio . . . . . . . . . . . . . . . . . . 9-9
Ajout d’un turbobouton à un volet . . . 8-48 Barres d’outils . . . . . . . . . . . . . . . . . 9-10
Spécification du glyphe Barres multiples (VCL seulement) . . . . . 9-10
d’un turbobouton . . . . . . . . . . . . . 8-49 Contrôles liste . . . . . . . . . . . . . . . . . . . 9-11
Définition de l’état initial Boîtes liste et boîtes liste de cases à cocher 9-11
d’un turbobouton . . . . . . . . . . . . . 8-49 Boîtes à options . . . . . . . . . . . . . . . . 9-12
Création d’un groupe de turboboutons . 8-49 Vues arborescentes . . . . . . . . . . . . . . 9-13
Utilisation de boutons bascule . . . . . . 8-50 Vues liste . . . . . . . . . . . . . . . . . . . . 9-13
Ajout d’une barre d’outils en utilisant Sélecteurs Date/Heure et calendriers
le composant barre d’outils . . . . . . . . . 8-50 mensuels (VCL seulement). . . . . . . . . 9-14
Ajout d’un bouton outil . . . . . . . . . . 8-50 Regroupement de contrôles . . . . . . . . . . . 9-14
Affectation d’images Boîtes groupe et groupes de boutons radio 9-14
à des boutons outil . . . . . . . . . . . . 8-51 Volets . . . . . . . . . . . . . . . . . . . . . . 9-15
Définition de l’aspect et des conditions Boîtes de défilement . . . . . . . . . . . . . 9-15
initiales d’un bouton outil . . . . . . . . 8-51 Contrôles onglets . . . . . . . . . . . . . . . 9-16
v
Contrôles pages . . . . . . . . . . . . . . . . 9-16 Enregistrement d’une image
Contrôles en-têtes . . . . . . . . . . . . . . . 9-16 dans un fichier . . . . . . . . . . . . . 10-21
Contrôles d’affichage . . . . . . . . . . . . . . . 9-16 Remplacement de l’image . . . . . . . 10-22
Barres d’état. . . . . . . . . . . . . . . . . . . 9-17 Utilisation du presse-papiers
Barres de progression . . . . . . . . . . . . . 9-17 avec les graphiques . . . . . . . . . . . . 10-23
Propriétés d’aide ou de conseil d’aide . . . 9-17 Copier des graphiques
Grilles . . . . . . . . . . . . . . . . . . . . . . . . 9-18 dans le presse-papiers. . . . . . . . . 10-23
Grilles de dessin . . . . . . . . . . . . . . . . 9-18 Couper des graphiques
Grilles de chaînes . . . . . . . . . . . . . . . 9-18 dans le presse-papiers. . . . . . . . . 10-23
Editeur de liste de valeurs (VCL seulement) . 9-19 Coller des graphiques
Contrôles graphiques . . . . . . . . . . . . . . . 9-20 depuis le presse-papiers . . . . . . . 10-24
Images . . . . . . . . . . . . . . . . . . . . . . 9-20 Techniques de dessin
Formes . . . . . . . . . . . . . . . . . . . . . . 9-20 dans une application . . . . . . . . . . . 10-25
Biseaux . . . . . . . . . . . . . . . . . . . . . 9-20 Répondre à la souris . . . . . . . . . . 10-25
Boîtes à peindre . . . . . . . . . . . . . . . . 9-21 Ajout d’un champ à un objet fiche . . 10-28
Contrôles animation (VCL seulement) . . . 9-21 Amélioration du dessin des lignes . . 10-29
Utilisation du multimédia . . . . . . . . . . . 10-31
Chapitre 10 Ajout de séquences vidéo silencieuses
Utilisation des graphiques à une application . . . . . . . . . . . . . 10-31
Exemple d’ajout de séquences vidéo
et du multimédia 10-1 silencieuses . . . . . . . . . . . . . . . 10-32
Présentation de la programmation relative
Ajout de séquences audio et/ou vidéo
aux graphiques . . . . . . . . . . . . . . . . . . 10-1
à une application . . . . . . . . . . . . . 10-33
Rafraîchissement de l’écran . . . . . . . . . . 10-2
Exemple d’ajout de séquences audio
Types des objets graphiques . . . . . . . . . 10-3
et/ou vidéo (VCL seulement) . . . . 10-35
Propriétés et méthodes communes
du canevas . . . . . . . . . . . . . . . . . . 10-4
Utilisation des propriétés
Chapitre 11
de l’objet canevas . . . . . . . . . . . . . . 10-5 Ecriture d’applications multithreads 11-1
Utilisation des crayons. . . . . . . . . . . 10-6 Définition d’objets thread . . . . . . . . . . . . 11-2
Utilisation des pinceaux . . . . . . . . . . 10-8 Initialisation du thread . . . . . . . . . . . . 11-3
Lecture et définition de pixels . . . . . 10-10 Affectation d’une priorité par défaut . . 11-3
Utilisation des méthodes du canevas Libération des threads . . . . . . . . . . 11-4
pour dessiner des objets graphiques. . . 10-10 Ecriture de la fonction thread . . . . . . . . 11-4
Dessin de lignes et de polylignes . . . 10-10 Utilisation du thread principal
Dessin de formes . . . . . . . . . . . . . 10-12 VCL/CLX . . . . . . . . . . . . . . . . . 11-4
Gestion de plusieurs objets de dessin Utilisation de variables locales
dans votre application . . . . . . . . . . . 10-13 aux threads . . . . . . . . . . . . . . . . 11-6
Faire le suivi de l’outil de dessin Vérification de l’arrêt
à utiliser . . . . . . . . . . . . . . . . . 10-13 par d’autres threads . . . . . . . . . . . 11-6
Changement d’outil en utilisant Gestion des exceptions
un turbobouton . . . . . . . . . . . . 10-14 dans la fonction thread . . . . . . . . . 11-7
Utilisation des outils de dessin . . . . . 10-14 Ecriture du code de nettoyage . . . . . . . 11-7
Dessiner sur un graphique . . . . . . . . . 10-18 Coordination de threads . . . . . . . . . . . . . 11-8
Création de graphiques défilables . . . 10-18 Eviter les accès simultanés . . . . . . . . . . 11-8
Ajout d’un contrôle image . . . . . . . 10-18 Verrouillage d’objets. . . . . . . . . . . . 11-8
Chargement et enregistrement Utilisation de sections critiques . . . . . 11-8
de fichiers graphiques . . . . . . . . . . . 10-20 Utilisation du synchronisateur à écriture
Chargement d’une image exclusive et lecture multiple . . . . . . 11-9
depuis un fichier . . . . . . . . . . . . 10-21
vi
Autres techniques de partage Classes d’exception VCL et CLX . . . . . 12-18
de la mémoire . . . . . . . . . . . . . . 11-10 Considérations de portabilité . . . . . . . 12-20
Attente des autres threads . . . . . . . . . 11-10
Attente de la fin d’exécution Chapitre 13
d’un thread . . . . . . . . . . . . . . . 11-10 Gestion en langage C++
Attente de l’achèvement d’une tâche . 11-11
Exécution d’objets thread . . . . . . . . . . . . 11-12
de VCL et CLX 13-1
Les modèles objet en C++ et en Pascal Objet . 13-1
Redéfinition de la priorité par défaut . . . 11-12
Héritage et interfaces . . . . . . . . . . . . . 13-2
Démarrage et arrêt des threads . . . . . . 11-13
Utilisation d’interface à la place
Débogage d’applications multithreads . . . . 11-13
de l’héritage multiple . . . . . . . . . . 13-2
Nommer un thread . . . . . . . . . . . . . 11-14
Déclaration des classes interfaces . . . . 13-2
Conversion d’un thread anonyme
IUnknown et IInterface . . . . . . . . . . 13-3
en thread nommé . . . . . . . . . . . . 11-14
Création de classes gérant IUnknown . 13-4
Affectation de noms distincts
Classes interfaces et gestion
à des threads similaires . . . . . . . . 11-15
de la durée de vie . . . . . . . . . . . . 13-5
Identification et instanciation des objets . . 13-6
Chapitre 12 Différences entre les références C++
Gestion des exceptions 12-1 et Pascal Objet . . . . . . . . . . . . . . 13-6
Gestion des exceptions C++ . . . . . . . . . . . 12-1 Copie d’objets . . . . . . . . . . . . . . . 13-7
Syntaxe de gestion des exceptions . . . . . . 12-2 Utilisation d’objets comme arguments
Le bloc try . . . . . . . . . . . . . . . . . . 12-2 de fonction . . . . . . . . . . . . . . . . 13-8
L’instruction throw . . . . . . . . . . . . . 12-3 Construction d’objets en C++Builder
L’instruction catch . . . . . . . . . . . . . 12-3 pour les classes VCL/CLX . . . . . . . . . 13-8
Redéclenchement des exceptions . . . . . . 12-4 Construction d’objets en C++ . . . . . . 13-8
Spécifications des exceptions . . . . . . . . . 12-4 Construction d’objets Pascal Objet . . . 13-8
Déroulement des exceptions . . . . . . . . . 12-5 Construction des objets C++Builder . . 13-8
Pointeurs sécurisés . . . . . . . . . . . . . 12-6 Appels de méthodes virtuelles dans les
Constructeurs dans la gestion d’exceptions 12-6 constructeurs des classes de base . . . . 13-10
Gestion des exceptions non interceptées Modèle Pascal Objet. . . . . . . . . . . .13-11
et inattendues . . . . . . . . . . . . . . . . . 12-6 Modèle C++ . . . . . . . . . . . . . . . .13-11
Exceptions structurées sous Win32 . . . . . . . 12-7 Modèle C++Builder . . . . . . . . . . . .13-11
Syntaxe des exceptions structurées . . . . . 12-8 Exemple : appel de méthodes virtuelles13-11
Gestion des exceptions structurées . . . . . 12-8 Initialisation par le constructeur
Filtres d’exceptions. . . . . . . . . . . . . . . 12-9 des données membres
Mélange du C++ avec des exceptions pour les fonctions virtuelles . . . . . 13-12
structurées. . . . . . . . . . . . . . . . . . 12-11 Destruction d’objets. . . . . . . . . . . . . 13-14
Exemple d’un programme C++ Exceptions déclenchées
ayant des exceptions C. . . . . . . . . 12-12 dans les constructeurs. . . . . . . . . 13-14
Définition d’exceptions . . . . . . . . . . . 12-13 Méthodes virtuelles appelées
Déclenchement d’exceptions . . . . . . . . 12-13 dans les destructeurs . . . . . . . . . 13-15
Blocs de terminaison. . . . . . . . . . . . . 12-14 AfterConstruction et BeforeDestruction . 13-15
Options de gestion des exceptions Fonctions virtuelles de classe . . . . . . . 13-15
C++Builder . . . . . . . . . . . . . . . . . 12-15 Gestion des types de données et des concepts
Gestion des exceptions VCL/CLX. . . . . . . 12-16 du langage Pascal Objet . . . . . . . . . . . 13-16
Différences entre la gestion d’exceptions Typedefs . . . . . . . . . . . . . . . . . . . 13-16
C++ et VCL/CLX . . . . . . . . . . . . . 12-16 Classes gérant le langage Pascal Objet . . 13-16
Gestion des exceptions du système Equivalents dans le langage C++
d’exploitation . . . . . . . . . . . . . . . . 12-17 du langage Pascal Objet . . . . . . . . . 13-17
Gestion des exceptions VCL et CLX. . . . 12-18 Paramètres var . . . . . . . . . . . . . . 13-17
vii
Paramètres sans type. . . . . . . . . . . 13-17 Registre . . . . . . . . . . . . . . . . . . . 14-7
Tableaux ouverts . . . . . . . . . . . . . . . 13-18 Autres différences . . . . . . . . . . . . . 14-8
Calcul du nombre d’éléments. . . . . . 13-18 Fonctionnalités manquantes dans la CLX . 14-9
Temporaires . . . . . . . . . . . . . . . . 13-19 Fonctionnalités non portées directement. . 14-9
Tableau de constantes . . . . . . . . . . 13-19 Comparaison entre les unités CLX et VCL 14-10
Macro OPENARRAY . . . . . . . . . . . 13-20 Différences dans les constructeurs
Macro EXISTINGARRAY . . . . . . . . 13-20 d’objets CLX . . . . . . . . . . . . . . . . 14-13
Fonctions C++ attendant un argument Gestion des événements widget
tableau ouvert . . . . . . . . . . . . . . 13-20 et système . . . . . . . . . . . . . . . . . 14-14
Types définis différemment . . . . . . . . . 13-20 Partage des fichiers source
Types de données booléens . . . . . . . 13-21 entre Windows et Linux . . . . . . . . . 14-14
Types de données Char . . . . . . . . . 13-21 Différences d’environnement
Interfaces Delphi . . . . . . . . . . . . . . . 13-21 entre Windows et Linux . . . . . . . . . 14-14
Chaînes de ressource . . . . . . . . . . . . 13-22 Structure de répertoires sous Linux . . . 14-17
Paramètres par défaut . . . . . . . . . . . . 13-22 Ecriture de code portable . . . . . . . . . 14-18
Informations de type à l’exécution . . . . 13-23 Utilisation des directives
Types sans correspondants . . . . . . . . . 13-24 conditionnelles . . . . . . . . . . . . . 14-19
Type réel sur six octets. . . . . . . . . . 13-24 Emission de messages . . . . . . . . . 14-20
Tableaux renvoyés par des fonctions . 13-24 Inclusion de code assembleur inline . 14-21
Extensions des mots clés . . . . . . . . . . 13-25 Différences de programmation
__classid . . . . . . . . . . . . . . . . . . 13-25 sous Linux . . . . . . . . . . . . . . . . . 14-22
__closure . . . . . . . . . . . . . . . . . . 13-25 Applications de bases de données
__property . . . . . . . . . . . . . . . . . 13-27 multiplates-formes . . . . . . . . . . . . . . 14-22
__published . . . . . . . . . . . . . . . . 13-29 Différences de dbExpress . . . . . . . . . 14-23
Extensions du mot clé __declspec . . . . . 13-29 Différences au niveau composant . . . . . 14-24
__declspec(delphiclass) . . . . . . . . . 13-29 Différences au niveau
__declspec(delphireturn). . . . . . . . . 13-30 de l’interface utilisateur . . . . . . . . . 14-25
__declspec(delphirtti) . . . . . . . . . . 13-30 Portage d’applications
__declspec(dynamic) . . . . . . . . . . . 13-30 de bases de données vers Linux. . . . . 14-26
__declspec(hidesbase) . . . . . . . . . . 13-30 Mise à jour des données
__declspec(package) . . . . . . . . . . . 13-31 dans les applications dbExpress. . . . . 14-28
__declspec(pascalimplementation) . . . 13-31 Applications Internet multiplates-formes . . 14-30
__declspec(uuid) . . . . . . . . . . . . . 13-31 Portage d’applications Internet
vers Linux . . . . . . . . . . . . . . . . . 14-31
Chapitre 14
Développement d’applications Chapitre 15
multiplates-formes 14-1 Utilisation des paquets
Création d’applications multiplates-formes . . 14-1 et des composants 15-1
Portage d’applications Windows vers Linux. . 14-2 Pourquoi utiliser des paquets ? . . . . . . . . 15-2
Techniques de portage. . . . . . . . . . . . . 14-2 Les paquets et les DLL standard . . . . . . 15-2
Portages propres à une plate-forme . . . 14-3 Paquets d’exécution . . . . . . . . . . . . . . . 15-3
Portages multiplates-formes. . . . . . . . 14-3 Utilisation des paquets
Portages d’émulation Windows . . . . . 14-3 dans une application . . . . . . . . . . . . 15-3
Portage de votre application . . . . . . . . . 14-3 Paquets chargés dynamiquement . . . . . . 15-4
CLX et VCL . . . . . . . . . . . . . . . . . . . 14-5 Choix des paquets d’exécution à utiliser. . 15-4
Différences de CLX . . . . . . . . . . . . . . 14-6 Paquets personnalisés . . . . . . . . . . . . 15-5
Présentation visuelle . . . . . . . . . . . . 14-6 Paquets de conception . . . . . . . . . . . . . . 15-5
Styles . . . . . . . . . . . . . . . . . . . . . 14-7 Installation de paquets de composants. . . 15-6
Variants . . . . . . . . . . . . . . . . . . . 14-7 Création et modification de paquets . . . . . . 15-7
viii
Création d’un paquet . . . . . . . . . . . . . 15-7 Basculement dynamique de DLL
Modification d’un paquet existant . . . . . . 15-8 de ressource . . . . . . . . . . . . . . . . 16-13
Fichiers source de paquet et fichiers Localisation des applications . . . . . . . . . 16-13
d’options de projet . . . . . . . . . . . . . . 15-9 Localisation des ressources . . . . . . . . 16-13
Empaquetage des composants . . . . . . 15-9
Présentation de la structure d’un paquet . 15-10 Chapitre 17
Nom de paquets . . . . . . . . . . . . . 15-10 Déploiement des applications 17-1
Liste Requires . . . . . . . . . . . . . . . 15-10 Déploiement d’applications généralistes . . . 17-1
Liste Contains . . . . . . . . . . . . . . 15-11 Utilisation des programmes d’installation . 17-2
Construction des paquets . . . . . . . . . . 15-11 Identification des fichiers
Directives de compilation de l’application. . . . . . . . . . . . . . 17-3
propres aux paquets . . . . . . . . . . 15-12 Fichiers de l’application . . . . . . . . . 17-3
Utilisation du compilateur et du lieur Fichiers paquet. . . . . . . . . . . . . . . 17-3
en ligne de commande . . . . . . . . . 15-13 Modules de fusion. . . . . . . . . . . . . 17-4
Fichiers de paquets créés Contrôles ActiveX . . . . . . . . . . . . . 17-5
lors d’une construction. . . . . . . . . 15-14 Applications complémentaires . . . . . . 17-6
Déploiement de paquets . . . . . . . . . . . . 15-14 Emplacement des DLL . . . . . . . . . . 17-6
Déploiement d’applications utilisant Déploiement d’applications CLX . . . . . . . . 17-6
des paquets . . . . . . . . . . . . . . . . . 15-15 Déploiement d’applications
Distribution de paquets de bases de données . . . . . . . . . . . . . . 17-7
à d’autres développeurs . . . . . . . . . . 15-15 Déploiement d’applications de bases
Fichiers de collection de paquets . . . . . 15-15 de données dbExpress . . . . . . . . . . . 17-8
Déploiement d’applications BDE . . . . . . 17-9
Chapitre 16 Le moteur de bases de données
Création d’applications Borland . . . . . . . . . . . . . . . . . . 17-9
internationales 16-1 SQL Links . . . . . . . . . . . . . . . . 17-10
Internationalisation et localisation. . . . . . . . 16-1 Déploiement d’applications de bases de
Internationalisation . . . . . . . . . . . . . . 16-1 données multiniveaux (DataSnap) . . . .17-11
Localisation . . . . . . . . . . . . . . . . . . . 16-2 Déploiement d’applications Web . . . . . . . .17-11
Internationalisation des applications . . . . . . 16-2 Déploiement sur serveur Apache . . . . . 17-12
Codage de l’application . . . . . . . . . . . . 16-2 Activation des modules. . . . . . . . . 17-12
Jeux de caractères. . . . . . . . . . . . . . 16-2 Applications CGI . . . . . . . . . . . . 17-12
Jeux de caractères OEM et ANSI . . . . . 16-3 Programmation pour des environnements
Jeux de caractères sur plusieurs octets . 16-3 hôtes hétérogènes . . . . . . . . . . . . . . . 17-13
Caractères larges . . . . . . . . . . . . . . 16-3 Résolution d’écran et profondeur
Inclure des fonctionnalités bi-directionnelles de couleurs . . . . . . . . . . . . . . . . . 17-14
dans les applications . . . . . . . . . . . 16-4 Si vous n’utilisez pas de redimensionnement
Propriété BiDiMode . . . . . . . . . . . . 16-6 dynamique . . . . . . . . . . . . . . . 17-14
Fonctionnalités spécifiques Si vous redimensionnez dynamiquement
aux cibles locales . . . . . . . . . . . . . 16-9 les fiches et les contrôles . . . . . . . 17-14
Conception de l’interface utilisateur. . . . . 16-9 Adaptation à des profondeurs de couleurs
Texte . . . . . . . . . . . . . . . . . . . . . 16-9 variables. . . . . . . . . . . . . . . . . 17-16
Images graphiques . . . . . . . . . . . . 16-10 Fontes . . . . . . . . . . . . . . . . . . . . . 17-16
Formats et ordre de tri. . . . . . . . . . 16-10 Versions des systèmes d’exploitation . . . 17-17
Correspondances entre claviers. . . . . 16-10 Termes du contrat de licence logicielle . . . 17-17
Isolement des ressources . . . . . . . . . . 16-11 DEPLOY . . . . . . . . . . . . . . . . . . . 17-17
Création de DLL de ressource . . . . . . . 16-11 README . . . . . . . . . . . . . . . . . . . 17-18
Utilisation des DLL de ressource . . . . . 16-12 Contrat de licence . . . . . . . . . . . . . . 17-18
Documentation de produits
vendus par un tiers . . . . . . . . . . . . 17-18
ix
Partie II Edition des données affichées
dans un contrôle . . . . . . . . . . . . . 19-6
Développement d’applications Activation et désactivation de l’affichage
de bases de données des données . . . . . . . . . . . . . . . . . 19-7
Rafraîchissement de l’affichage
Chapitre 18 des données . . . . . . . . . . . . . . . . . 19-7
Conception d’applications Activation des événements souris,
clavier et timer. . . . . . . . . . . . . . . . 19-8
de bases de données 18-1 Choix de l’organisation des données. . . . . . 19-8
Utilisation des bases de données . . . . . . . . 18-1
Affichage d’un seul enregistrement. . . . . 19-8
Types de bases de données . . . . . . . . . . 18-3
Affichage de données
Sécurité des bases de données . . . . . . . . 18-4
en tant que libellés. . . . . . . . . . . . 19-9
Transactions . . . . . . . . . . . . . . . . . . . 18-5
Affichage et édition de champs
Intégrité référentielle, procédures stockées
dans une zone de saisie . . . . . . . . . 19-9
et déclencheurs . . . . . . . . . . . . . . . . 18-6
Affichage et édition de texte
Architecture des bases de données . . . . . . . 18-6
dans un contrôle mémo . . . . . . . . 19-10
Structure générale . . . . . . . . . . . . . . . 18-7
Affichage et édition dans un contrôle mémo
Fiche interface utilisateur . . . . . . . . . 18-7
de texte formaté . . . . . . . . . . . . 19-10
Module de données . . . . . . . . . . . . 18-7
Affichage et édition de champs graphiques
Connexion directe à un serveur
dans un contrôle image . . . . . . . . .19-11
de bases de données . . . . . . . . . . . . . 18-9
Affichage de données dans des boîtes liste
Utilisation d’un fichier dédié sur disque . 18-10
et des boîtes à options . . . . . . . . .19-11
Connexion à un autre ensemble
Manipulation de champs booléens
de données . . . . . . . . . . . . . . . . . 18-12
avec des cases à cocher . . . . . . . . 19-15
Connexion d’un ensemble de données client
Limitation de valeurs de champ
à un autre ensemble de données
avec des boutons radio . . . . . . . . 19-16
dans la même application . . . . . . . 18-14
Affichage de plusieurs enregistrements . 19-17
Utilisation d’une architecture
Visualisation et édition des données
multiniveau . . . . . . . . . . . . . . . 18-15
avec un contrôle TDBGrid . . . . . . . . . . 19-17
Combinaison des approches . . . . . . . . 18-16
Utilisation d’un contrôle grille
Conception de l’interface utilisateur . . . . . 18-17
à son état par défaut . . . . . . . . . . . 19-18
Analyse des données . . . . . . . . . . . . 18-18
Création d’une grille personnalisée. . . . 19-19
Ecriture de rapports . . . . . . . . . . . . . 18-18
Présentation des colonnes persistantes 19-20
Création de colonnes persistantes . . . 19-21
Chapitre 19 Suppression de colonnes persistantes. 19-22
Utilisation de contrôles de données 19-1 Modification de l’ordre
Fonctionnalités communes des colonnes persistantes . . . . . . . 19-22
des contrôles de données . . . . . . . . . . . . 19-2 Définition des propriétés de colonne
Association d’un contrôle de données en mode conception . . . . . . . . . . 19-23
à un ensemble de données . . . . . . . . . 19-3 Définition d’une colonne
Modification de l’ensemble de données de liste de référence . . . . . . . . . . 19-24
associé à l’exécution . . . . . . . . . . . 19-4 Insertion d’un bouton
Activation et désactivation dans une colonne . . . . . . . . . . . 19-24
de la source de données . . . . . . . . . 19-4 Restauration des valeurs par défaut
Réponse aux modifications effectuées d’une colonne . . . . . . . . . . . . . 19-25
par le biais de la source de données . . 19-4 Affichage des champs ADT et tableau . . 19-25
Edition et mise à jour des données . . . . . 19-5 Définition des options de la grille . . . . 19-28
Activation de l’édition des contrôles Saisie de modifications dans la grille. . . 19-29
lors d’une saisie utilisateur . . . . . . . 19-5 Contrôle du dessin de la grille . . . . . . 19-30
x
Comment répondre aux actions de l’utilisateur Ouverture et fermeture des champs
à l’exécution. . . . . . . . . . . . . . . . . 19-30 d’une grille de décision . . . . . . . . 20-12
Création d’une grille qui contient d’autres Réorganisation des lignes et des colonnes
contrôles orientés données . . . . . . . . . . 19-31 d’une grille de décision . . . . . . . . 20-12
Navigation et manipulation Perforation pour voir les détails
d’enregistrements . . . . . . . . . . . . . . . 19-33 dans les grilles de décision . . . . . . 20-13
Choix des boutons visibles . . . . . . . . . 19-34 Limite des dimensions à sélectionner
Affichage et dissimulation des boutons dans les grilles de décision . . . . . . 20-13
en mode conception . . . . . . . . . . 19-34 Propriétés des grilles de décision . . . . . 20-13
Affichage et dissimulation des boutons Création et utilisation de graphes
à l’exécution . . . . . . . . . . . . . . . 19-34 de décision . . . . . . . . . . . . . . . . . . . 20-14
Affichage de panneaux d’information. . . 19-35 Création de graphes de décision . . . . . 20-14
Utilisation d’un navigateur pour plusieurs Utilisation de graphes de décision . . . . 20-15
ensembles de données . . . . . . . . . . . 19-35 Affichage du graphe de décision . . . . . 20-16
Personnalisation du graphe de décision . 20-17
Chapitre 20 Définition des modèles de graphe
Utilisation de composants de décision par défaut . . . . . . . . 20-18
Personnalisation des séries
d’aide à la décision 20-1 d’un graphe de décision . . . . . . . 20-19
Présentation . . . . . . . . . . . . . . . . . . . . 20-1
Utilisation des composants d’aide
Présentation des références croisées. . . . . . . 20-2
à la décision à l’exécution . . . . . . . . . . 20-20
Références croisées à une dimension . . . . 20-3
Pivots de décision à l’exécution . . . . . . 20-20
Références croisées à plusieurs
Grilles de décision à l’exécution . . . . . 20-21
dimensions . . . . . . . . . . . . . . . . . . 20-3
Graphes de décision à l’exécution . . . . 20-21
Instructions relatives à l’utilisation de composants
Considérations relatives au contrôle
d’aide à la décision . . . . . . . . . . . . . . . 20-3
de la mémoire . . . . . . . . . . . . . . . . . 20-21
Utilisation d’ensembles de données
Définition du maximum de dimensions,
avec les composants d’aide à la décision . . . 20-5
de champs récapitulatifs, et de cellules 20-22
Création d’ensembles de données de décision
Définition de l’état des dimensions. . . . 20-22
avec TQuery ou TTable . . . . . . . . . . . 20-6
Utilisation de dimensions paginées. . . . 20-23
Création d’ensembles de données de décision
avec l’éditeur de requête de décision . . . 20-6
Utilisation des cubes de décision . . . . . . . . 20-7
Chapitre 21
Propriétés et événements Connexion aux bases de données 21-1
des cubes de décision . . . . . . . . . . . . 20-8 Utilisation de connexions implicites . . . . . . 21-2
Utilisation de l’éditeur de cube de décision 20-8 Contrôles des connexions . . . . . . . . . . . . 21-3
Visualisation et modification des paramètres Connexion à un serveur
de dimensions . . . . . . . . . . . . . . . 20-8 de bases de données . . . . . . . . . . . . 21-3
Définition du maximum de dimensions Déconnexion d’un serveur
et de récapitulations . . . . . . . . . . . 20-9 de base de données . . . . . . . . . . . . . 21-4
Visualisation et modification des options Contrôle de la connexion au serveur . . . . . 21-4
de conception . . . . . . . . . . . . . . . 20-9 Gestion des transactions . . . . . . . . . . . . . 21-6
Utilisation de sources de décision . . . . . . . 20-10 Démarrage d’une transaction . . . . . . . . 21-7
Propriétés et événements . . . . . . . . . . 20-10 Achèvement d’une transaction . . . . . . . 21-9
Utilisation de pivots de décision . . . . . . . 20-10 Achèvement d’une transaction réussie . 21-9
Propriétés des pivots de décision . . . . . 20-11 Achèvement d’une transaction
Création et utilisation de grilles de décision . 20-11 non réussie . . . . . . . . . . . . . . . . 21-9
Création de grilles de décision . . . . . . . 20-12 Spécification du niveau d’isolation
Utilisation de grilles de décision . . . . . . 20-12 des transactions . . . . . . . . . . . . . . 21-10
Envoi de commandes au serveur. . . . . . . .21-11
xi
Utilisation d’ensembles de données associés 21-13 Définition d’options de filtre . . . . . . . 22-18
Fermeture d’ensembles de données Navigation parmi les enregistrements
sans déconnexion du serveur . . . . . . . 21-13 d’un ensemble de données filtré . . . . 22-19
Déplacement parmi les ensembles Modification des données . . . . . . . . . . . 22-20
de données associés . . . . . . . . . . . . 21-14 Modification d’enregistrements . . . . . . 22-20
Obtention de métadonnées . . . . . . . . . . . 21-14 Ajout de nouveaux enregistrements . . . 22-21
Enumération des tables disponibles . . . . 21-15 Insertion d’enregistrements . . . . . . 22-22
Enumération des champs d’une table . . . 21-15 Ajout d’enregistrements à la fin . . . . 22-23
Enumération des procédures stockées Suppression d’enregistrements . . . . . . 22-23
disponibles . . . . . . . . . . . . . . . . . 21-15 Validation des données . . . . . . . . . . . 22-24
Enumération des index disponibles . . . . 21-16 Annulation des modifications . . . . . . . 22-24
Enumération des paramètres Modification d’enregistrements entiers. . 22-25
de procédure stockée . . . . . . . . . . . 21-16 Champs calculés . . . . . . . . . . . . . . . . 22-26
Types d’ensembles de données . . . . . . . . 22-27
Chapitre 22 Utilisation d’ensembles de données
Présentation de type table . . . . . . . . . . . . . . . . . . 22-29
Avantages de l’utilisation des ensembles
des ensembles de données 22-1 de données de type table. . . . . . . . . 22-30
Utilisation des descendants de TDataSet . . . . 22-2
Tri des enregistrements avec des index . 22-30
Détermination des états d’un ensemble
Obtention d’informations sur les index 22-31
de données . . . . . . . . . . . . . . . . . . . . 22-3
Spécification d’un index
Ouverture et fermeture des ensembles
avec IndexName . . . . . . . . . . . . 22-31
de données . . . . . . . . . . . . . . . . . . . . 22-5
Création d’un index
Navigation dans les ensembles de données . . 22-6
avec IndexFieldNames . . . . . . . . 22-32
Utilisation des méthodes First et Last . . . . 22-7
Utilisation d’index pour chercher
Utilisation des méthodes Next et Prior . . . 22-7
des enregistrements . . . . . . . . . . . . 22-32
Utilisation de la méthode MoveBy . . . . . 22-8
Exécution d’une recherche
Utilisation des propriétés Eof et Bof. . . . . 22-9
avec les méthodes Goto . . . . . . . . 22-33
Eof . . . . . . . . . . . . . . . . . . . . . . 22-9
Exécution d’une recherche
Bof . . . . . . . . . . . . . . . . . . . . . 22-10
avec les méthodes Find . . . . . . . . 22-34
Marquage d’enregistrements . . . . . . . . 22-11
Spécification de l’enregistrement en cours
La propriété Bookmark . . . . . . . . . 22-11
après une recherche réussie . . . . . 22-34
La méthode GetBookmark . . . . . . . 22-11
Recherche sur des clés partielles . . . 22-34
Les méthodes GotoBookmark
Réitération ou extension
et BookmarkValid . . . . . . . . . . . . 22-11
d’une recherche . . . . . . . . . . . . 22-35
La méthode CompareBookmarks. . . . 22-11
Limitation des enregistrements
La méthode FreeBookmark . . . . . . . 22-11
avec des portées . . . . . . . . . . . . . . 22-35
Un exemple d’utilisation de signets . . 22-12
Présentation des différences
Recherche dans les ensembles de données . . 22-12
entre les portées et les filtres . . . . . 22-35
Utilisation de la méthode Locate. . . . . . 22-12
Spécification de portées. . . . . . . . . 22-36
Utilisation de la méthode Lookup . . . . . 22-13
Modification d’une portée . . . . . . . 22-39
Affichage et édition d’ensembles de données
Application ou annulation
en utilisant des filtres . . . . . . . . . . . . . 22-15
d’une portée . . . . . . . . . . . . . . 22-40
Activation et désactivation des filtres . . . 22-15
Création de relations maître/détail . . . . 22-40
Création de filtres . . . . . . . . . . . . . . 22-16
Comment faire de la table la partie détail
Définition de la propriété Filter . . . . 22-16
d’un autre ensemble de données . . 22-41
Ecriture d’un gestionnaire d’événement
Utilisation de tables détail imbriquées 22-43
OnFilterRecord . . . . . . . . . . . . . 22-18
Contrôle des accès en lecture/écriture
Permutation entre les gestionnaires
aux tables . . . . . . . . . . . . . . . . . . 22-44
d’événements filtre à l’exécution . . . 22-18
xii
Création et suppression des tables. . . . . 22-44 Définition d’un champ de données . . . 23-7
Création de tables . . . . . . . . . . . . 22-44 Définition d’un champ calculé . . . . . . 23-8
Suppression de tables . . . . . . . . . . 22-47 Programmation d’un champ calculé . . 23-9
Vidage des tables. . . . . . . . . . . . . . . 22-47 Définition d’un champ de référence . 23-10
Synchronisation des tables . . . . . . . . . 22-48 Définition d’un champ agrégat . . . . 23-12
Utilisation d’ensembles de données Suppression de champs persistants. . . . 23-12
de type requête. . . . . . . . . . . . . . . . . 22-48 Définition des événements et des propriétés
Spécification de la requête . . . . . . . . . 22-49 des champs persistants . . . . . . . . . . 23-13
Spécification d’une requête en utilisant Définition des propriétés d’affichage
la propriété SQL . . . . . . . . . . . . 22-50 et d’édition en mode conception . . 23-13
Spécification d’une requête en utilisant Définition des propriétés des composants
la propriété CommandText . . . . . . 22-51 champ à l’exécution . . . . . . . . . . 23-15
Utilisation de paramètres Création des ensembles d’attributs
dans les requêtes . . . . . . . . . . . . . . 22-51 pour les composants champ . . . . . 23-15
Fourniture des paramètres Association des ensembles d’attributs
pendant la conception . . . . . . . . . 22-52 aux composants champ . . . . . . . . 23-16
Fourniture des paramètres Suppression des associations
pendant l’exécution. . . . . . . . . . . 22-53 d’ensembles d’attributs . . . . . . . . 23-16
Etablissement de relations maître/détail Contrôle ou dissimulation de la saisie
en utilisant des paramètres . . . . . . . . 22-54 utilisateur . . . . . . . . . . . . . . . . 23-17
Préparation des requêtes . . . . . . . . . . 22-55 Utilisation des formats par défaut pour les
Exécution de requêtes qui ne renvoient pas champs numériques, date et heure . 23-17
d’ensemble de résultats . . . . . . . . . . 22-56 Gestion des événements . . . . . . . . 23-18
Utilisation d’ensembles de résultats Manipulation des méthodes de champ
unidirectionnels. . . . . . . . . . . . . . . 22-57 lors de l’exécution . . . . . . . . . . . . . . 23-19
Utilisation d’ensembles de données de type Affichage, conversion et accès aux valeurs
procédure stockée . . . . . . . . . . . . . . . 22-57 des champs . . . . . . . . . . . . . . . . . . 23-20
Utilisation de paramètres Affichage de valeurs dans les contrôles
avec les procédures stockées . . . . . . . 22-59 standard . . . . . . . . . . . . . . . . . . 23-20
Définition des paramètres Conversion des valeurs de champs. . . . 23-21
pendant la conception . . . . . . . . . 22-60 Accès à des valeurs par la propriété par défaut
Utilisation des paramètres d’un ensemble de données . . . . . . . . 23-22
pendant l’exécution. . . . . . . . . . . 22-61 Accès à des valeurs par la propriété Fields
Préparation des procédures stockées . . . 22-62 d’un ensemble de données . . . . . . . . 23-23
Exécution de procédures stockées qui ne Accès à des valeurs par la méthode
renvoient pas d’ensemble de résultats. . 22-62 FieldByName d’un ensemble
Lecture de plusieurs ensembles de données . . . . . . . . . . . . . . . . . 23-23
de résultats . . . . . . . . . . . . . . . . . 22-63 Définition de la valeur par défaut
d’un champ . . . . . . . . . . . . . . . . . . 23-24
Chapitre 23 Utilisation de contraintes . . . . . . . . . . . 23-24
Manipulation Création de contrainte personnalisée . . . 23-24
Utilisation des contraintes du serveur . . 23-25
des composants champ 23-1 Utilisation des champs objet . . . . . . . . . 23-26
Composants champ dynamique . . . . . . . . . 23-2
Affichage des champs ADT et tableau . . 23-27
Champs persistants . . . . . . . . . . . . . . . . 23-3
Utilisation des champs ADT. . . . . . . . 23-27
Création de champs persistants . . . . . . . 23-4
Utilisation de composants champ
Modification de l’ordre des champs
persistant . . . . . . . . . . . . . . . . 23-27
persistants . . . . . . . . . . . . . . . . . . . 23-6
Utilisation de la méthode FieldByName
Définition de nouveaux champs
d’un ensemble de données . . . . . . 23-28
persistants . . . . . . . . . . . . . . . . . . . 23-6
xiii
Utilisation de la propriété FieldValues Liaison des paramètres . . . . . . . . . 24-13
d’un ensemble de données . . . . . . 23-28 Manipulation des procédures stockées
Utilisation de la propriété FieldValues redéfinies d’Oracle. . . . . . . . . . . 24-13
d’un champ ADT . . . . . . . . . . . . 23-28 Connexion aux bases de données
Utilisation de la propriété Fields avec TDatabase . . . . . . . . . . . . . . 24-14
d’un champ ADT . . . . . . . . . . . . 23-28 Association d’un composant
Utilisation des champs tableau. . . . . . . 23-29 base de données à une session. . . . 24-14
Utilisation de champs persistants . . . 23-29 Interactions entre les composants
Utilisation de la propriété FieldValues base de données et session . . . . . . 24-15
d’un champ tableau . . . . . . . . . . 23-29 Identification de la base de données . 24-15
Utilisation de la propriété Fields Ouverture d’une connexion
d’un champ tableau . . . . . . . . . . 23-29 avec TDatabase. . . . . . . . . . . . . 24-17
Utilisation des champs ensemble Utilisation des composants base de données
de données . . . . . . . . . . . . . . . . . 23-30 dans les modules de données . . . . 24-18
Affichage des champs ensemble Gestion des sessions de bases de données 24-18
de données. . . . . . . . . . . . . . . . 23-30 Activation d’une session . . . . . . . . 24-20
Accès aux données d’un ensemble Spécification du comportement
de données imbriqué . . . . . . . . . . 23-30 de la connexion de base de données
Utilisation de champs de référence . . . . 23-31 par défaut . . . . . . . . . . . . . . . . 24-21
Affichage des champs de référence . . 23-31 Gestion des connexions de bases
Accès aux données d’un champ de données . . . . . . . . . . . . . . . 24-22
de référence . . . . . . . . . . . . . . . 23-31 Manipulation des tables Paradox et dBASE
protégées par mot de passe . . . . . 24-24
Chapitre 24 Spécification des répertoires Paradox. 24-27
Utilisation du moteur de bases Manipulation des alias BDE . . . . . . 24-28
Récupération des informations
de données Borland 24-1 d’une session . . . . . . . . . . . . . . 24-29
Architecture BDE . . . . . . . . . . . . . . . . . 24-1
Création de sessions supplémentaires 24-30
Utilisation d’ensembles de données BDE . . 24-2
Affectation d’un nom à une session . 24-31
Association d’un ensemble de données
Gestion de sessions multiples . . . . . 24-32
avec les connexions de bases de données
Utilisation des transactions avec le BDE . . 24-34
et de session . . . . . . . . . . . . . . . . 24-3
Utilisation du SQL transparent . . . . . . 24-35
Mise en cache des BLOBS . . . . . . . . . 24-4
Utilisation de transactions locales . . . . 24-35
Obtention d’un handle BDE. . . . . . . . 24-5
Utilisation du BDE pour placer
Utilisation de TTable. . . . . . . . . . . . . . 24-5
en mémoire cache les mises à jour . . . . . 24-36
Spécification du type d’une table locale . 24-6
Activation des mises à jour BDE
Contrôle d’accès en lecture/écriture
en mémoire cache . . . . . . . . . . . . . 24-38
aux tables locales . . . . . . . . . . . . . 24-6
Application des mises à jour BDE
Spécification d’un fichier d’index
en mémoire cache . . . . . . . . . . . . . 24-38
dBASE . . . . . . . . . . . . . . . . . . . 24-7
Application des mises à jour en mémoire
Renommer une table locale . . . . . . . . 24-8
cache avec une base de données. . . 24-40
Importation des données
Application des mises à jour en mémoire
d’une autre table . . . . . . . . . . . . . 24-8
cache avec les méthodes de composant
Utilisation de TQuery . . . . . . . . . . . . . 24-9
base de données . . . . . . . . . . . . 24-41
Création de requêtes hétérogènes . . . 24-10
Création d’un gestionnaire d’événement
Obtention d’un ensemble de résultats
OnUpdateRecord. . . . . . . . . . . . 24-41
modifiable . . . . . . . . . . . . . . . . 24-11
Gestion des erreurs de mise à jour
Mise à jour des ensembles de résultats
en mémoire cache . . . . . . . . . . . 24-43
en lecture seule . . . . . . . . . . . . . 24-12
Utilisation de TStoredProc . . . . . . . . . 24-13
xiv
Utilisation d’objets mise à jour pour mettre Utilisation des ensembles
à jour un ensemble de données . . . . . 24-45 d’enregistrements . . . . . . . . . . . .25-11
Création d’instructions SQL Filtrage d’enregistrements
pour les composants mise à jour . . . 24-46 à partir de signets . . . . . . . . . . . 25-12
Utilisation de plusieurs objets Lecture d’enregistrements
mise à jour . . . . . . . . . . . . . . . . 24-50 de façon asynchrone. . . . . . . . . . 25-13
Exécution des instructions SQL. . . . . 24-52 Utilisation des mises à jour groupées. 25-13
Utilisation de TBatchMove . . . . . . . . . . . 24-55 Lecture et enregistrement des données
Création d’un composant action groupée. 24-55 dans des fichiers . . . . . . . . . . . . 25-16
Spécification d’un mode d’action Utilisation de TADODataSet. . . . . . . . 25-17
groupée . . . . . . . . . . . . . . . . . . . 24-56 Utilisation d’objets commande . . . . . . . . 25-19
Ajout d’enregistrements . . . . . . . . . 24-57 Spécification de la commande . . . . . . . 25-19
Mise à jour d’enregistrements . . . . . 24-57 Utilisation de la méthode Execute . . . . 25-20
Ajout et mise à jour d’enregistrements 24-57 Annulation des commandes . . . . . . . . 25-20
Copie d’ensembles de données . . . . . 24-57 Récupération d’ensembles de résultats
Suppression d’enregistrements . . . . . 24-58 à l’aide de commandes . . . . . . . . . . 25-21
Mappage des types de données . . . . . . 24-58 Gestion des paramètres de commande. . 25-21
Exécution d’une action groupée . . . . . . 24-59
Gestion des erreurs relatives Chapitre 26
aux actions groupées. . . . . . . . . . . . 24-59 Utilisation d’ensembles de données
Dictionnaire de données . . . . . . . . . . . . 24-60
Outils de manipulation du BDE . . . . . . . . 24-62
unidirectionnels 26-1
Types d’ensembles de données
unidirectionnels . . . . . . . . . . . . . . . . . 26-2
Chapitre 25 Connexion au serveur de bases de données . 26-3
Utilisation des composants ADO 25-1 Configuration de TSQLConnection . . . . . 26-4
Présentation générale des composants ADO. . 25-2 Identification du pilote . . . . . . . . . . 26-4
Connexion à des stockages de données ADO . 25-3 Spécification des paramètres
Connexion à un stockage de données de connexion . . . . . . . . . . . . . . . 26-4
avec TADOConnection . . . . . . . . . . . 25-3 Dénomination d’une description
Accès à l’objet connexion . . . . . . . . . 25-5 de connexion . . . . . . . . . . . . . . . 26-5
Optimisation d’une connexion . . . . . . . . 25-5 Utilisation de l’éditeur de connexion . . 26-5
Connexions asynchrones . . . . . . . . . 25-5 Spécification des données à afficher . . . . . . 26-6
Contrôle des dépassements de délais . . 25-6 Représentation des résultats d’une requête 26-7
Indication des types d’opérations Représentation des enregistrements
pris en charge par la connexion . . . . 25-6 d’une table . . . . . . . . . . . . . . . . . . 26-7
Spécification de l’exécution automatique Représentation d’une table en utilisant
des transactions par la connexion . . . 25-7 TSQLDataSet . . . . . . . . . . . . . . . . 26-8
Accès aux commandes d’une connexion . . 25-8 Représentation d’une table
Evénements connexion ADO . . . . . . . . . 25-8 en utilisant TSQLTable . . . . . . . . . 26-8
Evénements se produisant pendant Représentation des résultats
l’établissement d’une connexion . . . . 25-8 d’une procédure stockée . . . . . . . . . . 26-8
Evénements se produisant pendant Récupération des données. . . . . . . . . . . . 26-9
la déconnexion . . . . . . . . . . . . . . 25-9 Préparation de l’ensemble de données . . . 26-9
Evénements se produisant pendant Récupération de plusieurs ensembles
la gestion des transactions. . . . . . . . 25-9 de données . . . . . . . . . . . . . . . . . 26-10
Autres événements . . . . . . . . . . . . . 25-9 Exécution des commandes ne renvoyant pas
Utilisation des ensembles de données ADO . . 25-9 d’enregistrement . . . . . . . . . . . . . . . 26-10
Connexion d’un ensemble de données ADO Spécification de la commande à exécuter .26-11
à un stockage de données . . . . . . 25-10 Exécution de la commande . . . . . . . . .26-11
xv
Création et modification des métadonnées Clonage d’un curseur d’ensemble
du serveur . . . . . . . . . . . . . . . . . . 26-12 de données client . . . . . . . . . . . 27-17
Définition de curseurs liés maître/détail . . . 26-13 Ajout d’informations d’application
Accès aux informations de schéma . . . . . . 26-13 aux données . . . . . . . . . . . . . . . . 27-18
Récupération de métadonnées dans un Utilisation d’un ensemble de données client
ensemble de données unidirectionnel . . 26-14 pour mettre en cache les mises à jour . . . 27-18
Lecture des données après l’utilisation Présentation de l’utilisation d’un cache
de l’ensemble de données pour les mises à jour . . . . . . . . . . . 27-19
pour des métadonnées . . . . . . . . . 26-15 Choix du type d’ensemble de données
Structure des ensembles pour les mises à jour en cache. . . . . . 27-21
de métadonnées. . . . . . . . . . . . . 26-15 Indication des enregistrements modifiés . 27-22
Débogage d’applications dbExpress. . . . . . 26-19 Mise à jour des enregistrements . . . . . 27-24
Utilisation de TSQLMonitor pour contrôler Application des mises à jour . . . . . . 27-24
les commandes SQL . . . . . . . . . . . . 26-19 Intervention pendant l’application
Utilisation d’un callback pour contrôler des mises à jour . . . . . . . . . . . . 27-25
les commandes SQL . . . . . . . . . . . . 26-20 Conciliation des erreurs
de mise à jour . . . . . . . . . . . . . 27-27
Chapitre 27 Utilisation d’un ensemble de données client
Utilisation avec un fournisseur. . . . . . . . . . . . . . 27-29
Spécification d’un fournisseur. . . . . . . 27-29
d’ensembles de données client 27-1 Extraction des données dans l’ensemble
Manipulation des données avec un ensemble
de données ou le document source . . . 27-31
de données client . . . . . . . . . . . . . . . . 27-2
Extractions incrémentales. . . . . . . . 27-31
Navigation parmi les données des ensembles
Extraction à la demande . . . . . . . . 27-32
de données client . . . . . . . . . . . . . . . 27-2
Obtention de paramètres de l’ensemble
Limitation des enregistrements affichés. . . 27-3
de données source. . . . . . . . . . . . . 27-32
Edition des données . . . . . . . . . . . . . . 27-6
Transmission de paramètres à l’ensemble
Annulation des modifications. . . . . . . 27-6
de données source. . . . . . . . . . . . . 27-33
Enregistrement des modifications . . . . 27-7
Envoi de paramètres de requête
Définition de contraintes pour les valeurs
ou de procédure stockée . . . . . . . 27-34
des données . . . . . . . . . . . . . . . . . . 27-8
Limitation des enregistrements
Spécification de contraintes
avec des paramètres . . . . . . . . . . 27-34
personnalisées . . . . . . . . . . . . . . . 27-8
Gestion des contraintes liées au serveur . 27-35
Tri et indexation . . . . . . . . . . . . . . . . 27-9
Rafraîchissement des enregistrements . . 27-36
Ajout d’un nouvel index . . . . . . . . 27-10
Communication avec des fournisseurs à l’aide
Suppression et permutation d’index . . 27-11
d’événements personnalisés . . . . . . . 27-37
Utilisation des index pour regrouper
Redéfinition de l’ensemble de données
les données . . . . . . . . . . . . . . . 27-11
source . . . . . . . . . . . . . . . . . . . . 27-38
Représentation des valeurs calculées . . . 27-12
Utilisation d’un ensemble de données client
Utilisation de champs calculés de façon
avec des données basées sur des fichiers . 27-39
interne dans les ensembles de données
Création d’un nouvel ensemble
client . . . . . . . . . . . . . . . . . . . 27-13
de données . . . . . . . . . . . . . . . . . 27-39
Utilisation des agrégats maintenus . . . . 27-13
Chargement des données depuis un fichier
Spécification d’agrégats . . . . . . . . . 27-14
ou un flux . . . . . . . . . . . . . . . . . 27-40
Agrégats de groupes
Fusion des modifications
d’enregistrements . . . . . . . . . . . . 27-15
dans les données . . . . . . . . . . . . . 27-41
Obtention de valeurs d’agrégat. . . . . 27-16
Sauvegarde des données dans un fichier
Copie de données d’un autre ensemble
ou un flux . . . . . . . . . . . . . . . . . 27-41
de données . . . . . . . . . . . . . . . . . 27-16
Affectation directe des données . . . . 27-16
xvi
Chapitre 28 Structure de l’application client . . . . . . . 29-5
Structure du serveur d’applications . . . . 29-5
Utilisation des composants Contenu du module de données
fournisseur 28-1 distant . . . . . . . . . . . . . . . . . . . 29-6
Spécification de la source de données . . . . . 28-2 Utilisation des modules de données
Utilisation d’un ensemble de données comme transactionnels . . . . . . . . . . . . . . 29-7
source des données. . . . . . . . . . . . . . 28-2 Regroupement des modules de données
Utilisation d’un document XML comme source distants . . . . . . . . . . . . . . . . . . 29-9
des données . . . . . . . . . . . . . . . . . . 28-3 Sélection d’un protocole de connexion . . 29-10
Communication avec l’ensemble de données Utilisation de connexions DCOM . . . 29-10
client . . . . . . . . . . . . . . . . . . . . . . . . 28-3 Utilisation de connexions Socket . . . .29-11
Détermination du mode d’application Utilisation de connexions Web . . . . .29-11
des mises à jour à l’aide d’un fournisseur Utilisation de connexions SOAP. . . . 29-12
d’ensemble de données . . . . . . . . . . . . . 28-4 Construction d’une application multiniveau 29-13
Contrôle des informations placées Création du serveur d’applications . . . . . 29-13
dans les paquets de données . . . . . . . . . . 28-5 Configuration du module de données
Spécification des champs apparaissant distant. . . . . . . . . . . . . . . . . . . . 29-15
dans les paquets de données . . . . . . . . 28-5 Configuration d’un module de données
Initialisation des options contrôlant distant non transactionnel . . . . . . 29-15
les paquets de données . . . . . . . . . . . 28-6 Configuration d’un module de données
Ajout d’informations personnalisées distant transactionnel . . . . . . . . . 29-16
aux paquets de données . . . . . . . . . . . 28-7 Configuration de TSoapDataModule . 29-18
Comment répondre aux demandes Extension de l’interface du serveur
de données des clients . . . . . . . . . . . . . 28-8 d’applications . . . . . . . . . . . . . . . 29-18
Comment répondre aux demandes Ajout de rappels à l’interface du serveur
de mise à jour des clients . . . . . . . . . . . . 28-9 d’applications. . . . . . . . . . . . . . 29-19
Modification des paquets delta avant Extension de l’interface d’un serveur
la mise à jour de la base de données . . 28-10 d’applications transactionnel . . . . . 29-19
Comment contrôler l’application Gestion des transactions
des mises à jour . . . . . . . . . . . . . . 28-11 dans les applications multiniveaux . . . 29-19
Filtrage des mises à jour . . . . . . . . . . 28-13 Gestion des relations maître / détail . . . 29-20
Résolution des erreurs de mise à jour Gestion des informations d’état
par le fournisseur . . . . . . . . . . . . . 28-13 dans les modules de données distants . 29-21
Application des mises à jour à des ensembles Utilisation de plusieurs modules
de données représentant plusieurs de données distants . . . . . . . . . . . . 29-23
tables . . . . . . . . . . . . . . . . . . . . . 28-14 Recensement du serveur d’applications . . . 29-24
Comment répondre aux événements Création de l’application client . . . . . . . . 29-24
générés par le client . . . . . . . . . . . . . . 28-14 Connexion au serveur d’applications. . . 29-25
Gestion des contraintes du serveur . . . . . . 28-15 Spécification d’une connexion
à l’aide de DCOM . . . . . . . . . . . 29-26
Chapitre 29 Spécification d’une connexion
Création d’applications à l’aide de sockets . . . . . . . . . . . 29-27
multiniveaux 29-1 Spécification d’une connexion
Avantages du modèle de base de données à l’aide de HTTP . . . . . . . . . . . . 29-28
multiniveau . . . . . . . . . . . . . . . . . . . . 29-2 Spécification d’une connexion
Présentation des applications multiniveaux à l’aide de SOAP. . . . . . . . . . . . 29-28
basées sur les fournisseurs . . . . . . . . . . . 29-3 Courtage de connexions . . . . . . . . 29-29
Présentation d’une application Gestion des connexions serveur. . . . . . 29-29
à niveau triple . . . . . . . . . . . . . . . . 29-4 Connexion au serveur. . . . . . . . . . 29-30
xvii
Fermeture ou changement Obtention du paquet de données résultant 30-8
de connexion serveur. . . . . . . . . . 29-30 Conversion de nœuds définis
Appel des interfaces serveur . . . . . . . . 29-31 par l’utilisateur . . . . . . . . . . . . . . . 30-8
Connexion à un serveur d’applications qui Utilisation d’un document XML comme source
utilise plusieurs modules de données . . 29-32 pour un fournisseur . . . . . . . . . . . . . . 30-9
Ecriture des applications client Web . . . . . 29-33 Utilisation d’un document XML comme client
Distribution d’une application client en tant d’un fournisseur . . . . . . . . . . . . . . . 30-10
que contrôle ActiveX. . . . . . . . . . . . 29-34 Lecture d’un document XML
Création d’une fiche active à partir d’un fournisseur . . . . . . . . . 30-10
pour l’application client . . . . . . . . 29-34 Application de mises à jour d’un document
Construction des applications Web XML à un fournisseur . . . . . . . . . . .30-11
avec InternetExpress . . . . . . . . . . . . 29-35
Construction d’une application Partie III
InternetExpress . . . . . . . . . . . . . . . 29-36 Ecriture d’applications Internet
Utilisation des bibliothèques javascript 29-37
Droits d’accès au serveur d’applications Chapitre 31
et à son lancement . . . . . . . . . . . 29-38
Utilisation d’un courtier XML . . . . . . . 29-38 Ecriture d’applications CORBA 31-1
Lecture des paquets de données XML 29-39 Vue générale d’une application CORBA. . . . 31-2
Application des mises à jour Stubs et squelettes. . . . . . . . . . . . . . . 31-2
à partir des paquets delta XML. . . . 29-40 Utilisation de Smart Agent . . . . . . . . . 31-3
Création des pages Web avec un générateur Activation d’applications serveur . . . . . . 31-4
de page InternetExpress . . . . . . . . . . 29-41 Liaison dynamique d’appels d’interfaces . 31-4
Utilisation de l’éditeur de pages Web . 29-42 Ecriture de serveurs CORBA . . . . . . . . . . 31-5
Définition des propriétés Définition d’interfaces d’objets . . . . . . . 31-5
des éléments Web . . . . . . . . . . . . 29-43 Utilisation de l’expert serveur CORBA . . 31-6
Personnalisation du modèle d’un générateur Génération de stubs et de squelettes
de page InternetExpress . . . . . . . . 29-44 à partir d’un fichier IDL . . . . . . . . . . 31-6
Utilisation de l’expert d’implémentation
Chapitre 30 d’objet CORBA . . . . . . . . . . . . . . . 31-7
Instanciation des objets CORBA . . . . . 31-8
Utilisation de XML dans les applications Utilisation du modèle de délégation . . 31-9
de bases de données 30-1 Visualisation et changement
Définition des transformations. . . . . . . . . . 30-1 des modifications . . . . . . . . . . . 31-10
Correspondance entre les nœuds XML Implémentation des objets CORBA. . . . 31-10
et les champs du paquet de données . . . 30-2 Protection contre les conflits de thread 31-12
Utilisation de XMLMapper . . . . . . . . . . 30-4 Modification des interfaces CORBA . . . 31-13
Chargement d’un schéma XML Recensement d’interfaces serveur. . . . . 31-13
ou d’un paquet de données . . . . . . . 30-5 Ecriture de clients CORBA . . . . . . . . . . 31-14
Définition des mappages . . . . . . . . . 30-5 Utilisation des stubs . . . . . . . . . . . . 31-15
Génération de fichiers Utilisation de l’interface d’appel
de transformation . . . . . . . . . . . . . 30-6 dynamique . . . . . . . . . . . . . . . . . 31-16
Conversion de documents XML en paquets Test des serveurs CORBA . . . . . . . . . . . 31-18
de données . . . . . . . . . . . . . . . . . . . . 30-7 Configuration de l’outil de test . . . . . . 31-18
Spécification du document XML source . . 30-7 Enregistrement et exécution
Spécification de la transformation . . . . . . 30-7 de scripts de test. . . . . . . . . . . . . . 31-19
xviii
Chapitre 32 Type de méthode de requête . . . . . . . 33-7
Activation et désactivation
Création d’applications serveur des éléments d’action . . . . . . . . . . 33-7
Internet 32-1 Choix d’un élément d’action par défaut 33-7
A propos de WebBroker et de WebSnap . . . . 32-1 Réponse aux messages de requête
Terminologie et normes . . . . . . . . . . . . . . 32-3 avec des éléments d’action . . . . . . . . . 33-8
Composition d’une URL Envoi de la réponse . . . . . . . . . . . . 33-9
(Uniform Resource Locator) . . . . . . . . 32-4 Utilisation de plusieurs éléments
URI et URL . . . . . . . . . . . . . . . . . 32-4 d’action . . . . . . . . . . . . . . . . . . 33-9
En-tête de message de requête HTTP . . . . 32-4 Accès aux informations de requêtes client . . 33-9
Activité d’un serveur HTTP . . . . . . . . . . . 32-5 Propriétés contenant des informations
Composition des requêtes client . . . . . . . 32-5 d’en-tête de requête . . . . . . . . . . . . . 33-9
Traitement des requêtes client Propriétés identifiant la destination. . 33-10
par le serveur . . . . . . . . . . . . . . . . . 32-6 Propriétés décrivant le client Web. . . 33-10
Réponses aux requêtes client . . . . . . . . . 32-6 Propriétés identifiant le but
Types d’applications serveur Web . . . . . . . . 32-7 de la requête . . . . . . . . . . . . . . 33-10
ISAPI et NSAPI . . . . . . . . . . . . . . . 32-7 Propriétés décrivant la réponse
CGI autonome . . . . . . . . . . . . . . . 32-7 attendue . . . . . . . . . . . . . . . . . .33-11
WinCGI autonome . . . . . . . . . . . . . 32-7 Propriétés décrivant le contenu . . . . .33-11
Apache . . . . . . . . . . . . . . . . . . . . 32-7 Contenu d’un message de requête HTTP .33-11
Débogueur d’application Web . . . . . . 32-8 Création de messages de réponse HTTP . . .33-11
Conversion des types cibles Informations d’en-tête de réponse . . . . 33-12
d’applications serveur Web . . . . . . . . . 32-9 Indication du statut de la réponse . . 33-12
Débogage d’applications serveur . . . . . . . 32-10 Indication d’attente d’une action
Utilisation du débogueur du client. . . . . . . . . . . . . . . . . 33-12
d’application Web . . . . . . . . . . . . . 32-10 Description de l’application serveur . 33-12
Démarrage de l’application Description du contenu . . . . . . . . . 33-13
avec le débogueur d’application Web 32-10 Définition du contenu de la réponse . . . 33-13
Conversion de votre application en un autre Envoi de la réponse. . . . . . . . . . . . . 33-13
type d’application serveur Web. . . . 32-11 Génération du contenu des messages
Débogage d’applications Web de réponse . . . . . . . . . . . . . . . . . . . 33-14
sous forme de DLL. . . . . . . . . . . . . 32-11 Utilisation du composant
Droits des utilisateurs nécessaires au générateur de page . . . . . . . . . . . . 33-14
débogage des DLL . . . . . . . . . . . 32-12 Modèles HTML . . . . . . . . . . . . . 33-14
Choix du modèle HTML . . . . . . . . 33-15
Chapitre 33 Conversion des balises HTML
Utilisation de l’agent Web 33-1 transparentes . . . . . . . . . . . . . . 33-16
Création d’applications serveur Web Utilisation du générateur de page
avec l’agent Web . . . . . . . . . . . . . . . . . 33-1 depuis un élément d’action. . . . . . 33-16
Module Web . . . . . . . . . . . . . . . . . . 33-2 Chaînage de générateurs de page . . . 33-17
Objet application Web . . . . . . . . . . . . . 33-3 Utilisation des bases de données
Structure d’une application agent Web . . . . . 33-3 dans les réponses . . . . . . . . . . . . . . . 33-18
Répartiteur Web . . . . . . . . . . . . . . . . . . 33-4 Ajout d’une session au module Web . . . 33-19
Ajout d’actions au répartiteur . . . . . . . . 33-5 Représentation HTML
Répartition des messages de requête . . . . 33-5 d’une base de données . . . . . . . . . . 33-19
Eléments d’action . . . . . . . . . . . . . . . . . 33-6 Utilisation des générateurs
Choix du déclenchement de page ensemble de données . . . . 33-19
des éléments d’action . . . . . . . . . . . . 33-6 Utilisation des générateurs de tableau 33-20
URL de destination. . . . . . . . . . . . . 33-6 Choix des attributs de tableau . . . . . 33-20
xix
Choix des attributs de lignes . . . . . . 33-21 Etape 3. Ajout d’un composant
Choix des attributs de colonnes . . . . 33-21 adaptateur . . . . . . . . . . . . . . . 34-16
Incorporation de tableaux Création d’une grille pour afficher
dans un document HTML . . . . . . . 33-21 les données . . . . . . . . . . . . . . . . . 34-17
Configuration d’un générateur Etape 1. Ajout d’une grille . . . . . . . 34-17
de tableau ensemble de données . . . 33-21 Etape 2. Ajout de commandes
Configuration d’un générateur de modification à la grille . . . . . . 34-19
de tableau requête . . . . . . . . . . . 33-22 Ajout d’une fiche de modification . . . . 34-20
Etape 1. Ajout d’un nouveau module
Chapitre 34 de page Web . . . . . . . . . . . . . . 34-20
Création d’applications serveur Web Etape 2. Enregistrement
du nouveau module . . . . . . . . . . 34-20
avec WebSnap 34-1 Etape 3. Mise à disposition
Composants WebSnap de base. . . . . . . . . . 34-2
de CountryTableU pour le nouveau
Modules Web . . . . . . . . . . . . . . . . . . 34-2
module . . . . . . . . . . . . . . . . . 34-20
Types de module d’application Web . . . 34-3
Etape 4. Ajout des champs de saisie . 34-20
Modules de page Web . . . . . . . . . . . 34-4
Etape 5. Ajout de boutons . . . . . . . 34-21
Modules de données Web . . . . . . . . . 34-5
Etape 6. Liaison entre les actions
Adaptateurs . . . . . . . . . . . . . . . . . . . 34-6
de la fiche et la page de la grille. . . 34-22
Champs . . . . . . . . . . . . . . . . . . . 34-6
Etape 7. Liaison des actions de grille
Actions . . . . . . . . . . . . . . . . . . . . 34-6
avec la page de la fiche . . . . . . . . 34-23
Erreurs . . . . . . . . . . . . . . . . . . . . 34-7
Exécution de l’application complète . . . 34-23
Enregistrements . . . . . . . . . . . . . . . 34-7
Ajout du compte-rendu des erreurs . . . 34-24
Générateurs de page . . . . . . . . . . . . . . 34-7
Etape 1. Ajout de la gestion des erreurs
Création d’applications serveur Web
à la grille . . . . . . . . . . . . . . . . 34-24
avec WebSnap . . . . . . . . . . . . . . . . . . 34-8
Etape 2. Ajout de la gestion des erreurs
Sélection d’un type de serveur . . . . . . . . 34-9
à la fiche . . . . . . . . . . . . . . . . 34-24
Spécification des composants du module
Etape 3. Test du mécanisme de gestion
d’application . . . . . . . . . . . . . . . . . 34-9
des erreurs . . . . . . . . . . . . . . . 34-24
Sélection des options du module
Conception HTML avancée . . . . . . . . . . 34-25
d’application Web . . . . . . . . . . . . . 34-11
Manipulation de script côté serveur
Didacticiel WebSnap. . . . . . . . . . . . . . . 34-12
dans des fichiers HTML . . . . . . . . . 34-26
Création d’une nouvelle application . . . 34-12
Prise en charge des ouvertures de session . 34-27
Etape 1. Démarrage de l’expert
Ajout d’une prise en charge
d’application WebSnap. . . . . . . . . 34-12
des ouvertures de session . . . . . . . . 34-28
Etape 2. Enregistrement
Utilisation du service de sessions . . . . . 34-29
des fichiers générés et du projet . . . 34-13
Pages de connexion . . . . . . . . . . . . . 34-30
Etape 3. Spécification du titre
Configuration des pages nécessitant
de l’application . . . . . . . . . . . . . 34-13
des connexions. . . . . . . . . . . . . . . 34-32
Création d’une page CountryTable . . . . 34-13
Droits d’accès utilisateur . . . . . . . . . . 34-32
Etape 1. Ajout d’un nouveau module
Affichage dynamique des champs sous la
de page Web. . . . . . . . . . . . . . . 34-14
forme de zones de saisie ou de texte 34-33
Etape 2. Enregistrement du nouveau
Masquage des champs
module de page Web . . . . . . . . . . 34-14
et de leur contenu . . . . . . . . . . . 34-34
Ajout des composants de données
Interdiction d’accès à la page . . . . . 34-34
au module CountryTable . . . . . . . . . 34-15
Utilisation de scripts côté serveur
Etape 1. Ajout des composants
avec WebSnap . . . . . . . . . . . . . . . . . 34-34
orientés données . . . . . . . . . . . . 34-15
Scripts actifs . . . . . . . . . . . . . . . . . 34-35
Etape 2. Spécification d’un champ clé . 34-16
Moteur de script. . . . . . . . . . . . . . . 34-36
xx
Blocs de script . . . . . . . . . . . . . . . . 34-36 Utilisation de l’expert
Création de scripts . . . . . . . . . . . . . . 34-36 d’application SOAP . . . . . . . . . . . . 36-12
Experts modèles . . . . . . . . . . . . . 34-36 Ajout de nouveaux services Web . . . . . 36-13
TAdapterPageProducer . . . . . . . . . 34-36 Modification du code généré. . . . . . 36-13
Modification et visualisation des scripts . 34-37 Utilisation d’une classe de base
Comment inclure un script différente . . . . . . . . . . . . . . . . 36-14
dans une page . . . . . . . . . . . . . . . 34-37 Utilisation de l’importateur
Objets de script . . . . . . . . . . . . . . . . 34-37 de services Web . . . . . . . . . . . . . . 36-15
Répartition des requêtes et des réponses . . . 34-38 Création de classes d’exception personnalisées
Composants répartiteur . . . . . . . . . . . 34-38 pour les services Web . . . . . . . . . . . 36-16
Fonctions d’un répartiteur d’adaptateur . 34-39 Génération de documents WSDL
Utilisation de composants d’adaptateur pour une application de service Web . . 36-17
pour générer du contenu . . . . . . . 34-39 Conception de clients pour les services Web 36-18
Réception de requêtes de l’adaptateur Importation de documents WSDL . . . . 36-18
et génération des réponses . . . . . . 34-40 Appel des interfaces invocables . . . . . . 36-18
Requête d’image . . . . . . . . . . . . . 34-42
Réponse d’image . . . . . . . . . . . . . 34-42 Chapitre 37
Répartition des éléments d’action . . . . . 34-43 Utilisation des sockets 37-1
Fonctions du répartiteur de page . . . . . 34-44 Implémentation des services . . . . . . . . . . 37-1
Description des protocoles de services . . . 37-2
Chapitre 35 Communication avec les applications . 37-2
Utilisation de documents XML 35-1 Services et ports . . . . . . . . . . . . . . . . 37-2
Utilisation du modèle DOM . . . . . . . . . . . 35-2 Types de connexions par socket . . . . . . . . 37-2
Utilisation des composants XML . . . . . . . . 35-3 Connexions client . . . . . . . . . . . . . . . 37-3
Utilisation de TXMLDocument. . . . . . . . 35-3 Connexions d’écoute . . . . . . . . . . . . . 37-3
Utilisation des nœuds XML. . . . . . . . . . 35-4 Connexions serveur . . . . . . . . . . . . . . 37-3
Utilisation de la valeur d’un nœud . . . 35-5 Description des sockets . . . . . . . . . . . . . 37-3
Utilisation des attributs d’un nœud . . . 35-5 Description des hôtes . . . . . . . . . . . . . 37-4
Ajout et suppression de nœuds enfant . 35-5 Choix entre le nom de l’hôte
Abstraction de documents XML et son adresse IP . . . . . . . . . . . . . 37-5
avec l’expert Liaison de données . . . . . . . 35-6 Utilisation des ports . . . . . . . . . . . . . 37-5
Utilisation de l’expert Utilisation des composants socket . . . . . . . 37-5
Liaison de données XML . . . . . . . . . . 35-8 Obtenir des informations sur la connexion 37-6
Utilisation du code généré par l’expert Utilisation de sockets client . . . . . . . . . 37-6
Liaison de données XML . . . . . . . . . . 35-9 Désignation du serveur souhaité . . . . 37-6
Formation de la connexion . . . . . . . . 37-7
Chapitre 36 Obtention d’informations
Utilisation de services Web 36-1 sur la connexion . . . . . . . . . . . . . 37-7
Présentation des interfaces invocables . . . . . 36-2 Fermeture de la connexion . . . . . . . . 37-7
Utilisation de types non scalaires Utilisation de sockets serveur . . . . . . . . 37-7
dans des interfaces invocables . . . . . . . 36-4 Désignation du port . . . . . . . . . . . . 37-7
Recensement des types non scalaires . . 36-5 Ecoute des requêtes client . . . . . . . . 37-8
Recensement des types typedef Connexion aux clients. . . . . . . . . . . 37-8
et des types énumérés . . . . . . . . . . 36-6 Fermeture des connexions serveur . . . 37-8
Emploi d’objets distants . . . . . . . . . . 36-8 Réponse aux événements socket . . . . . . . . 37-8
Exemple d’objet distant . . . . . . . . . . 36-9 Evénements d’erreurs. . . . . . . . . . . . . 37-9
Conception de serveurs Evénements client . . . . . . . . . . . . . . . 37-9
gérant les services Web . . . . . . . . . . . . 36-11 Evénements serveur . . . . . . . . . . . . . 37-9
Conception d’un serveur de service Web . 36-11 Evénements d’écoute . . . . . . . . . . . 37-9
xxi
Evénements de connexions client . . . 37-10 Chapitre 39
Lectures et écritures sur des connexions
socket . . . . . . . . . . . . . . . . . . . . . . 37-10
Utilisation
Connexions non bloquantes . . . . . . . . 37-10 des bibliothèques de types 39-1
Lecture et écriture d’événements . . . . 37-11 L’éditeur de bibliothèques de types . . . . . . 39-2
Connexions bloquantes . . . . . . . . . . . 37-11 Composants de l’éditeur
de bibliothèques de types . . . . . . . . . 39-3
Partie IV Barre d’outils . . . . . . . . . . . . . . . 39-4
Volet liste des objets. . . . . . . . . . . . 39-5
Développement d’applications COM Barre d’état . . . . . . . . . . . . . . . . . 39-6
Les pages d’informations de type . . . . 39-6
Chapitre 38 Eléments d’une bibliothèque de types . . . 39-9
Présentation Interfaces . . . . . . . . . . . . . . . . . . 39-9
des technologies COM 38-1 Dispinterfaces . . . . . . . . . . . . . . 39-10
COM, spécification et implémentation . 38-2 CoClasses . . . . . . . . . . . . . . . . . 39-10
Extensions de COM . . . . . . . . . . . . 38-2 Définitions de types . . . . . . . . . . . 39-10
Composantes d’une application COM . . . . . 38-3 Modules. . . . . . . . . . . . . . . . . . .39-11
Interfaces COM. . . . . . . . . . . . . . . . . 38-3 Utilisation de l’éditeur de bibliothèques
L’interface COM de base, IUnknown . . 38-4 de types. . . . . . . . . . . . . . . . . . . 39-12
Pointeurs d’interface COM . . . . . . . . 38-5 Types autorisés. . . . . . . . . . . . . . 39-13
Serveurs COM . . . . . . . . . . . . . . . . . 38-5 Création d’une nouvelle bibliothèque
CoClasses et fabricants de classes . . . . 38-6 de types . . . . . . . . . . . . . . . . . 39-14
Serveurs en processus, hors processus Ouverture d’une bibliothèque de types
et distants . . . . . . . . . . . . . . . . . 38-7 existante . . . . . . . . . . . . . . . . . 39-15
Le mécanisme du marshaling. . . . . . . 38-8 Ajout d’une interface à une bibliothèque
Agrégation. . . . . . . . . . . . . . . . . . 38-9 de types . . . . . . . . . . . . . . . . . 39-15
Clients COM . . . . . . . . . . . . . . . . . 38-10 Modification d’une interface en utilisant
Extensions de COM . . . . . . . . . . . . . . . 38-10 la bibliothèque de types . . . . . . . 39-15
Serveurs Automation . . . . . . . . . . . . 38-13 Ajout de propriétés et méthodes
Pages Active Server . . . . . . . . . . . . . 38-14 à une interface ou dispinterface . . . 39-16
Contrôles ActiveX . . . . . . . . . . . . . . 38-14 Ajout d’une CoClasse à une bibliothèque
Documents Active . . . . . . . . . . . . . . 38-15 de types . . . . . . . . . . . . . . . . . 39-17
Objets transactionnels . . . . . . . . . . . . 38-15 Ajout d’une interface à une CoClasse 39-18
Objets événement COM+ et souscripteurs Ajout d’une énumération à une bibliothèque
d’événement . . . . . . . . . . . . . . . . 38-16 de types . . . . . . . . . . . . . . . . . 39-18
Bibliothèques de types . . . . . . . . . . . 38-17 Ajout d’un alias à une bibliothèque
Contenu d’une bibliothèque de types . 38-17 de types . . . . . . . . . . . . . . . . . 39-18
Création de bibliothèques de types . . 38-18 Ajout d’un enregistrement ou d’une union
Quand utiliser les bibliothèques à une bibliothèque de types . . . . . 39-19
de types . . . . . . . . . . . . . . . . . 38-18 Ajout d’un module à une bibliothèque
Accès aux bibliothèques de types . . . 38-19 de types . . . . . . . . . . . . . . . . . 39-19
Avantages des bibliothèques de types . 38-19 Enregistrement et recensement
Utilisation des outils de bibliothèques des informations d’une bibliothèque
de types . . . . . . . . . . . . . . . . . 38-20 de types . . . . . . . . . . . . . . . . . 39-19
Implémentation des objets COM Enregistrement d’une bibliothèque
à l’aide d’experts . . . . . . . . . . . . . . . . 38-20 de types . . . . . . . . . . . . . . . . . 39-20
Code généré par les experts . . . . . . . . 38-23
xxii
Rafraîchissement de la bibliothèque Utilisation de l’expert objet COM . . . . . . . 41-3
de types . . . . . . . . . . . . . . . . . 39-20 Utilisation de l’expert objet Automation . . . 41-4
Recensement d’une bibliothèque Choix d’un modèle de thread . . . . . . . . 41-5
de types . . . . . . . . . . . . . . . . . 39-21 Ecriture d’un objet supportant
Exportation d’un fichier IDL . . . . . . 39-21 le modèle de thread libre . . . . . . . . 41-7
Déploiement des bibliothèques de types . . . 39-21 Ecriture d’un objet supportant
le modèle de thread apartment . . . . 41-8
Chapitre 40 Ecriture d’un objet supportant
Création de clients COM 40-1 le modèle de thread neutre . . . . . . . 41-8
Importation des informations Spécification des options ATL . . . . . . . . . 41-9
d’une bibliothèque de types . . . . . . . . . . 40-2 Définition de l’interface d’un objet COM . . 41-10
Utilisation de la boîte de dialogue Importation Ajout d’une propriété
de bibliothèque de types . . . . . . . . . . 40-3 à l’interface de l’objet . . . . . . . . . . . 41-10
Utilisation de la boîte de dialogue Ajout d’une méthode
Importation d’ActiveX . . . . . . . . . . . . 40-4 à l’interface de l’objet . . . . . . . . . . . .41-11
Code généré par l’importation des Exposition d’événements aux clients . . . .41-11
informations d’une bibliothèque de types 40-5 Gestion des événements
Contrôle d’un objet importé . . . . . . . . . . . 40-7 dans un objet Automation . . . . . . 41-12
Utilisation des composants enveloppe . . . 40-7 Interfaces d’Automation . . . . . . . . . . . . 41-13
Enveloppes ActiveX . . . . . . . . . . . . 40-8 Interfaces doubles . . . . . . . . . . . . . . 41-13
Enveloppes des serveurs Automation . . 40-8 Interfaces de répartition . . . . . . . . . . 41-14
Utilisation de contrôles ActiveX Interfaces personnalisées . . . . . . . . . . 41-15
orientés données . . . . . . . . . . . . . . . 40-9 Marshaling des données . . . . . . . . . . . . 41-15
Exemple : impression d’un document Types compatibles avec l’Automation . . 41-16
avec Microsoft Word . . . . . . . . . . . . 40-11 Restrictions de type
Etape 1 : préparation de C++Builder pour le marshaling automatique . . . . 41-16
pour cet exemple . . . . . . . . . . . . 40-11 Marshaling personnalisé . . . . . . . . . . 41-17
Etape 2 : importation de la bibliothèque Recensement d’un objet COM . . . . . . . . 41-17
de types Word. . . . . . . . . . . . . . 40-12 Recensement d’un serveur en processus . 41-17
Etape 3 : utilisation d’un objet interface Recensement d’un serveur
VTable ou de répartition hors processus . . . . . . . . . . . . . . . 41-18
pour contrôler Microsoft Word . . . . 40-12 Test et débogage de l’application . . . . . . . 41-18
Etape 4 : nettoyage de l’exemple . . . . 40-13
Ecriture de code client basé sur les définitions Chapitre 42
de la bibliothèque de types . . . . . . . . 40-14 Création d’une page Active Server 42-1
Connexion à un serveur . . . . . . . . . 40-14 Création d’un objet Active Server . . . . . . . 42-2
Contrôle d’un serveur Automation Utilisation des éléments intrinsèques ASP. 42-3
en utilisant une interface double . . . 40-14 Application . . . . . . . . . . . . . . . . . 42-4
Contrôle d’un serveur Automation en Request . . . . . . . . . . . . . . . . . . . 42-4
utilisant une interface de répartition . 40-15 Response . . . . . . . . . . . . . . . . . . 42-5
Gestion des événements Session . . . . . . . . . . . . . . . . . . . 42-6
dans un contrôleur Automation . . . 40-16 Server . . . . . . . . . . . . . . . . . . . . 42-7
Création de clients pour les serveurs Création d’ASP pour des serveurs
n’ayant pas une bibliothèque de types . . . 40-18 en et hors processus. . . . . . . . . . . . . 42-7
Recensement d’un objet Active Server. . . . . 42-8
Chapitre 41 Recensement d’un serveur en processus . . 42-8
Création de serveurs COM simples 41-1 Recensement d’un serveur hors processus 42-9
Présentation de la création d’un objet COM . . 41-2 Test et débogage d’une application ASP . . . 42-9
Conception d’un objet COM . . . . . . . . . . . 41-2
xxiii
Chapitre 43 Regroupement des ressources . . . . . . . . 44-6
Fournisseurs de ressources
Création d’un contrôle ActiveX 43-1 base de données . . . . . . . . . . . . . 44-6
Présentation de la création
Gestionnaire de propriétés partagées . . 44-7
d’un contrôle ActiveX . . . . . . . . . . . . . . 43-2
Libération des ressources . . . . . . . . 44-10
Eléments d’un contrôle ActiveX . . . . . . . 43-3
Regroupement d’objets . . . . . . . . . . . 44-10
Contrôle VCL . . . . . . . . . . . . . . . . 43-3
Support transactionnel MTS et COM+. . . . .44-11
Enveloppe ActiveX . . . . . . . . . . . . . 43-3
Attributs transactionnels . . . . . . . . . . 44-12
Bibliothèque de types . . . . . . . . . . . 43-3
Initialisation de l’attribut
Page de propriétés . . . . . . . . . . . . . 43-4
transactionnel. . . . . . . . . . . . . . 44-13
Conception d’un contrôle ActiveX . . . . . . . 43-4
Objets avec état et sans état . . . . . . . . 44-13
Génération d’un contrôle ActiveX
Contrôle de l’arrêt des transactions. . . . 44-14
à partir d’un contrôle VCL . . . . . . . . . . . 43-4
Démarrage des transactions . . . . . . . . 44-14
Génération d’un contrôle ActiveX
Définition d’un objet transaction
basé sur une fiche VCL . . . . . . . . . . . . . 43-6
côté client . . . . . . . . . . . . . . . . 44-15
Licences des contrôles ActiveX . . . . . . . . . 43-8
Définition d’un objet transaction
Personnalisation de l’interface
côté serveur. . . . . . . . . . . . . . . 44-16
du contrôle ActiveX . . . . . . . . . . . . . . . 43-9
Délais des transactions . . . . . . . . . . . 44-17
Ajout de propriétés, méthodes
Sécurité en fonction des rôles . . . . . . . . . 44-17
et événements supplémentaires . . . . . 43-10
Présentation de la création
Ajout de propriétés et de méthodes . . 43-10
des objets transactionnels . . . . . . . . . . 44-18
Ajout d’événement . . . . . . . . . . . . 43-12
Utilisation de l’expert objet transactionnel . 44-19
Activation de la liaison de données simple
Choix d’un modèle de thread
avec la bibliothèque de types . . . . . . . 43-12
pour un objet transactionnel . . . . . . . 44-20
Création d’une page de propriétés
Activités. . . . . . . . . . . . . . . . . . 44-21
pour un contrôle ActiveX . . . . . . . . . . . 43-14
Génération d’événements dans COM+ . . . 44-22
Création d’une nouvelle page
Utilisation de l’expert objet événement . 44-24
de propriétés . . . . . . . . . . . . . . . . 43-15
Utilisation de l’expert Objet Abonnement
Ajout de contrôles à une page
d’événement COM+. . . . . . . . . . . . 44-25
de propriétés . . . . . . . . . . . . . . . . 43-15
Déclenchement d’événement en utilisant
Association des contrôles
un objet événement COM+ . . . . . . . 44-26
de la page de propriétés
Transfert de références d’objets . . . . . . . . 44-27
aux propriétés du contrôle ActiveX . . . 43-15
Utilisation de la méthode SafeRef . . . 44-27
Actualisation de la page de propriétés 43-16
Callbacks . . . . . . . . . . . . . . . . . 44-28
Actualisation de l’objet . . . . . . . . . 43-16
Débogage et test des objets transactionnels . 44-28
Connexion d’une page de propriétés
Installation d’objets transactionnels . . . . . 44-29
à un contrôle ActiveX . . . . . . . . . . . 43-16
Administration d’objets transactionnels . . . 44-30
Recensement d’un contrôle ActiveX . . . . . 43-17
Test d’un contrôle ActiveX . . . . . . . . . . . 43-17
Déploiement d’un contrôle ActiveX
Partie V
sur le Web. . . . . . . . . . . . . . . . . . . . 43-18 Création de composants
Paramétrage des options . . . . . . . . . . 43-19 personnalisés
Chapitre 44 Chapitre 45
Création d’objets MTS ou COM+ 44-1 Présentation générale
Principe des objets transactionnels . . . . . . . 44-2
Contraintes d’un objet transactionnel . . . . 44-3 de la création d’un composant 45-1
Gestion des ressources . . . . . . . . . . . . . . 44-4 Bibliothèques de classes . . . . . . . . . . . . . 45-1
Accès au contexte d’un objet . . . . . . . . . 44-4 Composants et classes . . . . . . . . . . . . . . 45-2
Activation juste-à-temps . . . . . . . . . . . 44-5 Comment créer un composant ? . . . . . . . . 45-3
xxiv
Modification de contrôles existants . . . . . 45-3 Définition de l’interface d’exécution . . . . 46-7
Création de contrôles fenêtrés . . . . . . . . 45-4 Définition de l’interface de conception. . . 46-8
Création de contrôles graphiques . . . . . . 45-4 Répartition des méthodes . . . . . . . . . . . . 46-9
Sous-classement de contrôles Windows. . . 45-5 Méthodes standard . . . . . . . . . . . . . . 46-9
Création de composants non visuels . . . . 45-5 Méthodes virtuelles . . . . . . . . . . . . . 46-10
Contenu d’un composant ? . . . . . . . . . . . . 45-5 Surcharge des méthodes . . . . . . . . 46-10
Suppression des dépendances . . . . . . . . 45-6 Membres abstraits d’une classe . . . . . . . . .46-11
Définition des propriétés, méthodes Classes et pointeurs . . . . . . . . . . . . . . .46-11
et événements. . . . . . . . . . . . . . . . . 45-6
Propriétés . . . . . . . . . . . . . . . . . . 45-6 Chapitre 47
Evénements . . . . . . . . . . . . . . . . . 45-7 Création de propriétés 47-1
Méthodes . . . . . . . . . . . . . . . . . . 45-7 Pourquoi créer des propriétés ? . . . . . . . . . 47-1
Encapsulation des graphiques . . . . . . . . 45-8 Types de propriétés. . . . . . . . . . . . . . . . 47-2
Recensement des composants . . . . . . . . 45-9 Publication des propriétés héritées . . . . . . . 47-3
Création d’un nouveau composant . . . . . . . 45-9 Définition des propriétés . . . . . . . . . . . . 47-4
Création d’un composant Déclaration des propriétés . . . . . . . . . . 47-4
avec l’expert composant . . . . . . . . . . 45-10 Stockage interne des données . . . . . . . . 47-4
Création manuelle d’un composant . . . . 45-12 Accès direct . . . . . . . . . . . . . . . . . . 47-5
Création d’un fichier unité . . . . . . . 45-13 Méthodes d’accès . . . . . . . . . . . . . . . 47-5
Dérivation du composant . . . . . . . . 45-13 Méthode read . . . . . . . . . . . . . . . 47-7
Déclaration d’un nouveau Méthode write . . . . . . . . . . . . . . . 47-7
constructeur . . . . . . . . . . . . . . . 45-14 Valeurs par défaut d’une propriété . . . . . 47-8
Recensement du composant. . . . . . . 45-14 Spécification d’aucune
Création de bitmaps pour les composants 45-16 valeur par défaut . . . . . . . . . . . . 47-8
Test des composants non installés. . . . . . . 45-17 Création de propriétés tableau . . . . . . . . . 47-9
Test des composants installés . . . . . . . . . 45-19 Création de propriétés
Installation d’un composant pour les sous-composants . . . . . . . . . . 47-10
dans la palette de composants . . . . . . . . 45-20 Stockage et chargement des propriétés . . . .47-11
Emplacement des fichiers du composant . 45-20 Utilisation du mécanisme de stockage
Ajout du composant . . . . . . . . . . . . . 45-21 et de chargement . . . . . . . . . . . . . 47-12
Spécification des valeurs par défaut . . . 47-12
Chapitre 46 Détermination du stockage . . . . . . . . 47-13
Programmation orientée objet Initialisation après chargement . . . . . . 47-14
et écriture des composants 46-1 Stockage et chargement des propriétés
Définition de nouvelles classes . . . . . . . . . 46-1 non publiées . . . . . . . . . . . . . . . . 47-14
Dérivation de nouvelles classes . . . . . . . 46-2 Création de méthodes pour le stockage et le
Modifier les valeurs par défaut chargement de valeurs de propriétés 47-15
d’une classe pour éviter Redéfinition de la méthode
les répétitions . . . . . . . . . . . . . . . 46-2 DefineProperties . . . . . . . . . . . . 47-15
Ajout de nouvelles capacités
à une classe . . . . . . . . . . . . . . . . 46-3 Chapitre 48
Déclaration d’une nouvelle classe Création d’événements 48-1
de composant . . . . . . . . . . . . . . . . . 46-3 Qu’est-ce qu’un événement ? . . . . . . . . . . 48-1
Ancêtres, descendants et hiérarchies Les événements sont des closures . . . . . 48-2
des classes. . . . . . . . . . . . . . . . . . . . . 46-4 Les événements sont des propriétés . . . . 48-2
Contrôle des accès . . . . . . . . . . . . . . . . . 46-4 Les types d’événements
Masquer les détails d’implémentation . . . 46-5 sont des types de closures . . . . . . . . . 48-3
Définition de l’interface avec le concepteur Le type de renvoi des gestionnaires
des composants . . . . . . . . . . . . . . . . 46-7 d’événements est void . . . . . . . . . 48-3
xxv
Les gestionnaires d’événements Spécification d’une palette
sont facultatifs . . . . . . . . . . . . . . . . 48-4 pour un contrôle . . . . . . . . . . . . . 50-6
Implémentation des événements standard . . . 48-4 Réponse aux changements de palette. . 50-6
Identification des événements standard. . . 48-5 Bitmaps hors écran . . . . . . . . . . . . . . . . 50-6
Evénements standard Création et gestion des bitmaps hors écran 50-7
pour tous les contrôles . . . . . . . . . . 48-5 Copie des images bitmap . . . . . . . . . . 50-7
Evénements standard Réponse aux changements . . . . . . . . . . . 50-7
pour les contrôles standard . . . . . . . 48-5
Rendre visibles des événements . . . . . . . 48-5 Chapitre 51
Changement de la gestion Gestion des messages
des événements standard . . . . . . . . . . 48-6
Définition de vos propres événements . . . . . 48-7
et des notifications système 51-1
Compréhension du système
Déclenchement de l’événement . . . . . . . 48-7
de gestion des messages . . . . . . . . . . . . 51-1
Deux sortes d’événements. . . . . . . . . 48-7
Que contient un message Windows ? . . . 51-2
Définition du type de gestionnaire . . . . . 48-8
Répartition des messages . . . . . . . . . . 51-3
Notifications simples . . . . . . . . . . . . 48-8
Suivi du flux des messages . . . . . . . 51-3
Gestionnaires d’événements spécifiques. 48-8
Modification de la gestion des messages . . . 51-4
Renvoi d’informations
Surcharge de la méthode du gestionnaire . 51-4
à partir du gestionnaire . . . . . . . . . 48-8
Utilisation des paramètres d’un message . 51-5
Déclaration de l’événement . . . . . . . . . . 48-9
Interception des messages . . . . . . . . . . 51-5
Les noms d’événement débutent
Création de nouveaux gestionnaires
par “On” . . . . . . . . . . . . . . . . . . 48-9
de messages . . . . . . . . . . . . . . . . . . . 51-6
Appel de l’événement . . . . . . . . . . . . . 48-9
Définition de vos propres messages . . . . 51-6
Les gestionnaires vides
Déclaration d’un identificateur
doivent être valides. . . . . . . . . . . . 48-9
de message . . . . . . . . . . . . . . . . 51-6
Les utilisateurs peuvent surcharger
Déclaration d’un type
la gestion par défaut . . . . . . . . . . 48-10
structure de message . . . . . . . . . . 51-7
Déclaration d’une nouvelle méthode
Chapitre 49 de gestion d’un message . . . . . . . . . . 51-8
Création de méthodes 49-1 Envoi des messages . . . . . . . . . . . . . . 51-8
Eviter les interdépendances . . . . . . . . . . . 49-1 Diffusion d’un message
Noms des méthodes. . . . . . . . . . . . . . . . 49-2 à tous les contrôles d’une fiche . . . . 51-9
Protection des méthodes . . . . . . . . . . . . . 49-3 Appel direct du gestionnaire
Méthodes qui doivent être publiques . . . . 49-3 de message d’un contrôle. . . . . . . . 51-9
Méthodes qui doivent être protégées . . . . 49-3 Envoi d’un message à l’aide de la file
Rendre virtuelles des méthodes . . . . . . . . . 49-4 d’attente des messages Windows . . 51-10
Déclaration des méthodes . . . . . . . . . . . . 49-4 Envoi d’un message qui ne s’exécute pas
immédiatement. . . . . . . . . . . . . 51-10
Chapitre 50 Réponse aux notifications du système
Graphiques et composants 50-1 à l’aide de CLX . . . . . . . . . . . . . . . . .51-11
Présentation des graphiques . . . . . . . . . . . 50-1 Réponse aux signaux . . . . . . . . . . . . .51-11
Utilisation du canevas . . . . . . . . . . . . . . 50-3 Affectation de gestionnaires
Travail sur les images . . . . . . . . . . . . . . . 50-3 de signaux personnalisés . . . . . . . 51-12
Utilisation d’une image, d’un graphique Réponse aux événements système . . . . 51-13
ou d’un canevas . . . . . . . . . . . . . . . 50-4 Evénements couramment utilisés . . . 51-14
Chargement et stockage des graphiques . . 50-4 Surcharge de la méthode EventFilter . 51-15
Gestion des palettes . . . . . . . . . . . . . . 50-5 Génération des événements Qt . . . . 51-16
xxvi
Chapitre 52 Chapitre 53
Accessibilité des composants Modification
au moment de la conception 52-1 d’un composant existant 53-1
Recensement des composants . . . . . . . . . . 52-1 Création et recensement du composant . . . . 53-1
Déclaration de la fonction Register . . . . . 52-2 Modification de la classe composant. . . . . . 53-3
Ecriture de la fonctionRegister . . . . . . . . 52-2 Surcharge du constructeur . . . . . . . . . . 53-3
Spécification des composants . . . . . . . 52-2 Spécification de la nouvelle valeur
Spécification de la page de palette . . . . 52-3 par défaut de la propriété . . . . . . . . . 53-4
Utilisation de la fonction
RegisterComponents . . . . . . . . . . . 52-3 Chapitre 54
Ajout de bitmaps à la palette . . . . . . . . . . 52-4 Création d’un contrôle graphique 54-1
Fournir l’aide pour vos composants . . . . . . 52-5 Création et recensement du composant . . . . 54-1
Création du fichier d’aide. . . . . . . . . . . 52-5 Publication des propriétés héritées . . . . . . . 54-3
Création des entrées . . . . . . . . . . . . 52-5 Ajout de fonctionnalités graphiques . . . . . . 54-3
Aide contextuelle des composants . . . . 52-7 Détermination de ce qui doit être dessiné . 54-4
Ajout des fichiers d’aide Déclaration du type de la propriété. . . 54-4
des composants . . . . . . . . . . . . . . 52-7 Déclaration de la propriété . . . . . . . . 54-4
Ajout d’éditeurs de propriétés . . . . . . . . . . 52-8 Ecriture de la méthode
Dérivation d’une classe d’implémentation . . . . . . . . . . . . 54-5
éditeur de propriétés. . . . . . . . . . . . . 52-8 Surcharge du constructeur
Modification de la propriété et du destructeur . . . . . . . . . . . . . . 54-5
sous une forme textuelle . . . . . . . . . . 52-9 Modification des valeurs par défaut
Affichage de la valeur de la propriété . 52-10 des propriétés . . . . . . . . . . . . . . 54-5
Définition de la valeur de la propriété 52-10 Publication du crayon et du pinceau . . . . 54-6
Modification globale de la propriété . . . 52-10 Déclaration des données membres . . . 54-6
Spécification des attributs de l’éditeur . . 52-11 Déclaration des propriétés d’accès . . . 54-7
Recensement de l’éditeur de propriétés. . 52-12 Initialisation des classes
Catégories de propriété . . . . . . . . . . . . . 52-13 ayant un propriétaire . . . . . . . . . . 54-8
Recensement d’une propriété à la fois . . 52-14 Définition des propriétés des classes
Recensement de plusieurs propriétés ayant un propriétaire . . . . . . . . . . 54-8
en une seule fois . . . . . . . . . . . . . . 52-14 Dessin de l’image du composant . . . . . . 54-9
Spécification de catégories de propriétés . 52-15 Adaptation du dessin de la forme . . . . 54-10
Utilisation de la fonction
IsPropertyInCategory . . . . . . . . . . . 52-16 Chapitre 55
Ajout d’éditeurs de composants . . . . . . . . 52-17 Personnalisation d’une grille 55-1
Ajout d’éléments au menu contextuel. . . 52-17 Création et recensement du composant . . . . 55-1
Spécification d’éléments de menu . . . 52-17 Publication des propriétés héritées . . . . . . . 55-3
Implémentation des commandes . . . . 52-18 Modification des valeurs initiales . . . . . . . 55-4
Modification du comportement suite Redimensionnement des cellules . . . . . . . . 55-5
à un double-clic. . . . . . . . . . . . . . . 52-18 Remplissage des cellules. . . . . . . . . . . . . 55-6
Ajout de formats de Presse-papiers . . . . 52-19 Suivi de la date . . . . . . . . . . . . . . . . 55-6
Recensement d’un éditeur de composants 52-20 Stockage interne de la date. . . . . . . . 55-7
Compilation des composants en paquets. . . 52-20 Accès au jour, au mois et à l’année . . . 55-8
Problèmes d’installation Génération des numéros de jours . . . . 55-9
de composants personnalisés. . . . . . . . . 52-21 Sélection du jour en cours . . . . . . . .55-11
Navigation de mois en mois
et d’année en année . . . . . . . . . . . . . 55-12
xxvii
Navigation de jour en jour . . . . . . . . . . . 55-13 Chapitre 58
Déplacement de la sélection . . . . . . . . 55-13
Fourniture d’un événement OnChange . . 55-13
Extensions de l’EDI 58-1
Présentation de l’API Tools . . . . . . . . . . . 58-2
Exclusion des cellules vides . . . . . . . . 55-14
Conception d’une classe expert . . . . . . . . . 58-3
Implémentation des interfaces de l’expert . 58-4
Chapitre 56 Simplification de l’implémentation
Contrôles orientés données 56-1 d’interfaces . . . . . . . . . . . . . . . . . . 58-6
Création d’un contrôle Installation du paquet de l’expert. . . . . . 58-7
pour scruter les données . . . . . . . . . . . . 56-2 Accès aux services de l’API Tools . . . . . . . 58-8
Création et recensement du composant . . . 56-2 Utilisation d’objets natifs de l’EDI . . . . . 58-9
Fonctionnement du contrôle Utilisation de l’interface INTAServices . 58-9
en lecture seulement . . . . . . . . . . . . . 56-3 Ajout d’une image à la liste d’images . 58-9
Ajout de la propriété ReadOnly . . . . . 56-3 Ajout d’une action à la liste d’actions 58-10
Autorisation des mises à jour Suppression de boutons
nécessaires . . . . . . . . . . . . . . . . . 56-4 de barres d’outils . . . . . . . . . . . .58-11
Ajout du lien aux données . . . . . . . . . . 56-5 Débogage d’un expert . . . . . . . . . . . 58-12
Déclaration de la donnée membre . . . . 56-6 Numéros de version de l’interface . . . . 58-12
Déclaration des propriétés d’accès . . . . 56-6 Utilisation des fichiers et des éditeurs . . . . 58-13
Exemple de déclaration Utilisation des interfaces de module . . . 58-14
des propriétés d’accès . . . . . . . . . . 56-6 Utilisation des interfaces d’éditeur . . . . 58-14
Initialisation du lien de données . . . . . 56-7 Création de fiches et de projets . . . . . . . . 58-15
Réponse aux changements de données . . . 56-8 Création de modules . . . . . . . . . . . . 58-15
Création d’un contrôle de modification Notification d’un expert
de données . . . . . . . . . . . . . . . . . . . . 56-9 des événements de l’EDI. . . . . . . . . . . 58-19
Modification de la valeur par défaut Installation d’une DLL expert. . . . . . . . . 58-23
de FReadOnly. . . . . . . . . . . . . . . . . 56-9 Utilisation d’une DLL
Gestion des messages liés à la souris sans paquets d’exécution . . . . . . . . . 58-25
ou au clavier . . . . . . . . . . . . . . . . . 56-9
Réponse aux messages indiquant Annexe A
la manipulation de la souris. . . . . . 56-10 Implémentations spécifiques
Réponse aux messages indiquant
la manipulation du clavier . . . . . . 56-11 de la norme ANSI A-1
Mise à jour de la classe lien de données
sur un champ . . . . . . . . . . . . . . . . 56-12
Annexe B
Modification de la méthode Change . . . 56-12 Référence de scripts
Mise à jour de l’ensemble de données . . 56-13 côté serveur WebSnap B-1
Types d’objets . . . . . . . . . . . . . . . . . . . . B-2
Chapitre 57 Type Adapter . . . . . . . . . . . . . . . . . . B-2
Transformation d’une boîte Propriétés . . . . . . . . . . . . . . . . . . . B-3
de dialogue en composant 57-1 Type AdapterAction . . . . . . . . . . . . . . B-4
Propriétés . . . . . . . . . . . . . . . . . . . B-5
Définition de l’interface du composant . . . . . 57-2
Méthodes . . . . . . . . . . . . . . . . . . . B-6
Création et recensement du composant . . . . 57-2
Type AdapterErrors . . . . . . . . . . . . . . . B-6
Création de l’interface du composant. . . . . . 57-3
Propriétés . . . . . . . . . . . . . . . . . . . B-6
Inclusion des fichiers de l’unité de la fiche. 57-4
Type AdapterField . . . . . . . . . . . . . . . B-7
Ajout des propriétés de l’interface . . . . . . 57-4
Propriétés . . . . . . . . . . . . . . . . . . . B-7
Ajout de la méthode Execute . . . . . . . . . 57-5
Méthodes . . . . . . . . . . . . . . . . . . B-10
Test du composant. . . . . . . . . . . . . . . . . 57-7
Type AdapterFieldValues . . . . . . . . . . B-10
Propriétés . . . . . . . . . . . . . . . . . . B-10
xxviii
Méthodes . . . . . . . . . . . . . . . . . .B-11 Propriétés . . . . . . . . . . . . . . . . . . B-19
Type AdapterFieldValuesList . . . . . . . . .B-11 Méthodes . . . . . . . . . . . . . . . . . . B-19
Propriétés . . . . . . . . . . . . . . . . . .B-11 Objet Session. . . . . . . . . . . . . . . . . . B-19
Méthodes . . . . . . . . . . . . . . . . . .B-12 Propriétés . . . . . . . . . . . . . . . . . . B-19
Type AdapterHiddenFields . . . . . . . . . .B-12 Exemples JScript . . . . . . . . . . . . . . . . . B-20
Propriétés . . . . . . . . . . . . . . . . . .B-12 Exemple 1 . . . . . . . . . . . . . . . . . . . B-21
Méthodes . . . . . . . . . . . . . . . . . .B-12 Exemple 2 . . . . . . . . . . . . . . . . . . . B-21
Type AdapterImage . . . . . . . . . . . . . .B-12 Exemple 3 . . . . . . . . . . . . . . . . . . . B-22
Propriétés . . . . . . . . . . . . . . . . . .B-12 Exemple 4 . . . . . . . . . . . . . . . . . . . B-22
Type Module . . . . . . . . . . . . . . . . . .B-13 Exemple 5 . . . . . . . . . . . . . . . . . . . B-22
Propriétés . . . . . . . . . . . . . . . . . .B-13 Exemple 6 . . . . . . . . . . . . . . . . . . . B-23
Type Page . . . . . . . . . . . . . . . . . . . .B-13 Exemple 7 . . . . . . . . . . . . . . . . . . . B-23
Propriétés . . . . . . . . . . . . . . . . . .B-13 Exemple 8 . . . . . . . . . . . . . . . . . . . B-24
Objets globaux . . . . . . . . . . . . . . . . . . .B-14 Exemple 9 . . . . . . . . . . . . . . . . . . . B-24
Objet Application . . . . . . . . . . . . . . .B-15 Exemple 10 . . . . . . . . . . . . . . . . . . . B-25
Propriétés . . . . . . . . . . . . . . . . . .B-15 Exemple 11 . . . . . . . . . . . . . . . . . . . B-27
Méthodes . . . . . . . . . . . . . . . . . .B-16 Exemple 12 . . . . . . . . . . . . . . . . . . . B-28
Objet EndUser . . . . . . . . . . . . . . . . .B-16 Exemple 13 . . . . . . . . . . . . . . . . . . . B-29
Propriétés . . . . . . . . . . . . . . . . . .B-16 Exemple 14 . . . . . . . . . . . . . . . . . . . B-30
Objet Modules . . . . . . . . . . . . . . . . .B-17 Exemple 15 . . . . . . . . . . . . . . . . . . . B-32
Objet page. . . . . . . . . . . . . . . . . . . .B-17 Exemple 16 . . . . . . . . . . . . . . . . . . . B-33
Objet pages . . . . . . . . . . . . . . . . . . .B-17 Exemple 17 . . . . . . . . . . . . . . . . . . . B-34
Objet Producer . . . . . . . . . . . . . . . . .B-17 Exemple 18 . . . . . . . . . . . . . . . . . . . B-35
Propriétés . . . . . . . . . . . . . . . . . .B-18 Exemple 19 . . . . . . . . . . . . . . . . . . . B-36
Méthodes . . . . . . . . . . . . . . . . . .B-18 Exemple 20 . . . . . . . . . . . . . . . . . . . B-36
Objet Request . . . . . . . . . . . . . . . . . .B-18 Exemple 21 . . . . . . . . . . . . . . . . . . . B-37
Propriétés . . . . . . . . . . . . . . . . . .B-18 Exemple 22 . . . . . . . . . . . . . . . . . . . B-38
Objet Response . . . . . . . . . . . . . . . . .B-19
xxix
xxx
Chapitre
1
Introduction
Chapitre 1
Contenu de ce manuel
Ce manuel est composé des cinq parties suivantes :
• La partie I, “Programmation C++Builder”, décrit la manière de concevoir des
applications C++Builder généralistes. Cette partie donne des détails sur les
techniques de programmation utilisables dans toute application C++Builder.
Elle décrit, par exemple, la manière d’utiliser les objets courants de la
bibliothèque de composants visuels (VCL) ou de la bibliothèque de
composants Borland multiplate-forme (CLX) qui simplifient le développement
de l’interface utilisateur : gestion des chaînes, manipulation du texte,
implémentation des dialogues communs, manipulation des graphiques, gestion
des erreurs et des exceptions, utilisation des DLL, automation OLE et écriture
d’applications internationales.
En général, il est rarement important que la VCL de C++Builder soit écrite en
Pascal Objet. Mais, dans un petit nombre de cas, cela peut affecter vos
programmes C++Builder. Un chapitre concernant le langage C++ et la VCL
Introduction 1-1
Contenu de ce manuel
Conventions typographiques
Ce manuel utilise les polices et les symboles décrits dans le tableau suivant pour
mettre en évidence des parties particulières du texte :
Support technique
Borland propose diverses options de support, notamment des services gratuits
sur Internet vous permettant de faire des recherches dans notre base
documentaire et de contacter d’autres utilisateurs de produits Borland.
Vous disposez aussi de différents services de support technique et d’un support
payant de type Consulting.
Pour plus d’informations sur les services de support développeur proposés
par Borland, visitez notre site Web à l’adresse http://www.borland.com/
devsupport/bcppbuilder. Si vous résidez en France, consultez www.borland.fr
ou http://www.borland.com/bww/intlcust.html si vous êtes situé dans un
autre pays.
Quand vous contactez le support, soyez prêt à fournir des informations
complètes sur l’environnement, la version et l’édition du produit que vous
utilisez, ainsi qu’une description détaillée du problème.
Introduction 1-3
1-4 Guide du développeur
Partie
I
Programmation C++Builder
Partie I
Programmation C++Builder
Chapitre
Développement d’applications
Chapitre 2
2
avec C++Builder
Borland C++Builder est un environnement de programmation visuelle orienté
objet permettant le développement d’applications 32 bits en vue de leur
déploiement sous Windows et sous Linux. En utilisant C++Builder, vous pouvez
créer de puissantes applications avec un minimum de programmation.
C++Builder propose un ensemble d’outils de conception pour le développement
rapide d’applications (RAD), dont des experts programmateur et des modèles
d’applications ou de fiches, et gère la programmation orientée objet avec deux
bibliothèques étendues de classes :
• La bibliothèque de classes VCL comprend des objets qui encapsulent l’API
Windows ainsi que d’autres techniques de programmation utiles (Windows).
• La bibliothèque de composants Borland multiplate-forme (CLX), qui contient des
objets encapsulant la bibliothèque Qt (Windows ou Linux).
Ce chapitre décrit brièvement l’environnement de développement C++Builder et
comment il s’inscrit dans le cycle de développement. Le reste de ce manuel
donne des détails techniques sur le développement d’applications, la gestion des
bases de données et les applications Internet ou Intranet, la création de contrôles
ActiveX ou COM, et sur l’écriture de composants personnalisés.
L’EDI dispose de tous les outils nécessaires pour commencer à concevoir une
application :
• Le concepteur de fiche, une fenêtre vide, appelée une fiche, dans laquelle
concevoir l’interface utilisateur, de l’application.
• La palette des composants qui affiche des composants visuels ou non visuels
que vous pouvez utiliser pour concevoir votre interface utilisateur.
• L’inspecteur d’objets pour connaître ou modifier les propriétés et événements
d’un objet.
• L’arborescence d’objets pour afficher ou modifier les relations logiques d’un
objet.
• L’éditeur de code pour écrire ou modifier la logique sous-jacente d’un
programme.
• Le gestionnaire de projet qui permet de gérer les fichiers constituant un ou
plusieurs projets.
• Le débogueur intégré pour rechercher et corriger les erreurs dans votre code.
• De nombreux outils, comme les éditeurs de propriété qui permettent de
modifier la valeur des propriétés d’un objet.
• Des outils en ligne de commande, y compris des compilateurs, des éditeurs de
liens.
• Des bibliothèques de classes contenant de nombreux objets réutilisables. De
nombreux objets fournis dans la bibliothèque des classes sont accessibles dans
la palette des composants de l’EDI. Par convention, les noms des objets de la
bibliothèque des classes commencent par un T, comme TStatusBar.
Certains d’entre eux ne font pas partie de toutes les éditions du produit.
Une présentation plus complète de l’environnement de développement est
proposée dans le manuel Prise en main, livré avec le produit. En outre, le système
d’aide en ligne offre de l’aide sur tous les menus, boîtes de dialogues et fenêtres.
Conception d’applications
Vous pouvez utiliser C++Builder pour concevoir tout type d’application 32 bits,
que ce soit un utilitaire de portée générale ou un programme complexe de
gestion de données ou des applications distribuées.
Alors même que vous concevez visuellement l’interface utilisateur d’une
application, C++Builder génère le code C++ sous-jacent pour gérer l’application.
Dès que vous sélectionnez et modifiez les propriétés des composants et des
fiches, le résultat de ces modifications apparaît automatiquement dans le code
source, et vice-versa. Vous pouvez modifier directement les fichiers source avec
tout éditeur de texte, y compris l’éditeur de code intégré. Les modifications
effectuées dans le code sont immédiatement reflétées dans l’environnement
visuel.
Dans C++Builder vous pouvez créer vos propres composants. La plupart des
composants fournis sont écrits en Pascal Objet. Vous pouvez ajouter à la palette
les composants que vous avez écrits et la personnaliser à votre convenance en
insérant de nouveaux onglets.
Modification du code
L’éditeur de code C++Builder est un éditeur ASCII complet. Si vous utilisez
l’environnement de programmation visuel, une fiche est automatiquement
affichée dans un nouveau projet. Vous pouvez commencer la conception de
l’interface de votre application en plaçant des objets sur la fiche et en modifiant
leur fonctionnement dans l’inspecteur d’objets. Mais d’autres tâches de
programmation, comme l’écriture des gestionnaires d’événements pour les objets,
doivent se faire en tapant directement le code.
Le contenu d’une fiche et toutes ses propriétés ainsi que ses composants et leurs
propriétés peuvent être modifiés sous forme de texte dans l’éditeur de code.
Vous pouvez ajuster le code généré dans l’éditeur de code et ajouter d’autres
composants en tapant du code dans l’éditeur. Au fur et à mesure que vous tapez
du code dans l’éditeur, le compilateur l’analyse constamment afin de changer la
disposition de la fiche. Vous pouvez revenir à la fiche, voir et tester les
changements apportés dans l’éditeur, puis continuer à modifier la fiche elle-
même.
La génération de code C++Builder et le système de flux des propriétés est
entièrement ouvert à l’examen. Le code source de tout ce qui se trouve dans le
fichier exécutable final (tous les objets VCL, les objets CLX, les sources RTL et
les fichiers projet) peut être visualisé et modifié dans l’éditeur de code.
CLX Pour déployer une application CLX sous Linux, une application Borland C++
n’est pas encore disponible, mais vous pouvez déjà développer l’application dans
C++Builder.
Pour davantage d’informations sur le déploiement, voir chapitre 17,
“Déploiement des applications”.
Les composants visuels, comme TForm ou TSpeedButton sont appelés des contrôles
et dérivent de TControl. TControl propose des propriétés qui spécifient les
attributs visuels des contrôles comme la hauteur ou la largeur.
Les composants non visuels sont utilisés pour diverses tâches. Si, par exemple,
vous écrivez une application qui se connecte à une base de données, vous
pouvez placer un composant TDataSource dans une fiche pour connecter un
contrôle et l’ensemble de données utilisé par le contrôle. Cette connection est
invisible pour l’utilisateur, TDataSource est donc non visuel. A la conception,
les composants non visuels sont représentés par une icône. Cela vous permet
de manipuler leurs propriétés et événements comme pour un contrôle visuel.
Vous pouvez accéder à des informations détaillées sur tous les objets VCL ou
CLX, en utilisant l’aide en ligne pendant que vous programmez. Dans l’éditeur
de code, placez le curseur en un endroit quelconque de l’objet et appuyez sur F1
pour afficher de l’aide. Les objets, propriétés, méthodes et événements qui font
partie de la VCL sont marqués “Référence VCL” et ceux faisant partie de CLX
sont marqués “Référence CLX”.
Propriétés
Les Propriétés sont les caractéristiques d’un objet, relatives à son comportement
visible ou aux opérations qu’il effectue. Par exemple, la propriété Visible
détermine si un objet doit être vu ou non dans l’interface d’une application.
Des propriétés bien conçues simplifient l’utilisation de vos composants par
d’autres programmeurs et en facilite la maintenance.
Voici quelques fonctionnalités utiles des propriétés :
• Alors que les méthodes ne sont disponibles qu’à l’exécution, vous pouvez
accéder aux propriétés et les modifier au cours de la conception et obtenir une
réponse immédiate des composants dans l’EDI.
• Les propriétés peuvent être accédées via l’inspecteur d’objets dans lequel vous
pouvez changer les valeurs visuellement. Définir les propriétés au moment de
la conception est plus simple qu’écrire directement le code, et ce dernier est
plus facile à maintenir.
• Comme les données sont encapsulées, elles sont protégées et privées pour
l’objet réel.
• Les appels effectués pour obtenir ou définir des valeurs sont des méthodes, et
donc le traitement reste invisible pour l’utilisateur de l’objet. Par exemple, les
données peuvent résider dans une table, mais apparaître au programmeur
comme des données membres normales.
• Vous pouvez implémenter la logique qui déclenche des événements ou
modifier d’autres données pendant l’accès à la propriété. Par exemple, changer
la valeur d’une propriété peut nécessiter la modification d’une autre. Vous
pouvez modifier les méthodes créées pour la propriété.
• Les propriétés peuvent être virtuelles.
• Une propriété n’est pas limitée à un seul objet. Changer une propriété d’un
objet peut affecter plusieurs autres objets. Par exemple, définir la propriété
Checked d’un bouton radio affecte tous les autres boutons radio du groupe.
Méthodes
Une méthode est une fonction qui est un membre d’une classe. Les méthodes
définissent le comportement d’un objet. Les méthodes de classe peuvent accéder
à toutes les propriétés publiques, protégées et privées et aux données membres de la
classe, on les désigne fréquemment par le terme fonctions membres.
Voir “Contrôle des accès” à la page 46-4.
Evénements
Un événement est une action ou une occurrence détectée par un programme.
La plupart des applications modernes sont dites pilotées par événements, car
elles sont conçues pour répondre à des événements. Dans un programme, le
programmeur n’a aucun moyen de prévoir la séquence exacte des actions que
va entreprendre l’utilisateur. Il peut, par exemple, choisir un élément de menu,
cliquer sur un bouton ou sélectionner du texte. Vous allez donc écrire le code
qui gère chacun des événements qui vous intéressent au lieu d’écrire du code
s’exécutant toujours selon le même ordre.
Quelle que soit la façon dont un événement a été appelé, C++Builder recherche
si du code a été écrit pour gérer cet événement. Si c’est le cas, ce code est
exécuté, sinon, le comportement par défaut se produit.
Les types d’événements qui peuvent survenir se divisent en deux grandes
catégories :
• Evénements utilisateur
• Evénements système
Evénements utilisateur
Les événements utilisateur sont des actions initiées par l’utilisateur.
Les événements utilisateur sont, par exemple, OnClick (l’utilisateur a cliqué avec
la souris), OnKeyPress (l’utilisateur a appuyé sur une touche du clavier)
et OnDblClick (l’utilisateur a double-cliqué sur un bouton de la souris).
Evénements système
Ce sont des événements que le système d’exploitation déclenche pour vous.
Par exemple, l’événement OnTimer (le composant Timer déclenche l’un de ces
événements lorsqu’un intervalle prédéfini s’est écoulé), l’événement OnCreate (le
composant est en train d’être créé), l’événement OnPaint (un composant ou une
fenêtre a besoin d’être redessiné), etc. En règle générale, ces événements ne sont
pas directement déclenchés par des actions de l’utilisateur.
TObject
TComponent
TControl
[Objets]
[Objets] [Objets] TGraphicControl [Objets]
[Objets]
Exception [Objets]
Plusieurs importantes classes de base montrées dans la figure sont décrites dans
le tableau suivant :
Les quelques sections suivantes présentent une description générale des types de
classes que contient chaque branche. Pour avoir une présentation complète de la
hiérarchie des objets VCL et CLX, reportez-vous aux posters VCL et CLX fournis
avec ce produit.
Branche TObject
La branche TObject comprend tous les objets VCL et CLX qui dérivent de TObject
mais non de TPersistent. L’essentiel des capacités des objets VCL et CLX est basé
sur les méthodes définies dans TObject. TObject encapsule le comportement
fondamental commun à tous les objets VCL ou CLX, en introduisant des
méthodes qui permettent :
• De répondre à la création ou à la destruction d’objets.
• De donner des informations sur le type de classe et d’instance d’un objet et
des informations de type à l’exécution (RTTI) sur ses propriétés publiées.
• De gérer le traitement des messages (VCL) ou les événements système (CLX).
TObject est l’ancêtre immédiat de nombreuses classes simples. Les classes
contenues dans la branche de TObject ont une caractéristique commune
importante : elles sont transitoires. Cela signifie que ces classes ne disposent pas
d’une méthode pour enregistrer leur état avant leur destruction ; elles ne sont
pas persistantes.
Le groupe de classes le plus important de cette branche est constitué par la
classe Exception. Cette classe propose un grand nombre de classes d’exceptions
prédéfinies pour gérer automatiquement de nombreuses conditions d’exception
comme les erreurs de division par zéro, les erreurs d’entrées/sorties ou les
transtypages incorrects.
La branche TObject contient également un autre groupe de classes qui
encapsulent des structures de données, comme :
• TBits, une classe qui stocke un “tableau” de valeur booléennes.
• TList, une classe liste liée.
• TStack, une classe qui gère un tableau de pointeurs du type dernier entré,
premier sorti.
• TQueue, une classe qui gère un tableau de pointeurs du type premier entré,
premier sorti.
Dans la VCL, vous trouverez aussi des enveloppes pour les objets externes
comme TPrinter, qui encapsulent l’interface imprimante Windows, et TRegistry,
une enveloppe de bas niveau pour le registre du système et les fonctions qui
opèrent sur le registre. Elles sont spécifiques à l’environnement Windows.
TStream est un bon exemple du type de classes contenues dans cette branche.
TStream est la classe de base des objets flux qui permettent de lire ou d’écrire sur
divers types de support de données, comme les fichiers disque ou la mémoire
vive.
Globalement, cette branche contient un grand nombre de différents types de
classes particulièrement utiles pour le développeur.
Branche TPersistent
La branche TPersistent comprend tous les objets VCL et CLX qui dérivent de
TPersistent mais pas de TComponent. La persistance détermine ce qui est
enregistré dans un fichier fiche ou un module de données et ce qui est chargé
dans la fiche ou le module de données lorsqu’il est extrait de la mémoire.
Les objets de cette branche implémentent des propriétés pour les composants.
Les propriétés sont uniquement chargés et enregistrés avec une fiche si elles ont
un propriétaire. Le propriétaire doit être un composant. Cette branche introduit
la fonction GetOwner qui vous permet de déterminer le propriétaire de la
propriété.
Les objets de cette branche sont également les premiers à inclure une section
publiée dans laquelle les propriétés peuvent être automatiquement chargées et
enregistrées. Un méthode DefineProperties vous permet aussi d’indiquer la façon
de charger et d’enregistrer les propriétés.
Voici quelques autres classes de la branche TPersistent de la hiérarchie :
• TGraphicsObject, une classe de base abstraite pour les objets graphiques, par
exemple : TBrush, TFont et TPen.
• TGraphic, une classe de base abstraite pour les objets comme TBitmap et TIcon,
qui peuvent stocker et afficher des images visuelles.
• TStrings, une classe de base pour les objets qui représentent une liste de
chaînes.
• TClipboard, une classe contenant du texte ou des graphiques qui ont été
coupés ou copiés d’une application.
• TCollection, TOwnedCollection et TCollectionItem, classes qui maintiennent les
collections indexées d’éléments spécialement définis.
Branche TComponent
La branche TComponent contient des objets qui dérivent de TComponent mais pas
de TControl. Les objets de cette branche sont des composants que vous pouvez
manipuler sur des fiches au cours de la conception. Ce sont des objets persistants
aux capacités suivantes :
• Ils apparaissent dans la palette des composants et peuvent être modifiés dans
le concepteur de fiche.
• Ils peuvent posséder et gérer d’autres composants.
• Ils se chargent et s’enregistrent eux-mêmes.
Plusieurs méthodes de TComponent dictent la façon dont agissent les composants
durant la conception et les informations qui sont enregistrées avec le composant.
La gestion des flux est introduite dans cette branche de la VCL et de CLX.
C++Builder gère automatiquement la plupart des opérations principales relatives
aux flux. Les propriétés sont persistantes si elles sont publiées et les propriétés
publiées sont automatiquement mises en flux.
Branche TControl
La branche TControl est constituée de composants qui dérivent de TControl mais
pas de TWinControl (TWidgetControl dans CLX). Les objets de cette branche sont
des contrôles, c’est-à-dire des objets visuels que l’utilisateur de l’application peut
voir et manipuler à l’exécution. Tous les contrôles ont des propriétés, méthodes
et événements communs qui sont propres à l’aspect visuel des contrôles, comme
la position du contrôle, le curseur associé à la fenêtre (au widget dans CLX) du
contrôle, des méthodes pour dessiner ou déplacer le contrôle et des événements
permettant de répondre aux actions de la souris. Ils ne peuvent jamais recevoir
la saisie du clavier.
Si TComponent définit des comportements communs à tous les composants,
TControl définit ceux communs à tous les contrôles visuels. Il s’agit de routines
de dessin, des événements standard et de la notion de conteneur.
Tous les contrôles visuels partagent certaines propriétés. Ces propriétés sont
héritées de TControl mais elles ne sont publiées (elles apparaissent dans
l’inspecteur d’objets) que pour les composants où elles sont applicables. Ainsi,
TImage ne publie pas la propriété Color car sa couleur est déterminée par l’image
qu’il affiche.
Il y a deux types de contrôles :
• Ceux qui ont leur propre fenêtre (ou widget).
• Ceux qui utilisent la fenêtre (ou le widget) de leur parent.
Les contrôles qui ont leur propre fenêtre sont appelés contrôles “fenêtrés” (VCL)
ou “basés sur des widgets” (CLX) et dérivent de TWinControl (TWidgetControl
dans CLX). Les boutons et les cases à cocher en font partie.
Les contrôles qui utilisent une fenêtre (ou un widget) parent sont appelés
contrôles graphiques et dérivent de TGraphicControl. Les contrôles image et forme
en font partie. Les contrôles graphique ne possèdent pas de handle et ne peuvent
pas recevoir la focalisation de saisie. Comme un contrôle graphique n’a pas
besoin d’un handle, il utilise moins de ressources système. Les contrôles
graphique doivent se dessiner eux-mêmes et ne peuvent pas servir de parent
à d’autres contrôles.
Voir “Contrôles graphiques” à la page 9-20 pour davantage d’informations sur
les autres contrôles graphiques et le chapitre 9, “Types de contrôles”, pour
davantage d’informations sur les différents types de contrôles. Voir le chapitre 6,
“Manipulation des contrôles”, pour davantage d’informations sur la manière
d’interagir sur les contrôles à l’exécution.
Branche TWinControl/TWidgetControl
Dans la VCL, la branche TWinControl contient tous les contrôles qui dérivent de
TWinControl. TWinControl est la classe de base de tous les contrôles fenêtrés, qui
sont des éléments que vous utilisez dans l’interface utilisateur d’une application,
comme les boutons, les étiquettes ou les barres de défilement. Les contrôles
fenêtrés encapsulent un contrôle de Windows.
Dans CLX, TWidgetControl, qui remplace TWinControl, est la classe de base de
tous les contrôles widget qui encapsulent des widgets.
Les contrôles fenêtrés et widgets :
• Peuvent recevoir la focalisation lors de l’exécution de l’application, ce qui
signifie qu’ils peuvent recevoir les saisies clavier effectuées par l’utilisateur de
l’application. Par comparaison, d’autres contrôles peuvent seulement afficher
des données.
• Peuvent être le parent d’un ou de plusieurs contrôles enfant.
• Ont un handle ou un identificateur unique.
La branche TWinControl/TWidgetControl contient des contrôles dessinés
automatiquement (comme TEdit, TListBox, TComboBox, TPageControl, etc) et des
contrôles personnalisés que C++Builder doit dessiner, comme TDBNavigator,
TMediaPlayer (VCL uniquement) ou TGauge (VCL uniquement). Les descendants
directs de TWinControl /TWidgetControl implémentent typiquement des contrôles
standard, comme un champ d’édition, une boîte à option ou un contrôle page, et
savent donc déjà comment se dessiner eux-mêmes.
La classe TCustomControl est fournie pour les composants qui nécessitent un
handle mais n’encapsulent pas de contrôle standard ayant la capacité de se
redessiner lui-même. Vous n’avez jamais à vous soucier de la façon dont les
contrôles s’affichent ou répondent aux événements — C++Builder encapsule
complètement ce comportement pour vous.
Utilisation de BaseCLX
Chapitre 4
4
De nombreuses unités communes à la VCL et à CLX fournissent la prise en
charge sous-jacente des deux bibliothèques de composants. Ces unités sont
collectivement dénommées BaseCLX. BaseCLX n’inclut aucun des composants
qui apparaissent sur la palette des composants. Elle inclut à la place un certain
nombre de classes et de routines globales utilisées par les composants qui
apparaissent sur la palette des composants. Ces classes et routines sont
également disponibles pour une utilisation dans du code d’application ou pour
l’écriture de vos propres classes.
Remarque Les routines globales constituant BaseCLX sont souvent appelées la bibliothèque
d’exécution. Il ne faut pas confondre ces routines avec la bibliothèque
d’exécution C++. Un grand nombre de ces routines ont des fonctions similaires
à celles de la bibliothèque d’exécution C++, mais elles peuvent se distinguer à
cause de leurs noms de fonctions qui commencent par une lettre capitale, et elles
sont déclarées dans l’en-tête d’une unité.
Les rubriques suivantes traitent de bon nombre des classes et routines qui
constituent BaseCLX, et elles montrent la manière de les utiliser. Ces utilisations
incluent :
• Utilisation des flux
• Utilisation des fichiers
• Utilisation des fichiers ini et du registre
• Utilisation des listes
• Utilisation des listes de chaînes
• Utilisation des chaînes
• Conversion de mesures
• Création d’espaces de dessin
Remarque Cette liste de tâches n’est pas exhaustive. La bibliothèque d’exécution de
BaseCLX contient de nombreuses routines pour l’exécution de tâches qui ne sont
pas mentionnées ici. Ces routines incluent ainsi un ensemble de fonctions
mathématiques (définies dans l’unité Math), des routines pour la manipulation
des valeurs date/heure (définies dans les unités SysUtils et DateUtils) et des
routines pour la manipulation des Variants Pascal Objet (définies dans l’unité
Variants).
Valeur Signification
soFromBeginning Offset part du début de la ressource. Seek se déplace vers la position
Offset. Offset doit être >= 0.
soFromCurrent Offset part de la position en cours dans la ressource. Seek se déplace
vers Position + Offset.
soFromEnd Offset part de la fin de la ressource. Offset doit être <= 0 afin d’indiquer
le nombre d’octets avant la fin du fichier.
modifiée, une exception est déclenchée. Ainsi, tenter de modifier la taille d’un
flux de fichier ouvert en lecture seule déclenche une exception.
Le mode de partage peut prendre l’une des valeurs suivantes, avec les
restrictions énumérées ci-dessous :
Manipulation de fichiers
Plusieurs opérations courantes portant sur les fichiers sont prédéfinies dans la
bibliothèque d’exécution BaseCLX. Les procédures et fonctions manipulant les
fichiers agissent à un niveau élevé. Pour la plupart des routines, il vous suffit de
spécifier le nom du fichier, et la routine effectue alors pour vous les appels
nécessaires au système d’exploitation. Dans certains cas, vous utiliserez à la place
des handles de fichiers.
Attention Au contraire du langage Pascal Objet, le système d’exploitation Linux distingue
majuscules et minuscules. Faites attention à la casse des caractères lorsque vous
travaillez avec des fichiers dans des applications multi-plates-formes.
pas déjà, il est créé automatiquement. Vous êtes alors libre de lire les valeurs en
utilisant différentes méthodes de lecture, comme ReadString, ReadDate, ReadInteger
ou ReadBool. Par ailleurs, si vous souhaitez lire une section entière du fichier ini,
vous pouvez utiliser la méthode ReadSection. De même, vous pouvez écrire des
valeurs en utilisant WriteBool, WriteInteger, WriteDate ou WriteString.
L’exemple suivant lit des informations de configuration d’un fichier ini dans le
constructeur d’une fiche et écrit des valeurs dans le gestionnaire d’événement
OnClose.
__fastcall TForm1::TForm1(TComponent *Owner) : TForm(Owner)
{
TIniFile *ini;
ini = new TIniFile( ChangeFileExt( Application->ExeName, ".INI" ) );
delete ini;
}
delete ini;
}
Chacune des routines Read attend trois paramètres. Le premier identifie la
section du fichier ini. Le deuxième paramètre identifie la valeur à lire et le
troisième est une valeur par défaut à utiliser si la section ou la valeur n’existe
pas dans le fichier ini. De même que les méthodes Read gèrent de manière
élégante la non existence d’une section ou d’une valeur, les routines Write
crééent la section et/ou la valeur si elle n’existe pas. L’exemple précédent crée
un fichier ini la première fois qu’il est exécuté, et ce fichier est de la forme :
[Form]
Top=185
Left=280
Caption=Default Caption
InitMax=0
Lors des exécutions ultérieures de cette application, les valeurs ini sont lues lors
de la création de la fiche et réécrites dans l’événement OnClose.
Utilisation de TRegistryIniFile
De nombreuses applications Windows 32 bits stockent leurs informations dans la
base de registres plutôt que dans des fichiers ini, car cette base est hiérarchique
et ne souffre pas des limitations de taille inhérentes aux fichiers ini. Si vous êtes
habitué à utiliser des fichiers ini et souhaitez transférer vos informations de
configuration dans la base de registres, vous pouvez utiliser la classe
TRegistryIniFile. Vous pouvez également utiliser TRegistryIniFile dans des
applications multi-plates-formes si vous voulez utiliser la base de registres sous
Windows et un fichier ini sous Linux. Vous pouvez écrire la plus grande partie
de votre application de façon à ce qu’elle utilise le type TCustomIniFile. Vous
devez uniquement introduire des conditions dans le code qui crée une instance
de TRegistryIniFile (sous Windows) ou TMemIniFile (sous Linux) et l’affecter à
l’objet TCustomIniFile utilisé par votre application.
TRegistryIniFile crée une similitude entre les entrées de la base de registres et
celles du fichier ini. Toutes les méthodes de TIniFile et TMemIniFile (lecture et
écriture) existent dans TRegistryIniFile.
Quand vous créez un objet TRegistryIniFile, le paramètre que vous transmettez au
constructeur (correspondant au nom du fichier pour un objet IniFile ou
TMemIniFile) devient une valeur de clé sous la clé de l’utilisateur dans la base de
registres. Toutes les sections et valeurs commencent à partir de la clé ainsi
transmise. TRegistryIniFile simplifie considérablement l’interfaçage avec la base de
registres, de sorte que vous pourriez vouloir l’utiliser à la place du composant
TRegistry, même si vous ne migrez pas un code existant ou si vous n’écrivez pas
une application multi-plates-formes.
Utilisation de TRegistry
Si vous écrivez une application uniquement sous Windows et si vous connaissez
bien la structure de la base de registres, vous pouvez utiliser TRegistry. A la
différence de TRegistryIniFile, qui utilise les mêmes propriétés et méthodes des
autres composants du fichier ini, les propriétés et les méthodes de TRegistry
correspondent plus directement à la structure de la base de registres. Par
exemple, TRegistry vous permet de spécifier la clé racine et la sous-clé, alors que
TRegistry adopte HKEY_CURRENT_USER comme clé racine. En plus des
méthodes pour l’ouverture, la fermeture, l’enregistrement, le déplacement et la
suppression des clés, TRegistry vous permet de spécifier le niveau d’accès que
vous voulez utiliser.
Remarque TRegistry ne peut pas être utilisé en programmation multiplates-formes.
L’exemple suivant lit une valeur dans une entrée de registre :
#include <Registry.hpp>
Listes persistantes
Les listes persistantes peuvent être enregistrées dans un fichier de fiche. C’est la
raison pour laquelle elles sont souvent utilisées comme type d’une propriété
publiée sur un composant. Vous pouvez ajouter des éléments à la liste lors de la
conception, et ces éléments sont enregistrés avec l’objet afin d’être présents
lorsque le composant qui les utilise est chargé en mémoire à l’exécution. Il existe
deux types principaux de listes persistantes : les listes de chaînes et les
collections.
Parmi les listes de chaînes figurent TStringList et THashedStringList. Comme leur
nom l’indique, les listes de chaînes contiennent des chaînes. Elles fournissent une
prise en charge particulière des chaînes de la forme Nom=Valeur, pour vous
permettre de rechercher la valeur associée à un nom. De plus, la plupart des
listes de chaînes vous permettent d’associer un objet à chaque chaîne de la liste.
Les listes de chaînes sont décrites plus en détail dans “Utilisation des listes de
chaînes” à la page 4-17.
Les collections dérivent de la classe TCollection. Chaque descendant de TCollection
est spécialement conçu pour gérer une classe particulière d’éléments, où cette
classe dérive de TCollectionItem. Les collections prennent en charge de
nombreuses opérations de listes courantes. Toutes les collections sont conçues
pour être le type d’une propriété publiée, et un grand nombre ne peuvent pas
fonctionner indépendamment de l’objet qui les utilise pour une implémentation
sur la base de ses propriétés. Lors de la conception, la propriété dont la valeur
est une collection peut utiliser l’éditeur de collection pour vous permettre
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ClickList = new TStringList;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
ClickList->SaveToFile(ChangeFileExt(Application->ExeName, ".LOG"));//enregistre la liste
delete ClickList;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
TVarRec v[] = {X,Y};
ClickList->Add(Format("Clic à (%d, %d)",v,ARRAYSIZE(v) - 1));// ajoute une chaîne
// à la liste
}
}
Clear et Move agissent à la fois sur les chaînes et les objets ; ainsi, la suppression
d’une chaîne supprime également l’éventuel objet correspondant.
Pour associer un objet à une chaîne existante, affectez l’objet à la propriété
Objects pour le même indice. Vous ne pouvez pas ajouter d’objet sans ajouter
une chaîne correspondante.
Remarque Les routines utilisées pour les noms de fichiers sous forme de chaîne,
AnsiCompareFileName, AnsiLowerCaseFileName et AnsiUpperCaseFileName, utilisent
la localisation Windows. Vous devez toujours utiliser des noms de fichiers
portables, car la localisation (le jeu de caractères) utilisée pour les noms de
fichiers peut différer de celle de l’interface utilisateur par défaut.
Tableau 4.11 Routines de conversion majuscules/minuscules pour les chaînes à zéro terminal
Utilisation
des paramètres
Routine de localisation Gestion MBCS
AnsiStrLower Oui Oui
AnsiStrUpper Oui Oui
StrLower Non Non
StrUpper Non Non
Impression
Techniquement parlant, la classe TPrinter n’appartient pas à BaseCLX car il
existe deux versions séparées, une pour la VCL (dans l’unité Printers) et une
pour CLX (dans l’unité QPrinters). L’objet VCL TPrinter encapsule les détails de
l’impression sous Windows. L’objet CLX TPrinter est un dispositif de peinture
qui opère sur une imprimante. Il génère du code postscript et l’envoie à lpr, lp
ou à toute autre commande d’impression. Les deux versions de TPrinter sont
toutefois très similaires.
Pour obtenir une liste des imprimantes installées et disponibles, utilisez la
propriété Printers. Les deux objets imprimante utilisent un TCanvas (similaire au
TCanvas de la fiche), ce qui signifie que tout ce qui peut être dessiné sur une
fiche peut également être imprimé. Pour imprimer une image, appelez d’abord la
méthode BeginDoc, puis les routines des dessins de canevas à imprimer (y
compris du texte en utilisant la méthode TextOut), et envoyez la tâche à
l’imprimante en appelant la méthode EndDoc.
Cet exemple utilise un bouton et un mémo sur une fiche. Quand l’utilisateur
clique sur le bouton, le contenu du mémo s’imprime avec une marge de
200 pixels autour de la page.
Pour exécuter cet exemple, vous devez inclure <Printers.hpp> dans votre fichier
d’unité.
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TPrinter *Prntr = Printer();
TRect r = Rect(200,200,Prntr->PageWidth - 200,Prntr->PageHeight- 200);
Prntr->BeginDoc();
for( int i = 0; i < Memo1->Lines->Count; i++)
Prntr->Canvas->TextOut(200,200 + (i *
Prntr->Canvas->TextHeight(Memo1->Lines->Strings[i])),
Memo1->Lines->Strings[i]);
Prntr->Canvas->Brush->Color = clBlack;
Prntr->Canvas->FrameRect(r);
Prntr->EndDoc();
}
Pour davantage d’informations sur l’utilisation de l’objet TPrinter, voir dans
l’aide en ligne la rubrique TPrinter.
Conversion de mesures
L’unité ConvUtils déclare une fonction Convert que vous pouvez utiliser pour
convertir des mesures entre plusieurs unités. Vous pouvez effectuer des
conversions entre unités compatibles, par exemple des pouces et des pieds ou
des jours et des semaines. Les unités mesurant les mêmes types d’éléments sont
dites appartenir à la même famille de conversion. Les unités que vous convertissez
doivent appartenir à la même famille de conversion. Pour plus d’informations
sur les conversions, reportez-vous à la section suivante “Exécution des
conversions” et à Convert dans l’aide en ligne.
L’unité StdConvs définit plusieurs familles de conversion et les unités de mesure
de chacune de ces familles. De plus, vous pouvez créer vos propres familles de
conversion et leurs unités associées en utilisant les fonctions
RegisterConversionType et RegisterConversionFamily. Pour savoir comment étendre
les conversions et les unités de conversion, reportez-vous à la section “Ajout de
nouveaux types de mesure” à la page 4-29 et à Convert dans l’aide en ligne.
conversion entre jours et mois, jours et années, etc. n’est pas exacte. Les mois ont
différentes longueurs, les années ont des facteurs de correction pour les années
bissextiles, les secondes supplémentaires, etc.
Si vous utilisez uniquement des unités de mesure égales ou supérieures au mois,
vous pouvez créer une famille de conversion plus précise en prenant l’année
comme unité de base. Cet exemple crée une nouvelle famille de conversion
nommée cbLongTime.
Appel de méthodes
Une méthode s’appelle comme une procédure ou une fonction ordinaire. Par
exemple, les contrôles visuels disposent de la méthode Repaint qui rafraîchit
l’image du contrôle à l’écran. Vous pouvez appeler la méthode Repaint d’un objet
grille de dessin de la manière suivante :
DrawGrid1->Repaint;
Comme pour les propriétés, c’est la portée d’une méthode qui impose ou pas
l’utilisation de qualificateurs. Par exemple, pour redessiner une fiche depuis le
gestionnaire d’événement de l’un des contrôles enfant de la fiche, il n’est pas
nécessaire de préfixer l’appel de méthode avec le nom de la fiche :
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Repaint;
}
Les sites d’ancrage peuvent réagir lorsque les contrôles enfant sont retirés, et
même empêcher le désancrage, dans un gestionnaire d’événement OnUnDock :
__property TUnDockEvent OnUnDock = {read=FOnUnDock, write=FOnUnDock};
typedef void __fastcall (__closure *TUnDockEvent)(System::TObject* Sender, TControl*
Client, TWinControl* NewTarget, bool &Allow);
Le paramètre Client indique le contrôle enfant qui tente un désancrage et le
paramètre Allow permet au site d’ancrage (Sender) de rejeter le désancrage.
Lorsque vous implémentez un gestionnaire d’événement OnUnDock, il peut être
utile de connaître les autres enfants éventuellement ancrés. Ces informations
figurent dans la propriété en lecture seule DockClients, qui est un tableau indexé
de TControl. Le nombre de clients ancrés est donné par la propriété en lecture
seule DockClientCount.
Sélection de texte
Pour transférer du texte d’un contrôle de saisie dans le presse-papiers, il faut
d’abord sélectionner ce texte. La possibilité de mettre en surbrillance le texte
sélectionné est intégrée aux composants éditeur. Lorsque l’utilisateur sélectionne
un texte, celui-ci apparaît en surbrillance.
Le tableau suivant dresse la liste des propriétés fréquemment utilisées pour la
manipulation du texte sélectionné.
texte des éléments. Pour des informations sur l’utilisation du style “dessiné par
le propriétaire” pour ajouter des images aux menus, voir “Ajout d’images à des
éléments de menu” à la page 8-39.
Les contrôles dessinés par le propriétaire ont un point commun : ils contiennent
tous des listes d’éléments. Généralement, il s’agit de listes de chaînes qui sont
affichées sous forme de texte ou de liste d’objets contenant des chaînes qui sont
affichées sous forme de texte. Il est possible d’associer un objet à chaque élément
de ces listes et d’utiliser l’objet lorsque vous dessinez un élément.
Dans C++Builder, la création d’un contrôle dessiné par le propriétaire se fait
généralement en trois étapes :
1 Spécification du style dessiné par le propriétaire
2 Ajout d’objets graphiques à une liste de chaînes
3 Dessiner des éléments dessinés par le propriétaire
Floppy->Picture->Graphic);
DriveName[1] = ’:’ // Remplacer le deux points
break;
case DRIVE_FIXED:// Ajouter un élément à la liste
DriveName[1] = ’\0’; // convertir la lettre du lecteur en chaîne
AddedIndex = DriveList->Items->AddObject(DriveName,
Fixed->Picture->Graphic);
DriveName[1] = ’:’ // Remplacer le deux points
break;
case DRIVE_REMOTE:// Ajouter un élément à la liste
DriveName[1] = ’\0’; // convertir la lettre du lecteur en chaîne
AddedIndex = DriveList->Items->AddObject(DriveName,
Network->Picture->Graphic);
DriveName[1] = ’:’ // Remplacer le deux points
break;
}
if ((int)(Drive - ’A’) == getdisk()) // lecteur en cours?
DriveList->ItemIndex = AddedIndex; // en faire l’élément en cours de la liste
}
}
Pour dessiner chaque élément d’un contrôle dessiné par le propriétaire, attachez
un gestionnaire à l’événement draw-item de ce contrôle.
Les noms des événements relatifs aux objets dessinés par le propriétaire
commencent généralement par :
• OnDraw, comme OnDrawItem ou OnDrawCell
• OnCustomDraw, comme OnCustomDrawItem
• OnAdvancedCustomDraw, comme OnAdvancedCustomDrawItem
L’événement draw-item contient des paramètres identifiant l’élément à dessiner, le
rectangle dans lequel il s’inscrit et, habituellement, des informations sur son état
(actif, par exemple). L’application gère chaque événement en plaçant l’élément
approprié dans le rectangle transmis.
Par exemple, le code suivant montre comment dessiner des éléments dans une
boîte liste ayant un bitmap associé à chaque chaîne. Il attache ce gestionnaire à
l’événement OnDrawItem :
void __fastcall TForm1::ListBox1DrawItem(TWinControl *Control, int Index,
TRect &Rect, TOwnerDrawState State)
Création d’applications,
Chapitre 7
7
de composants et de bibliothèques
Ce chapitre donne un aperçu de la manière d’utiliser C++Builder pour créer des
applications, des bibliothèques et des composants.
Création d’applications
L’utilisation principale de C++Builder est la conception et la génération des types
d’applications suivants :
• Les applications d’interface utilisateur graphique
• Les applications console
• Les applications service (pour les applications Windows seulement)
• Paquets et DLL
Les applications d’interface utilisateur graphique (GUI) ont en général une
interface qui facilite leur utilisation. Les applications console s’exécutent dans
une fenêtre console. Les applications service s’exécutent en tant que services
Windows. Ces applications sont compilées en tant qu’exécutables, avec du code
de démarrage.
Vous pouvez créer d’autres types de projets, comme les paquets et les DLL,
bibliothèques de liaison dynamique. Ces applications produisent du code
exécutable sans code de démarrage. Reportez-vous à “Création de paquets et de
DLL” à la page 7-10.
Applications SDI
Pour créer une nouvelle application SDI :
1 Sélectionnez Fichier|Nouveau|Autre pour afficher la boîte de dialogue
Nouveaux éléments.
2 Cliquez sur l’onglet Projets et double-cliquez sur Application SDI.
3 Cliquez sur OK.
Par défaut, la propriété FormStyle de l’objet Form a la valeur fsNormal,
C++Builder suppose que toute nouvelle application est une application SDI.
Applications MDI
Pour créer une nouvelle application MDI :
1 Sélectionnez Fichier|Nouveau|Autre pour afficher la boîte de dialogue
Nouveaux éléments.
2 Cliquez sur l’onglet Projets et double-cliquez sur Application MDI.
3 Cliquez sur OK.
Les applications MDI nécessitent plus de réflexion et sont plus complexes à
concevoir que les applications SDI. Les applications MDI contiennent des fenêtres
enfant qui se trouvent dans la fenêtre client ; la fiche principale contient des
fiches enfant. Affectez la propriété FormStyle de l’objet TForm pour spécifier si la
fiche est un enfant (fsMDIForm) ou si c’est la fiche principale (fsMDIChild). Pour
éviter d’avoir à redéfinir à plusieurs reprises les propriétés des fenêtres enfant,
vous avez intérêt à définir une classe de base pour les fiches enfant et à dériver
chaque fiche enfant de cette classe.
Les applications MDI proposent souvent des options du menu principal comme
Cascade et Mosaïque pour afficher plusieurs fenêtres de diverses manières.
Quand une fenêtre enfant est réduite, son icône est placée dans la fenêtre parent
MDI.
Pour résumer, pour créer les fenêtres d’une application MDI :
1 Créez la fenêtre principale, ou fenêtre parent MDI. Initialisez sa propriété
FormStyle à fsMDIForm.
2 Créez un menu pour la fenêtre principale proposant les options Fichier|
Ouvrir, Fichier|Enregistrer et un menu Fenêtre proposant les options Cascade,
Mosaïque et Réorganiser.
3 Créez les fiches enfant MDI et initialisez leur propriété FormStyle à fsMDIChild.
Modèles de programmation
Les modèles de programmation sont des structures communément appelées
squelettes que vous pouvez ajouter au code source puis remplir. Certains modèles
de code standard, comme les déclarations de tableaux, de classes ou de fonction,
ainsi que de nombreuses instructions, sont livrés avec C++Builder.
Vous pouvez aussi écrire vos propres modèles de code pour les structures que
vous utilisez souvent. Par exemple, si vous voulez utiliser une boucle for dans
votre code, insérez le modèle suivant :
for (; ;)
{
}
Pour insérer un modèle de code dans l’éditeur de code, appuyez sur Ctrl-j et
sélectionnez le modèle que vous voulez utiliser. Vous pouvez ajouter vos propres
modèles à cette collection.
Applications console
Les applications console sont des programmes 32 bits exécutés sans interface
graphique, généralement dans une fenêtre console. Habituellement, ces
applications ne nécessitent pas une saisie utilisateur importante et accomplissent
un jeu limité de fonctions.
Pour créer une nouvelle application console :
1 Choisissez Fichier|Nouveau|Autre puis double-cliquez sur Expert Console
dans la boîte de dialogue Nouveaux éléments.
2 Dans la boîte de dialogue Expert console, cochez l’option Application console,
choisissez le type de source (C ou C++) de la fiche principale du projet ou
spécifiez un fichier préexistant contenant une fonction main ou winmain, puis
choisissez le bouton OK.
C++Builder crée alors un fichier projet pour le type de fichier source spécifié et
affiche l’éditeur de code.
Applications service
Les applications service reçoivent les requêtes des applications client, traitent ces
requêtes et renvoient les informations aux applications client. Habituellement,
elles s’exécutent en arrière-plan, sans nécessiter de saisie utilisateur importante.
Threads de service
Chaque service dispose de son propre thread (TServiceThread), donc si votre
application service implémente plusieurs services, vous devez vous assurer que
l’implémentation de vos services est compatible avec l’utilisation de threads. La
classe TServiceThread est ainsi conçue de façon à implémenter le service dans le
gestionnaire d’événement OnExecutede TService. Le thread du service dispose de
sa propre méthode Execute qui contient une boucle appelant les gestionnaires
OnStart et OnExecute du service avant de traiter de nouvelles requêtes.
Comme le traitement des requêtes de service peut prendre longtemps et que
l’application service peut recevoir simultanément plusieurs requêtes d’un ou de
plusieurs clients, il est plus efficace de lancer un nouveau thread (dérivé de
TThread et non de TServiceThread) pour chaque requête et de déplacer
l’implémentation du service dans la méthode Execute du nouveau thread. Cela
permet à la boucle Execute du thread du service de traiter continuellement de
nouvelles requêtes sans avoir à attendre la fin du gestionnaire OnExecute du
service. L’exemple suivant en est une illustration.
Exemple Ce service sonne tous les 500 millisecondes depuis le thread standard. Il gère la
pause, la reprise et l’arrêt du thread quand on indique au service de se
suspendre, de reprendre ou de s’arrêter.
1 Choisissez Fichier|Nouveau|Autre et double-cliquez sur Application Service
dans la boîte de dialogue Nouveaux éléments. La fenêtre Service1 apparaît.
Propriétés de TDependency
La propriété DisplayName de TDependency est à la fois le nom d’affichage et le
nom réel du service. Elle est presque toujours identique à la propriété Name
TDependency.
fonctionnalités à une application. Vous pouvez créer des DLL dans des
programmes multiplates-formes. Cependant, sous Linux, les DLL et les paquets
sont recompilés en tant qu’objets partagés.
Les paquets sont des DLL spéciales utilisées par les applications C++Builder, par
l’EDI ou les deux à la fois. Il y a deux sortes de paquets : les paquets d’exécution
et les paquets de conception. Les paquets d’exécution fournissent des
fonctionnalités à un programme lors de son exécution. Les paquets de conception
permettent d’étendre les fonctionnalités de l’EDI.
Les DLL et les bibliothèques doivent gérer toutes les exceptions pour empêcher
l’affichage d’erreurs ou d’avertissements dans des boîtes de dialogue Windows.
Les directives du compilateur suivantes peuvent être placées dans les fichiers
projet bibliothèque :
Pour davantage d’informations sur les paquets, voir chapitre 15, “Utilisation des
paquets et des composants”.
Par exemple, vous voulez créer une DLL afin d’afficher une simple boîte de
dialogue :
//---------------------------------------------------------------------
extern TYesNoDialog *YesNoDialog;
//---------------------------------------------------------------------
#endif
// DLLMAIN.CPP
//---------------------------------------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop
#include "dllMain.h"
//---------------------------------------------------------------------
#pragma resource "*.dfm"
TYesNoDialog *YesNoDialog;
//---------------------------------------------------------------------
Liaison de DLL
Vous pouvez définir les options du lieur pour votre DLL sur la page Lieur de la
boîte de dialogue Options du projet. La case à cocher par défaut de cette page
permet également de créer une bibliothèque d’importation pour votre DLL. Si la
compilation est effectuée à partir de la ligne de commande, appelez le lieur,
ILINK32.EXE, avec le commutateur -Tpd. Par exemple :
ilink32 /c /aa /Tpd c0d32.obj mydll.obj, mydll.dll, mydll.map, import32.lib cw32mt.lib
Si vous avez besoin d’une bibliothèque d’importation, utilisez aussi le
commutateur -Gi, qui permet de la générer.
Vous pouvez, si vous le souhaitez, créer une bibliothèque d’importation avec
l’utilitaire de ligne de commande IMPLIB.EXE. Par exemple :
implib mydll.lib mydll.dll
Pour plus d’informations sur les différentes options de liaison de DLL et leur
utilisation avec d’autres modules statiquement ou dynamiquement liés à la
bibliothèque d’exécution, voir l’aide en ligne.
Lorsque vous concevez une application de base de données, vous devez choisir
le mécanisme d’accès aux données à utiliser. Chaque mécanisme d’accès aux
données diffère par l’éventail des fonctions prises en charge, la facilité de
déploiement et la capacité des pilotes à gérer divers serveurs de bases de
données.
Voir la partie II, “Développement d’applications de bases de données”, dans ce
manuel, pour plus de détails sur la façon d’utiliser C++Builder pour créer des
applications de bases de données client ou serveur. Reportez-vous à
“Déploiement d’applications de bases de données” à la page 17-7 pour avoir des
informations sur le déploiement.
Remarque Les éditions de C++Builder n’offrent pas toutes le support des bases de données.
Utilisation de WebBroker
Vous pouvez utiliser WebBroker (appelé aussi architecture NetCLX) pour créer
des applications serveur Web comme les applications CGI ou les bibliothèques
de liaison dynamiques (DLL). Ces applications serveur web peuvent ne contenir
aucun composant visuel. Les composants de la page Internet de la palette de
composants vous permettent de créer des gestionnaires d’événements, de
construire par programme des documents HTML ou XML et de les transférer
au client.
Pour créer une nouvelle application serveur Web en utilisant l’architecture
WebBroker, choisissez Fichier|Nouveau|Autre et double-cliquez sur Application
serveur Web dans la boîte de dialogue Nouveaux éléments. Choisissez ensuite le
type d’application serveur Web :
Utilisation d’InternetExpress
InternetExpress est un ensemble de composants permettant d’étendre
l’architecture d’application serveur Web de base pour qu’elle agisse en tant que
client d’une application serveur. Vous utilisez InternetExpress pour les
applications dans lesquelles les clients dans un navigateur peuvent accéder aux
données d’un fournisseur, résoudre les mises à jour du fournisseur tout en
s’exécutant sur un client.
Les applications InternetExpress génèrent des pages HTML qui associent HTML,
XML et javascript. HTML régit la disposition et l’aspect des pages affichées dans
le navigateur des utilisateurs finals. XML code les paquets de données et les
paquets delta qui représentent les informations base de données. Javascript
permet aux contrôles HTML d’interpréter et de manipuler les données des
paquets XML sur la machine client.
Pour plus d’informations sur InternetExpress, voir chapitre “Construction des
applications Web avec InternetExpress” à la page 29-35.
une machine différente. Vous pouvez aussi utiliser COM+, ActiveX et les pages
Active Server.
COM est un modèle de composant logiciel indépendant du langage qui permet
l’interaction entre des composants logiciels et des applications s’exécutant sous
Windows. L’aspect fondamental de COM est de permettre la communication
entre composants, entre applications et entre clients et serveurs, par le biais
d’interfaces clairement définies. Les interfaces offrent aux clients un moyen de
demander à un composant COM quelles fonctionnalités il supporte à l’exécution.
Pour fournir d’autres fonctionnalités à votre composant, il suffit d’ajouter une
autre interface pour ces fonctionnalités.
Pour davantage d’informations sur les modules de données, voir l’aide en ligne.
L’option Utiliser est disponible pour les fiches, les boîtes de dialogue et les
modules de données.
Implémentation de ICustomHelpViewer
L’interface ICustomHelpViewer contient trois types de méthodes : les méthodes
servant à communiquer au gestionnaire d’aide les informations du niveau
système (par exemple, des informations non liées à une requête d’aide
particulière) ; les méthodes servant à afficher l’aide en fonction du mot clé fourni
par le gestionnaire d’aide ; les méthodes servant à afficher le sommaire.
pages Man (Linux), la liste de chaînes contient plusieurs chaînes, une pour
chaque section du manuel contenant une page pour ce mot clé.
void__fastcall ICustomHelpViewer::ShowHelp(const AnsiString HelpString)
est appelée par le gestionnaire d’aide s’il a besoin que le visualiseur d’aide
affiche de l’aide sur un mot clé particulier. C’est le dernier appel de méthode de
l’opération ; elle n’est jamais appelée sauf si UnderstandsKeyword a été invoquée
au préalable.
Implémentation de IExtendedHelpViewer
ICustomHelpViewer est seule à fournir un support direct de l’aide par mot clé.
Certains systèmes d’aide (spécialement WinHelp) opèrent en associant un
nombre (appelé ID de contexte) aux mots clés, de manière interne au système
d’aide et donc de manière invisible pour l’application. De tels systèmes
nécessitent que l’application supporte l’aide par contexte, où l’application
invoque le système d’aide avec un nombre plutôt qu’une chaîne, et que le
système d’aide effectue la traduction du nombre.
Les applications écrites en CLX ou VCL peuvent communiquer avec les systèmes
utilisant l’aide contextuel, en étendant l’objet qui implémente ICustomHelpViewer
afin qu’il implémente également IExtendedHelpViewer. IExtendedHelpViewer prend
aussi en charge la communication avec les systèmes d’aide vous permettant
d’aller directement aux rubriques de haut niveau au lieu d’utiliser les recherches
par mot clé. Le visualiseur intégré WinHelp le fait automatiquement.
IExtendedHelpViewer expose quatre fonctions. Deux d’entre elles,
UnderstandsContext et DisplayHelpByContext, sont utilisées pour supporter l’aide
par contexte ; les deux autres, UnderstandsTopic et DisplayTopic, sont utilisées pour
supporter les rubriques.
Lorsque l’utilisateur d’une application appuie sur F1, le gestionnaire d’aide
appelle
int__fastcall IExtendedHelpViewer::UnderstandsContext(const int ContextID, AnsiString
HelpFileName)
et le contrôle actif prend en charge l’aide par contexte et non l’aide par mot clé.
Comme poure ICustomHelpViewer::UnderstandsKeyword(), le gestionnaire d’aide
interroge successivement tous les visualiseurs d’aide recensés. Mais, au contraire
de ICustomHelpViewer::UnderstandsKeyword(), si plusieurs visualiseurs gèrent un
contexte spécifié, c’est le premier visualiseur recensé et gérant le contexte qui est
invoqué.
Le gestionnaire d’aide appelle
void__fastcall IExtendedHelpViewer::DisplayHelpByContext(const int ContextID, AnsiString
HelpFileName)
après avoir consulté les visualiseurs d’aide recensés.
Les fonctions de support des rubriques se comportent de la même façon :
bool__fastcall IExtendedHelpViewer::UnderstandsTopic(const AnsiString Topic)
est utilisée pour demander aux visualiseurs d’aide s’ils supportent une rubrique ;
void__fastcall IExtendedHelpViewer::DisplayTopic(const AnsiString Topic)
est utilisée pour invoquer le premier visualiseur recensé indiquant qu’il peut
fournir de l’aide sur cette rubrique.
Implémentation de IHelpSelector
IHelpSelector est un compagnon de ICustomHelpViewer. Lorsque plusieurs
visualiseurs recensés peuvent assurer le support du mot clé, du contexte ou de la
rubrique spécifié, ou peuvent fournir un sommaire, le gestionnaire d’aide doit
faire un choix entre eux. Dans le cas des contextes ou des rubriques, le
gestionnaire d’aide sélectionne toujours le premier visualiseur d’aide prétendant
assurer le support. Dans le cas des mots clés ou des sommaires, le gestionnaire
d’aide, par défaut, sélectionne le premier visualiseur d’aide. Ce comportement
peut être redéfini par une application.
Pour supplanter la décision du gestionnaire d’aide, une application doit recenser
une classe fournissant une implémentation de l’interface IHelpSelector.
IHelpSelector exporte deux fonctions : SelectKeyword et TableOfContents. Les deux
acceptent comme argument un TStrings contenant, l’un à la suite de l’autre, soit
les correspondances possibles des mots clés, soit les noms des visualiseurs
pouvant fournir un sommaire. L’implémenteur est nécessaire pour renvoyer
l’indice (dans le TStringList) représentant la chaîne sélectionnée, puis le
TStringList est libéré par le gestionnaire d’aide
Remarque Le gestionnaire d’aide risque de se tromper si les chaînes sont réarrangées ; il est
conseillé que les implémenteurs de IHelpSelector ne le fassent pas. Le système
Les quatre fonctions prennent les données qui leurs sont transmises et les font
suivre via une donnée membre de TApplication qui représente le système d’aide.
Cette donnée membre est directement accessible via la propriété HelpSystem.
Utilisation de IHelpSystem
IHelpSystem permet à l’application VCL ou CLX de réaliser trois choses :
• Fournit au gestionnaire d’aide les informations de chemin d’accès.
• Fournit un nouveau sélecteur d’aide.
• Demande au gestionnaire d’aide d’afficher l’aide.
Assigner un sélecteur d’aide permet au gestionnaire d’aide de déléguer la prise
de décision au cas où plusieurs systèmes d’aide externes peuvent apporter l’aide
pour le même mot clé. Pour plus d’informations, voir la section “Implémentation
de IHelpSelector” à la page 7-35.
IHelpSystem exporte quatre procédure et une fonction utilisées pour demander au
gestionnaire d’aide d’afficher l’aide :
• ShowHelp
• ShowContextHelp
• ShowTopicHelp
• ShowTableOfContents
• Hook
Hook est entièrement destinée à la compatibilité WinHelp et ne doit pas être
utilisée dans une application CLX ; elle permet le traitement des messages
WM_HELP qui ne peuvent pas être directement traduits en requêtes d’aide basée
sur un mot clé, un contexte ou une rubrique. Les autres méthodes prennent
chacune deux arguments : le mot clé, l’ID de contexte ou la rubrique pour lequel
l’aide est demandée, et le fichier d’aide dans lequel on s’attend à la trouver.
En général, sauf si vous demandez une aide par rubrique, il est aussi efficace et
plus clair de transmettre les requêtes au gestionnaire d’aide via la méthode
InvokeHelp de votre contrôle.
Manipulation de l’application
La variable globale Application de type TApplication se trouve dans chaque
application utilisant la VCL ou la CLX. Application encapsule l’application et
propose de nombreux services fonctionnant en arrière-plan du programme. Ainsi,
Application gère la manière d’appeler un fichier d’aide depuis les menus de votre
programme. La compréhension du fonctionnement de TApplication est plus
importante pour le concepteur de composants que pour le développeur
d’applications autonomes, mais vous devez définir les options gérées par
Application dans la page Application de la boîte de dialogue Options de projet
(Projet|Options) quand vous créez un projet.
De plus, Application reçoit de nombreux événements qui s’appliquent à
l’application dans son ensemble. Par exemple, l’événement OnActivate vous
permet de réaliser des actions au démarrage de l’application, l’événement OnIdle
vous permet d’exécuter des traitements en arrière-plan lorsque l’application n’est
pas occupée, l’événement OnMessage vous permet d’intercepter les messages
Windows (sous Windows uniquement), l’événement OnEvent vous permet
d’intercepter des événements, etc. Bien que vous ne puissiez pas utiliser l’EDI
pour examiner les propriétés et les événements de la variable globale Application,
un autre composant, TApplicationEvents, intercepte les événements et vous permet
de fournir les gestionnaires d’événements à l’aide de l’EDI.
Gestion de l’écran
Une variable globale de type TScreen, appelée Screen, est créée lors de la création
d’un projet. Screen encapsule l’état de l’écran dans lequel l’application s’exécute.
Parmi les fonctions imparties à Screen, il y a
• La gestion de l’aspect du curseur.
• La taille de la fenêtre dans laquelle s’exécute l’application.
• La liste des fontes disponibles pour le périphérique écran.
• Divers aspects de l’écran (Windows uniquement).
Si votre application Windows s’exécute sur plusieurs moniteurs, Screen gère une
liste des moniteurs et leurs dimensions afin que vous puissiez effectivement
gérer la disposition de l’interface utilisateur.
Lors de l’utilisation de la CLX pour la programmation multiplate-forme, le
comportement par défaut est le suivant : les applications créent un composant
écran en fonction des informations concernant le périphérique d’écran en cours
et l’assigne à Screen.
Ajout de fiches
Pour ajouter une fiche à votre projet, sélectionnez Fichier|Nouveau|Fiche.
Toutes les fiches d’un projet ainsi que les unités correspondantes sont affichées
dans le gestionnaire de projet (Voir|Gestionnaire de projet) et vous pouvez
afficher la liste des fiches en choisissant Voir|Fiches.
Liaison de fiches
L’ajout d’une fiche au projet ajoute au fichier projet une référence à cette fiche
mais pas aux autres unités du projet. Avant d’écrire du code faisant référence à
la nouvelle fiche, vous devez ajouter une référence à cette fiche dans les fichiers
unité des fiches y faisant référence. Cela s’appelle la liaison de fiche.
La liaison de fiche est fréquemment utilisée pour donner accès aux composants
contenus dans une autre fiche. Par exemple, la liaison de fiche est souvent
employée pour permettre à une fiche contenant des composants orientés données
de se connecter aux composants d’accès aux données d’un module de données.
Pour lier une fiche à une autre fiche :
1 Sélectionnez la fiche qui fait référence à une autre.
2 Choisissez Fichier|Inclure l’en-tête d’unité.
3 Sélectionnez le nom de l’unité de la fiche qui doit être référencée.
4 Choisissez OK.
La liaison d’une fiche à une autre se traduit simplement par le fait qu’une fiche
contient l’en-tête de l’unité de l’autre fiche. Par conséquent, la fiche liée et ses
composants se trouvent maintenant dans la portée de l’autre fiche.
Gestion de la disposition
A son niveau le plus élémentaire, vous contrôlez l’organisation de votre interface
utilisateur par la manière de disposer les contrôles dans les fiches. Le choix des
emplacements est reflété par les propriétés Top, Left, Width et Height des
contrôles. Vous pouvez modifier ces valeurs à l’exécution afin de modifier la
position ou la taille des contrôles dans les fiches.
Les contrôles disposent de nombreuses autres propriétés qui leur permettent de
s’adapter automatiquement à leur contenu ou à leur conteneur. Cela vous permet
d’organiser les fiches de telle manière que les différents éléments forment un
tout unifié.
Deux propriétés contrôlent la position et la taille d’un contrôle relativement à
celle de son parent. La propriété Align vous permet d’obliger un contrôle à
s’adapter exactement à un côté spécifié de son parent ou à occuper toute la place
disponible de la zone client du parent une fois les autres contrôles alignés.
Quand le parent est redimensionné, les contrôles alignés sont automatiquement
redimensionnés et restent positionnés le long d’un côté donné du parent.
Si vous voulez qu’un contrôle reste positionné relativement à un côté particulier
de son parent sans toucher ce bord ou être redimensionné pour occuper la
totalité du côté, vous pouvez utiliser la propriété Anchors.
Pour vous assurer qu’un contrôle ne devient ni trop grand ni trop petit, vous
pouvez utiliser la propriété Constraints. Constraints vous permet de spécifier la
hauteur maximum, la hauteur minimum, la largeur maximum et la largeur
minimum du contrôle. Initialisez ces valeurs afin de limiter la taille (en pixels)
de la hauteur et de la largeur du contrôle. Ainsi, en initialisant les contraintes
MinWidth et MinHeight d’un objet conteneur, vous êtes certain que ses objets
enfant sont toujours visibles.
La valeur de Constraints se propage le long de la hiérarchie parent/enfant de
telle manière que la taille d’un objet peut être restreinte car il contient des
enfants alignés qui ont des contraintes de taille. Constraints peut également
empêcher un contrôle d’être mis à l’échelle dans une dimension particulière lors
de l’appel de sa méthode ChangeScale.
fichier en-tête (.h) de la fiche peut accéder à la fiche par l’intermédiaire de cette
variable.
Comme la fiche est ajoutée au point d’entrée principal de l’application, elle
apparaît lorsque le programme est exécuté et existe en mémoire pour la durée de
l’application.
Bien entendu, vous ne pouvez pas utiliser de variables locales pour les fiches
non modales dans les gestionnaires d’événements car elles doivent avoir une
portée globale pour garantir que la fiche existe aussi longtemps qu’elle est
utilisée. Show rend la main dès que la fiche est ouverte, donc si vous utilisez une
variable locale, la variable locale sort de portée immédiatement.
Par exemple, le gestionnaire OnClick suivant d’un bouton de la fiche crée une
instance de TResultsForm en utilisant le paramètre supplémentaire :
void __fastcall TMainMForm::SecondButtonClick(TObject *Sender)
{
TResultsForm *rf = new TResultsForm(2, this);
rf->ShowModal();
delete rf;
}
il est possible de l’interroger via ses propriétés et ses fonctions membres tout
comme les fiches non modales de l’exemple précédent. Mais comment faire si la
fiche B est retirée de la mémoire une fois fermée ? Comme une fiche ne renvoie
pas explicitement de valeur, il est nécessaire de préserver les informations
importantes de la fiche avant de la détruire.
Pour illustrer cette manière de procéder, considérez une version modifiée de la
fiche ColorForm conçue comme une fiche modale. Sa classe est déclarée de la
manière suivante :
class TColorForm : public TForm
{
__published: // Composants gérés par l’EDI
TListBox *ColorListBox;
TButton *SelectButton;
TButton *CancelButton;
void __fastcall CancelButtonClick(TObject *Sender);
void __fastcall SelectButtonClick(TObject *Sender);
private: // Déclarations de l’utilisateur
String* curColor;
public: // Déclarations de l’utilisateur
virtual __fastcall TColorForm(TComponent* Owner);
virtual __fastcall TColorForm(String* s, TComponent* Owner);
};
La fiche contient une boîte liste nommée ColorListBox contenant une liste de
noms de couleur. Quand il est choisi, le bouton nommé SelectButton mémorise le
nom de la couleur sélectionnée dans ColorListBox puis ferme la fiche.
CancelButton est un bouton qui ferme simplement la fiche.
Remarquez l’ajout à la déclaration de la classe d’un constructeur défini par
l’utilisateur qui attend un argument String*. Normalement, ce paramètre String*
pointe sur une chaîne gérée par la fiche qui déclenche ColorForm. Ce constructeur
a l’implémentation suivante :
void__fastcall TColorForm::TColorForm(String* s, TComponent* Owner)
: TForm(Owner)
{
curColor = s;
*curColor = "";
}
Le constructeur enregistre le pointeur dans une donnée membre privée curColor
et initialise la chaîne avec une chaîne vide.
Remarque Pour utiliser ce constructeur défini par l’utilisateur, la fiche doit être créée
explicitement. Ce ne peut pas être une fiche auto-créée au démarrage de
l’application. Pour davantage d’informations, voir “Contrôle du stockage en
mémoire des fiches” à la page 8-5.
Dans l’application, l’utilisateur sélectionne une couleur dans la boîte liste puis
clique sur le bouton SelectButton pour enregistrer son choix et fermer la fiche.
Création de cadres
Pour créer un cadre vide, choisissez Fichier|Nouveau|Cadre, ou Fichier|
Nouveau|Autre et double-cliquez sur Cadre. Vous pouvez alors déposer des
composants (y compris d’autres cadres) sur le nouveau cadre.
Il est généralement préférable, bien que non nécessaire, d’enregistrer les cadres
en tant que partie d’un projet. Si vous souhaitez créer un projet ne contenant
que des cadres et aucune fiche, choisissez Fichier|Nouveau|Application, fermez
la nouvelle fiche et la nouvelle unité sans les enregistrer, puis choisissez Fichier|
Nouveau|Cadre et enregistrez le projet.
Remarque Lorsque vous enregistrez des cadres, évitez d’utiliser les noms par défaut Unit1,
Project1 etc., car ils peuvent être à la source de conflits au moment de
l’utilisation ultérieure des cadres.
A la conception, vous pouvez afficher n’importe quel cadre contenu dans le
projet en cours en choisissant Voir|Fiches et en sélectionnant le cadre. Comme
dans le cas des fiches et des modules de données, vous pouvez passer du
concepteur de fiche au fichier fiche du cadre en cliquant avec le bouton droit et
en choisissant Voir comme fiche ou Voir comme texte.
cadre incorporé, mais que les modifications apportées au cadre incorporé ne sont
pas répercutées sur le cadre ancêtre.
Supposons que vous souhaitiez regrouper des composants d’accès aux données
et des contrôles orientés données en vue d’une utilisation fréquente,
éventuellement dans plusieurs applications. Pour ce faire, vous pourriez
rassembler les composants dans un modèle de composant ; mais si vous
commencez à utiliser le modèle et changez d’avis ultérieurement sur
l’organisation des contrôles, vous devez faire marche arrière et modifier
manuellement dans chaque projet la partie sur laquelle le modèle a été placé.
Par contre, si vous placez vos composants base de données dans un cadre, les
modifications ultérieures ne doivent être apportées que dans un seul endroit ; les
modifications apportées à un cadre d’origine sont automatiquement répercutées
sur ses descendants incorporés lors de la recompilation des projets.
Parallèlement, vous pouvez modifier n’importe quel cadre incorporé sans affecter
le cadre d’origine ni aucun de ses descendants incorporés. La seule restriction à
la modification des cadres incorporés est que vous ne pouvez pas leur ajouter
des composants.
Figure 8.1 Cadre avec des contrôles orientés données et un composant source de données
L’exemple de code suivant peut être placé dans une Action et lié à la propriété
Action du sous-élément d’un menu TMainMenu ou placé dans l’événement
OnClick du sous-élément :
if(OpenDialog1->Execute()){
filename = OpenDialog1->FileName;
};
Ce code affiche la boîte de dialogue et si l’utilisateur choisit le bouton OK, le
nom du fichier sélectionné est copié dans la variable filename de type AnsiString
préalablement déclarée.
Pour ajouter des actions définies par l’utilisateur, créez une nouvelle TAction en
cliquant sur le bouton Nouvelle action et en écrivant le gestionnaire d’événement
qui définit la réponse qu’elle donnera à son déclenchement. Voir “Que se passe-
t-il lors du déclenchement d’une action ?” à la page 8-27 pour plus de détails.
Lorsque vous avez défini les actions, vous pouvez les placer dans les menus ou
les barres d’outils par glisser-déplacer comme les actions standard.
4 Terminez l’application.
Lorsque vous compilez et exécutez l’application, les utilisateurs ont accès à une
commande Personnaliser qui affiche une boîte de dialogue de personnalisation
semblable à l’éditeur du gestionnaire d’actions. Ils peuvent “glisser-déplacer” des
éléments de menu et créer des barres d’outils en utilisant les actions que vous
avez fournies dans le gestionnaire d’actions.
Cacher les éléments et les catégories inutilisés dans les bandes d’actions
Un des avantages de l’utilisation des ActionBands est que les éléments et les
catégories inutilisés peuvent être cachés à l’utilisateur. Avec le temps, les bandes
d’actions s’adaptent aux utilisateurs de l’application en montrant les éléments
qu’ils utilisent et en cachant les autres. Les éléments cachés peuvent redevenir
visibles : il suffit que l’utilisateur appuie sur un bouton déroulant. De plus,
l’utilisateur peut restaurer la visibilité de tous les éléments d’une bande d’action
en réinitialisant les statistiques d’usage dans la boîte de dialogue de
personnalisation. Le masquage des éléments fait partie du comportement par
défaut des bandes d’actions, mais ce comportement peut être modifié afin
d’inhiber le masquage d’éléments particuliers, de tous les éléments d’une
collection particulière (par exemple, le menu Fichier), ou de tous les éléments
d’une bande d’action particulière.
Le gestionnaire d’actions mémorise le nombre de fois qu’une action a été
invoquée par l’utilisateur en l’enregistrant dans le champ UsageCount du
TActionClientItem correspondant. Le gestionnaire d’actions enregistre également le
nombre de fois que l’application a été exécutée (ce qui correspond au numéro de
la dernière session), ainsi que le numéro de la session où une action a été utilisée
pour la dernière fois. La valeur de UsageCount sert à rechercher le nombre
maximal de sessions pendant lesquelles un élément est inutilisé avant d’être
masqué, il ensuite est comparé avec la différence entre le numéro de session
actuel et le numéro de session de la dernière utilisation de l’élément. Si cette
différence est supérieure au nombre défini dans PrioritySchedule, l’élément est
caché. Les valeurs par défaut de PrioritySchedule sont indiquées dans le tableau
suivant :
ou
3 Créez une nouvelle action qui vous sera propre : cliquez avec le bouton
droit et choisissez Nouvelle action.
3 Définissez les propriétés de chaque action dans l’inspecteur d’objets. Les
propriétés que vous définissez affectent chaque client de l’action.
La propriété Name identifie l’action, les autres propriétés et événements
(Caption, Checked, Enabled, HelpContext, Hint, ImageIndex, ShortCut, Visible et
Execute) correspondent aux propriétés et événements de ses contrôles client.
Elles portent généralement, mais pas obligatoirement, le même nom que la
propriété du client. Par exemple, la propriété Enabled d’une action correspond
à la propriété Enabled d’un TToolButton. Mais, la propriété Checked d’une action
correspond à la propriété Down d’un TToolButton.
4 Si vous utilisez les actions prédéfinies, l’action inclut une réponse standard qui
intervient automatiquement. Si vous créez votre propre action, vous devez
écrire un gestionnaire d’événement définissant comment l’action répond
lorsqu’elle est déclenchée. Voir “Que se passe-t-il lors du déclenchement d’une
action ?” à la page 8-27 pour plus de détails.
5 Attachez les actions de la liste d’actions aux clients qui le nécessitent :
• Cliquez sur le contrôle (par exemple, le bouton ou l’élément de menu) dans
la fiche ou le module de données. Dans l’inspecteur d’objets, la propriété
Action est la liste des actions disponibles.
• Sélectionnez celle que vous souhaitez.
Les actions standard, comme TEditDelete ou TDataSetPost, accomplissent l’action
attendue. L’aide en ligne de référence peut vous donner tous les détails sur le
fonctionnement de chacune des actions standard. Si vous écrivez vos propres
actions, vous aurez besoin de mieux comprendre ce qui se passe lorsqu’une
action est déclenchée.
Vous pouvez fournir un gestionnaire d’événement qui réponde à l’un des trois
différents niveaux : action, liste d’actions ou application. Cela ne vous concerne
que si vous utilisez une nouvelle action générique et non une action standard
prédéfinie. En effet, les actions standard ont un comportement intégré qui
s’exécute automatiquement lorsque ces événements se produisent.
L’ordre dans lequel les gestionnaires d’événements répondront aux événements
est le suivant :
• Liste d’actions
• Application
• Action
Lorsque l’utilisateur clique sur un contrôle client, C++Builder appelle la méthode
Execute de l’action qui s’adresse d’abord à la liste d’actions, puis à l’objet
Application, enfin à l’action elle-même lorsque ni la liste d’actions ni
l’application ne la gère. C++Builder suit cette séquence de répartition lors de la
recherche d’une façon de répondre à l’action de l’utilisateur :
1 Si vous fournissez un gestionnaire d’événement OnExecute pour la liste
d’actions et qu’il gère l’action, l’application se poursuit.
Le gestionnaire d’événement de la liste d’actions dispose d’un paramètre
Handled qui renvoie false par défaut. Si le gestionnaire est défini et gère
l’événement, il renvoie true et la séquence de traitement s’arrête là. Par
exemple :
void __fastcall TForm1::ActionList1ExecuteAction(TBasicAction *Action, bool &Handled)
{
Handled = true;
}
Si vous ne définissez pas Handled par true dans le gestionnaire d’événement
de la liste d’actions, le traitement se poursuit.
2 Si vous n’avez pas écrit de gestionnaire d’événement OnExecute pour la liste
d’actions ou si le gestionnaire ne gère pas l’action, le gestionnaire d’événement
OnActionExecute de l’application est déclenché. S’il gère l’action, l’application
continue.
L’objet Application global reçoit un événement OnActionExecute si l’une des
listes d’actions de l’application échoue en gérant un événement. Comme le
gestionnaire d’événement OnExecute de la liste d’actions, le gestionnaire
OnActionExecute dispose d’un paramètre Handled qui renvoie false par défaut.
Si un gestionnaire d’événement est défini et gère l’événement, il renvoie true
et la séquence de traitement s’arrête ici. Par exemple :
void __fastcall TForm1::ApplicationExecuteAction(TBasicAction *Action, bool &Handled)
{
// Empêche l’exécution de toutes les actions de Application
Handled = true;
}
3 Si le gestionnaire d’événement OnExecute de l’application ne gère pas l’action,
le gestionnaire d’événement OnExecute de l’action est déclenché.
Vous pouvez utiliser des actions intégrées ou créer vos propres classes d’actions
qui savent comment opérer sur des classes cibles spécifiques (telles que les
contrôles de saisie). Quand aucun gestionnaire d’événement n’est trouvé à
n’importe quel niveau, l’application essaie ensuite de trouver une cible sur
laquelle exécuter l’action. Quand l’application trouve une cible pour laquelle
l’action sait quoi faire, elle déclenche l’action. Voir la section suivante pour
davantage d’informations sur la manière dont l’application trouve une cible
pouvant correspondre à une classe d’actions prédéfinie.
Attention Ne placez pas de code nécessitant une exécution longue dans le gestionnaire
d’événement OnUpdate. En effet, il est exécuté à chaque fois que l’application est
inactive. Si l’exécution de ce gestionnaire d’événement est trop longue, les
performances de toute l’application s’en trouvent affectées.
Tous les objets action sont décrits sous leur nom dans l’aide en ligne de
référence. Reportez-vous à l’aide pour avoir des détails sur leur fonctionnement.
Méthode Description
HandlesTarget Automatiquement appelée lorsque l’utilisateur invoque un objet (comme
un bouton de barre d’outils ou un élément de menu) lié à l’action. La
méthode HandlesTarget laisse l’objet action indiquer s’il convient de
l’exécuter à ce moment avec comme “cible” l’objet spécifié par le
paramètre Target. Voir “Comment les actions trouvent leurs cibles” à la
page 8-29 pour plus de détails.
Méthode Description
UpdateTarget Automatiquement appelée lorsque l’application est inactive pour que les
actions puissent se mettre à jour elles-mêmes en fonction des conditions
en cours. Utilisez à la place de OnUpdateAction. Voir “Actualisation des
actions” à la page 8-29 pour plus de détails.
ExecuteTarget Automatiquement appelée lorsque l’action est déclenchée en réponse à
une action de l’utilisateur à la place de OnExecute (par exemple, quand
l’utilisateur sélectionne un élément de menu ou appuie sur un bouton de
barre d’outils qui est lié à cette action). Voir “Que se passe-t-il lors du
déclenchement d’une action ?” à la page 8-27 pour plus de détails.
Recensement d’actions
Si vous écrivez vos propres actions, il est possible de les recenser pour les faire
apparaître dans l’éditeur de liste d’actions. Vous les recensez ou vous en annulez
le recensement en utilisant les routines globales de l’unité ActnList :
extern PACKAGE void __fastcall RegisterActions(const AnsiString CategoryName, TMetaClass*
const * AClasses, const int AClasses_Size, TMetaClass* Resource);
extern PACKAGE void __fastcall UnRegisterActions(TMetaClass* const * AClasses, const int
AClasses_Size);
Quand vous appelez RegisterActions, les actions recensées apparaissent dans
l’éditeur de liste d’actions afin d’être utilisées dans vos applications. Vous
pouvez spécifier un nom de catégorie afin d’organiser vos actions, ainsi qu’un
paramètre Resource permettant de fournir des valeurs de propriété par défaut.
Par exemple, le code suivant recense dans l’EDI les actions de l’unité MyAction :
namespace MyAction
{
void __fastcall PACKAGE Register()
{
// du code vient ici pour recenser des composants et des éditeurs
TMetaClass classes[2] = {__classid(TMyAction1), __classid(TMyAction2)};
RegisterActions("MySpecialActions", classes, 1, NULL);
}
}
Quand vous appelez UnRegisterActions, les actions n’apparaissent plus dans
l’éditeur de liste d’actions.
Ligne de
séparation Raccourci clavier
ou
• Dans la page Propriétés de l’inspecteur d’objets, sélectionnez la propriété Items
puis double-cliquez sur [Menu] dans la colonne des valeurs ou cliquez sur le
bouton points de suspension (...).
Le concepteur de menus apparaît, le premier élément de menu (vide) est
sélectionné dans le concepteur et la propriété Caption est sélectionnée dans
l’inspecteur d’objets.
Figure 8.5 Concepteur pour un menu surgissant
Emplacement pour le
premier élément de menu
Si, par exemple, vous spécifiez Fichier comme valeur de la propriété Caption,
C++Builder affecte la valeur Fichier1 à la propriété Name de l’élément de
menu. Si vous renseignez d’abord la propriété Name avant de renseigner la
propriété Caption, C++Builder laisse la propriété Caption vide jusqu’à ce que
vous saisissiez une valeur.
Remarque Si vous saisissez dans la propriété Caption des caractères qui ne sont pas
autorisés dans un identificateur C++, C++Builder modifie la propriété Name en
conséquence. Si par exemple, l’intitulé commence par un chiffre, C++Builder
fait précéder le chiffre d’un caractère pour en dériver la valeur de la propriété
Name.
Le tableau suivant donne des exemples de ce processus en supposant que tous
ces éléments sont placés dans la même barre de menu.
Emplacement
pour les éléments
de menu
Création de sous-menus
La plupart des menus d’application contiennent des listes déroulantes qui
apparaissent à côté d’un élément de menu afin de proposer des commandes
associées supplémentaires. De telles listes sont signalées par un pointeur à droite
6 Créez vos éléments de menu et vos sous-menus comme décrit plus haut.
7 Sélectionnez dans l’inspecteur d’objets l’élément de menu pour lequel vous
voulez spécifier une image et affectez à sa propriété ImageIndex le numéro
correspondant dans la liste d’images (la valeur par défaut de la propriété
ImageIndex est -1 : pas d’image affichée).
Remarque Pour un affichage correct dans les menus, utilisez des images de 16 sur 16 pixels.
Même si vous pouvez utiliser d’autres tailles pour les images placées dans les
menus, il peut y avoir des problèmes d’alignement si vous utilisez des images
plus grandes ou plus petites que 16 x 16 pixels.
Affichage du menu
Vous pouvez voir votre menu dans la fiche à la conception sans exécuter le code
de votre programme. Les composants menu surgissant sont visibles dans la fiche
à la conception, mais pas le menu surgissant lui-même. Utilisez le concepteur de
menus pour visualiser un menu surgissant à la conception.
Pour visualiser le menu :
1 Si la fiche n’est pas visible, cliquez dans la fiche ou dans le menu Voir,
choisissez la fiche que vous voulez voir.
2 Si la fiche contient plusieurs menus, sélectionnez le menu à visualiser dans la
liste déroulante de la propriété Menu de la fiche.
Le menu apparaît dans la fiche exactement tel qu’il apparaîtra à l’exécution du
programme.
Cette boîte de dialogue énumère tous les menus associés à la fiche dont les
menus sont ouverts dans le concepteur de menus.
2 Dans la liste de la boîte de dialogue Sélection de menu, choisissez le menu
que vous voulez voir ou modifier.
Pour utiliser l’inspecteur d’objets afin de passer d’un menu de la fiche à un
autre :
1 Attribuez la focalisation à la fiche dans laquelle vous voulez choisir un menu.
2 Dans la liste des composants, sélectionnez le menu à éditer.
3 Dans la page Propriétés de l’inspecteur d’objets, sélectionnez la propriété Items
de ce menu, puis cliquez sur le bouton points de suspension ou double-
cliquez sur [Menu].
2 Sélectionnez le modèle de menu que vous voulez insérer, puis appuyez sur
Entrée ou choisissez OK.
Cela insère le menu dans votre fiche à l’emplacement du curseur. Si, par
exemple, le curseur est positionné sur un élément de menu d’une liste, le
modèle de menu est inséré au-dessus de l’élément sélectionné. Si le curseur
est dans une barre de menus, le modèle de menu est inséré à gauche du
curseur.
Pour supprimer un modèle de menu,
1 Cliquez avec le bouton droit de la souris dans le concepteur de menus et
choisissez Supprimer des modèles.
(S’il n’y a pas de modèle, l’option Supprimer des modèles est estompée dans
le menu contextuel.)
La boîte de dialogue Suppression de modèles s’ouvre en affichant une liste
des modèles disponibles.
2 Sélectionnez le modèle de menu à supprimer et appuyez sur Suppr.
C++Builder retire le modèle de menu de la liste et du disque dur.
Les modèles de menu que vous enregistrez sont stockés dans le sous-répertoire
BIN dans des fichiers .dmt.
Pour enregistrer un menu comme modèle,
1 Concevez le menu que vous voulez pouvoir réutiliser.
Ce menu peut contenir de nombreux éléments, commandes et sous-menus :
tout dans le contenu de la fenêtre active du concepteur de menus est
enregistré comme un seul menu réutilisable.
2 Cliquez avec le bouton droit de la souris dans le concepteur de menus et
choisissez Enregistrer comme modèle. La boîte de dialogue Enregistrement de
modèle s’ouvre.
Figure 8.10 Boîte de dialogue Enregistrement de modèle pour les menus
Fusion de menus
Pour les applications MDI, comme l’application exemple éditeur de texte ou dans
les applications client OLE, le menu principal de votre application doit être
capable d’intégrer les éléments de menu d’une autre fiche ou d’un objet serveur
OLE. Ce processus s’appelle la fusion de menus. Notez que la technologie OLE est
limitée aux applications Windows et n’est pas utilisable en programmation
multiplate-forme.
Pour préparer des menus à la fusion, vous devez spécifier les valeurs de deux
propriétés :
• Menu, une propriété de la fiche.
• GroupIndex, une propriété des éléments du menu.
La hauteur par défaut d’un volet est 41 et la hauteur par défaut d’un
turbobouton est 25. Si vous affectez la valeur 8 à la propriété Top de chaque
bouton, ils sont centrés verticalement. Le paramétrage par défaut de la grille
aligne verticalement le turbobouton sur cette position.
Si, par exemple, votre application propose un outil de dessin activé par défaut,
vérifiez que le bouton correspondant de la barre d’outils est enfoncé au
démarrage de l’application. Pour ce faire, affectez une valeur non nulle à sa
propriété GroupIndex et la valeur true à sa propriété Down.
(comme les libellés ou les turboboutons), mais ils n’apparaissent pas dans des
bandes distinctes.
Types de contrôles
Chapitre 9
9
Les contrôles sont des composants visuels qui vous aident à concevoir votre
interface utilisateur.
Ce chapitre décrit les différents contrôles que vous pouvez utiliser, dont les
contrôles texte, les contrôles de saisie, les boutons, les contrôles liste, les
contrôles de regroupement, les contrôles d’affichage, les grilles, les éditeurs de
listes et les contrôles graphiques.
Pour créer un contrôle graphique, voir chapitre 54, “Création d’un contrôle
graphique”. Pour apprendre à implémenter ces contrôles, voir chapitre 6,
“Manipulation des contrôles”.
Contrôles texte
La plupart des applications utilisent des contrôles texte pour afficher du texte à
l’utilisateur. Vous pouvez utiliser :
• Les contrôles de saisie, qui permettent à l’utilisateur de saisir du texte.
Utilisez
ce composant : Quand l’utilisateur doit :
TEdit Modifier une seule ligne de texte.
TMemo Modifier plusieurs lignes de texte.
TMaskEdit Utiliser un format particulier, par exemple celui d’un code postal
ou d’un numéro de téléphone.
TRichEdit Modifier plusieurs lignes de texte en utilisant du texte mis en
forme (VCL seulement).
Utilisez ce
composant : Quand l’utilisateur doit :
TTextBrowser Afficher un fichier texte ou une page HTML simple que
l’utilisateur peut faire défiler.
TTextViewer Afficher un fichier texte ou une page HTML simple. Les
utilisateurs peuvent faire défiler la page ou cliquer sur des liens
pour voir d’autres pages et d’autres images.
TLCDNumber Afficher des informations numériques dans un format d’affichage
digital.
TLabel Afficher du texte dans un contrôle non fenêtré..
TStaticText Afficher du texte dans un contrôle fenêtré..
Contrôles de saisie
Les contrôles de saisie présentent du texte à l’utilisateur et lui permettent d’en
saisir. Le type de contrôle à employer pour contenir les informations dépend de
la taille et du format des informations.
TEdit et TMaskEdit sont de simples contrôles texte comprenant une boîte texte
d’une ligne dans laquelle vous pouvez entrer des informations. Quand la boîte
texte détient la focalisation, un point d’insertion clignotant apparaît.
Vous pouvez inclure du texte dans la boîte en donnant une valeur chaîne à sa
propriété Text. Vous contrôlez l’apparence du texte dans la boîte en donnant des
valeurs à sa propriété Font. Vous pouvez spécifier la police, la taille, la couleur et
des attributs de fonte. Ces attributs affectent tout le texte de la boîte et ne
peuvent s’appliquer individuellement à chacun des caractères.
Une boîte texte peut être conçue pour changer de taille en fonction de la taille de
la police qu’elle contient. Vous faites cela en définissant la propriété AutoSize par
true. Vous pouvez limiter le nombre de caractères que peut contenir une boîte de
texte en attribuant une valeur à la propriété MaxLength.
TMaskEdit est un contrôle d’édition spécial qui valide le texte entré par le biais
d’un masque indiquant les formats corrects du texte. Le masque peut également
formater le texte affiché à l’utilisateur.
TMemo et TRichEdit permettent d’ajouter plusieurs lignes de texte.
Libellés
Les libellés (TLabel et TStaticText (VCL uniquement)) servent à afficher du texte,
généralement ils sont placés à côté d’autres contrôles. Vous placez un libellé sur
une fiche lorsque vous avez besoin d’identifier ou d’annoter un autre composant,
comme une boîte de saisie, ou lorsque vous voulez inclure du texte dans la fiche.
Le composant libellé standard, TLabel, est un contrôle non-fenêtré (dans CLX,
non basé sur un widget), qui ne peut donc pas recevoir la focalisation ; si vous
avez besoin d’un libellé disposant d’un handle de fenêtre, utilisez à la place
TStaticText.
Les propriétés des libellés sont les suivantes :
• Caption contient la chaîne de texte du libellé.
• Font, Color et d’autres propriétés déterminent l’apparence du libellé. Chaque
libellé ne peut utiliser qu’une seule police, taille et couleur.
• FocusControl relie le contrôle libellé à un autre contrôle de la fiche. Si Caption
comporte une touche accélératrice, le contrôle spécifié dans la propriété
FocusControl obtient la focalisation quand l’utilisateur appuie sur la touche de
raccourci.
• ShowAccelChar détermine si le libellé peut afficher un caractère de raccourci
souligné. Si ShowAccelChar a la valeur true, tout caractère précédé d’un &
apparaît souligné et active une touche de raccourci.
• Transparent détermine si les éléments sur lesquels le libellé est placé (par
exemple des images) sont visibles.
Les libellés contiennent généralement du texte statique en lecture seule, que
l’utilisateur de l’application ne peut pas modifier. Vous pouvez modifier le texte
lorsque l’application est exécutée en attribuant une nouvelle valeur à la propriété
Caption. Pour ajouter à une fiche un objet texte que l’utilisateur peut faire défiler
ou modifier, utilisez TEdit.
Utilisez ce
composant : Quand l’utilisateur doit :
TScrollBar Sélectionner des valeurs dans un intervalle continu.
TTrackBar Sélectionner des valeurs dans un intervalle continu (visuellement plus
parlant qu’une barre de défilement).
TUpDown Sélectionner une valeur à l’aide d’un incrémenteur associé à un
composant de saisie (VCL seulement)
THotKey Entrer des séquences clavier Ctrl/Maj/Alt (VCL seulement).
TSpinEdit Sélectionner une valeur à l’aide d’un widget incrémenteur (CLX
seulement).
Barres de défilement
Le composant barre de défilement crée une barre de défilement utilisée pour
faire défiler le contenu d’une fenêtre, d’une fiche ou d’un autre contrôle. Le code
écrit dans le gestionnaire d’événement OnScroll détermine comment le contrôle
se comporte quand l’utilisateur fait défiler la barre de défilement.
Le composant barre de défilement est rarement utilisé car la plupart des
composants visuels disposent de leurs propres barres de défilement sans
nécessiter de programmation. Par exemple, TForm propose les propriétés
VertScrollBar et HorzScrollBar qui configurent automatiquement des barres de
défilement pour la fiche. Pour créer une région défilante dans une fiche, utilisez
TScrollBox.
Barres graduées
Une barre graduée peut définir des valeurs entières dans un intervalle continu.
Elle sert à ajuster des propriétés telle qu’une coleur, un volume ou une
luminosité. L’utilisateur déplace la glissière en la faisant glisser à une position
donnée ou en cliquant dans la barre.
• Utilisez les propriétés Max et Min pour définir les bornes supérieure et
inférieure de l’intervalle de la barre graduée.
• Position définit une position par défaut dans la barre graduée et indique à
l’exécution la valeur sélectionnée par l’utilisateur.
• Par défaut, l’utilisateur peut se déplacer d’une graduation vers le haut ou vers
le bas en utilisant les touches de déplacement correspondantes. Affectez
LineSize pour changer cet incrément.
• Affectez PageSize pour déterminer le nombre de graduations du déplacement
quand l’utilisateur appuie sur les touches Pg. Haut et Pg. Bas.
Contrôles séparateur
Un séparateur (TSplitter) placé entre deux contrôles alignés permet aux
utilisateurs de redimensionner les contrôles. Utilisés avec des composants comme
les volets ou les boîtes de groupe, les séparateurs vous permettent de
décomposer une fiche en plusieurs volets contenant chacun plusieurs contrôles.
Après avoir placé un volet ou un autre contrôle dans une fiche, ajoutez un
séparateur ayant le même alignement que le contrôle. Le dernier contrôle doit
être aligné sur le client afin qu’il remplisse tout l’espace restant quand les autres
sont redimensionnés. Vous pouvez, par exemple, placer un volet sur le bord
gauche d’une fiche, initialiser sa propriété Alignment par alLeft, puis placer un
séparateur (ayant également l’alignement alLeft) à droite du volet, et enfin placer
un autre volet (avec l’alignement alLeft ou alClient) à droite du séparateur.
Initialisez MinSize afin de spécifier la taille minimum que le séparateur doit
laisser quand il redimensionne le contrôle adjacent. Initialisez Beveled à true pour
donner au séparateur un aspect 3D.
Utilisez ce
composant : Pour :
TButton Présenter des choix de commandes avec du texte dans des boutons
TBitBtn Présenter des choix de commandes dans des boutons contenant du
texte et des glyphes
TSpeedButton Créer des groupes de boutons dans les barres d’outils
TCheckBox Présenter des options de type Oui/Non
TRadioButton Présenter un ensemble de choix mutuellement exclusifs
Utilisez ce
composant : Pour :
TToolBar Disposer des boutons et d’autres contrôles en ligne et ajuster
automatiquement leur taille et leur position
TCoolBar Afficher une collection de contrôles fenêtrés dans des bandes
déplaçables et redimensionnables (VCL seulement)
Contrôles bouton
Les utilisateurs cliquent sur les contrôles bouton pour initier des actions. Les
boutons sont libellés par du texte qui représente l’action. Vous spécifiez le texte
en attribuant une valeur chaîne à la propriété Caption. Vous pouvez aussi
sélectionner la plupart des boutons en appuyant sur une touche du clavier,
appelée raccourci clavier. Le raccourci est indiqué sur le bouton par une lettre
soulignée.
Les utilisateurs cliquent sur les contrôles bouton pour initier des actions. Vous
pouvez associer une action à un composant TButton en créant un gestionnaire
d’événement OnClick correspondant. En double-cliquant sur un bouton à la
conception, vous affichez le gestionnaire d’événement OnClick du bouton dans
l’éditeur de code.
• Affectez la valeur true à la propriété Cancel pour que le bouton déclenche son
événement OnClick quand l’utilisateur appuie sur Echap.
• Affectez la valeur true à la propriété Default pour que la touche Entrée
déclenche l’événement OnClick du bouton.
Boutons bitmap
Un bouton bitmap (BitBtn) est un contrôle bouton qui contient une image
bitmap.
• Pour attribuer un bitmap personnalisé à votre bouton, affectez la propriété
Glyph.
• Utilisez la propriété Kind pour configurer automatiquement un bouton avec
un glyphe et un comportement par défaut.
• Par défaut, le glyphe est à gauche du texte. Pour le déplacer, utilisez la
propriété Layout.
• Le glyphe et le texte sont automatiquement centrés dans le bouton. Pour
changer leur position, utilisez la propriété Margin. Margin détermine le
nombre de pixels entre le bord de l’image et le bord du bouton.
• Par défaut, l’image et le texte sont séparés par 4 pixels. Utilisez Spacing pour
augmenter ou réduire cette distance.
• Les boutons bitmap peuvent avoir 3 états : haut, bas et enfoncé. Affectez la
valeur 3 à la propriété NumGlyphs pour attribuer un bitmap différent à
chaque état.
Turboboutons
Les turboboutons, qui affichent généralement une image, peuvent fonctionner en
groupe. Ils sont souvent utilisés avec des volets pour créer des barres d’outils.
• Pour faire fonctionner des turboboutons en groupe, affectez à la propriété
GroupIndex de tous les boutons la même valeur non-nulle.
• Par défaut, des turboboutons apparaissent à l’état haut (non sélectionné). Pour
afficher un turbobouton à l’état sélectionné, affectez la valeur true à la
propriété Down.
• Si AllowAllUp a la valeur true, tous les turboboutons d’un groupe peuvent être
non sélectionnés. Affectez la valeur false à AllowAllUp pour qu’un groupe de
boutons se comporte comme un groupe de boutons radio.
Pour davantage d’informations sur les turboboutons, voir “Ajout d’une barre
d’outils en utilisant un composant volet” à la page 8-48 et “Organisation des
actions pour les barres d’outils et les menus” à la page 8-18.
Cases à cocher
Une case à cocher est une bascule qui permet à l’utilisateur de sélectionner un
état activé ou désactivé. Quand l’option est activée, la case est cochée. Sinon, la
case à cocher est vide. Vous créez des cases à cocher à l’aide de TCheckBox.
• Affectez true à Checked pour que la case soit cochée par défaut.
• Affectez true à AllowGrayed pour que la case à cocher puisse prendre trois
états : activée, désactivée et grisée.
• La propriété State indique si la case est cochée (cbChecked), non cochée
(cbUnchecked) ou grisée (cbGrayed).
Remarque Les contrôles case à cocher affichent un des deux états binaires. L’état
indéterminé est utilisé quand les autres choix rendent impossible de déterminer
la valeur en cours de la case à cocher.
Boutons radio
Les boutons radio proposent un ensemble de choix mutuellement exclusifs. Vous
pouvez créer des boutons radio individuels à l’aide de TRadioButton ou utiliser le
composant groupe de boutons radio (TRadioGroup) qui regroupe automatiquement
des boutons radio. Cela permet à l’utilisateur de sélectionner une option dans un
ensemble de choix limité. Pour davantage d’informations, voir “Regroupement
de contrôles” à la page 9-14.
Un bouton radio sélectionné s’affiche sous forme d’un cercle dont le centre est
rempli. S’il n’est pas sélectionné, le bouton radio affiche un cercle vide. Donnez
la valeur true ou false à la propriété Checked pour changer l’état visuel du
bouton radio.
Barres d’outils
Les barres d’outils permettent aisément d’organiser et de gérer des contrôles
visuels. Vous pouvez créer une barre d’outils à partir d’un composant volet et de
turboboutons, ou utiliser le composant ToolBar puis choisir Nouveau bouton dans
son menu contextuel pour chaque bouton à ajouter.
Le composant TToolBar présente plusieurs avantages : les boutons d’une barre
d’outils ont automatiquement des dimensions et un espacement homogènes, les
autres contrôles conservent leur position et hauteur relatives ; les contrôles
peuvent automatiquement passer à la ligne s’il n’y a pas assez de place
horizontalement. Le composant TToolBar propose également des options comme
la transparence, les bordures en relief et les espaces et des séparations pour
regrouper des contrôles.
Vous pouvez utiliser un ensemble d’actions regroupées sur des barres d’outils et
des menus, en utilisant des listes d’actions ou des bandes d’actions. Reportez-vous à
“Utilisation des listes d’actions” à la page 8-26 pour savoir comment utiliser les
listes d’actions avec boutons et barres d’outils.
Les barres d’outils peuvent aussi être parents d’autres contrôles, comme les
boîtes de saisie, les boîtes à options, etc.
Contrôles liste
Les listes proposent à l’utilisateur une collection d’éléments dans laquelle il peut
choisir. Plusieurs composants affichent des listes :
Utilisez ce
composant : Pour afficher :
TListBox Une liste de chaînes de texte
TCheckListBox Une liste avec une case à cocher devant chaque élément
TComboBox Une boîte de saisie avec une liste surgissante déroulante
TTreeView Une liste hiérarchique
TListView Une liste d’éléments (déplaçables) avec éventuellement des icônes,
des en-têtes et des colonnes
TIconView Une liste d’éléments ou de données, en lignes et en colonnes, sous
(CLX seulement) forme de petites ou grandes icônes.
TDateTimePicker Une boîte liste permettant de saisir des dates ou des heures
(VCL seulement)
TMonthCalendar Un calendrier permettant de sélectionner des dates (VCL seulement)
Boîtes à options
Une boîte à options (TComboBox) combine une boîte de saisie et une liste
déroulante. Quand les utilisateurs saisissent des données, en entrant du texte
dans la boîte de saisie ou en sélectionnant un élément de la liste, la valeur de la
propriété Text change. Si AutoComplete est activée, l’application recherche et
affiche la correspondance la plus proche dans la liste au fur et à mesure que
l’utilisateur tape des données.
Les trois types de boîtes à options sont : standard, déroulante (par défaut) et liste
déroulante.
• Utilisez la propriété Style pour spécifier le type de boîte à options que vous
souhaitez.
• Utilisez csDropDown si vous voulez une boîte de saisie avec une liste
déroulante. Utilisez csDropDownList pour que la boîte de saisie soit en lecture
seule (ce qui oblige les utilisateurs à sélectionner dans la liste). Initialisez la
propriété DropDownCount pour changer le nombre d’éléments affichés dans la
liste.
• Utilisez csSimple pour créer une boîte à options avec une liste fixe qui reste
toujours ouverte. Prenez soin de redimensionner la boîte à options pour que
les éléments de la liste soient affichés.
• Utilisez csOwnerDrawFixed ou csOwnerDrawVariable pour créer des boîtes à
options dessinées par le propriétaire qui affichent des éléments graphiques ou de
hauteur variable. Pour plus d’informations sur les contrôles dessinés par le
propriétaire, voir “Ajout de graphiques à des contrôles” à la page 6-12.
Pendant l’exécution, les boîtes à options CLX fonctionnent différemment des
boîtes à options VCL. Dans CLX (mais pas dans la boîte à options VCL), vous
pouvez ajouter un élément à une liste déroulante en entrant du texte et en
appuyant sur Entrée dans le champ d’édition d’une boîte à options. Vous pouvez
désactiver cette fonctionnalité en définissant InsertMode par ciNone. Il est
également possible d’ajouter des éléments vides (sans chaîne) à la liste de la
boîte à options. De plus, si vous maintenez la flèche bas enfoncée, vous ne vous
arrêtez pas au dernier élément de la liste. Vous refaites un tour en
recommençant au début.
Vues arborescentes
Une vue arborescente (TTreeView) affiche des éléments dans une table des
matières indentée. Le contrôle propose des boutons qui permettent de
développer ou de réduire les nœuds. Vous pouvez inclure des icônes en plus du
libellé des éléments et afficher différentes icônes pour indiquer si un nœud est
développé ou réduit. Vous pouvez également inclure des éléments graphiques,
par exemple des cases à cocher, afin de refléter des informations sur l’état des
éléments.
• Indent définit le nombre de pixels séparant horizontalement les éléments de
leurs parents.
• ShowButtons active l’affichage des boutons ’+’ et ’–’ pour indiquer si un
élément peut être développé.
• ShowLines active l’affichage de lignes de connexion qui montrent les relations
hiérarchiques (VCL seulement).
• ShowRoot détermine si des lignes connectent les éléments racine (VCL
seulement).
Pour lui ajouter des éléments au cours de la conception, double-cliquez sur le
contrôle vue arborescente afin d’afficher l’éditeur d’éléments TreeView. Les
éléments ajoutés deviennent la valeur de la propriété Items. Vous pouvez
modifier les éléments pendant l’exécution en utilisant les méthodes de la
propriété Items, qui est un objet de type TTreeNodes. TTreeNodes possède des
méthodes pour ajouter des éléments, supprimer des éléments et naviguer entre
les éléments dans la vue arborescente.
Les vues arborescentes peuvent afficher des colonnes et des sous-éléments
semblables aux vues liste en mode vsReport.
Vues liste
Les vues liste, créées à l’aide de TListView, affichent des listes dans divers
formats. Utilisez la propriété ViewStyle pour choisir le type de liste utilisé :
• vsIcon et vsSmallIcon affichent chaque élément sous la forme d’une icône avec
un libellé. Les utilisateurs peuvent faire glisser les éléments dans la fenêtre de
la vue liste (VCL seulement).
• vsList affiche les éléments comme icônes libellées qui ne peuvent pas être
déplacées.
• vsReport affichent les éléments à raison d’un par ligne avec des informations
organisées en colonnes. La colonne de gauche contient une petite icône et un
libellé et les autres colonnes contiennent des sous-éléments spécifiés par
l’application. Utilisez la propriété ShowColumnHeaders afin d’afficher des en-
têtes de colonne.
Regroupement de contrôles
Une interface utilisateur graphique est plus facile à utiliser quand des contrôles
et les contrôles associés sont présentés dans des groupes. C++Builder propose
plusieurs composants permettant de regrouper des composants :
Utilisez ce
composant : Pour :
TGroupBox Une boîte groupe standard avec un titre
TRadioGroup Un groupe simple de boutons radio
TPanel Un groupe de contrôles plus flexible visuellement
TScrollBox Une zone défilante contenant des contrôles
TTabControl Un ensemble d’onglets (du type classeur) mutuellement exclusifs
TPageControl Un ensemble d’onglets (du type classeur) mutuellement exclusifs avec
les pages correspondantes, chacune pouvant contenir d’autres
contrôles
THeaderControl Des en-têtes de colonne redimensionnables
Volets
Le composant TPanel constitue un conteneur générique pour d’autres contrôles.
Les volets sont généralement utilisés pour regrouper visuellement des
composants sur une fiche. Il est possible d’aligner des volets dans la fiche pour
conserver la même position relative quand la fiche est redimensionnée.
La propriété BorderWidth détermine la largeur, en pixels, de la bordure entourant
un volet.
Vous pouvez aussi placer d’autres contrôles sur un volet et utiliser la propriété
Align pour positionner correctement tous les contrôles du groupe ou de la fiche.
Vous pouvez choisir pour un volet un alignement alTop, pour que sa position
soit maintenue même si la fiche est redimensionnée.
S vous voulez que le volet paraisse élevé ou enfoncé, utilisez les propriétés
BevelOuter et BevelInner. Vous pouvez varier les valeurs de ces propriétés pour
créer différents effets visuels 3D. Remarquez que si vous voulez seulement un
biseau élevé ou enfoncé, il vaut mieux utiliser le contrôle TBevel, moins
gourmand en ressources.
Vous pouvez aussi utiliser les volets pour construire des barres d’état ou des
zones d’affichage d’information.
Boîtes de défilement
Les boîtes de défilement (TScrollBox) permettent de créer des zones défilantes à
l’intérieur d’une fiche. Souvent, les applications ont besoin d’afficher plus
d’informations qu’il ne peut apparaître dans une zone particulière. Certains
contrôles, comme les boîtes liste, les mémos ou les fiches mêmes, peuvent
automatiquement faire défiler leur contenu.
Les boîtes de défilement s’utilisent aussi pour créer des zones de défilement
(vues) multiples dans une fenêtre. Les vues sont fréquentes dans les traitements
de texte, les tableurs et les applications de gestion. Les boîtes de défilement vous
offrent davantage de souplesse en vous permettant de définir arbitrairement une
zone défilante dans une fiche.
Comme les volets et les boîtes groupe, les boîtes de défilement contiennent
d’autres contrôles, comme les objets TButton et TCheckBox. Mais, normalement
une boîte de défilement est invisible. Si les contrôles qu’elle contient ne peuvent
rentrer dans sa partie visible, la boîte de défilement affiche automatiquement des
barres de défilement.
A l’aide d’une boîte de défilement, vous pouvez aussi empêcher le défilement
dans certaines zones d’une fenêtre, par exemple dans une barre d’outils ou dans
une barre d’état (composants TPanel). Pour empêcher le défilement dans une
barre d’outils ou dans une barre d’état, cachez les barres de défilement, puis
placez une boîte de défilement dans la zone client de la fenêtre, entre la barre
d’outils et la barre d’état. Les barres de défilement associées à la boîte de
défilement sembleront appartenir à la fenêtre, mais vous pourrez seulement faire
défiler la zone se trouvant à l’intérieur de la boîte de défilement.
Contrôles onglets
Le composant contrôle onglets (TTabControl) crée un ensemble d’onglets
semblables aux séparateurs d’un classeur. Vous pouvez créer des onglets en
modifiant la propriété Tabs à l’aide de l’inspecteur d’objets ; chaque chaîne de
Tabs représente un onglet. Le contrôle onglets est un simple volet avec un seul
ensemble de composants dedans. Pour changer l’aspect du contrôle quand les
onglets sont sélectionnés, écrivez un gestionnaire d’événement OnChange.
Pour créer une boîte de dialogue multipage, utilisez plutôt un contrôle pages.
Contrôles pages
Le composant contrôle pages (TPageControl) est un ensemble de pages utilisé
pour constituer une boîte de dialogue multipage. Un contrôle pages affiche
plusieurs pages les unes sur les autres, et ce sont des objets TTabSheet. Vous
sélectionnez une page dans l’interface utilisateur en cliquant sur son onglet, en
haut du contrôle.
Pour créer une nouvelle page dans un contrôle pages lors de la conception,
cliquez avec le bouton droit de la souris sur le contrôle pages et choisissez
Nouvelle page. A l’exécution, vous ajoutez de nouvelles pages en créant l’objet
correspondant à la page et en définissant sa propriété PageControl :
TTabSheet *pTabSheet = new TTabSheet(PageControl1);
pTabSheet->PageControl = PageControl1;
Pour accéder à la page active, utilisez la propriété ActivePage. Pour changer de
page active, définissez la propriété ActivePage ou la propriété ActivePageIndex.
Contrôles en-têtes
Un contrôle en-têtes (THeaderControl) est un ensemble d’en-têtes de colonnes que
l’utilisateur peut sélectionner ou redimensionner à l’exécution. Modifiez la
propriété Sections du contrôle pour ajouter ou modifier les en-têtes. Vous pouvez
placer les sections d’en-tête au-dessus des colonnes ou des champs. Par exemple,
les sections d’en-tête peuvent être placées sur une boîte liste (TListBox).
Contrôles d’affichage
Il existe plusieurs moyens de donner à l’utilisateur des informations sur l’état
d’une application. Par exemple, certains composants, dont TForm, disposent de la
propriété Caption qui peut être définie à l’exécution. Vous pouvez également
créer des boîtes de dialogue pour afficher des messages. De plus, les composants
suivants sont particulièrement utiles pour fournir des indications visuelles à
l’exécution.
Utilisez ce composant
ou cette propriété : Pour :
TStatusBar Afficher une zone d’état (généralement en bas d’une fenêtre)
TProgressBar Afficher le pourcentage effectué d’une tâche donnée
Hint et ShowHint Activer les conseils d’aide (appelés aussi bulles d’aide)
HelpContext et HelpFile Effectuer la liaison avec le système d’aide en ligne
Barres d’état
Même si vous pouvez utiliser un volet pour créer une barre d’état, il est plus
simple d’utiliser le composant barre d’état. Par défaut, la propriété Align d’une
barre d’état a la valeur alBottom, ce qui gère à la fois la position et la taille.
Si vous voulez afficher une seule chaîne de texte à la fois dans la barre d’état,
définissez sa propriété SimplePanel par true et utilisez la propriété SimpleText
pour contrôler le texte affiché dans la barre d’état.
Vous pouvez aussi diviser une barre d’état en plusieurs zones de texte, appelées
volets. Pour créer des volets, modifiez la propriété Panels avec l’inspecteur
d’objets et spécifiez les propriétés Width, Alignment et Text de chaque volet à
l’aide de l’éditeur de volets. La propriété Text de chaque volet contient le texte
affiché dans le volet.
Barres de progression
Quand une application effectue une opération longue, vous pouvez utiliser une
barre de progression pour indiquer le pourcentage réalisé de l’opération. Une
barre de progression affiche une ligne pointillée qui progresse de gauche à
droite.
Figure 9.2 Une barre de progression
Grilles
Les grilles affichent des informations disposées en lignes et en colonnes. Si vous
concevez une application de base de données, utilisez les composants TDBGrid et
TDBCtrlGrid décrits au chapitre 19, “Utilisation de contrôles de données”. Sinon,
utilisez une grille de dessin ou une grille de chaînes standard.
Grilles de dessin
Une grille de dessin (TDrawGrid) affiche des données quelconques dans un
format tabulaire. Ecrivez un gestionnaire d’événement OnDrawCell pour remplir
les cellules de la grille.
• La méthode CellRect renvoie les coordonnées écran de la cellule spécifiée alors
que la méthode MouseToCell renvoie la colonne et la ligne de la cellule se
trouvant aux coordonnées écran spécifiées. La propriété Selection indique les
limites de la sélection de cellules en cours.
• La propriété TopRow détermine la ligne qui apparaît en haut de la grille. La
propriété LeftCol détermine la première colonne visible sur la gauche de la
grille. VisibleColCount et VisibleRowCount indiquent, respectivement, le nombre
de colonnes et de lignes visibles dans la grille.
• Vous pouvez modifier la largeur et la hauteur d’une colonne ou d’une ligne
en utilisant les propriétés ColWidths et RowHeights. Définissez l’épaisseur des
lignes du quadrillage de la grille avec la propriété GridLineWidth. Ajoutez des
barres de défilement à la grille en utilisant la propriété ScrollBars.
• Vous pouvez spécifier les colonnes ou les lignes fixes (qui ne défilent pas) à
l’aide des propriétés FixedCols et FixedRows. Attribuez une couleur aux
colonnes et aux lignes fixes en utilisant la propriété FixedColor.
• Les propriétés Options, DefaultColWidth et DefaultRowHeight affectent également
l’aspect et le comportement de la grille.
Grilles de chaînes
Le composant grille de chaînes est un descendant de TDrawGrid spécialisé afin
de simplifier l’affichage de chaînes. La propriété Cells énumère les chaînes pour
chaque cellule de la grille ; la propriété Objects énumère les objets associés à
chaque chaîne. Il est possible d’accéder à toutes les chaînes et objets associés
d’une colonne ou d’une ligne donnée en utilisant les propriétés Cols et Rows.
Contrôles graphiques
Les composants suivants facilitent l’incorporation d’éléments graphiques dans
une application.
Utilisez ce
composant : Pour afficher :
TImage des fichiers graphiques
TShape des formes géométriques
TBevel des lignes et des cadres en 3D
TPaintBox des graphiques dessinés par l’application à l’exécution
TAnimate des fichiers AVI (VCL seulement)
Ces classes contiennent les routines de dessin courantes (Repaint, Invalidate, etc.)
qui ne peuvent pas recevoir la focalisation.
Images
Le composant image affiche une image graphique : bitmap, icône ou métafichier.
La propriété Picture spécifie l’image à afficher. Utilisez les propriétés Center,
AutoSize, Stretch et Transparent pour spécifier les options d’affichage. Pour
davantage d’informations, voir “Présentation de la programmation relative aux
graphiques” à la page 10-1.
Formes
Le composant forme affiche une forme géométrique. C’est un contrôle non
fenêtré (dans CLX, non basé sur un widget), il ne peut donc pas recevoir la
saisie de l’utilisateur. La propriété Shape spécifie la forme du contrôle. Pour
modifier la couleur de la forme ou lui ajouter un motif, utilisez la propriété
Brush qui contient un objet TBrush. Les propriétés Color et Style de TBrush
contrôlent la manière dont la forme est dessinée.
Biseaux
Le composant biseau (TBevel) est une ligne qui peut apparaître en relief ou en
creux. Certains composants, comme TPanel, disposent de propriétés intégrées
pour créer des contours biseautés. Quand ces propriétés ne sont pas disponibles,
utilisez un composant TBevel pour créer des contours, des boîtes ou des cadres
biseautés.
Boîtes à peindre
Le composant boîte à peindre (TPaintBox) permet à une application de dessiner
dans une fiche. Ecrivez un gestionnaire d’événement OnPaint pour restituer
directement l’image dans le canevas (Canvas) de la boîte à peindre. Il n’est pas
possible de dessiner hors des limites d’une boîte à peindre. Pour davantage
d’informations, voir “Présentation de la programmation relative aux graphiques”
à la page 10-1.
Rafraîchissement de l’écran
A certains moments, le système d’exploitation détermine que l’apparence des
objets affichés à l’écran doit être rafraîchie. Windows génère des messages
WM_PAINT que la VCL redirige vers des gestionnaires d’événements OnPaint.
(Si vous utilisez CLX dans le cadre du développement multiplate-forme, un
événement de dessin est généré que CLX redirige vers des gestionnaires
d’événements OnPaint.) Si vous avez écrit un gestionnaire de l’événement
OnPaint pour cet objet, il est appelé lorsque vous utilisez la méthode Refresh.
Le nom généré par défaut pour le gestionnaire d’événement OnPaint dans un
fiche est FormPaint. La méthode Refresh est parfois utilisée pour rafraîchir un
composant ou une fiche. Par exemple, la méthode Refresh peut être appelée dans
Pour davantage d’informations sur ces propriétés, voir “Utilisation des propriétés
de l’objet canevas” à la page 10-5.
Le tableau suivant liste les différentes méthodes pouvant être utilisées :
Pour davantage d’informations sur ces méthodes, voir “Utilisation des méthodes
du canevas pour dessiner des objets graphiques” à la page 10-10.
chaîne de lignes droites, reliées bout à bout. Le canevas dessine toutes les lignes en
utilisant son crayon.
Dessin de lignes
Pour dessiner une ligne droite sur un canevas, utilisez la méthode LineTo du
canevas.
La méthode LineTo dessine une ligne partant de la position en cours du crayon et
allant au point spécifié, et fait du point d’arrivée de la ligne la position en cours. Le
canevas dessine la ligne en utilisant son crayon.
Par exemple, la méthode suivante dessine des lignes diagonales qui se croisent sur
une fiche, chaque fois que la fiche est peinte :
void __fastcall TForm1::FormPaint(TObject *Sender)
{
Canvas->MoveTo(0,0);
Canvas->LineTo(ClientWidth, ClientHeight);
Canvas->MoveTo(0, ClientHeight);
Canvas->LineTo(ClientWidth, 0);
}
Dessin de polylignes
En plus des lignes individuelles, le canevas peut dessiner des polylignes, qui
sont des groupes composés d’un nombre quelconque de segments de ligne reliés
entre eux.
Pour dessiner une polyligne sur un canevas, appelez la méthode Polyline du
canevas.
Le paramètre passé à la méthode Polyline est un tableau de points. Imaginez
qu’une polyligne réalise une méthode MoveTo sur le premier point et une méthode
LineTo sur chaque point successif. Si vous voulez dessiner plusieurs lignes, vous
devez savoir que Polyline est plus rapide que la méthode MoveTo et que la
méthode LineTo, car elle élimine un certain nombre d’appels supplémentaires.
La méthode suivante, par exemple, dessine un losange dans une fiche :
void __fastcall TForm1::FormPaint(TObject *Sender)
{
TPoint vertices[5];
vertices[0] = Point(0, 0);
vertices[1] = Point(50, 0);
vertices[2] = Point(75, 50);
vertices[3] = Point(25, 50);
vertices[4] = Point(0, 0);
Canvas->Polyline(vertices, 4);
}
Remarquez que le dernier paramètre de Polyline est l’indice du dernier point et
pas le nombre de points.
Dessin de formes
Les canevas disposent de méthodes vous permettant de dessiner différents types
de formes. Le canevas dessine le pourtour d’une forme avec son crayon, puis
remplit l’intérieur avec son pinceau. La ligne qui définit la bordure de la forme
est déterminée par l’objet Pen en cours.
Cette section couvre :
• Dessin de rectangles et d’ellipses
• Dessin de rectangles à coins arrondis
• Dessin de polygones
Dessin de polygones
Pour dessiner, sur un canevas, un polygone ayant un nombre quelconque de côtés,
appelez la méthode Polygon du canevas.
Polygon prend un tableau de points comme seul paramètre et relie les points avec le
crayon, puis relie le dernier point au premier de façon à fermer le polygone. Après
avoir dessiné les lignes, Polygon utilise le pinceau pour remplir la zone interne au
polygone.
Le code suivant dessine un triangle rectangle dans la moitié inférieure gauche de la
fiche :
void __fastcall TForm1::FormPaint(TObject *Sender)
{
TPoint vertices[3];
vertices[0] = Point(0, 0);
vertices[1] = Point(0, ClientHeight);
vertices[2] = Point(ClientWidth,ClientHeight);
Canvas->Polygon(vertices,2);
}
case dtEllipse:
Canvas->Ellipse(Origin.x, Origin.y, MovePt.x, MovePt.y);
Canvas->Ellipse(Origin.x, Origin.y, X, Y);
break;
case dtRoundRect:
Canvas->Rectangle(Origin.x, Origin.y, MovePt.x, MovePt.y,
(Origin.x - MovePt.x)/2,(Origin.y - MovePt.y)/2);
Canvas->Rectangle(Origin.x, Origin.y, X, Y,
(Origin.x - X)/2, (Origin.y - Y)/2);
break;
}
MovePt = Point(X, Y);
}
Canvas->Pen->Mode = pmCopy;
}
En principe, tout le code répétitif de l’exemple précédent devrait être dans une
routine séparée. La section suivante présente le code relatif au dessin des formes
dans une seule routine pouvant être appelée par tous les gestionnaires
d’événements de souris.
Positionnement du contrôle
Un contrôle image peut être placé n’importe où dans une fiche. Pour tirer le
meilleur parti de la capacité d’un contrôle image à ajuster sa taille sur celle de son
image, le seul point à définir est le coin supérieur gauche du contrôle. Si le contrôle
image sert d’emplacement non visible pour un bitmap, il peut être placé n’importe
où dans la fiche, comme un composant non visuel.
Si vous placez le contrôle image en le mettant à l’intérieur de la boîte de
défilement déjà installée dans la zone client de la fiche, vous serez sûr que la boîte
de défilement affichera des barres de défilement pour permettre l’accès aux parties
Cet exemple explique comment utiliser ScanLine pour extraire des pixels ligne
par ligne.
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Graphics::TBitmap *pBitmap = new Graphics::TBitmap();
// Cet exemple montre comment dessiner directement dans le Bitmap
Byte *ptr;
try
{
pBitmap->LoadFromFile("C:\\Program Files\\Borland\\CBuilder\\Images\\Splash\\256color\\
factory.bmp ");
for (int y = 0; y < pBitmap->Height; y++)
{
ptr = pBitmap->ScanLine[y];
for (int x = 0; x < pBitmap->Width; x++)
ptr[x] = (Byte)y;
}
Canvas->Draw(0,0,pBitmap);
}
catch (...)
{
ShowMessage("Impossible de charger ou de modifier le bitmap");
}
delete pBitmap;
}
CLX Pour les applications multiplates-formes, changez le code spécifique à Windows
et à la VCL pour que votre application s’exécute sous Linux. Par exemple, les
chemins d’accès dans Linux utilise le caractère “/” comme délimiteur. Pour
davantage d’informations sur la CLX et les applications multiplates-formes, voir
chapitre 14, “Développement d’applications multiplates-formes”.
Remplacement de l’image
Il est possible à tout moment de remplacer l’image d’un contrôle image. Si un
nouveau graphique est affecté à l’image ayant déjà un graphique, le nouveau
graphique remplace l’ancien.
Pour remplacer l’image contenue dans un contrôle image, affectez un nouveau
graphique à l’objet Picture du contrôle image.
La création d’un nouveau graphique passe par le même processus que la création
du premier graphique (voir la section “Définition de la taille initiale du bitmap” à
la page 10-19), mais il faut également permettre à l’utilisateur de choisir une taille
différente de celle utilisée par défaut pour le graphique initial. Un moyen simple de
proposer une telle option est de présenter une boîte de dialogue comme celle de la
figure suivante.
Figure 10.1 Boîte de dialogue Dimension bitmap de l’unité BMPDlg
WidthEdit
HeightEdit
Cette boîte de dialogue particulière est créée dans l’unité BMPDlg incluse dans le
projet GraphEx (répertoire EXAMPLES\DOC\GRAPHEX).
Cette boîte de dialogue étant dans votre projet, ajoutez une instruction include
pour BMPDlg.hpp dans le fichier .cpp de votre fiche principale. Vous pouvez
ensuite attacher un gestionnaire à l’événement OnClick de l’élément de menu
Fichier|Nouveau. Voici un exemple :
void __fastcall TForm1::New1Click(TObject *Sender)
{
Graphics::TBitmap *Bitmap;
// vérifier que la focalisation se trouve dans la largeur de champ
NewBMPForm->ActiveControl = NewBMPForm->WidthEdit;
// initialiser les dimensions en cours comme défaut ...
NewBMPForm->WidthEdit->Text = IntToStr(Image->Picture->Graphic->Width);
NewBMPForm->HeightEdit->Text = IntToStr(Image->Picture->Graphic->Height);
if (NewBMPForm->ShowModal() != IDCANCEL){ // Si l’utilisateur n’annule pas ...
Bitmap = new Graphics::TBitmap(); // créer un nouvel objet bitmap
// utiliser les dimensions spécifiées
Bitmap->Width = StrToInt(NewBMPForm->WidthEdit->Text);
Bitmap->Height = StrToInt(NewBMPForm->HeightEdit->Text);
Image->Picture->Graphic = Bitmap; // remplacer le graphique par le nouveau bitmap
CurrentFile = EmptyStr; //Indiquer un fichier sans nom
delete Bitmap;
}
}
Remarque L’affectation d’un nouveau bitmap à la propriété Graphic de l’objet Picture oblige
l’objet Picture à copier le nouveau graphique, mais il ne devient pas son
propriétaire. L’objet Picture maintient son propre objet graphique interne. A
cause de cela, le code précédent libère l’objet bitmap après l’affectation.
Répondre à la souris
Votre application peut répondre aux actions de la souris : enfoncement du
bouton de la souris, déplacement de la souris et relâchement du bouton de la
souris. Elle peut aussi répondre à un clic (un appui suivi d’un relâchement, sans
déplacer la souris) qui peut être généré par certaines frappes de touches (comme
l’appui sur la touche Entrée dans une boîte de dialogue modale).
Cette section traite des sujets suivants :
• Qu’y a-t’il dans un événement de souris ?
• Réponse à l’action bouton de souris enfoncé
• Réponse à l’action bouton de souris relâché
• Réponse au déplacement de la souris
Nous disposons maintenant d’un champ Drawing permettant de déterminer s’il faut
dessiner. Il faut donc l’initialiser à true lorsque l’utilisateur enfonce le bouton de la
souris et à false lorsqu’il le relâche :
void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
Drawing = true; // Définit l’indicateur de dessin
Canvas->MoveTo(X, Y); // Définit la position du crayon
}
void __fastcall TForm1::FormMouseUp(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
Canvas->LineTo(X, Y); // dessine une ligne de PenPos à (X, Y)
Drawing = false; // efface l’indicateur de dessin
}
Ensuite, vous pouvez modifier le gestionnaire de l’événement OnMouseMove de
façon à ne dessiner que si Drawing est à true :
void __fastcall TForm1::FormMouseMove(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
if (Drawing)
Canvas->LineTo(X, Y);// ne dessiner que si la souris est enfoncée
}
Désormais, le dessin n’est effectué qu’entre les événements bouton de souris
enfoncé et bouton de souris relâché, mais il y a toujours cette ligne brisée qui suit le
déplacement de la souris au lieu d’une belle ligne droite.
Le problème tient à ce qu’à chaque déplacement de la souris, le gestionnaire de
l’événement déplacement de souris appelle LineTo qui déplace la position du
crayon. Par conséquent, le point d’origine de la ligne droite est perdu lorsque le
bouton de la souris est relâché.
}
void __fastcall TForm1::FormMouseUp(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
Canvas->MoveTo(Origin.x, Origin.y); // placer le crayon sur le point de départ
Canvas->LineTo(X, Y); // dessine une ligne de PenPos à (X, Y)
Drawing = false; // efface l’indicateur de dessin
}
Cette modification permet de redessiner la ligne finale. Mais qu’en est-il des dessins
intermédiaires ?
// point de départ
Canvas->LineTo(X, Y); // dessiner la nouvelle ligne
}
MovePt = Point(X, Y); // stocker le nouveau point final
Canvas->Pen->Mode = pmCopy;
}
Maintenant, un effet satisfaisant est obtenu lorsque la ligne est dessinée. En
modifiant le mode du crayon en pmNotXor, il combine la ligne avec les pixels de
l’arrière-plan. Lorsque la ligne est effacée, les pixels sont en fait ramenés à leur état
antérieur. En remettant le mode du crayon à pmCopy (sa valeur par défaut) après
avoir dessiné les lignes, le crayon est prêt pour le dessin final lorsque le bouton de
la souris est relâché.
Utilisation du multimédia
C++Buildervous permet d’ajouter des composants multimédia à vos applications
Windows (mais pas dans les applications CLX ou Linux). Vous pouvez le faire
en ajoutant le composant TAnimate de la page Win32 ou le composant
TMediaPlayer de la page Système de la palette des composants. Utilisez le
composant animation pour jouer des séquences vidéo silencieuses dans votre
application. Utilisez le composant lecteur multimédia pour jouer des séquences
audio ou vidéo dans une application.
Pour davantage d’informations sur les composants TAnimate et TMediaPlayer, voir
l’aide en ligne de la VCL.
Cette section aborde les sujets suivants :
• Ajout de séquences vidéo silencieuses à une application
• Ajout de séquences audio et/ou vidéo à une application
#include "Unit2.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
__fastcall TMyThread::TMyThread(bool CreateSuspended): TThread(CreateSuspended)
{
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::Execute()
{
// ---- Placez le code du thread ici ----
}
//---------------------------------------------------------------------------
Initialisation du thread
Utilisez le constructeur pour initialiser la nouvelle classe thread. C’est là que
vous pouvez affecter une priorité par défaut au thread et indiquer s’il doit être
libéré automatiquement à la fin de son exécution.
Remarque Si vous écrivez une application multiplate-forme, vous devez séparer le code
destiné à attribuer les priorités pour Windows du code pour Linux. Sous Linux,
Priority est une valeur numérique qui dépend de la politique choisie pour les
threads, politique qui ne peut être modifiée que par l’utilisateur root. Voir la
version CLX de TThread et Priority dans l’aide en ligne pour plus de détails.
Attention “Gonfler” la priorité du thread pour une opération utilisant intensivement la
CPU peut “sous-alimenter” les autres threads de l’application. Il ne faut accorder
une priorité élevée qu’à des threads qui passent l’essentiel du temps à attendre
des événements extérieurs.
Le code suivant illustre le constructeur d’un thread de priorité basse qui effectue
des tâches d’arrière-plan ne devant pas interférer avec les performances du reste
de l’application :
//---------------------------------------------------------------------------
__fastcall TMyThread::TMyThread(bool CreateSuspended): TThread(CreateSuspended)
{
Priority = tpIdle;
}
//---------------------------------------------------------------------------
{
ƒ
Synchronize((TThreadMethod)PushTheButton);
ƒ
}
Synchronize attend le thread principal pour entrer dans la boucle des messages
puis exécute la méthode qui lui est transmise.
Remarque Comme Synchronize utilise la boucle des messages, elle ne fonctionne pas dans
les applications console. Vous devez utiliser d’autres mécanismes, comme les
sections critiques, pour protéger l’accès aux objets VCL ou CLX dans les
applications console.
Il n’est pas toujours nécessaire d’utiliser le thread principal. Certains objets sont
adaptés aux threads. Il est préférable de ne pas utiliser la méthode Synchronize
quand vous savez que les méthodes d’un objet sont adaptées à l’utilisation des
threads, car cela améliore les performances en évitant d’avoir à attendre le
thread VCL ou CLX pour entrer dans la boucle de messages. Il n’est pas
nécessaire d’utiliser la méthode Synchronize dans les objets suivants :
• Les composants d’accès aux données sont adaptés aux threads comme suit :
pour les ensembles de données BDE chaque thread doit disposer de son
propre composant session de base de données. Il n’y a qu’une seule
exception : les pilotes Microsoft Access. Ces pilotes sont conçus en utilisant la
bibliothèque ADO Microsoft qui n’est pas adaptée aux threads. Pour dbDirect,
il suffit que la bibliothèque client du fournisseur soit adaptée aux threads
pour que les composants dbDirect le soient également. Les composants ADO
et InterbaseExpress sont adaptés aux threads.
Lorsque vous utilisez des composants d’accès aux données, vous devez
néanmoins encadrer tous les appels aux contrôles orientés données dans la
méthode Synchronize. Ainsi, il est nécessaire de synchroniser les appels qui
relient un contrôle orienté données à un ensemble de données, mais il n’est
pas nécessaire de le faire pour accéder aux données d’un champ de l’ensemble
de données.
Pour davantage d’informations sur l’utilisation de sessions de base de données
avec les threads dans des applications BDE, voir “Gestion de sessions
multiples” à la page 24-32.
• Les objets DataCLX sont adaptés aux threads mais pas les objets VisualCLX.
• Les objets graphiques sont adaptés aux threads. Il n’est pas nécessaire
d’utiliser le thread principal VCL ou CLX pour accéder aux objets TFont, TPen,
TBrush, TBitmap, TMetafile (VCL seulement), TDrawing (CLX seulement) et
TIcon. Il est possible d’accéder aux objets canevas en dehors de la méthode
Synchronize en les verrouillant (voir “Verrouillage d’objets” à la page 11-8).
• Les listes d’objets ne sont pas adaptées aux threads, mais vous pouvez utiliser
une version adaptée aux threads, TThreadList, à la place de TList.
Appelez régulièrement la routine CheckSynchronize depuis le thread principal de
votre application pour que les threads d’arrière-plan synchronisent leur exécution
sur le thread principal. Le meilleur emplacement pour appeler CheckSynchronize
• Il est possible d’accéder en toute sécurité à tous les composants et objets VCL
ou CLX dans le gestionnaire d’événement OnTerminate sans se préoccuper des
conflits avec les autres threads.
Pour davantage d’informations sur le thread principal VCL ou CLX, voir
“Utilisation du thread principal VCL/CLX” à la page 11-4.
Coordination de threads
Quand vous écrivez le code exécuté lorsque le thread s’exécute, vous devez tenir
compte du comportement des autres threads qui peuvent s’exécuter
simultanément. En particulier, il faut éviter que deux threads tentent d’utiliser
simultanément le même objet ou la même variable globale. De plus, le code d’un
thread peut dépendre de tâches effectuées par d’autres threads.
Verrouillage d’objets
Certains objets disposent d’un verrouillage intégré qui empêche les autres
threads d’utiliser cette instance d’objet.
Ainsi, les objets canevas (TCanvas et ses descendants) ont une méthode Lock qui
empêche les autres threads d’accéder au canevas jusqu’à l’appel de la méthode
Unlock.
La VCL et CLX contiennent également tous les deux un objet liste adapté aux
threads, TThreadList. L’appel deTThreadList::LockList renvoie l’objet liste tout en
empêchant les autres threads d’exécution d’utiliser la liste jusqu’à l’appel de la
méthode UnlockList. Les appels des méthodes TCanvas::Lock et
TThreadList::LockList peuvent être imbriqués. Le verrou n’est pas libéré tant que le
dernier verrouillage n’est pas associé au déverrouillage correspondant dans le
même thread.
Chaque section critique est associée à la mémoire globale devant être protégée.
Chaque thread accédant à cette mémoire globale doit commencer par utiliser la
méthode Acquire pour vérifier qu’un autre thread n’est pas en train de l’utiliser.
Une fois terminé, le thread appelle la méthode Release afin que les autres threads
puissent accéder à la mémoire globale en appelant Acquire.
Attention Les sections critiques ne peuvent fonctionner que si tous les threads les utilisent
pour accéder à la mémoire globale associée. Les threads qui ne tiennent pas
compte des sections critiques et accèdent à la mémoire globale sans appeler
Acquire peuvent provoquer des problèmes d’accès simultanés.
Par exemple, une application a une section critique des variables globales,
pLockXY, qui bloque l’accès aux variables globales X et Y. Tout thread utilisant X
ou Y doit encadrer cette utilisation d’appels à la section critique comme ci-
dessous :
pLockXY->Acquire(); // Bloque les autres threads
try
{
Y = sin(X);
}
__finally
{
pLockXY->Release();
}
WaitFor quand elle est appelée par d’autres threads. Les valeurs renvoyées sont
des entiers. Votre application en détermine la signification.
Le code suivant montre comment le thread principal lance les threads de tâche et
reprend la main lorsque leur exécution est achevée :
Event1->ResetEvent(); // Efface l’événement avant de lancer les threads
for (int i = 0; i < Counter; i++)
new TaskThread(false); // Crée et exécute les threads de tâche
if (Event1->WaitFor(20000) != wrSignaled)
throw Exception;
// poursuivre maintenant dans le thread principal, toutes les tâches sont finies
Remarque Si vous ne voulez pas cesser d’attendre un événement après un délai spécifié,
transmettez à la méthode WaitFor une valeur de paramètre INFINITE. Faites
attention en utilisant INFINITE, car cela peut provoquer le blocage du thread si
le signal attendu n’arrive pas.
Remarque Si vous écrivez une application multiplate-forme, vous devez séparer le code
destiné à attribuer les priorités pour Windows du code pour Linux. Sous Linux,
Priority est une valeur numérique qui dépend de la politique choisie pour les
threads, politique qui ne peut être modifiée que par l’utilisateur root. Voir la
version CLX de TThread et Priority dans l’aide en ligne pour plus de détails.
Nommer un thread
Comme il est difficile de déterminer quel ID de thread correspond à quel thread
dans la boîte de dialogue Etat des threads, vous pouvez nommer vos classes de
thread. Lors de la création d’une classe de thread dans la boîte dialogue Objet
thread, outre la saisie du nom de la classe, cochez la case Thread nommé,
saisissez le nom du thead et choisissez OK.
Nommer la classe de thread ajoute à la classe une méthode appelée SetName.
Au démarrage du thread, il commence par appeler la méthode SetName.
CLX Vous ne pouvez nommer les threads que dans les applications VCL.
__try
{
RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD),(DWORD*)&info );
}
__except (EXCEPTION_CONTINUE_EXECUTION)
{
}
}
//---------------------------------------------------------------------------
Remarque Attribuez le nom de votre classe de thread à info.szName.
Le débogeur trouve l’exception et recherche le nom de thread dans la
structure transmise. Lors du débogage, le débogeur affiche le nom du thread
dans la zone ID de la boîte de dialogue Etat des threads.
2 Ajoutez un appel de la méthode SetName au début de la méthode Execute du
thread :
//---------------------------------------------------------------------------
void __fastcall TMyThread::Execute()
{
SetName();
//---- Placez ici le code existant de la méthode Execute ----
}
//---------------------------------------------------------------------------
12
Gestion des exceptions
Chapitre 12
Le bloc try
Le bloc try contient une ou plusieurs instructions qui peuvent déclencher une
exception. Un programme lance une exception en exécutant une instruction
throw. L’instruction throw se produit généralement à l’intérieur d’une fonction.
Par exemple :
void SetFieldValue(DF *dataField, int userValue)
{
if ((userValue < 0) || userValue > 10)
throw EIntegerRange(0, 10, userValue);
. . .
}
Une autre partie du programme peut intercepter l’objet exception déclenché et le
gérer en conséquence. Par exemple :
try
{
SetFieldValue(dataField, userValue);
}
catch (EIntegerRange &rangeErr)
{
printf("Valeur attendue entre %d et %d, mais obtention de %d\n",
rangeErr.min, rangeErr.max, rangeErr.value);
}
Dans l’exemple précédent, si la fonction SetFieldValue constate que ses paramètres
d’entrée sont incorrects, elle peut déclencher une exception pour indiquer cette
erreur. Le bloc try/catch encapsule SetFieldValue pour intercepter l’exception
déclenchée par SetFieldValue et exécute l’instruction printf. Si aucune exception
n’est déclenchée, l’instruction printf ne s’exécute pas.
Un bloc try spécifié par try doit être immédiatement suivi par le gestionnaire
spécifié par catch. Le bloc try est une instruction qui spécifie le flux de contrôle
au fur et à mesure que le programme s’exécute. Si une exception est déclenchée
dans ce bloc, le contrôle du programme est remis au gestionnaire d’exception
approprié.
Le gestionnaire est un bloc de code conçu pour gérer l’exception. Le langage C++
nécessite qu’il y ait au moins un gestionnaire de disponible après un bloc try.
Il doit y avoir un gestionnaire pour chaque exception susceptible d’être générée
par le programme.
L’instruction throw
L’instruction throw peut déclencher divers types d’objets. Dans C++, les objets
peuvent être déclenchés par valeur, par référence ou par pointeur. Par exemple :
// déclenche un objet à intercepter par valeur ou par référence
throw EIntegerRange(0, 10, userValue);
// déclenche un char *
throw "foo";
Dans la plupart des cas, vous intercepterez les exceptions par référence, en
particulier par référence const. Parfois, vous intercepterez avec précaution des
objets par valeur. Les objets ainsi interceptés doivent être copiés avant d’être
affectés au paramètre catch. Si un utilisateur fournit un constructeur de copie,
celui-ci est appelé, ce qui peut altérer l’efficacité.
L’instruction catch
L’instruction catch se présente sous diverses formes. Les objets peuvent être
interceptés par valeur, par référence ou par pointeur. En outre, des modificateurs
const peuvent être appliqués au paramètre catch. Pour qu’un bloc try puisse
intercepter plusieurs types d’exceptions différents, plusieurs instructions catch
peuvent être ajoutées. Dans tous les cas, il doit y avoir une instruction catch
pour chaque exception susceptible d’être déclenchée. Par exemple :
try
CommitChange(dataBase, recordMods);
catch (const EIntegerRange &rangeErr)
printf("Obtention d’une exception d’intervalle d’entiers");
catch (const EFileError &fileErr)
printf("Obtention d’une erreur d’E/S de fichier");
Si la fonction CommitChange utilise plusieurs sous-systèmes qui peuvent
déclencher différents types d’exceptions, vous pouvez gérer chaque type
d’exception séparément. Avec plusieurs instructions catch pour une seule
instruction try, vous pouvez avoir des gestionnaires pour chaque type
d’exception.
Si un objet exception est dérivé d’une classe de base, vous pouvez ajouter des
gestionnaires spécialisés pour certaines exceptions dérivées, mais aussi inclure un
gestionnaire générique pour la classe de base. Pour ce faire, placez les
instructions catch dans l’ordre dans lequel vous voulez qu’elles soient
recherchées quand une exception est déclenchée. Par exemple, le code suivant
gère d’abord EIntegerRange puis ERange, dont EIntegerRange est dérivée.
try
SetFieldValue(dataField, userValue);
catch (const EIntegerRange &rangeErr)
printf("Obtention d’une exception d’intervalle d’entiers");
catch (const ERange &rangeErr)
printf("Obtention d’une exception d’intervalle");
Enfin, si vous voulez que votre gestionnaire intercepte toutes les exceptions
susceptibles d’être déclenchées après le bloc try, utilisez la forme spéciale
catch(…). Cette instruction indique que le gestionnaire doit être invoqué pour
toutes les exceptions. Par exemple :
try
SetFieldValue(dataField, userValue);
catch (...)
printf("Obtention d’une exception quelconque");
Pointeurs sécurisés
Si vous avez des variables locales qui sont des pointeurs sur des objets et si une
exception est déclenchée, ces pointeurs ne sont pas automatiquement supprimés.
Ceci est dû au fait que le compilateur ne peut pas faire la différence entre un
pointeur sur des données qui ont été allouées à cette fonction uniquement et un
autre pointeur. Pour vous assurer que des objets alloués à une utilisation locale
sont détruits même en cas d’exception, utilisez la classe auto_ptr. Dans certains
cas, la mémoire est libérée pour un pointeur alloué dans une fonction :
TMyObject *pMyObject = new TMyObject;
Dans cet exemple, si le constructeur de TMyObject déclenche une exception, le
pointeur sur l’objet alloué à TMyObject est supprimé par la RTL quand elle
déroule l’exception. C’est le seul cas où le compilateur supprime
automatiquement une valeur de pointeur.
void my_terminate()
{
printf("Exception non interceptée");
abort();
}
// Définit my_terminate() comme fonction de terminaison
set_terminate(my_terminate);
// Appelle SetFieldValue. Ceci génère une exception car la valeur de l’utilisateur est
// supérieure à 10. Comme l’appel n’est pas dans un bloc try, my_terminate est appelée.
SetFieldValue(DF, 11);
Si une fonction spécifie les exceptions qu’elle déclenche puis déclenche une
exception non spécifiée, une fonction inattendue est appelée. Vous pouvez
spécifier votre propre fonction inattendue avec set_unexpected. Si vous ne
spécifiez aucune fonction inattendue, la fonction unexpected est appelée.
Valeur Description
EXCEPTION_CONTINUE_SEARCH (0) Pas d’entrée dans le gestionnaire et le système
d’exploitation continue de rechercher un
gestionnaire d’exception.
EXCEPTION_CONTINUE_EXECUTION (-1) Continue l’exécution au point de l’exception.
Valeur Description
EXCEPTION_EXECUTE_HANDLER (1) Entre dans le gestionnaire d’exception. Si le
code a été compilé alors que le nettoyage des
destructeurs était activé (option -xd, activée
par défaut), tous les destructeurs des objets
locaux créés entre le point de l’exception et le
gestionnaire d’exception sont appelés lorsque
la pile est déroulée. Le déroulement de la pile
prend fin avant d’entrer dans le gestionnaire.
Win32 fournit deux fonctions qui peuvent être utilisées pour obtenir des
informations sur l’exception en cours : GetExceptionCode() et
GetExceptionInformation(). Si vous voulez appeler une fonction depuis l’expression
de “filtre” présentée précédemment, elle doit l’être directement depuis le
contexte de __except() :
#include <Windows.h>
#include <excpt.h>
int filter_func(EXCEPTION_POINTERS *);
...
EXCEPTION_POINTERS *xp = 0;
try {
foo();
}
__except(filter_func(xp = GetExceptionInformation())) {
//...
}
Si vous le souhaitez, vous pouvez aussi utiliser l’opérateur virgule pour les
affectations imbriquées dans des appels de fonction, comme dans l’exemple ci-
dessous :
__except((xp = GetExceptionInformation()), filter_func(xp))
Filtres d’exceptions
Une expression filtre peut appeler une fonction filtre, mais une fonction filtre ne
peut pas appeler GetExceptionInformation. La valeur de retour de
GetExceptionInformation peut être transmise comme paramètre de la fonction filtre.
Pour transmettre les informations EXCEPTION_POINTERS à un gestionnaire
d’exceptions, l’expression filtre ou la fonction filtre doit copier le pointeur ou les
données de GetExceptionInformation à un emplacement où le gestionnaire peut
ultérieurement y accéder.
Dans le cas où des instructions try-except sont imbriquées, l’expression filtre de
chaque instruction est évaluée jusqu’à ce qu’elle trouve
EXCEPTION_EXECUTE_HANDLER ou EXCEPTION_CONTINUE_EXECUTION.
Une expression filtre peut appeler GetExceptionInformation pour obtenir des
informations sur l’exception.
switch (xr->ExceptionCode) {
case EXCEPTION_BREAKPOINT:
// hops, quelqu’un a oublié un point d’arrêt incorporé.
// passer dessus (1 octet sur x86)
++xc->Eip;
rc = EXCEPTION_CONTINUE_EXECUTION;
break;
case EXCEPTION_ACCESS_VIOLATION:
rc = EXCEPTION_EXECUTE_HANDLER;
break;
default:
// abandon
rc = EXCEPTION_CONTINUE_SEARCH;
break;
};
return rc;
}
...
EXCEPTION_POINTERS *xp;
try {
func();
}
__except(xfilter(xp = GetExceptionInformation())) {
abort();
}
try {
func();
}
__except(xfilter(xp = GetExceptionInformation())) {
//...
}
}
catch (...) {
//...
}
La spécification throw() d’une fonction n’affecte pas le comportement d’un
programme en ce qui concerne une exception Win32. En conséquence, une
exception non gérée est finalement gérée par le système d’exploitation (si un
débogueur ne la gère pas d’abord), à la différence d’un programme C++ qui
appelle terminate().
Tout module compilé avec l’option de compilation -xd (activée par défaut)
appellera les destructeurs pour tous les objets avec le stockage auto. Le
déroulement de pile se produit depuis le point où l’exception est déclenchée
jusqu’au point où elle est interceptée.
class Exception
{
public:
Exception(char* s = "Unknown"){ what = strdup(s); }
Exception(const Exception& e ){ what = strdup(e.what); }
~Exception() { delete[] what; }
char* msg() const { return what; }
private:
char* what;
};
int main()
{
float e, f, g;
try
{
try
{
f = 1.0;
g = 0.0;
try
{
puts("Une autre exception:");
e = f / g;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
puts("Interception d’une exception C.");
throw(Exception("Erreur matérielle: division par 0"));
}
}
catch(const Exception& e)
{
printf("Interception d’une exception C++ : %s :\n", e.msg());
}
}
__finally
{
puts("C++ autorise aussi __finally !");
}
return e;
}
Définition d’exceptions
Le fait de déclencher une exception Win32 gérée à l’intérieur d’un même
programme n’a pas grand intérêt : les exceptions C++ ont plus d’efficacité, sont
plus portables et utilisent une syntaxe plus simple. Les exceptions Win32 ont
toutefois un avantage : elles peuvent être gérées par des composants n’ayant pas
été compilés par le même compilateur C++.
La première étape consiste à définir l’exception. Une exception est un entier
32 bits qui a le format suivant (en commençant au bit 0) :
Bit Signification
31-30 11 = erreur (normal)
00 = réussite,
01 = informatif
10 = avertissement
29 1 = défini par
l’utilisateur
28 Réservé
27-0 Défini par
l’utilisateur
Déclenchement d’exceptions
Une exception Win32 est déclenchée par un appel à RaiseException(), qui est
déclarée comme suit :
void RaiseException(DWORD ec, DWORD ef, DWORD na, const DWORD *a);
où :
ec Code d’exception
ef Indicateurs d’exception (0 ou EXCEPTION_NONCONTINUABLE)
(Si l’exception est considérée comme ne pouvant pas être continuée et qu’un filtre tente
de la continuer, EXCEPTION_NONCONTINUABLE_EXCEPTION est déclenchée.)
na Nombre d’éléments dans le tableau d’arguments.
a Pointeur sur le premier élément du tableau d’arguments – la signification de ces
arguments dépend de chaque exception.
Blocs de terminaison
Le modèle de gestion des exceptions structurées supporte un bloc de terminaison
qui est exécuté même si la sortie s’effectue normalement d’un bloc protégé ou
via une exception. Le compilateur C++Builder supporte cette opération en C avec
la syntaxe suivante :
__try {
func();
}
__finally {
// cela se produit selon que func() déclenche une exception ou non
}
Les blocs de terminaison sont supportés par une extension C++ où vous pouvez
traiter du code final dans le bloc __finally :
try {
func();
}
__finally {
// cela se produit selon que func() déclenche une exception ou non
}
L’exemple suivant illustre les blocs de terminaison :
/* Résultat du programme :
Une exception :
Interception d’une exception.
Le bloc __finally est aussi exécuté !
Aucune exception :
Aucune exception ne s’est produite, mais __finally s’exécute toujours !
*/
#include <stdio.h>
#include <windows.h>
int main()
{
float e, f, g;
try
{
f = 1.0;
g = 0.0;
try
{
puts("Une exception:");
e = f / g;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
puts("Interception d’une exception.");
}
}
__finally
{
puts("Le bloc __finally est aussi exécuté !");
}
try
{
f = 1.0;
g = 2.0;
try
{
puts("Aucune exception:");
e = f / g;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
puts("Interception d’une exception.");
}
}
__finally
{
puts("Aucune exception ne s’est produite, mais le bloc __finally s’exécute toujours
!");
}
return e;
}
Le code C++ peut aussi gérer un “bloc de terminaison” en créant des objets
locaux avec des destructeurs qui sont appelés au moment de la sortie de la
portée. Etant donné que les exceptions structurées C++Builder supportent le
nettoyage des destructeurs, cela fonctionne quel que soit le type de l’exception.
Remarque Un cas particulier concerne ce qui se produit lorsqu’une exception est déclenchée
et qu’elle n’est jamais gérée par le programme. Pour une exception C++, le
compilateur C++Builder appelle des destructeurs pour les objets locaux (non
requis par les définitions de langage), étant donné qu’aucun nettoyage de
destructeur ne se produit avec une exception Win32 non gérée.
Comme vous avez pu le voir dans la liste précédente, les classes d’exception
VCL et CLX incorporées gèrent la plupart des exceptions à votre place et vous
permettent de simplifier la programmation. Dans certaines situations, il est
nécessaire de créer ses propres classes d’exception pour gérer des situations
uniques. Vous pouvez déclarer une nouvelle classe d’exception en créant un
descendant de type Exception et en créant autant de constructeurs que nécessaire
(ou en copiant les constructeurs depuis une classe existant dans Sysutils.hpp).
Considérations de portabilité
Plusieurs bibliothèques d’exécution (RTL) sont fournies avec C++Builder. La
plupart appartiennent à des applications C++Builder, mais une d’entre elles
(cw32mt.lib) est la RTL multithread normale ne contenant aucune référence à la
VCL/CLX. Cette RTL est fournie pour la gestion des applications existantes
pouvant faire partie d’un projet mais ne dépendant pas de la VCL/CLX. Cette
RTL ne supporte pas l’interception des exceptions du système d’exploitation, car
ces objets exceptions dérivent de TObject et nécessiteraient de lier des parties de
la VCL/CLX à l’application.
La bibliothèque cp32mt.lib (bibliothèque d’exécution multithread) propose une
gestion de la mémoire et une gestion des exceptions avec la VCL/CLX.
Deux bibliothèques d’importation (cw32mti.lib et cp32mti.lib) vous permettent
d’utiliser la DLL RTL. Utilisez la bibliothèque cp32mti.lib pour les exceptions
VCL et CLX.
Ces différences et leur impact sur les classes de style VCL dans C++Builder sont
décrites dans cette section.
Héritage et interfaces
A la différence du C++, le Pascal Objet ne supporte pas l’héritage multiple.
Toute classe créée en ayant un ancêtre VCL ou CLX hérite de cette restriction.
Vous ne pouvez donc pas avoir des classes de base multiple pour une classe
C++ de style VCL, même si la classe VCL, ou CLX, n’est pas l’ancêtre immédiat.
IUnknown et IInterface
Toutes les interfaces Pascal Objet dérivent d’un seul et même ancêtre commun,
IInterface. Les classes interface C++ ne sont pas obligées d’utiliser IInterface
comme classe de base, car une classe de style VCL peut l’utiliser comme classe
de base supplémentaire, mais le code VCL et CLX gérant les interfaces suppose
que les méthodes de IInterface sont présentes.
Dans la programmation COM, toutes les interfaces dérivent de IUnknown. La
gestion COM dans la VCL est basée sur une définition de IUnknown qui
correspond directement à IInterface. Donc, en Pascal Objet, IUnknown et IInterface
sont identiques.
Cependant, la définition Pascal Objet de IUnknown ne correspond pas à la
définition IUnknown utilisée dans C++Builder. Le fichier unknwn.h définit
IUnknown pour inclure les trois méthodes suivantes :
virtual HRESULT STDCALL QueryInterface( const GUID &guid, void ** ppv ) = 0;
virtual ULONG STDCALL AddRef() = 0;
virtual ULONG STDCALL Release() = 0;
Cela correspond à la définition de IUnknown indiquée par Microsoft dans la
spécification COM.
Remarque Pour obtenir des informations sur IUnknown et son utilisation, voir chapitre 38,
“Présentation des technologies COM”, ou la documentation Microsoft.
A la différence du Pascal Objet, la définition en C++Builder de IInterface n’est
pas équivalente à celle de IUnknown. IInterface est un descendant de IUnknown
comportant une méthode supplémentaire, Supports :
template <typename T>
HRESULT __stdcall Supports(DelphiInterface<T>& smartIntf)
{
return QueryInterface(__uuidof(T),
reinterpret_cast<void**>(static_cast<T**>(&smartIntf)));
}
Supports vous permet d’obtenir un DelphiInterface pour une autre interface gérée
par l’objet qui implémente IInterface. Si, par exemple vous avez un DelphiInterface
pour une interface IMyFirstInterface et que l’objet d’implémentation implémente
également IMySecondInterface (dont le type DelphiInterface est
_di_IMySecondInterface), vous pouvez obtenir le DelphiInterface de la seconde
interface de la manière suivante :
_di_IMySecondInterface MySecondIntf;
MyFirstIntf->Supports(MySecondIntf);
La VCL et la CLX utilisent un correspondant de IUnknown en Pascal Objet. Cette
correspondance convertit les types utilisés dans les méthodes de IUnknown en
types Pascal Objet et renomme les méthodes AddRef et Release en _AddRef et
_Release pour indiquer qu’elles ne doivent jamais être appelées directement. En
Pascal Objet, le compilateur génère automatiquement les appels nécessaires aux
méthodes de IUnknown. Quand les méthodes de IUnknown (ou de IInterface)
gérées par les objets VCL ou CLX sont converties en C++, cela donne les
signatures de méthode suivantes :
virtual HRESULT __stdcall QueryInterface(const GUID &IID, void *Obj);
int __stdcall _AddRef(void);
int __stdcall _Release(void);
Cela signifie que les objets VCL et CLX gérant IUnknown ou IInterface en Pascal
Objet ne gèrent pas les versions C++Builder de IUnknown et IInterface.
Copie d’objets
A la différence de C++, Pascal Objet ne dispose pas d’une gestion par le
compilateur de la copie d’objets. Cette section décrit les effets de cette différence
sur les opérateurs d’affectation et les constructeurs de copie dans les classes de
style VCL.
Opérateurs d’affectation
L’opérateur d’affectation Pascal Objet (:=) n’est pas un opérateur d’affectation de
classe (opérateur=()). L’opérateur d’affectation copie la référence et non l’objet.
Ainsi, dans le code suivant, B et C désignent tout deux le même objet :
B, C: TButton;
B:= TButton.Create(ownerCtrl);
C:= B;
Cet exemple se traduit dans le code C++Builder suivant :
TButton *B = NULL;
TButton *C = NULL;
B = new TButton(ownerCtrl);
C = B; // copie le pointeur et pas l’objet
Les classes de style VCL en C++Builder suivent les règles du langage Pascal
Objet pour les opérateurs d’affectation. Cela signifie que dans le code suivant, les
affectations entres les pointeurs déréférencés ne sont pas valides car elles tentent
de copier l’objet et pas le pointeur :
TVCLStyleClass *p = new TVCLStyleClass;
TVCLStyleClass *q = new TVCLStyleClass;
*p = *q; // interdit pour les objets des classes de style VCL
Remarque Pour les classes de style VCL, il est légal d’utiliser une syntaxe C++ pour lier à
une référence. Ainsi, le code suivant est légal :
TVCLStyleClass *ptr = new TVCLStyleClass;
TVCLStyleClass &ref = *ptr;// OK pour les classes de style VCL
Bien que cela soit différent de l’utilisation d’un opérateur d’affectation, la syntaxe
est suffisamment semblable pour la mentionner ici à titre de comparaison.
Constructeurs de copie
Pascal Objet n’a pas de constructeurs de copie intégrés. De ce fait, les classes de
style VCL de C++Builder n’ont pas de constructeurs de copie prédéfinis.
L’exemple de code suivant tente de créer un pointeur TButton en utilisant un
constructeur de copie :
TButton *B = new TButton(ownerCtrl);
TButton *C = new TButton(*B);// interdit pour les objets des classes de style VCL
N’écrivez pas de code dépendant de l’existence d’un constructeur de copie pour
les classes de style VCL et CLX. Pour créer une copie d’un objet d’une classe de
style VCL avec C++Builder, vous pouvez écrire le code d’une fonction membre
copiant cet objet. Sinon, les descendants de la classe VCL et CLX TPersistent
peuvent redéfinir la méthode Assign pour copier les données d’un objet dans un
autre. Cela se fait, par exemple, dans les classes graphiques comme TBitmap ou
TIcon qui contiennent des ressources image. Enfin, la manière de copier un objet
peut être déterminée par le programmeur (le concepteur de composants) ; mais il
faut faire attention car certaines méthodes de copie utilisées en C++ standard ne
sont pas utilisables pour les classes de style VCL.
TWinControl
TObject (constructeur appelant
inherited)
TControl
TPersistent (constructeur appelant
inherited)
TComponent TComponent
TPersistent
TControl (pas de constructeur)
TPersistent
TWinControl (constructeur vide)
Frontière
C++ / Pascal Objet
MyBase MyBase
MyDerived MyDerived
Remarque TComponent n’appelle pas inherited car TPersistent n’a pas de constructeur.
TObject a un constructeur vide, il n’est donc pas appelé. Si les constructeurs de
ces classes étaient appelés, l’ordre suivrait le schéma dans lequel ces classes
apparaissent en gris.
Les modèles de construction d’objet en C++, Pascal Objet et C++Builder sont
résumés dans le tableau suivant :
d’exécution d’un objet avec le modèle C++ de construction des classes de base
avant la construction de la classe dérivée, l’appel des méthodes virtuelles dans
les constructeurs des classes de base dans les classes de style VCL peut induire
des effets secondaires indésirables. Ces effets sont décrits plus loin et illustrés
par un exemple d’une classe instanciée dérivée d’au moins une classe de base.
Dans cette discussion, la classe instanciée est désignée comme étant la classe
dérivée.
Modèle C++
La syntaxe C++ ne dispose pas du mot clé inherited pour appeler le
constructeur de la classe de base lors de la construction de la classe dérivée.
Dans le modèle C++, l’utilisation de inherited est inutile puisque le type à
l’exécution de l’objet est celui de la classe en cours de construction et pas celui
de la classe dérivée. Donc, les méthodes virtuelles appelées sont celles de la
classe en cours et pas celles de la classe dérivée. De ce fait, il n’est pas nécessaire
d’initialiser les données membres ou de configurer l’objet de la classe dérivée
avant d’appeler ces méthodes.
Modèle C++Builder
En C++Builder, les objets de style VCL ont le type à l’exécution de la classe
dérivée durant les appels aux constructeurs de classe de base. Donc, si le
constructeur de la classe de base appelle une méthode virtuelle, la méthode de la
classe dérivée est appelée si elle a été redéfinie par la classe dérivée. Si la
méthode virtuelle dépend de la liste d’initialisation ou du corps du constructeur
de la classe dérivée, la méthode est appelée avant que cela ne se produise. Par
exemple, CreateParams est une fonction membre virtuelle qui est appelée
indirectement dans le constructeur de TWinControl. Si vous dérivez une classe de
TWinControl et redéfinissez CreateParams afin qu’elle dépende de quelque chose
effectué dans votre constructeur, ce code est traité après l’appel de CreateParams.
Cette situation est valable pour toutes les classes dérivées d’une base. Supposons
qu’une classe C dérive de B qui dérive de A. Quand une instance C est créée, A
doit également appeler la méthode redéfinie de B si B redéfinit la méthode alors
que C ne le fait pas.
Remarque Il faut faire attention aux méthodes virtuelles comme CreateParams qui ne sont
pas appelées directement dans les constructeurs mais qui le sont indirectement.
méthodes dans les constructeurs des classes de base sont résolus dans les deux
cas. MyBase et MyDerived sont des classes C++ standard. MyVCLBase et
MyVCLDerived sont des classes de style VCL descendant de TObject. La méthode
virtuelle what_am_I() est redéfinie dans les deux classes dérivées mais elle est
appelée uniquement dans le constructeur de la classe de base et pas dans le
constructeur de la classe dérivée.
#include <sysutils.hpp>
#include <iostream.h>
// Classes de style non VCL
class MyBase {
public:
MyBase() { what_am_I(); }
virtual void what_am_I() { cout << "Je suis une base" << endl; }
};
class MyDerived : public MyBase {
public:
virtual void what_am_I() { cout << "Je suis dérivée" << endl; }
};
// Classes de style VCL
class MyVCLBase : public TObject {
public:
__fastcall MyVCLBase() { what_am_I(); }
virtual void __fastcall what_am_I() { cout << "Je suis une base" << endl; }
};
class MyVCLDerived : public MyVCLBase {
public:
virtual void __fastcall what_am_I() { cout << "Je suis dérivée" << endl; }
};
int main(void)
{
MyDerived d; // instanciation de la classe C++
MyVCLDerived *pvd = new MyVCLDerived; // instanciation de la classe de style VCL
return 0;
}
Le résultat de cet exemple est :
Je suis une base
Je suis dérivée
Il est dû à la différence des types d’exécution de MyDerived et de MyVCLDerived
lors de l’appel à leur constructeur respectif de classe de base.
inherited. En C++ standard, la valeur des données membres non initialisées est
indéterminée. Les types suivants de données membres de classe doivent être
initialisés dans la liste d’initialisation du constructeur de la classe :
• Les références.
• Les données membres n’ayant pas de constructeur par défaut.
Sinon, la valeur de ces données membres ou de celles initialisées dans le corps
du constructeur est non définie quand les constructeurs de classe de base sont
appelés. En C++Builder, la mémoire des classes de style VCL est initialisée à
zéro.
Remarque Techniquement parlant c’est la mémoire des classes VCL ou CLX qui est à zéro,
c’est-à-dire les bits qui sont à zéro. Les valeurs elle-mêmes sont indéfinies. Par
exemple, une référence est un zéro.
Une fonction virtuelle dépendant de la valeur de variables membres initialisées
dans le corps du constructeur ou dans la liste d’initialisation peuvent se
comporter comme si les variables sont initialisées à zéro. En effet, le constructeur
de la classe de base est appelé avant le traitement de la liste d’initialisation ou
l’entrée dans le corps du constructeur. Cela est illustré par l’exemple suivant :
#include <sysutils.hpp>
class Base : public TObject {
public:
__fastcall Base() { init(); }
virtual void __fastcall init() { }
};
class Derived : public Base {
public:
Derived(int nz) : not_zero(nz) { }
virtual void __fastcall init()
{
if (not_zero == 0)
throw Exception("not_zero vaut zéro!");
}
private:
int not_zero;
};
int main(void)
{
Derived *d42 = new Derived(42);
return 0;
}
Cet exemple déclenche une exception dans le constructeur de Base. Comme Base
est construite avant Derived, not_zero n’a pas encore été initialisé avec la valeur 42
transmise au constructeur. Attention : vous ne pouvez pas initialiser les données
membres des classes de style VCL avant l’appel des constructeurs de classe
de base.
Destruction d’objets
Deux mécanismes diffèrent dans la destruction d’objets en C++ et en Pascal
Objet : Ce sont :
• Les destructeurs appelés à cause d’exceptions déclenchées dans les
constructeurs.
• Les méthodes virtuelles appelées dans les destructeurs.
Les classes de style VCL combinent les méthodes de ces deux langages.
Les sections suivantes décrivent ces points plus en détail.
• Dans les classes de style VCL, les classes de base VCL ou CLX (celles
implémentées en Pascal Objet) respectent la méthode Pascal Objet d’appel des
destructeurs. Les classes dérivées (celles implémentées en C++) ne suivent
aucune des deux méthodes précédentes. Tous les destructeurs sont appelés ;
mais l’exécution ne passe pas par le corps de ceux qui n’auraient pas été
appelés en appliquant les règles de langage C++.
Les classes implémentées en Pascal Objet offrent l’opportunité de mettre en
œuvre du code de nettoyage placé dans le corps du destructeur. Cela inclut le
code libérant la mémoire des sous-objets (c’est-à-dire des données membres qui
sont des objets) construits avant que l’exception se soit produite. Attention : pour
les classes de style VCL, le code de nettoyage peut ne pas être exécuté pour la
classe instanciée ou pour ses bases implémentées en C++ même si les
destructeurs sont appelés.
Pour davantage d’informations sur la gestion des exceptions en C++Builder, voir
“Gestion des exceptions VCL/CLX” à la page 12-16.
AfterConstruction et BeforeDestruction
TObject introduit deux méthodes virtuelles, BeforeDestruction et AfterConstruction,
qui permettent aux programmeurs d’écrire du code traité avant la destruction et
après la création d’objets. AfterConstruction est appelée après l’appel du dernier
constructeur. BeforeDestruction est appelée avant l’appel du premier destructeur.
Ces méthodes sont publiques et appelées automatiquement.
Typedefs
La plupart des types de données intrinsèques du Pascal Objet sont implémentés
dans C++Builder en utilisant typedef dans un type C++ natif. Ils se trouvent
dans sysmac.h. Dans la mesure du possible, vous devez utiliser le type C++ de
préférence au type Pascal Objet.
• wstring.h
• sysclass.h
• syscomp.h
• syscurr.h
• sysdyn.h
• sysopen.h
• sysset.h
• systdate.h
• systobj.h
• systvar.h
• sysvari.h
Les classes implémentées dans ces fichiers d’en-tête sont créées pour gérer des
types natifs utilisés dans des routines du Pascal Objet. Elles sont également
utilisables pour appeler ces routines dans du code de base VCL et CLX.
Paramètres var
Le C++ et le Pascal Objet ont tous les deux le concept de “transfert par
référence” (appelé également transfert par adresse). Ce sont des arguments
modifiables. En Pascal Objet ce sont des paramètres var. La syntaxe des fonctions
attendant un paramètre var est :
procedure myFunc(var x : Integer);
En C++, il faut transmettre ce type de paramètre par référence :
void myFunc(int& x);
Les références C++ et les pointeurs peuvent s’utiliser pour modifier l’objet.
Cependant, une référence correspond mieux à un paramètre var car, à la
différence d’un pointeur, une référence ne peut être réassociée et un paramètre
var ne peut être réaffecté ; toutefois les deux permettent de modifier la valeur de
ce qui est référencé.
return 1 + *pi;
}
Tableaux ouverts
Pascal Objet dispose de la construction “tableau ouvert” qui permet de
transmettre un tableau de taille indéterminé à une fonction. Bien qu’il n’y ait pas
d’équivalent direct de ce type en C++, il est possible d’appeler une fonction
Pascal Objet qui attend un paramètre tableau ouvert en lui transmettant
explicitement un pointeur sur le premier élément du tableau et la valeur du
dernier indice (le nombre d’éléments du tableau moins un). Par exemple, la
fonction Mean de math.hpp a la déclaration suivante en Pascal Objet :
function Mean(Data: array of Double): Extended;
La déclaration C++ est :
Extended __fastcall Mean(const double * Data, const int Data_Size);
Le code suivant illustre l’appel de la fonction Mean en C++ :
double d[] = { 3.1, 4.4, 5.6 };
// spécification explicite du dernier indice
long double x = Mean(d, 2);
// mieux : utiliser sizeof pour s’assurer que la valeur correcte est transmise
long double y = Mean(d, (sizeof(d) / sizeof(d[0])) - 1);
// utiliser la macro définie dans sysopen.h
long double z = Mean(d, ARRAYSIZE(d) - 1);
Remarque Dans des cas similaires à cet exemple mais dans lesquels la fonction Pascal Objet
attend un paramètre var, la déclaration des paramètres de la fonction en C++ ne
serait pas const.
Temporaires
Pascal Objet gère le transfert de tableaux ouverts temporaires sans nom à des
fonctions. Il n’y a pas de syntaxe équivalente en C++. Cependant comme des
définitions de variable peuvent être mélangées à d’autres instructions, une
approche consiste à fournir la variable avec un nom.
En Pascal Objet :
Result := Mean([3.1, 4.4, 5.6]);
En C++, en utilisant une variable “temporaire” nommée :
double d[] = { 3.1, 4.4, 5.6 };
return Mean(d, ARRAYSIZE(d) - 1);
Pour limiter la portée de la variable “temporaire” nommée et éviter des conflits
avec des variables locales, il suffit de créer sur place une nouvelle portée :
long double x;
{
double d[] = { 4.4, 333.1, 0.0 };
x = Mean(d, ARRAYSIZE(d) - 1);
}
Pour d’autres solutions, voir “Macro OPENARRAY” à la page 13-20.
Tableau de constantes
Le Pascal Objet gère une construction appelée array of const. Ce type
d’argument revient à utiliser par valeur un tableau ouvert de TVarRec.
Le segment de code suivant déclare en Pascal Objet une fonction attendant un
array of const :
function Format(const Format: string; Args: array of const): string;
En C++, le prototype est ;
AnsiString __fastcall Format(const AnsiString Format,
TVarRec const *Args, const int Args_Size);
La fonction est appelée comme n’importe quelle fonction attendant un tableau
ouvert :
void show_error(int error_code, AnsiString const &error_msg)
{
TVarRec v[] = { error_code, error_msg };
ShowMessage(Format("%d: %s", v, ARRAYSIZE(v) - 1));
}
Macro OPENARRAY
La macro OPENARRAY définie dans sysopen.h peut être également utilisée au
lieu de définir une variable nommée pour transmettre un tableau ouvert
temporaire à une fonction qui attend un tableau ouvert transféré par valeur.
Cette macro s’utilise de la manière suivante :
OPENARRAY(T, (value1, value2, value3)) // Jusqu’à 19 valeurs
Où T est le type du tableau ouvert à construire, les paramètres value servant à
remplir le tableau. Les parenthèses autour des paramètres value sont obligatoires.
Par exemple :
void show_error(int error_code, AnsiString const &error_msg)
{
ShowMessage(Format("%d: %s", OPENARRAY(TVarRec, (error_code, error_msg))));
}
Il est possible de transmettre jusqu’à 19 valeurs en utilisant la macro
OPENARRAY. Si un tableau plus important est nécessaire, il faut définir une
variable explicite. De plus, l’utilisation de la macro OPENARRAY entraîne un
certain coût (mais faible) à l’exécution en raison de l’allocation du tableau sous-
jacent et d’une copie supplémentaire de chaque valeur.
Macro EXISTINGARRAY
La macro EXISTINGARRAY définie dans sysopen.h peut être utilisée pour
transmettre un tableau existant quand un tableau ouvert est attendu. Cette macro
s’utilise de la manière suivante :
long double Mean(const double *Data, const int Data_Size);
double d[] = { 3.1, 3.14159, 2.17128 };
Mean(EXISTINGARRAY (d));
Remarque La section “Calcul du nombre d’éléments” à la page 13-18 s’applique également à
la macro EXISTINGARRAY.
Interfaces Delphi
Le compilateur Pascal Objet gère automatiquement de nombreux détails de la
manipulation des interfaces. Il augmente automatiquement le compteur des
références à une interface quand le code de l’application obtient un pointeur
d’interface et le décrémente quand l’interface sort de la portée.
Dans C++Builder, le modèle de classe DelphiInterface fournit certains de ces
services aux classes interface C++. Pour les propriétés et méthodes de la VLC ou
de la CLX qui utilisent les types d’interface Pascal Objet, l’équivalent C++ utilise
un DelphiInterface construit en utilisant la classe interface sous-jacente.
Le constructeur, le constructeur de copie, l’opérateur d’affectation et le
destructeur de DelphiInterface incrémentent ou décrémentent le compteur de
références quand cela est nécessaire. Cependant, DelphiInterface n’est pas aussi
pratique que la gestion des interfaces par le compilateur en Pascal Objet.
D’autres opérateurs donnant accès au pointeur d’interface sous-jacent ne gèrent
pas le compteur de références car la classe ne sait pas toujours si c’est approprié.
Il peut être nécessaire d’appeler explicitement AddRef ou Release pour conserver
un compteur de références correct.
Chaînes de ressource
Si vous avez du code dans une unité Pascal qui utilise des chaînes de ressource,
le compilateur Pascal (DCC32) génère une variable globale et une macro du
préprocesseur correspondante pour chaque chaîne de ressource quand il génère
le fichier d’en-tête. Les macros sont utilisées pour charger automatiquement les
chaînes de ressource et doivent être utilisées dans le code C++ à chaque fois
qu’une chaîne de ressource doit être référencée. Par exemple, la section
resourcestring du code Pascal Objet doit contenir
unit borrowed;
interface
resourcestring
Warning = ’Attention quand vous accédez aux ressources chaîne.’;
implementation
begin
end.
Le code correspondant généré par le compilateur Pascal pour C++Builder doit
être :
extern PACKAGE System::Resource ResourceString _Warning;
#define Borrowed_Warning System::LoadResourceString(&Borrowed::_Warning)
Cela vous permet d’utiliser la ressource chaîne Pascal Objet exportée sans avoir à
appeler explicitement LoadResourceString.
Dans le tableau 13.3, ClassName est une méthode de TObject qui renvoie une
chaîne contenant le nom du type réel de l’objet sans tenir compte du type de la
variable déclarée. D’autres méthodes RTTI définies dans TObject n’ont pas
d’équivalent C++. Ce sont les méthodes publiques suivantes :
• ClassInfo renvoie un pointeur sur la table des informations de type à
l’exécution (RTTI) du type d’objet.
• ClassNameIs détermine si un objet est d’un type donné.
• ClassParent renvoie le type de l’ancêtre immédiat de la classe. Pour TObject,
ClassParent renvoie nil car TObject n’a pas de parent. Elle est utilisée par les
opérateurs is et as et par la méthode InheritsFrom.
• ClassType détermine dynamiquement le type réel d’un objet. Elle est utilisée de
manière interne par les opérateurs Pascal Objet is et as.
• FieldAddress utilise le RTTI pour obtenir l’adresse d’un champ publié. Elle est
utilisée de manière interne par le système de flux.
• InheritsFrom détermine la relation entre deux objets. Elle est utilisée de
manière interne par les opérateurs Pascal Objet is et as.
• MethodAddress utilise le RTTI pour trouver l’adresse d’une méthode. Elle est
utilisée de manière interne par le système de flux.
Certaines de ces méthodes de TObject sont conçues pour un usage interne par le
compilateur ou pour le système de flux. Pour davantage d’informations sur ces
méthodes, voir l’aide en ligne.
__classid
L’opérateur __classid est utilisé par le compilateur pour générer un pointeur sur
la vtable pour le nom de classe spécifié. Cet opérateur est utilisé pour obtenir la
méta classe d’une classe.
Syntaxe __classid(classname)
Par exemple, __classid est utilisé pour enregistrer des éditeurs de propriété, des
composants ou des classes, et avec la méthode InheritsFrom de TObject. Le code
suivant illustre l’utilisation de __classid pour créer un nouveau composant
dérivé de TWinControl:
namespace Ywndctrl
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(MyWndCtrl)};
RegisterComponents("Additional", classes, 0);
}
}
__closure
Le mot clé __closure est utilisé pour déclarer un type particulier de pointeur sur
une fonction membre. En C++ standard,le seul moyen d’obtenir un pointeur sur
une fonction membre est d’utiliser le nom complet du membre, comme indiqué
dans l’exemple suivant :
class base
{
public:
void func(int x) { };
};
Cependant, vous ne pouvez pas affecter un pointeur sur un membre d’une classe
dérivée à un pointeur sur un membre d’une classe de base. Cette règle (appelée
contravariance) est illustrée dans l’exemple suivant :
class derived: public base
{
public:
void new_func(int i) { };
};
return 0;
}
Cependant l’extension __closure permet d’éviter cette limitation et davantage. En
utilisant un closure, vous pouvez obtenir un pointeur sur une fonction membre
d’un objet (c’est-à-dire sur une instance donnée d’une classe). L’objet peut être
quelconque, sans tenir compte de sa hiérarchie d’héritage. Le pointeur this de
l’objet est automatiquement utilisé lors de l’appel de la fonction membre via le
closure. L’exemple suivant montre comment déclarer et utiliser un closure. On
suppose définies les classes base et dérivée spécifiées dans l’exemple précédent.
int main(int argc, char* argv[])
{
derived derivedObject;
void (__closure *derivedClosure)(int);
derived derivedObject;
void (__closure *derivedClosure)(int);
__property
Le mot clé __property déclare un attribut d’une classe. Les propriétés
apparaissent au programmeur juste comme un autre attribut (champ) d’une
classe. Néanmoins, comme sa contrepartie en Pascal Objet, le mot clé C++
Builder __property ajoute beaucoup plus de fonctionnalités que la simple
consultation et modification de la valeur de l’attribut. Comme les attributs de
propriété contrôlent complètement l’accès à la propriété, il n’y a pas de limites à
l’implémentation de la propriété dans la classe même.
Syntaxe
__property type NomPropriété[index1Type index1][indexNType indexN] = { attributs };
Où
• type est un type de donnée intrinsèque ou préalablement déclaré.
• NomPropriété est un identificateur correct.
• indexNType est un type de donnée intrinsèque ou préalablement déclaré.
• indexN est le nom d’un paramètre indice qui sera transmis aux fonctions read
et write de la propriété.
• attributs est une liste séparée par des virgules de read, write, stored, default
(ou nodefault), ou index.
Le paramètre entre crochets indexN est facultatif. S’il est présent, il déclare une
propriété tableau. Les paramètres indices sont transmis aux méthodes read et
write de la propriété tableau.
L’exemple suivant illustre des déclarations de propriétés simples :
class PropertyExample {
private:
int Fx,Fy;
float Fcells[100][100];
protected:
int readX() { return(Fx); }
void writeX(int newFx) { Fx = newFx; }
double computeZ() {
// Effectue des calculs et renvoie une valeur à virgule flottante...
return(0.0);
}
public:
__property int X = { read=readX, write=writeX };
__property int Y = { read=Fy };
__property double Z = { read=computeZ };
__property float Cells[int row][int col] = { read=cellValue };
};
Cet exemple utilise plusieurs déclarations de propriétés. La propriété X a un
accès en lecture-écriture via, respectivement, les fonctions membres readX et
writeX. La propriété Y correspond directement à la variable membre Fy, elle est
en lecture seule. La propriété Z est une valeur en lecture seule qui est calculée,
elle n’est pas stockée dans une donnée membre de la classe. Enfin, la propriété
Cells propose une propriété tableau avec deux indices. L’exemple suivant illustre
la manière d’accéder ces propriétés depuis votre code :
PropertyExample myPropertyExample;
myPropertyExample.X = 42; // S’évalue à : myPropertyExample.WriteX(42);
int myVal1 = myPropertyExample.Y; // S’évalue à : myVal1 = myPropertyExample.Fy;
double myVal2 = myPropertyExample.Z; // S’évalue à : myVal2 = myPropertyExample.ComputeZ();
float cellVal = myPropertyExample[3][7]; // S’évalue à :
// cellVal = myPropertyExample.cellValue(3,7);
Les propriétés ont de nombreuses possibilités et caractéristiques que cet exemple
ne met pas en avant. Les propriétés peuvent
• Associer la même méthode de lecture ou d’écriture à plusieurs propriétés en
utilisant l’attribut index.
• Ont des valeurs par défaut.
__published
Le mot clé __published spécifie que les propriétés de cette section sont affichées
dans l’inspecteur d’objets si la classe est dans la palette des composants. Seules
les classes dérivées de TObject peuvent avoir une section __published.
Les règles de visibilité pour les membres publiés sont les mêmes que celles
s’appliquant aux membres publics. Il n’y a qu’une seule différence entre membre
public et membre publié : les informations de type à l‘exécution (RTTI) Pascal
Objet sont générées pour les données membres et les propriétés déclarées dans
une section __published. RTTI permet à une application d’interroger
dynamiquement les données membres, les fonctions membres et les propriétés
d’un type de classe qui sinon serait inconnu.
Remarque Les constructeurs et les destructeurs ne sont pas permis dans une section
__published. Les propriétés, les données membres Pascal ou dérivées de VCL ou
CLX, les fonctions membres et les closures sont autorisés dans une section
__published. Les champs définis dans une section __published doivent être d’un
type classe. Les propriétés définies dans une section __published ne peuvent être
des propriétés tableau. Une propriété définie dans une section __published doit
être de type ordinal, réel, chaîne, ensemble court, classe ou pointeur de méthode.
__declspec(delphiclass)
L’argument delphiclass est utilisé pour la déclaration de classes dérivées de
TObject. Ces classes sont créées avec les compatibilités suivantes :
• RTTI compatible Pascal Objet
• Comportement de constructeur-destructeur compatible avec VCL/CLX
• Gestion des exceptions compatible avec VCL/CLX
Une classe compatible avec VCL/CLX présente les limitations suivantes :
• Les classes de base virtuelles sont interdites.
• Pas d’héritage multiple sauf dans le cas décrit dans “Héritage et interfaces” à
la page 13-2.
• Elle doit être allouée dynamiquement en utilisant l’opérateur global new.
__declspec(delphireturn)
L’argument delphireturn est utilisé en usage interne uniquement par la VCL et
la CLX dans C++Builder. Il est utilisé pour les déclarations de classes créées
dans C++Builder pour gérer les types prédéfinis et les constructions Pascal Objet
n’ayant pas d’équivalent dans un type C++ natif. Ce sont, entre autres, Currency,
AnsiString, Variant, TDateTime et Set. L’argument delphireturn marque les classes
C++ comme compatibles avec la VCL ou la CLX pour la gestion des appels de
fonction et les valeurs renvoyées. Ce modificateur est nécessaire pour transmettre
une structure par valeur à une fonction entre Pascal Objet et le C++.
__declspec(delphirtti)
L’argument delphirtti oblige le compilateur à inclure des informations de type à
l’exécution dans une classe lors de sa compilation. Quand ce modificateur est
utilisé, le compilateur génère des informations de type à l’exécution pour tous les
champs, méthodes, et propriétés déclarés dans une section published. Pour les
interfaces, le compilateur génère des informations de type à l’exécution pour
toutes les méthodes de l’interface. Si une classe est compilée avec des
informations de type à l’exécution, tous ses descendants le sont également.
Comme la classe TPersistent est compilée avec des informations de type à
l’exécution, cela signifie qu’il n’est pas nécessaire d’utiliser ce modificateur avec
toutes les classes que vous créez ayant TPersistent comme ancêtre. Ce
modificateur est surtout utilisé pour les interfaces dans des applications qui
implémentent ou utilisent des services Web.
__declspec(dynamic)
L’argument dynamic est utilisé pour la déclaration de fonctions dynamiques.
Les fonctions dynamiques sont similaires à des fonctions virtuelles mais elles ne
sont stockées que dans les vtables des objets qui les définissent et pas dans les
vtables des descendants. Si vous appelez une fonction dynamique alors que cette
fonction n’est pas définie dans l’objet, les vtables de ces ancêtres sont examinées
jusqu’à trouver la fonction. Les fonctions dynamiques ne sont autorisées que
pour les classes dérivées de TObject.
__declspec(hidesbase)
L’argument hidesbase préserve la sémantique d’un programme Pascal Objet
quand des fonctions virtuelles ou redéfinies sont exportées en C++Builder. En
Pascal Objet, les fonctions virtuelles des classes de base peuvent apparaître dans
la classe dérivée comme une fonction de même nom, mais conçue comme une
fonction entièrement nouvelle sans relation explicite avec la précédente.
__declspec(package)
L’argument package indique que le code définissant la classe peut être compilé
dans un paquet. Ce modificateur est généré automatiquement par le compilateur
lors de la création de paquets dans l’EDI. Pour davantage d’informations sur les
paquets, voir chapitre 15, “Utilisation des paquets et des composants”.
__declspec(pascalimplementation)
L’argument pascalimplementation indique que le code définissant la classe a été
implémenté en Pascal Objet. Ce modificateur apparaît dans les fichiers d’en-tête
de portabilité Pascal Objet d’extension .hpp.
__declspec(uuid)
L’argument uuid associe une classe avec un GUID. Il peut s’utiliser dans toute
classe, mais il s’emploie généralement pour les classes qui représentent des
interfaces Pascal Objet (ou des interfaces COM). Vous pouvez obtenir le GUID
d’une classe déclarée en utilisant ce modificateur, en appelant la directive
__uuidof.
Développement d’applications
Chapitre 14
14
multiplates-formes
Vous pouvez utiliser C++Builder pour développer des applications 32 bits
multiplates-formes qui s’exécuteront sur les systèmes d’exploitation Windows et
Linux. Les applications multiplates-formes utilisent des composants CLX sans
appels API spécifiques à un système d’exploitation. Pour développer une
application multiplate-forme, créez une nouvelle application CLX ou modifiez
une application Windows existante. Ensuite, compilez-la et déployez-la sur la
plate-forme sur laquelle vous prévoyez de l’exécuter. Pour Windows, utilisez
C++Builder. Pour Linux, aucune solution Borland C++ n’est encore disponible,
mais vous pouvez dès à présent développer l’application avec C++Builder.
Ce chapitre décrit d’une part la manière de modifier les applications C++Builder
pour qu’elles se compilent sous Linux et d’autre part d’écrire un code
indépendant de la plate-forme et portable entre les deux environnements.
Il contient en outre des informations sur les différences entre le développement
d’applications sous Windows et sous Linux.
La palette des composants montre les pages et les composants pouvant être
utilisés dans les applications CLX.
2 Développez votre application dans l’EDI.
3 Compilez et testez l’application. Examinez tous les messages d’erreur pour
repérer les endroits où des modifications supplémentaires seront nécessaires.
Remarque Avec une solution C++Builder disponible pour Linux, vous pouvez compiler et
tester votre application sous Linux.
Quand vous portez votre application vers Linux, vous devez réinitialiser les
options de votre projet. En effet, le fichier .dof stockant les options du projet est
recréé par Linux avec une extension différente (avec les options par défaut).
Le fichier fiche d’une application multiplate-forme a l’extension .xfm et non pas
.dfm. Cela permet de distinguer les fiches multiplates-formes utilisant des
composants CLX et les fiches utilisant des composants VCL. Un fichier fiche .xfm
fonctionne à la fois sous Windows et sous Linux, mais une fiche .dfm ne
fonctionne que sous Windows.
Pour plus d’informations sur l’écriture des applications de bases de données ou
des applications Internet indépendantes des plates-formes, consultez
“Applications de bases de données multiplates-formes” à la page 14-22 et
“Applications Internet multiplates-formes” à la page 14-30.
Techniques de portage
Les approches que vous pouvez adopter pour porter une application d’une plate-
forme vers une autre sont les suivantes :
Portages multiplates-formes
Les portages multiplates-formes permettent généralement de gagner du temps
car les applications portées ciblent plusieurs plates-formes. En revanche, la
quantité de travail nécessaire au développement d’applications multiplates-
formes dépend beaucoup du code existant. Si le code a été développé sans souci
d’indépendance par rapport à la plate-forme, vous pouvez rencontrer des
scénarios où la logique indépendante de la plate-forme et la mise en œuvre
dépendante de la plate-forme sont mélangées.
L’approche multiplate-forme est préférable, car la logique métier s’exprime en
termes indépendants de la plate-forme. Certains services sont masqués par une
interface interne qui est identique sur toutes les plates-formes mais possède une
mise en œuvre particulière sur chacune. La bibliothèque d’exécution de
C++Builder en est un exemple. L’interface est très similaire sur les deux plates-
formes, même si la mise en œuvre peut être très différente. Vous devez séparer
les éléments multiplates-formes, puis mettre en œuvre des services particuliers
au niveau supérieur. Cette approche est en fin de compte la solution la moins
coûteuse, grâce à la réduction des coûts de maintenance occasionnée par un
large partage de la base de source et une amélioration de l’architecture
d’application.
Les étapes générales pour porter votre application VCL vers CLX sont les
suivantes :
1 Ouvrez le projet contenant l’application que vous voulez modifier dans
C++Builder.
2 Copiez les fichiers .dfm dans des fichiers .xfm de même nom (par exemple,
renommez unit1.dfm en unit1.xfm). Renommez (ou utilisez un #ifdef) la
référence au fichier .dfm dans les fichiers en-tête de #pragma resource "*.dfm" vers
#pragma resource "*.xfm". (Le fichier .xfm fonctionnera dans une application
C++Builder et Linux.)
3 Modifiez (ou spécifiez avec un #ifdef) tous les fichiers en-tête de votre fichier
source pour qu’ils fassent référence aux unités correctes dans la CLX. (Pour
plus d’informations, consultez “Comparaison entre les unités CLX et VCL” à
la page 14-10.)
Par exemple, changez les instructions #include suivantes dans le fichier en-tête
d’une application Windows :
#include <vcl.h>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
en instructions ci-dessous pour une application CLX :
#include <clx.h>
#include <QControls.hpp>
#include <QStdCtrls.hpp>
#include <QForms.hpp>
4 Enregistrez le projet et rouvrez-le. Désormais, la palette des composants
propose des composants pouvant être utilisés dans les applications CLX.
Remarque Certains composants non visuels Windows peuvent être utilisés dans les
applications CLX, mais ils comportent des fonctionnalités qui ne
fonctionneront que dans les applications CLX Windows. Si vous prévoyez de
compiler votre application également sous Linux, n’utilisez pas les composants
VCL non visuels dans vos applications, ou utilisez des #ifdef pour marquer
les sections de code qui les utilisent comme étant uniquement destinées à
Windows. Vous ne pouvez pas utiliser la partie visuelle de la VCL avec
VisualCLX dans la même application.
5 Réécrivez le code qui nécessite des dépendances Windows afin de rendre le
code plus indépendant de la plate-forme. Utilisez pour cela les routines et
constantes de la bibliothèque d’exécution. (Pour plus d’informations, consultez
“Ecriture de code portable” à la page 14-18.)
6 Trouvez une fonctionnalité équivalente pour les caractéristiques qui sont
différentes sous Linux. Utilisez des #ifdef (avec modération cependant) pour
délimiter les informations propres à Windows. (Pour plus d’informations,
consultez “Utilisation des directives conditionnelles” à la page 14-19.)
CLX et VCL
Les applications CLX utilisent la bibliothèque des composants multiplates-formes
(CLX) Borland à la place de la bibliothèque des composants visuels (VCL). Dans
la VCL, de nombreux contrôles permettent d’accéder facilement aux contrôles
Windows avec des appels dans les bibliothèques d’API Windows. De même,
CLX fournit un accès aux widgets (de window + gadget) Qt avec des appels
dans les bibliothèques partagées Qt. C++Builder inclut la CLX et la VCL.
La CLX ressemble beaucoup à la VCL. La plupart des composants et propriétés
ont le même nom. En outre, la CLX et la VCL sont disponibles sous Windows
(selon votre édition de C++Builder).
Différences de CLX
Bien que la plus grande partie de la CLX soit mise en œuvre de la même façon
que la VCL, certaines fonctionnalités sont mises en œuvre autrement. Cette
section présente les différences entre les mises en œuvre de la CLX et de la VCL
auxquelles vous devez faire attention lorsque vous écrivez des applications
multiplates-formes.
Présentation visuelle
L’environnement visuel de Linux est quelque peu différent de celui de Windows.
L’aspect des boîtes de dialogue peut dépendre du gestionnaire de fenêtres utilisé
(par exemple, selon qu’il s’agisse de KDE ou de Gnome).
Styles
Il est possible d’utiliser des styles au niveau application en plus des propriétés
OwnerDraw. Vous pouvez utiliser la propriété TApplication::Style pour définir
l’aspect visuel des éléments graphiques d’une application. Avec des styles, un
widget ou une application peut prendre une toute nouvelle apparence. Vous
pouvez toujours utiliser le dessin propriétaire sous Linux mais l’utilisation des
styles est recommandée.
Variants
Tout le code des variants et tableaux sécurisés qui était dans l’unité System se
trouve dans deux nouvelles unités :
• Variants
• VarUtils
Le code dépendant du système d’exploitation est maintenant isolé dans l’unité
VarUtils et il contient des versions génériques de tout ce qui est nécessaire à
l’unité Variants. Si vous convertissez en application CLX une application VCL
qui contient des appels à Windows, vous devez remplacer ces appels par des
appels à l’unité VarUtils.
Si vous souhaitez utiliser des variants, vous devez inclure l’unité Variants au
fichier en-tête de votre fichier source.
VarIsEmpty effectue un test simple sur varEmpty pour vérifier si un variant est
effacé, et sous Linux vous pouvez utiliser la fonction VarIsClear pour savoir si la
valeur du variant est indéfinie.
Registre
Linux n’utilise pas de registre pour stocker des informations de configuration.
Vous devez utiliser des fichiers texte de configuration et des variables
d’environnement à la place du registre. Les fichiers de configuration système
sous Linux sont souvent installés dans /etc, par exemple /etc/hosts. Les autres
profils utilisateur sont installés dans des fichiers cachés (dont le nom commence
par un point), comme .bashrc, qui contient les paramètres du shell bash ou
.XDefaults, qui sert à définir des valeurs par défaut pour les programmes X.
Le code dépendant du registre peut être modifié pour utiliser à la place un
fichier texte de configuration local. Les paramètres modifiables par l’utilisateur
doivent être enregistrés dans son répertoire initial pour accorder l’autorisation
d’écriture. Les options de configuration devant être définies par l’utilisateur root
doivent se trouver dans /etc. Ecrire une unité contenant toutes les fonctions de
registre mais en détournant toutes les sorties vers un fichier de configuration
local est un moyen que vous pouvez utiliser pour gérer une dépendance par
rapport au registre.
Pour mémoriser des informations à un emplacement global sous Linux, vous
pouvez stocker un fichier de configuration global dans le répertoire /etc ou le
répertoire initial de l’utilisateur sous forme de fichier caché. Toutes vos
applications peuvent alors accéder au même fichier de configuration. Vous devez
toutefois vous assurer que les permissions du fichier et les droits d’accès sont
correctement définis.
Vous pouvez également utiliser des fichiers .ini dans des applications
multiplates-formes. Toutefois, dans la CLX, vous devez utiliser TMemIniFile au
lieu de TRegIniFile.
Autres différences
Par rapport à la VCL, la mise en œuvre de la CLX possède également d’autres
différences affectant le fonctionnement de vos composants. Cette section décrit
certaines de ces différences.
• Vous pouvez sélectionner un composant CLX dans la palette des composants,
puis utiliser le bouton gauche ou droit de la souris pour l’ajouter à une fiche.
Pour un composant VCL, vous ne pouvez utiliser que le bouton gauche.
• Le contrôle TButton CLX possède une propriété ToggleButton que le contrôle
VCL équivalent n’a pas.
• Dans la CLX, TColorDialog ne possède pas de propriété TColorDialog::Options à
initialiser. Par conséquent, vous ne pouvez pas personnaliser l’apparence et la
fonctionnalité de la boîte de dialogue de sélection de couleur. En outre, selon
le gestionnaire de fenêtres que vous utilisez dans Linux, TColorDialog n’est pas
toujours modale ou non-redimensionnable. Sous Windows, TColorDialog est
toujours modale et non-redimensionnable.
• A l’exécution, les boîtes à options fonctionnent différemment dans la CLX et
dans la VCL. Dans la CLX (mais pas dans la VCL), vous pouvez ajouter un
élément à une liste déroulante en entrant du texte et en appuyant sur Entrée
dans le champ d’édition d’une boîte à options. Vous pouvez désactiver cette
fonctionnalité en définissant InsertMode sur ciNone. Il est également possible
d’ajouter des éléments vides (sans chaîne) à la liste de la boîte à options. De
plus, si vous maintenez la flèche bas enfoncée quand la boîte de saisie est
fermée, vous ne vous arrêtez pas au dernier élément de la liste. Vous refaites
un tour en recommençant au début.
• TCustomEdit ne met pas en œuvre Undo, ClearUndo ou CanUndo. Il n’existe
donc aucune méthode pour annuler les saisies par programme. Mais les
utilisateurs d’une application peuvent annuler leurs saisies dans une boîte de
saisie (TEdit) lors de l’exécution en cliquant avec le bouton droit de la souris
sur cette boîte puis en choisissant la commande Annuler.
• La valeur des touches utilisées dans les événements peut être différente entre
la VCL et la CLX. Par exemple, la touche Entrée a la valeur 13 dans la VCL et
la valeur 4100 dans la CLX. Si vous codez les valeurs de touches dans vos
applications CLX, vous devez changer ces valeurs quand vous les portez de
Windows vers Linux et vice versa.
Il existe d’autres différences. Reportez-vous à la documentation en ligne de la
CLX pour des détails sur tous les objets CLX ou, dans les éditions de
C++Builder qui incluent le code source, situé dans {répertoire d’installation}\
C++Builder6\Source\CLX.
Les équivalents Linux des dll Windows sont les bibliothèques d’objets partagés
(fichiers .so), qui contiennent du code indépendant de la position (PIC). Par
conséquent, les références mémoire globales et les appels à des fonctions externes
sont relatifs au registre EBX, qui doit être préservé d’un appel à l’autre.
Vous ne devez vous préoccuper des références mémoire globales et des appels à
des fonctions externes que si vous utilisez l’assembleur —C++Builder génère le
code correct. (Pour plus d’informations, consultez “Inclusion de code assembleur
inline” à la page 14-21.)
Les unités suivantes existent dans la CLX mais pas dans la VCL :
Les unités VCL Windows suivantes ne sont pas incluses dans la CLX,
principalement parce qu’elles concernent des fonctionnalités propres à Windows
qui ne sont pas disponibles sous Linux comme ADO, COM et BDE.
Tableau 14.7 Différences dans les environnements d’exploitation Linux et Windows (suite)
Différence Description
DLL Sous Linux, vous utilisez des fichiers d’objets partagés (.so). Sous
Windows, il s’agit de bibliothèques de liens dynamiques (DLL).
Lettres de lecteurs Linux ne possède pas de lettres de lecteurs. Voici un exemple de nom
de chemin Linux :
/lib/security. Voir DriveDelim dans la bibliothèque d’exécution.
Exceptions Les exceptions du système d’exploitation sont appelées signaux sous
Linux.
Fichiers Sous Linux, les fichiers exécutables ne nécessitent pas d’extension. Sous
exécutables Windows, les fichiers exécutables possèdent l’extension exe.
Extensions de nom Linux n’utilise pas d’extensions de nom de fichier pour identifier les
de fichier types de fichiers ou associer les fichiers à des applications.
Permissions Sous Linux, des permissions de lecture, d’écriture et d’exécution sont
de fichiers affectées aux fichiers (et aux répertoires) pour le propriétaire du fichier,
le groupe et les autres. Par exemple,
-rwxr-xr-x signifie, de la gauche vers la droite :
- est le type de fichier (- = fichier ordinaire, d = répertoire, l = lien) ;
rwx représente les permissions pour le propriétaire du fichier (lecture,
écriture, exécution), r-x représente les permissions pour le groupe du
propriétaire du fichier (lecture, exécution) et r-x représente les
permissions pour tous les autres utilisateurs (lecture, exécution).
L’utilisateur root (super-utilisateur) peut outrepasser ces permissions.
Vous devez vous assurer que votre application s’exécute sous
l’utilisateur correct et dispose d’un droit d’accès correct aux fichiers
requis.
Utilitaire Make L’utilitaire make de Borland n’est pas disponible sur la plate-forme
Linux. A la place, vous pouvez utiliser l’utilitaire make GNU de Linux.
Multitâche Linux prend totalement en charge le fonctionnement multitâche. Vous
pouvez exécuter en même temps plusieurs programmes (appelés
processus sous Linux). Vous pouvez lancer des processus en arrière-
plan (en utilisant & après la commande) et continuer immédiatement à
travailler. Linux vous permet également de disposer de plusieurs
sessions.
Noms de chemins Linux utilise une barre oblique droite (/) là où DOS utilise une barre
oblique inverse (\). Une constante PathDelim peut être utilisée pour
spécifier le caractère adapté à la plate-forme. Voir PathDelim dans la
bibliothèque d’exécution.
Chemin Lors de l’exécution de programmes, Windows consulte toujours en
de recherche premier le répertoire en cours, puis il examine la variable
d’environnement PATH. Linux ne consulte jamais le répertoire en cours
mais recherche uniquement les répertoires énumérés dans PATH. Pour
exécuter un programme du répertoire en cours, vous devez
généralement taper ./ avant.
Vous pouvez également modifier votre PATH pour inclure ./ comme
premier chemin à rechercher.
Tableau 14.7 Différences dans les environnements d’exploitation Linux et Windows (suite)
Différence Description
Séparateur Windows utilise le point-virgule comme séparateur de chemin de
de chemin recherche. Linux utilise deux points. Voir PathDelim dans la
de recherche bibliothèque d’exécution.
Liens symboliques Sous Linux, un lien symbolique est un fichier spécial qui pointe sur un
autre fichier du disque. En plaçant les liens symboliques dans le
répertoire global bin qui contient les principaux fichiers de votre
application, vous n’aurez pas à modifier le chemin de recherche
système. Un lien symbolique se crée à l’aide de la commande ln (link).
Windows possède des raccourcis pour le bureau de l’interface
utilisateur graphique. Pour mettre un programme à la disposition de la
ligne de commande, les programmes d’installation Windows modifient
généralement le chemin de recherche système.
Remarque Les différentes distributions de Linux installent parfois les fichiers à différents
emplacements. Un programme utilitaire peut être installé dans /bin avec une
distribution Red Hat et dans /usr/local/bin avec une distribution Debian.
Reportez-vous à www.pathname.com pour des détails supplémentaires sur
l’organisation du système de fichiers hiérarchique UNIX/Linux. Vous pourrez
également consulter le document Filesystem Hierarchy Standard.
p++;
p++;
}
peut être remplacé par un code indépendant de la plate-forme comme celui-ci :
while(*p != 0)
{
if(LeadBytes.Contains(*p))
p = StrNextchar(p);
else
p++;
}
Cet exemple est portable d’une plate-forme à l’autre et évite toujours de nuire
aux performances en appelant une procédure pour les environnement régionaux
non multi-octets.
Si l’utilisation de fonctions de bibliothèque d’exécution n’est pas une solution
envisageable, essayez d’isoler le code propre à une plate-forme dans une partie
de votre routine ou une sous-routine. Essayez de limiter le nombre de blocs
#ifdef pour conserver la lisibilité et la portabilité du code source. Le symbole
conditionnel WIN32 n’est pas défini sous Linux. Le symbole conditionnel LINUX
est défini, pour indiquer que le code source est compilé pour la plate-forme
Linux.
• Evitez les tests négatifs du type #ifndef si ce n’est pas absolument nécessaire.
#ifndef __linux__ n’est pas équivalente à #ifdef WINDOWS.
• Evitez les combinaisons #ifndef/#else. Utilisez plutôt un test positif (#ifdef)
pour une meilleure lisibilité.
• Evitez les clauses #else sur des #ifdef sensibles à la plate-forme. Utilisez des
blocs #ifdef distincts pour Linux et du code spécifique à Windows au lieu de
#ifdef __linux__/#else ou #ifdef WINDOWS/#else.
Par exemple, un ancien code peut contenir
#ifdef WIN32
(Code Windows 32 bits)
#else
(Code Windows 16 bits) //!! Linux pourra tomber par erreur dans ce code.
#endif
Pour tout code non portable dans des #ifdef, il est préférable que le code
source échoue à la compilation que de voir la plate-forme tomber dans une
clause #else et échouer mystérieusement à l’exécution. Les échecs de
compilation sont plus faciles à résoudre que les erreurs à l’exécution.
• Utilisez la syntaxe #if pour les tests compliqués. Remplacez les #ifdef
imbriqués par une expression booléenne dans une directive #if. Terminez la
directive #if par #endif. Cela vous permet de placer des expressions #if dans
des #ifdef pour dissimuler la nouvelle syntaxe #if aux compilateurs
précédents.
Toutes les directives conditionnelles sont documentées dans l’aide en ligne. Pour
plus d’informations, consultez également la rubrique “Compilation
conditionnelle” dans l’aide.
Emission de messages
La directive de compilation #pragma message permet au code source d’émettre
des avertissements et des erreurs exactement comme le compilateur. Utilisez-la
pour spécifier un message défini par l’utilisateur dans votre code de
programmation, dans l’un des formats suivants.
Si vous avez un nombre variable de constantes chaîne, utilisez :
#pragma message( "bonjour vous" )
#pragma message( "bonjour" " vous" )
Pour écrire un texte après un message, utilisez :
#pragma message texte
Pour développer une valeur précédemment définie, utilisez :
#pragma message (texte)
#define text "une chaîne de test"
#pragma message (texte)
Par exemple, pour afficher ces messages sur un bouton, utilisez :
void __fastcall TForm1::Button1Click(TObject *Sender)
{
#pragma message( "bonjour vous 1" )
#pragma message( "bonjour vous 2" )
Différences de dbExpress
Sous Linux, dbExpress gère la communication avec les serveurs de bases de
données. dbExpress se compose d’un ensemble de pilotes légers qui mettent en
œuvre un ensemble d’interfaces communes. Chaque pilote est un objet partagé
(fichier .so) qui doit être lié à votre application. Comme dbExpress est conçu pour
être multiplate-forme, il est également disponible sous Windows sous la forme
d’un ensemble de bibliothèques de liens dynamiques (.dll).
Comme avec n’importe quelle couche d’accès aux données, dbExpress a besoin du
logiciel client du fournisseur de base de données. De plus, il utilise un pilote
propre à la base de données, plus deux fichiers de configuration, dbxconnections
et dbxdrivers. C’est beaucoup moins que, par exemple, pour le moteur BDE, qui
nécessite la bibliothèque principale du moteur de bases de données Borland
(Idapi32.dll) plus un pilote propre à la base de données et un certain nombre
d’autres bibliothèques de gestion.
En outre, dbExpress :
• Fournit un chemin plus simple et plus rapide aux bases de données distantes.
Par conséquent, vous pouvez vous attendre à une amélioration sensible des
performances pour un accès aux données simple et direct.
• Traite les requêtes et les procédures stockées, mais il ne prend pas en charge
l’ouverture des tables.
• Renvoie uniquement des curseurs unidirectionnels.
• Ne dispose pas d’autre possibilité de mise à jour intégrée que l’exécution
d’une requête INSERT, DELETE ou UPDATE.
• N’a pas de mémoire cache pour les métadonnées ; l’interface d’accès aux
métadonnées lors de la conception est mise en œuvre à l’aide de l’interface
centrale d’accès aux données.
• Exécute uniquement des requêtes transmises par l’utilisateur, optimisant ainsi
l’accès à la base de données sans introduire de requêtes supplémentaires.
• Vous pouvez ajuster votre interface utilisateur pour traiter les mises à jour en
mémoire cache. Cette approche possède certains avantages, comme la
réduction du trafic réseau et de la durée des transactions. Toutefois, si vous
adoptez l’enregistrement des mises à jour en mémoire cache, vous devrez
décider du moment où ces mises à jour devront être ré-appliquées au serveur
de base de données, et apporter probablement des modifications à l’interface
utilisateur pour laisser les utilisateurs spécifier l’application des mises à jour
ou leur indiquer si leurs modifications ont été écrites dans la base de données.
En outre, comme les erreurs de mise à jour ne sont pas détectées quand
l’utilisateur transmet un enregistrement, vous devrez changer la manière dont
vous signalez de telles erreurs à l’utilisateur, afin qu’il puisse voir quelle mise
à jour a causé un problème, ainsi que le type de problème.
Si votre application d’origine utilisait la prise en charge fournie par le BDE ou
ADO pour conserver les mises à jour en mémoire cache, vous aurez besoin
d’apporter des modifications à votre code pour passer à l’utilisation d’un
ensemble de données client. Le tableau ci-dessous présente les propriétés, les
événements et les méthodes qui prennent en charge les mises à jour en mémoire
cache sur les ensembles de données BDE et ADO, ainsi que les propriétés,
méthodes et événements correspondants sur TClientDataSet.
Tableau 14.10 Propriétés, méthodes et événements pour les mises à jour en mémoire cache
Sur les ensembles
de données Sur les
BDE (ou ensembles de
TDatabase) données ADO Sur TClientDataSet Utilisation
CachedUpdates LockType Non obligatoires, Détermine si les mises à jour en
les ensembles de mémoire cache sont effectives.
données client
conservent
toujours les mises
à jour en mémoire
cache.
Non géré CursorType Non géré Indique à quel point l’ensemble
de données est isolé des
modifications sur le serveur.
UpdatesPending Non géré ChangeCount Indique si la mémoire cache
locale contient des
enregistrements mis à jour qui
doivent être transmis à la base
de données.
UpdateRecordTypes FilterGroup StatusFilter Indique le type
d’enregistrements mis à jour à
rendre visibles lors de la
transmission de mises à jour en
mémoire cache.
UpdateStatus RecordStatus UpdateStatus Indique si un enregistrement est
inchangé, modifié, inséré ou
supprimé.
Tableau 14.10 Propriétés, méthodes et événements pour les mises à jour en mémoire cache (suite)
Sur les ensembles
de données Sur les
BDE (ou ensembles de
TDatabase) données ADO Sur TClientDataSet Utilisation
OnUpdateError Non géré OnReconcileError Evénement pour traiter les
erreurs de mise à jour
enregistrement par
enregistrement.
ApplyUpdates UpdateBatch ApplyUpdates Transmet les enregistrements de
(sur un ensemble la mémoire cache locale à la
de données ou base de données.
une base de
données)
CancelUpdates CancelUpdates ou CancelUpdates Efface les mises à jour en cours
CancelBatch dans la mémoire cache sans les
transmettre.
CommitUpdates Gérés Reconcile Réinitialise la mémoire cache de
automatiquement mise à jour après la transmission
réussie des mises à jour.
FetchAll Non géré GetNextPacket Copie des enregistrements de
(et PacketRecords) bases de données dans la
mémoire cache locale à des fins
de modification et de mise à
jour.
RevertRecord CancelBatch RevertRecord Annule les mises à jour de
l’enregistrement en cours si elles
ne sont pas encore effectuées.
Vous pouvez inclure les types de composants VCL et/ou CLX dans un paquet.
Les paquets destinés à être multi-plates-formes ne doivent inclure que des
composants CLX.
Remarque Les paquets partagent leurs données globales avec les autres modules d’une
application.
Paquets d’exécution
Les paquets d’exécution sont déployés avec les applications C++Builder. Ils
fournissent des fonctionnalités lorsqu’un utilisateur exécute une application.
Pour exécuter une application utilisant des paquets, le fichier exécutable de
l’application et tous les fichiers paquet (fichiers .bpl) qu’elle utilise doivent se
trouver sur l’ordinateur. Les fichiers .bpl doivent être dans le chemin du système
pour qu’une application puisse les utiliser. Quand vous déployez une
application, vérifiez que les utilisateurs possèdent la version correcte de chaque
bpl nécessaire.
Le paquet vcl contient les composants les plus couramment utilisés, et le paquet
rtl contient toutes les fonctions système qui ne sont pas des composants ainsi
que les éléments de l’interface Windows. Il ne contient pas les composants de
base de données ni les autres composants spéciaux, qui se trouvent dans des
paquets distincts.
Pour créer une application de base de données client/serveur utilisant des
paquets, vous avez besoin de plusieurs paquets d’exécution, parmi lesquels vcl,
vcldb, rtl et dbrtl. Si vous voulez utiliser dans votre application des composants
arborescence (Outline), vous avez besoin en plus de vclx. Pour utiliser ces
paquets, choisissez Projet|Options, sélectionnez la page Paquets et entrez la liste
suivante dans la boîte de saisie Paquets d’exécution.
rtl;vcl;vcldb;vclx;
Il n’est en fait pas nécessaire d’inclure vcl et rtl, car ils sont référencés dans la
liste Requires de vcldb. (Voir “Liste Requires” à la page 15-10.) Votre application
se compile peut être construite de la même façon que vcl et rtl figurent ou non
dans la liste des paquets d’exécution.
Paquets personnalisés
Un paquet personnalisé est soit un bpl que vous programmez et construisez
vous-même, soit un paquet existant développé par un fournisseur tiers. Pour
utiliser dans une application un paquet d’exécution personnalisé, choisissez
Projet|Options et ajoutez le nom du paquet à la boîte de saisie Paquets
d’exécution de la page Paquets. Par exemple, si vous avez créé un paquet
effectuant des statistiques, nommé stats.bpl, que vous souhaitez utiliser dans une
application, la boîte de saisie Paquets d’exécution doit être de la forme :
rtl;vcl;vcldb;stats
Si vous créez vos propres paquets, vous pouvez les ajouter selon vos besoins à
la liste.
Paquets de conception
Les paquets de conception sont utilisés pour installer des composants dans la
palette des composants de l’EDI ou pour créer les éditeurs de propriétés
spéciaux de composants personnalisés.
C++Builder est livré avec de nombreux paquets de conception déjà installés dans
l’EDI. Ils dépendent de la version de C++Builder que vous utilisez et de la
personnalisation à laquelle vous avez pu la soumettre. Vous pouvez voir la liste
des paquets installés sur votre système en choisissant la commande Composant|
Installer des paquets.
Les paquets de conception fonctionnent en appelant des paquets d’exécution
référencés dans leur liste Requires. (Voir “Liste Requires” à la page 15-10.)
Par exemple, dclstd référence vcl. Dclstd contient lui-même des fonctionnalités
La boîte de dialogue Options du projet possède une case à cocher Défaut dans le
coin inférieur gauche. Si vous cliquez sur OK quand cette case est cochée, les
options choisies sont enregistrées comme paramètres par défaut pour les
nouveaux projets de paquet. Pour restaurer les valeurs par défaut originales,
supprimez ou renommez le fichier default.bpk.
Nom de paquets
Les noms de paquets doivent être uniques dans un projet. Si vous nommez un
paquet Stats, l’éditeur de paquets générera un fichier source et un fichier des
options du projet nommés respectivement Stats.cpp et Stats.bpk ; le compilateur
et le lieur généreront un exécutable, un fichier image binaire et (en option) une
bibliothèque statique, appelés respectivement Stats.bpl, Stats.bpi et Stats.lib. Pour
utiliser le paquet dans une application, ajoutez Stats à la boîte de saisie Paquets
d’exécution (après avoir choisi Projet|Options puis avoir cliqué sur l’onglet
Paquets).
Vous pouvez également ajouter un préfixe, un suffixe et un numéro de version à
votre nom de paquet. Alors que l’éditeur de paquet est ouvert, cliquez sur le
bouton Options. Sur la Page Description de la boîte de dialogue Options du
projet, entrez le texte ou une valeur pour Suffixe LIB, Préfixe LIB ou Version
LIB. Par exemple, pour ajouter un numéro de version à votre projet de paquet,
entrez 6 après Version LIB pour que Paquet1 génère Paquet1.bpl.6.
Liste Requires
La liste Requires spécifie les autres paquets externes qui sont utilisés par le
paquet en cours. Un paquet externe inclus dans la liste Requires est
automatiquement lié lors de la compilation dans toute application utilisant le
paquet en cours ou l’une des unités contenues dans le paquet externe.
Si les fichiers d’unité contenus dans votre paquet font référence à d’autres unités
empaquetées, les autres paquets doivent apparaître dans la liste Requires de
votre paquet, sans quoi vous devrez les ajouter. Si les autres paquets sont
absents de la liste Requires, le compilateur les importera dans votre paquet
comme ‘unités contenues implicitement’.
Remarque La plupart des paquets que vous créez nécessitent rtl. Si vous utilisez des
composants VCL, vous devrez inclure également le paquet vcl. Si vous utilisez
des composants CLX en programmation multi-plate-forme, vous devrez inclure
VisualCLX.
Liste Contains
La liste Containsidentifie les fichiers d’unité qui doivent être liés dans le paquet.
Si vous écrivez votre propre paquet, placez votre code source dans des fichiers
cpp et incluez-les dans la liste liste Contains.
Paquets faibles
La directive #pragma package(smart_init, weak) affecte la manière dont un
fichier .obj est stocké dans les fichiers .bpi et .bpl d’un paquet. (Pour davantage
d’informations sur les fichiers générés par le compilateur et le lieur, voir
“Fichiers de paquets créés lors d’une construction” à la page 15-14.) Si #pragma
package(smart_init, weak) apparaît dans un fichier d’unité, le lieur ne place pas
l’unité dans les fichiers bpl si c’est possible, et il crée une copie locale non
empaquetée de l’unité si elle est nécessaire à une autre application ou un autre
paquet. Une unité compilée avec cette directive est dite faiblement empaquetée.
Supposons, par exemple, que vous avez créé un paquet appelé PACK ne
contenant qu’une seule unité UNIT1, et que UNIT1 n’utilise aucune autre unité
mais effectue des appels à RARE.dll. Si vous placez #pragma package(smart_init,
weak) dans UNIT1.cpp lorsque vous construisez le paquet, UNIT1 ne sera pas
incluse dans PACK.bpl ; vous n’aurez pas à distribuer de copies de RARE.dll
avec PACK. Cependant, UNIT1 sera toujours incluse dans PACK.bpi. Si un autre
paquet ou une autre application utilisant PACK fait référence à UNIT1, celle-ci
sera copiée à partir de PACK.bpi et liée directement dans le projet.
Supposons maintenant que vous ajoutiez à PACK une deuxième unité, UNIT2, et
que UNIT2 utilise UNIT1. Cette fois, même si vous compilez PACK avec
#pragma package(smart_init, weak) dans UNIT1.cpp, le lieur inclura UNIT1
dans PACK.bpl. Mais d’autres paquets ou applications faisant référence à UNIT1
utiliseront la copie (non empaquetée) extraite de PACK.bpi.
Remarque Les fichiers d’unités contenant la directive #pragma package(smart_init, weak)
ne doivent pas contenir de variables globales.
#pragma package(smart_init, weak) est une caractéristique avancée prévue pour
les programmeurs qui distribuent leur fichiers bpl à d’autres programmeurs
C++Builder. Elle vous permet d’éviter la distribution de DLL rarement utilisées
et supprime les conflits entre des paquets qui peuvent dépendre de la même
bibliothèque externe.
Ainsi, l’unité PenWin de C++Builder référence PenWin.dll. La plupart des projets
n’utilisent pas PenWin et la plupart des ordinateurs n’ont pas de fichier
PenWin.dll installé. C’est pour cela que l’unité PenWin est faiblement
empaquetée dans vcl. Quand vous liez un projet utilisant PenWin et le paquet
vcl, PenWin est copié depuis vcl60.bpi et lié directement à votre projet ;
l’exécutable résultant est lié statiquement à PenWin.dll.
Si PenWin n’avait pas été faiblement empaquetée, deux problèmes se seraient
produits. Tout d’abord, il aurait fallu que vcl soit lié de manière statique à
PenWin.dll et vous n’auriez donc pas pu le charger sur un système ne disposant
pas de PenWin.dll. De plus, si vous aviez tenté de créer un paquet contenant
PenWin, une erreur de construction aurait eu lieu, puisque l’unité PenWin aurait
été contenue à la fois dans vcl et dans votre paquet. Ainsi, sans “empaquetage
faible”, l’unité PenWin n’aurait pas pu être incluse dans les distributions
standard de vcl.
Déploiement de paquets
Vous déploierez les paquets de la même façon que les applications. Les fichiers
que vous distribuez avec un paquet déployé peuvent varier. Le fichier bpl et
tous les paquets et fichiers dll requis par le fichier bpl doivent être distribués.
Le tableau suivant énumère les fichiers qui peuvent s’avérer nécessaire, en
fonction de l’utilisation du paquet.
Création d’applications
Chapitre 16
16
internationales
Ce chapitre présente les règles d’écriture d’applications qui seront distribuées sur
les marchés internationaux. En planifiant le processus, il est possible de réduire
le temps et le code nécessaires pour que vos applications puissent fonctionner
parfaitement à l’étranger comme sur le marché domestique.
Internationalisation et localisation
Pour créer une application distribuable sur les marchés étrangers, vous devez
accomplir deux étapes :
• Internationalisation
• Localisation
Si votre édition de C++Builder comprend les Outils de traduction, vous pouvez
les utiliser pour gérer la localisation. Pour plus d’informations, voir l’aide en
ligne des outils de traduction (ETM.hlp).
Internationalisation
L’internationalisation est le processus permettant à votre application de
fonctionner selon divers paramètres régionaux. Les paramètres régionaux sont
l’environnement de l’utilisateur qui inclut les conventions culturelles du pays
cible aussi bien que sa langue. Windows gère un grand nombre de paramètres
régionaux, chacun d’eux décrits par l’association d’une langue et d’un pays.
Localisation
La localisation est le processus de traduction d’une application pour qu’elle
fonctionne pour des paramètres régionaux spécifiques. Outre la traduction de
l’interface utilisateur, la localisation peut également consister à personnaliser les
fonctionnalités. Par exemple, une application financière peut être modifiée afin
de respecter les règles fiscales dans différents pays.
Codage de l’application
Vous vous assurerez que le code de l’application peut gérer les chaînes qu’elle
rencontrera dans les divers environnements régionaux cible.
Jeux de caractères
Les versions occidentales de Windows (dont les versions anglaise, allemande et
française) utilisent le jeu de caractères ANSI Latin-1 (1252). Mais d’autres
éditions de Windows utilisent des jeux de caractères différents. Ainsi, la version
japonaise de Windows utilise le jeu de caractères Shift-JIS (page de code 932) qui
représente les caractères japonais avec des codes sur plusieurs octets.
Il y a, en général, trois types de jeux de caractères :
• Uni-octet (codé sur un seul octet)
• Multi-octet (codé sur plusieurs octets)
• Caractères étendus
Windows et Linux supportent tous les deux les jeux de caractères sur un seul
octet et sur plusieurs octets, comme le jeu Unicode. Dans un jeu sur un seul
octet, chaque octet d’une chaîne représente un caractère. Le jeu de caractères
ANSI utilisé par de nombreux systèmes d’exploitation occidentaux utilise un
seul octet.
Dans un jeu sur plusieurs octets, certains caractères sont représentés par un octet
et d’autres par plusieurs octets. Le premier octet d’un caractère sur plusieurs
octets est appelé l’octet de poids fort. En général, les 128 premiers caractères
d’un jeu multi-octet correspondent aux caractères ASII sur 7 bits, et tout octet
dont la valeur ordinale est supérieure à 127 est l’octet de poids fort d’un
caractère multi-octet. Seuls les caractères sur un octet peuvent contenir la valeur
null (#0). Les jeux de caractères multi-octets — en particulier les jeux sur deux
octets (DBCS) — sont employés pour les langues asatiatiques, tandis que le jeu
UTF-8 utilisé par Linux est un encodage sur plusieurs octets du jeu Unicode.
Caractères larges
Une autre approche de l’utilisation des jeux de caractères pour idéogrammes est
de convertir tous les caractères dans un système de caractères larges, comme
Unicode. Les caractères et les chaînes Unicode sont également appelés caractères
larges et chaînes de caractères larges. Dans le jeu Unicode, chaque caractère est
représenté par deux octets. Ainis, une chaîne Unicode est une suite non d’octets
séparés mais de mots de deux octets.
Propriétés bi-directionnelles
Les objets dont la liste est donnée dans le tableau 16.1, “Objets de la VCL
supportant les BiDi”, ont les propriétés : BiDiMode et ParentBiDiMode. Ces
propriétés, ainsi que BiDiKeyboard et NonBiDiKeyboard de TApplication gèrent la
localisation bi-directionnelle.
Remarque Les propriétés bi-directionnelles ne sont pas disponibles dans CLX pour la
programmation multiplate-forme.
Propriété BiDiMode
La propriété BiDiMode est un nouveau type d’énuméré, TBiDiMode, qui possède
quatre états : bdLeftToRight, bdRightToLeft, bdRightToLeftNoAlign et
bdRightToLeftReadingOnly.
bdLeftToRight
bdLeftToRight dessine le texte en utilisant le sens de lecture de gauche à droite,
l’alignement et la barre de défilement étant inchangés. Par exemple, lors de la
saisie de texte de droite à gauche, comme pour l’Arabe ou l’Hébreu, le curseur
passe en mode poussoir et le texte est saisi de droite à gauche. Pour du texte
bdRightToLeft
bdRightToLeft dessine le texte en utilisant le sens de lecture de droite à gauche,
l’alignement étant modifié et la barre de défilement déplacée. Le texte est saisi
normalement pour les langues allant de droite à gauche comme l’Arabe ou
l’Hébreu. Lorsque le clavier est modifié pour une langue latine, le curseur passe
en mode poussoir et le texte est saisi de gauche à droite.
Figure 16.2 Contrôles initialisés à bdRightToLeft
bdRightToLeftNoAlign
bdRightToLeftNoAlign dessine le texte en utilisant le sens de lecture de droite à
gauche, l’alignement étant inchangé et la barre de défilement déplacée.
Figure 16.3 Contrôles initialisés à bdRightToLeftNoAlign
bdRightToLeftReadingOnly
bdRightToLeftReadingOnly dessine le texte en utilisant le sens de lecture de droite
à gauche, l’alignement et la barre de défilement étant inchangés.
Figure 16.4 Contrôles initialisés à bdRightToLeftReadingOnly
Propriété ParentBiDiMode
ParentBiDiMode est une propriété booléenne. Lorsqu’elle est à true (la valeur par
défaut), le contrôle regarde la propriété de son parent pour connaître la valeur à
utiliser pour BiDiMode. Si le contrôle est un objet TForm, la fiche utilise la valeur
BiDiMode de Application. Si toutes les propriétés ParentBiDiMode sont à true,
lorsque la propriété BiDiMode de Application est modifiée, toutes les fiches et tous
les contrôles du projet sont initialisés avec la nouvelle valeur.
Méthode FlipChildren
La méthode FlipChildren vous permet de faire basculer la position des enfants
d’un contrôle conteneur. Les contrôles conteneur sont des contrôles qui
Autres méthodes
Il existe d’autres méthodes utiles afin de développer des applications pour des
utilisateurs bi-directionnels.
Texte
Tout le texte apparaissant dans l’interface utilisateur doit être traduit. Le texte
anglais étant presque toujours plus court que les traductions, vous devez
concevoir les éléments de votre interface utilisateur qui affiche du texte en
réservant de l’espace pour l’expansion de ce texte. Concevez également les boîtes
de dialogue, les menus, les barres d’état et les autres éléments de l’interface
utilisateur affichant du texte de telle sorte qu’ils puissent facilement afficher des
chaînes plus longues. Evitez les abréviations qui ne peuvent exister dans les
langues utilisant des idéogrammes.
Les chaînes courtes grandissent plus que les phrases longues. Le tableau suivant
fournit une approximation des taux de foisonnement selon la longueur de la
chaîne initiale (en anglais) :
Images graphiques
Le mieux est d’utiliser des images qui ne nécessitent pas de traduction, c’est-à-
dire des images qui ne contiennent pas de texte. Si vous devez inclure du texte
dans vos images, il est préférable d’utiliser un objet libellé avec arrière-plan
transparent par dessus l’image, plutôt que d’inclure le texte dans l’image elle-
même.
Voici quelques autres considérations à prendre en compte lors de la création des
images graphiques. Essayez d’éviter les images spécifiques à une culture. Par
exemple, les boîtes à lettres sont très différentes selon les pays. Les symboles
religieux ne conviennent pas aux pays où il existe plusieurs religions
dominantes. Même les couleurs ont des connotations symboliques différentes
selon les cultures.
}
/* Cet appel provoque l’exécution de la fonction de rappel pour chaque localisation */
EnumSystemLocales((LOCALE_ENUMPROC)EnumLocalesProc, LCID_SUPPORTED);
ressource. Vous pouvez ouvrir vos fiches dans l’EDI et traduire les propriétés
importantes.
Remarque Dans un projet DLL de ressource, vous ne pouvez pas ajouter ou supprimer de
composant. Pourtant, il est possible de modifier les propriétés, au risque de
générer des erreurs d’exécution. Veillez donc à ne modifier que les propriétés
qui requièrent une traduction. Pour éviter les erreurs, vous pouvez configurer
l’inspecteur d’objets pour n’afficher que les propriétés localisables ; pour ce faire,
cliquez avec le bouton droit sur l’inspecteur d’objets et utilisez le menu Voir
pour filtrer les catégories de propriétés non souhaitées.
Vous pouvez ouvrir le fichier RC et traduire des chaînes appropriées. Utilisez
l’éditeur StringTable en ouvrant le fichier RC à partir du gestionnaire de projet.
de registre. Les étapes suivantes sont les principales étapes d’un déploiement et
concernent quasiment tous les types d’application :
• Utilisation des programmes d’installation
• Identification des fichiers de l’application
Les applications C++Builder qui accèdent à des bases de données ou qui
fonctionnent sur le Web nécessitent des étapes complémentaires d’installation en
plus de celles s’appliquant aux applications générales. Pour davantage
d’informations sur l’installation d’applications de bases de données, voir
“Déploiement d’applications de bases de données” à la page 17-7. Pour
davantage d’informations sur l’installation d’applications Web, voir “Déploiement
d’applications Web” à la page 17-11. Pour davantage d’informations sur
l’installation de contrôles ActiveX, voir “Déploiement d’un contrôle ActiveX sur
le Web” à la page 43-18. Pour davantage d’informations sur le déploiement
d’applications CORBA, voir le VisiBroker Installation and Administration Guide.
Fichiers de l’application
Il peut être nécessaire de distribuer les types suivants de fichiers avec une
application :
Fichiers paquet
Si l’application utilise des paquets d’exécution, il faut distribuer les fichiers
paquet avec l’application. InstallShield Express gère l’installation des fichiers
paquet de la même manière que les DLL, copie ces fichiers et crée les entrées
nécessaires dans les registres Windows. Vous pouvez aussi utiliser des modules
de fusion pour déployer des paquets d’exécution avec des outils d’installation
basés sur MSI, comme InstallShield Express. Voir la section suivante pour plus
de détails.
Borland recommande l’installation des fichiers paquet d’exécution d’origine
Borland dans le répertoire Windows\System. Cela sert d’emplacement commun
afin que plusieurs applications puissent accéder à une seule instance de ces
fichiers. Pour les paquets que vous avez créés, il est recommandé de les installer
dans le répertoire de l’application. Seuls les fichiers .bpl doivent être distribués.
CLX Si vous déployez des paquets avec des applications CLX, vous devez inclure
clx60.bpl au lieu de vcl60.bpl.
Si vous distribuez des paquets à d’autres développeurs, fournissez les fichiers
.bpl, .bpi, et .lib (si vous autorisez la liaison dynamique à vos paquets).
Modules de fusion
InstallShield Express 3.0 est basé sur la technologie MSI, l’installateur de
Windows. C’est pour cette raison que C++Builder inclut les modules de fusion.
Les modules de fusion fournissent une méthode standard que vous pouvez
utiliser pour offrir aux applications du code partagé, des fichiers, des ressources,
des entrées du registre et la logique d’installation sous forme d’un seul fichier
composé. Vous pouvez utiliser des modules de fusion pour déployer des paquets
d’exécution avec des outils d’installation basés sur MSI, comme InstallShield
Express.
Les bibliothèques d’exécution ont certaines interdépendances en raison de la
façon dont elles ont été regroupées. Le résultat est que lorsqu’un paquet est
ajouté à un projet d’installation, l’outil d’installation ajoute automatiquement un
ou plusieurs autres paquets ou signale une dépendance sur eux. Par exemple, si
vous ajoutez le module de fusion VCLInternet à un projet d’installation, l’outil
d’installation va aussi ajouter automatiquement les modules VCLDatabase et
StandardVCL ou signaler une dépendance sur ces modules.
Les dépendances de chaque module de fusion sont énumérées dans le tableau
suivant. Les divers outils d’installation peuvent réagir différemment à ces
dépendances. InstallShield pour l’installateur Windows ajoute automatiquement
les modules requis s’il peut les trouver. Les autres outils peuvent se contenter de
signaler une dépendance ou peuvent générer un échec de construction si les
modules requis ne sont pas tous inclus dans le projet.
Contrôles ActiveX
Certains composants fournis avec C++Builder sont des contrôles ActiveX. Le
conteneur du composant est lié au fichier exécutable de l’application (ou à un
paquet d’exécution), mais le fichier .ocx du composant doit également être
distribué avec l’application. Ces composants sont :
• Chart FX, copyright par SoftwareFX Inc.
• VisualSpeller Control, copyright par Visual Components, Inc.
• Formula One (tableur), copyright par Visual Components, Inc.
• First Impression (VtChart), copyright par Visual Components, Inc.
• Graph Custom Control, copyright par Bits Per Second Ltd.
Les contrôles ActiveX que vous créez doivent également être enregistrés sur
l’ordinateur cible avant d’être utilisés. Les programmes d’installation comme
InstallShield Express automatisent le processus d’enregistrement. Pour enregistrer
manuellement un contrôle ActiveX, choisissez Exécuter|Serveur ActiveX dans
Applications complémentaires
Les applications complémentaires sont des programmes distincts en l’absence
desquels votre application C++Builder fonctionnerait de manière incomplète ou
ne fonctionnerait pas du tout. Les applications complémentaires peuvent être
celles fournies avec le système d’exploitation, par Borland ou des produits tiers.
Le programme utilitaire Server Manager de InterBase est un exemple de
programme complémentaire qui permet de gérer les utilisateurs et la sécurité des
bases de données InterBase.
Si une application dépend d’un programme complémentaire, assurez-vous de le
déployer avec votre application, si c’est possible. La distribution des programmes
complémentaires peut être limitée par des accords de licence de distribution.
Consultez la documentation d’un programme complémentaire pour des
informations spécifiques.
Outre les technologies décrites ici, vous pouvez utiliser des moteurs de bases de
données fournis par des tiers pour gérer l’accès aux bases de données des
applications C++Builder. Consultez la documentation ou le vendeur du moteur
de bases de données pour ce qui concerne les problèmes de droit, d’installation
et de configuration du moteur.
Remarque Pour les applications de bases de données utilisant Informix, vous ne pouvez pas
déployer d’exécutable autonome. Déployez à la place un fichier exécutable avec
la DLL de pilote dbexpinf.dll (listée dans le tableau suivant).
Si vous ne déployez pas un exécutable autonome, vous pouvez déployer avec
votre exécutable les pilotes dbExpress et les DLL DataSnap associés. Le tableau
suivant énumère les DLL appropriées et indique quand il faut les inclure:
Tableau 17.4 Déploiement dbExpress avec les DLL des pilotes (suite)
DLL de bases
de données Quand les déployer
dbexpora.dll Applications se connectant aux bases de données Oracle
dbexpdb2.dll. Applications se connectant aux bases de données DB2
dbexpmys.dll Applications se connectant aux bases de données MySQL 3.22.x
dbexpmysql.dll Applications se connectant aux bases de données MySQL 3.23.x
Midas.dll Requis par les applications de bases de données utilisant des ensembles
de données client
SQL Links
SQL Links propose les pilotes permettant de connecter une application au
logiciel client d’une base de données SQL (via le moteur de bases de données
Borland). Voir le document DEPLOY pour connaître les droits et restrictions
s’appliquant à la distribution de SQL Links. Comme pour le moteur de bases de
données Borland, SQL Links doit être déployé en utilisant InstallShield Express
(ou tout autre programme certifié).
Remarque SQL Links connecte le BDE au logiciel client et pas directement à la base de
données SQL même. Il est donc toujours nécessaire d’installer le programme
client du système de bases de données SQL utilisé. Reportez-vous à la
documentation de votre système SQL ou consultez le vendeur pour davantage
d’informations sur l’installation et la configuration du logiciel client.
Le tableau suivant présente les noms des fichiers de pilote et de configuration
utilisés par SQL Links pour se connecter aux différents systèmes de base de
données SQL. Ces fichiers sont fournis avec SQL Links et sont redistribuables en
accord avec la licence C++Builder.
Tableau 17.5 Fichiers des logiciels client des bases de données SQL
Vendeur Fichiers redistribuables
Oracle 7 SQLORA32.DLL et SQL_ORA.CNF
Oracle 8 SQLORA8.DLL et SQL_ORA8.CNF
Sybase Db-Lib SQLSYB32.DLL et SQL_SYB.CNF
Sybase Ct-Lib SQLSSC32.DLL et SQL_SSC.CNF
Microsoft SQL Server SQLMSS32.DLL et SQL_MSS.CNF
Informix 7 SQLINF32.DLL et SQL_INF.CNF
Informix 9 SQLINF9.DLL et SQL_INF9.CNF
DB/2 2 SQLDB232.DLL et SQL_DB2.CNF
DB/2 5 SQLDB2V5.DLL et SQL_DB2V5.CNF
InterBase SQLINT32.DLL et SQL_INT.CNF
Applications CGI
Quand vous créez des applications CGI, l’option ExecCGI et la clause SetHandler
du répertoire physique (spécifié dans la directive Directory du fichier httpd.conf)
doivent être définis pour permettre l’exécution de programmes, afin que le script
CGI puisse être exécuté. Pour vous assurer que les permissions ont été
correctement définies, utilisez la directive Alias en activant à la fois Options
ExecCGI et SetHandler.
Remarque Une autre approche consiste à utiliser la directive ScriptAlias (sans Options
ExecCGI), mais l’utilisation de cette approche peut empêcher votre application
CGI de lire des fichiers du répertoire ScriptAlias.
La ligne suivante de httpd.conf est un exemple d’utilisation de la directive Alias
pour créer un répertoire virtuel sur votre serveur et marquer l’emplacement
exact de votre script CGI :
Alias/MyWeb/"c:/httpd/docs/MyWeb/"
• Il faut éviter d’utiliser des coordonnées en pixel explicites, par exemple pour
écrire directement dans un canevas. Il faut à la place modifier les coordonnées
en leur appliquant un ratio proportionnel au ratio de différence des
résolutions écran entre le système de développement et celui d’utilisation. Si,
par exemple, l’application dessine un rectangle dans le canevas de dix pixels
de haut sur vingt pixels de large, multipliez les valeurs dix et vingt par le
ratio de différence de résolution. Ainsi, vous êtes certain que le rectangle
apparaît visuellement de la même taille pour différentes résolutions écran.
Fontes
Windows dispose d’un jeu standard de fontes TrueType et vectorielles. Linux est
founi avec un jeu de fontes dépendant de la distribution. Quand vous concevez
une application devant être déployée sur d’autres ordinateurs, tenez compte du
fait que tous les ordinateurs n’ont pas nécessairement de fontes en-dehors des
jeux standard.
Les composants texte utilisés dans l’application ne doivent utiliser que des fontes
qui sont très probablement disponibles sur les ordinateurs cible.
Quand l’utilisation d’une fonte non standard est absolument nécessaire dans une
application, vous devez distribuer cette fonte avec l’application. Soit le
programme d’installation, soit l’application même doit installer la fonte sur
l’ordinateur cible. La distribution de fontes créées par des tiers peut être sujette à
des restrictions imposées par leurs créateurs.
Windows dispose d’une protection contre l’utilisation d’une fonte inexistante sur
un système. Il lui substitue une fonte existante, la plus proche possible. Bien que
cela empêche les erreurs dues à des fontes manquantes, le résultat final peut
dégrader l’aspect visuel de l’application. Il est préférable de prévoir cette
éventualité à la conception.
Pour mettre à la disposition d’une application Windows une fonte non standard,
utilisez les fonctions AddFontResource et DeleteFontResource de l’API Windows.
Déployez les fichiers .fot des fontes non-standard avec l’application.
DEPLOY
Le document DEPLOY aborde certains aspects légaux de la distribution de divers
composants et utilitaires et autres produits pouvant faire partie ou être associés à
une application C++Builder. DEPLOY est un document installé dans le répertoire
principal de C++Builder. Il aborde les sujets suivants :
• Fichiers .exe, .dll et .bpl
• Composants et paquets de conception
• Moteur de bases de données Borland (BDE)
• Contrôles ActiveX
• Images exemple
• SQL Links
README
Le document README contient des informations de dernière minute
C++Builder ; il peut donc contenir des informations pouvant affecter les droits de
redistribution des composants, utilitaires ou autres éléments. README est un
document installé dans le répertoire principal de C++Builder.
Contrat de licence
Le contrat de licence C++Builder est un document imprimé qui traite des droits
et obligations légales concernant C++Builder.
II
Développement d’applications
Partie II
de bases de données
Les chapitres de cette partie présentent les concepts et les connaissances
nécessaires à la création d’applications de bases de données C++Builder.
Remarque Les niveaux de gestion possibles pour la conception d’applications de bases de
données dépendent de votre édition de C++Builder. En particulier, vous devez
disposer de l’édition Professionnelle pour utiliser les ensembles de données client
et de l’édition Entreprise pour développer des applications de bases de données
multiniveaux.
Conception d’applications
Chapitre 18
18
de bases de données
Les applications de bases de données permettent aux utilisateurs d’interagir avec
les informations stockées dans les bases de données. Les bases de données
permettent de structurer les informations et de les partager entre plusieurs
applications.
C++Builder permet de gérer les applications de bases de données relationnelles.
Les bases de données relationnelles organisent les informations en tables, qui
contiennent des lignes (enregistrements) et des colonnes (champs). Ces tables
peuvent être manipulées par des opérations simples appelées calculs relationnels.
Lorsque vous concevez une application de bases de données, vous devez
comprendre comment les données sont structurées. A partir de cette structure,
vous pouvez concevoir une interface utilisateur pour afficher les données et
permettre à l’utilisateur d’entrer de nouvelles informations et de modifier les
données existantes.
Ce chapitre présente certains aspects courants de la conception d’une application
de bases de données et les décisions inhérentes à la conception d’une interface
utilisateur.
Bien que tous ces types de bases de données contiennent des tables qui stockent
des informations, certains présentent certaines caractéristiques telles que :
• Sécurité des bases de données
• Transactions
• Intégrité référentielle, procédures stockées et déclencheurs
Si vous obligez les utilisateurs à fournir un mot de passe, vous devez déterminer
à quel moment ce dernier est requis. Si vous utilisez une base de données locale
mais envisagez de passer à un serveur SQL plus important, vous pouvez inviter
l’utilisateur à fournir son mot de passe au moment où il se connecte à la base de
données SQL plutôt qu’à l’ouverture des différentes tables.
Si votre application requiert plusieurs mots de passe pour la connexion à
plusieurs bases de données ou systèmes protégés, vous pouvez demander aux
utilisateurs de fournir un mot de passe maître unique qui permet d’accéder à
une table de mots de passe requis par ces systèmes. L’application fournit alors
les mots de passe par programmation, sans que les utilisateurs aient besoin de
fournir plusieurs mots de passe.
Dans les applications multiniveaux, vous pouvez utiliser un modèle de sécurité
différent. Vous pouvez utiliser HTTPs ou COM+ pour contrôler l’accès aux
niveaux intermédiaires et laisser ces derniers gérer tous les détails relatifs à
l’accès aux serveurs de bases de données.
Transactions
Une transaction est un groupe d’actions qui doivent être menées avec succès sur
une ou plusieurs tables dans une base de données avant d’être validées (rendues
définitives). Si l’une des actions du groupe échoue, toutes les actions sont
abandonnées (annulées).
Les transactions garantissent ce qui suit :
• Toutes les mises à jour d’une même transaction sont soit validées, soit
annulées et ramenées à leur état précédent. C’est ce que nous appelons
atomicité.
• Une transaction est une transformation valide de l’état d’un système, en
maintenant les constantes de cet état. C’est ce que nous appelons cohérence.
• Les transactions simultanées ne voient pas les résultats partiels et non validés
les unes des autres afin de ne pas créer d’incohérences dans l’état de
l’application. C’est ce que nous appelons isolation.
• Les mises à jour validées des enregistrements survivent aux pannes, y compris
les pannes de communication, les pannes de processus et les pannes système
des serveurs. C’est ce que nous appelons durabilité.
Les transactions protègent ainsi contre les défaillances matérielles qui se
produisent au milieu d’une commande de base de données ou d’un ensemble de
commandes. L’ouverture d’une transaction vous permet de bénéficier d’un état
durable après les pannes survenues sur les supports disque. Les transactions
constituent aussi la base du contrôle simultané de plusieurs utilisateurs sur les
serveurs SQL. Lorsque tous les utilisateurs interagissent avec la base de données
par le biais de transactions, les commandes d’un utilisateur ne peuvent pas
altérer l’unité d’une transaction d’un autre utilisateur ; le serveur SQL planifie les
transactions entrantes, qui réussissent ou échouent en bloc.
Bien que le support des transactions ne fasse pas partie de la plupart des bases
de données locales, il est fourni par InterBase local. En outre, les pilotes du
moteur de bases de données Borland offrent pour certaines un support des
transactions limité. Le support des transactions de bases de données est fourni
par le composant qui représente la connexion à la base de données. Pour plus de
détails sur la gestion des transactions à l’aide d’un composant connexion de base
de données, voir “Gestion des transactions” à la page 21-6.
Dans les applications multiniveaux, vous pouvez créer des transactions qui
comprennent des actions autres que des opérations de bases de données ou qui
englobent plusieurs bases de données. Pour plus de détails sur l’utilisation des
transactions dans les applications multiniveaux, voir “Gestion des transactions
dans les applications multiniveaux” à la page 29-19.
Structure générale
Bien qu’il existe de nombreuses façons d’organiser les composants d’une
application de base de données, la plupart d’entre elles suivent le schéma
général illustré par la figure suivante :
Figure 18.1 Architecture de base de données générique
Module de données
Si vous avez isolé votre interface utilisateur dans sa propre fiche, vous pouvez
utiliser un module de données afin d’y placer les composants qui représentent
les informations de bases de données (ensembles de données), et les composants
qui connectent ces ensembles de données aux autres éléments de votre
application. Comme les fiches de l’interface utilisateur, les modules de données
peuvent figurer dans le référentiel d’objets en vue d’être réutilisés ou partagés
par les applications.
Source de données
Le premier élément du module de données est une source de données. La source
de données relie l’interface utilisateur à un ensemble de données qui représente
les informations d’une base de données. Plusieurs contrôles orientés données
disposés sur une fiche peuvent partager une même source de données. Dans ce
cas, le contenu de chaque contrôle est synchronisé : lorsque l’utilisateur parcourt
les enregistrements, les valeurs figurant dans les différents champs de
l’enregistrement actif sont affichées dans les contrôles correspondants.
Ensemble de données
L’ensemble de données constitue le cœur de votre application de base de
données. Ce composant représente un ensemble d’enregistrements de la base de
données sous-jacente. Ces enregistrements peuvent être les données d’une seule
table de base de données, un sous-ensemble des champs ou des enregistrements
d’une table ou des informations émanant de plusieurs tables jointes en une vue
unique. L’utilisation d’ensembles de données protège la logique de votre
application de la restructuration des tables physiques de la base de données.
Lorsque la base de données sous-jacente change, vous pouvez être amené à
modifier la façon dont le composant ensemble de données spécifie les données
qu’il contient, mais le reste de votre application peut continuer à fonctionner
sans subir de modifications. Pour plus d’informations sur les propriétés et
méthodes courantes des ensembles de données, voir chapitre 22, “Présentation
des ensembles de données”.
Lorsque vous utilisez cette approche à base de fichiers, votre application écrit les
modifications sur disque à l’aide de la méthode SaveToFile de l’ensemble de
données client. SaveToFile accepte un paramètre, le nom du fichier qui est créé
(ou écrasé) et qui contient la table. Lorsque vous souhaitez lire une table
précédemment écrite à l’aide de la méthode SaveToFile, utilisez la méthode
LoadFromFile. LoadFromFile accepte aussi un paramètre, le nom du fichier
contenant la table.
Si vous chargez les données toujours à partir du même fichier et les y
enregistrez toujours, vous pouvez utiliser la propriété FileName au lieu des
méthodes SaveToFile et LoadFromFile. Lorsque FileName a pour valeur un nom de
fichier valide, les données sont automatiquement chargées à partir du fichier à
l’ouverture de l’ensemble de données client et enregistrées dans le fichier à la
fermeture de l’ensemble de données client.
Cette architecture simple de type fichier est une application à niveau unique.
La logique qui manipule les informations de bases de données figure dans
l’application qui implémente l’interface utilisateur, tout en étant confinée dans
un module de données.
L’approche de type fichier présente l’avantage de la simplicité. Aucun serveur de
bases de données ne doit être installé, configuré ou déployé (bien que l’ensemble
de données client requière midas.dll). Aucune licence de site ni administration de
base de données n’est nécessaire.
En outre, certaines versions de C++Builder vous permettent de réaliser des
conversions entre des documents XML arbitraires et les paquets de données
utilisés par un ensemble de données client. Par conséquent, l’approche à base de
fichiers permet d’utiliser des documents XML ainsi que des ensembles de
données dédiés. Pour plus d’informations sur la conversion entre des documents
XML et des paquets de données d’ensemble de données client, voir chapitre 30,
“Utilisation de XML dans les applications de bases de données”.
L’approche à base de fichiers ne gère pas les situations multi-utilisateurs.
L’ensemble de données doit être totalement dédié à l’application. Les données
sont enregistrées dans des fichiers sur disque puis chargées ultérieurement, mais
aucune protection intégrée n’empêche un utilisateur d’écraser les fichiers de
données d’un autre utilisateur.
Pour plus d’informations sur l’utilisation d’un ensemble de données client dont
les données sont stockées sur disque, voir “Utilisation d’un ensemble de données
client avec des données basées sur des fichiers” à la page 27-39.
Malgré son caractère quelque peu complexe, cette approche s’avère parfois
opportune :
• L’ensemble de données source et le fournisseur d’ensemble de données étant
externes, vous pouvez plus facilement contrôler la façon dont ils lisent les
données et appliquent les mises à jour. Par exemple, le composant fournisseur
met à disposition une série d’événements qui ne sont pas disponibles lorsque
vous utilisez un ensemble de données client spécialisé pour accéder aux
données.
• Lorsque l’ensemble de données source est externe, vous pouvez le lier à un
autre ensemble de données dans une relation maître/détail. Un fournisseur
externe convertit automatiquement cette organisation en un seul ensemble de
données comprenant des détails imbriqués. Lorsque l’ensemble de données
source est interne, vous ne pouvez pas créer d’ensembles détail imbriqués de
cette façon.
• La connexion d’un ensemble de données client à un ensemble de données
externe est une architecture qui peut facilement évoluer vers une architecture
multiniveau. Etant donné que le processus de développement est d’autant plus
coûteux et consommateur d’énergie que le nombre de niveaux augmente, vous
pouvez commencer à développer votre application en tant qu’application à
niveau unique ou double. A mesure qu’augmenteront la quantité de données,
le nombre d’utilisateurs et le nombre des différentes applications accédant aux
données, vous serez éventuellement amené à adopter une architecture
multiniveau. Si vous pensez utiliser à terme une architecture multiniveau, il
peut être judicieux de commencer en utilisant un ensemble de données client
avec un ensemble de données source externe. Ainsi, lorsque vous transférez
vers un niveau intermédiaire la logique de l’accès et de la manipulation des
données, le développement effectué est protégé car le code est réutilisable à
mesure que l’application prend de l’ampleur.
• TClientDataSet peut être lié à tout ensemble de données source. Cela signifie
que vous pouvez utiliser des ensembles de données personnalisés (composants
tierces parties) pour lesquels n’existe aucun ensemble de données client
spécialisé correspondant. Certaines versions de C++Builder incluent même des
composants fournisseur spéciaux qui connectent un ensemble de données
client à un document XML plutôt qu’à un autre ensemble de données. (Cela
fonctionne de la même façon que la connexion d’un ensemble de données
client à un autre ensemble de données (source), à la différence que le
fournisseur XML utilise un document XML à la place d’un ensemble de
données. Pour plus d’informations sur ces fournisseurs XML, voir “Utilisation
d’un document XML comme source pour un fournisseur” à la page 30-9.)
L’architecture qui connecte un ensemble de données client à un ensemble de
données externe se présente sous deux versions :
• Connexion d’un ensemble de données client à un autre ensemble de données
dans la même application.
• Utilisation d’une architecture multiniveau.
Pour plus d’informations sur l’utilisation d’un ensemble de données client avec
un fournisseur, voir “Utilisation d’un ensemble de données client avec un
fournisseur” à la page 27-29.
base de données, exploiter ces données sur leurs ordinateurs portables pendant
qu’ils sont en déplacement dans tout le pays, et même mettre à jour des
enregistrements sur des sites existants ou de nouveaux sites. Quand les
représentants reviennent dans l’entreprise, ils doivent charger leurs changements
de données dans la base de données de l’entreprise pour les mettre à la
disposition de tous.
Lors d’une opération sur site, l’ensemble de données client d’une application de
modèle “briefcase” obtient ses données d’un fournisseur. L’ensemble de données
client est ensuite connecté au serveur de base de données et peut, par le biais du
fournisseur, récupérer des données du serveur et lui communiquer des mises à
jour. Avant de se déconnecter du fournisseur, l’ensemble de données client
enregistre sa capture instantanée des informations dans un fichier sur disque.
Hors site, l’ensemble de données client charge ses données à partir du fichier et
enregistre toute modification dans ce fichier. Dans une dernière phase, une fois
de nouveau sur site, l’ensemble de données client se reconnecte au fournisseur
afin d’appliquer ses mises à jour au serveur de base de données ou d’actualiser
sa capture instantanée des données.
Ecriture de rapports
Si vous souhaitez que les utilisateurs puissent imprimer les informations de
bases de données émanant des ensembles de données de votre application, vous
pouvez utiliser les composants rapport de la page QReport de la palette des
composants. L’utilisation de ces composants vous permet de construire
visuellement des rapports à bandes pour présenter et résumer les informations
contenues dans vos tables de bases de données. Vous pouvez ajouter des
résumés aux en-têtes et aux pieds de page de groupe pour analyser les données
en fonction de critères de regroupement.
Démarrez un rapport pour votre application en sélectionnant l’icône QuickReport
dans la boîte de dialogue Nouveaux éléments. Sélectionnez Fichier|Nouveau|
Autre dans le menu principal et allez à la page Affaires. Double-cliquez sur
l’icône Expert QuickReport pour lancer l’expert.
Remarque Pour un exemple d’utilisation des composants de la page QReport, reportez-vous
au programme exemple QuickReport livré avec C++Builder.
Remarque Des contrôles orientés données d’aide à la décision plus complexes sont
présentés dans le chapitre 20, “Utilisation de composants d’aide à la décision”.
Quels que soient les contrôles orientés données que vous choisissez d’ajouter à
votre interface, ils présentent certaines fonctionnalités communes, décrites
ci-après.
interface utilisateur utilise des contrôles non orientés données, vous pouvez
utiliser les événements d’un composant source de données pour fournir
manuellement le même type de réponse.
L’événement OnDataChange se produit chaque fois que les données d’un
enregistrement sont susceptibles d’avoir évolué, notamment lorsque le contenu
des champs est modifié ou que le curseur est positionné sur un autre
enregistrement. Cet événement, déclenché par toute modification, garantit que le
contrôle reflète les valeurs de champ en cours dans l’ensemble de données.
Généralement, un gestionnaire d’événement OnDataChange rafraîchit la valeur
d’un contrôle non orienté données qui affiche des données de champ.
L’événement OnUpdateData se produit lorsque les données de l’enregistrement en
cours sont sur le point d’être validées. Par exemple, un événement OnUpdateData
se produit après l’appel de Post, mais avant la validation effective des données
dans le cache local ou le serveur de bases de données sous-jacent.
L’événement OnStateChange se produit lorsque l’état de l’ensemble de données
change. Lorsque cet événement est déclenché, vous pouvez examiner la propriété
State de l’ensemble de données afin de déterminer son état en cours.
Par exemple, le gestionnaire d’événement OnStateChange suivant active ou
désactive les boutons ou les éléments de menu en fonction de l’état en cours :
void __fastcall TForm1::DataSource1StateChange(TObject *Sender)
{
CustTableActivateBtn->Enabled = (CustTable->State == dsInactive);
CustTableEditBtn->Enabled = (CustTable->State == dsBrowse);
CustTableCancelBtn->Enabled = (CustTable->State == dsInsert ||
CustTable->State == dsEdit ||
CustTable->State == dsSetKey);
ƒ
}
Remarque Pour plus d’informations sur les états des ensembles de données, voir
“Détermination des états d’un ensemble de données” à la page 22-3.
texte formaté à true. Pour afficher les tabulations et permettre aux utilisateurs
d’entrer des tabulations dans le mémo, mettez la propriété WantTabs à true. Pour
limiter le nombre de caractères pouvant être saisis par les utilisateurs dans un
mémo de base de données, utilisez la propriété MaxLength. Par défaut,
MaxLength vaut 0, ce qui signifie qu’il n’y a aucune limite, en dehors de celles
du système d’exploitation, au nombre de caractères pouvant être saisi.
Comme TDBRichEdit peut contenir de grands volumes de données, il faut parfois
beaucoup de temps pour afficher les données à l’exécution. Pour accélérer le
défilement des enregistrements, TDBRichEdit a une propriété AutoDisplay qui
contrôle si les données auxquelles il accède doivent être affichées
automatiquement. Si AutoDisplay est à false, TDBRichEdit affiche le nom du
champ à la place des données. Pour visualiser les données, il suffit de double-
cliquer à l’intérieur du contrôle.
Affichage dans une boîte liste de référence et une boîte à options de référence
Les boîtes liste de référence et les boîtes à options de référence
(TDBLookupListBox et TDBLookupComboBox) proposent à l’utilisateur une liste
limitée de choix à partir desquels il peut définir une valeur de champ correcte.
Lorsqu’il sélectionne un élément dans la liste, la valeur de champ correspondante
est remplacée dans l’ensemble de données sous-jacent.
Prenons l’exemple d’un bon de commande dont les champs sont liés à
OrdersTable. OrdersTable contient un champ CustNo correspondant à un numéro
d’ID client, mais OrdersTable ne contient aucune autre information sur le client.
CustomersTable, en revanche, contient un champ CustNo correspondant à un
numéro d’ID client ainsi que des informations supplémentaires, telles que
l’entreprise et l’adresse du client. Lors de la facturation, il serait pratique que le
bon de commande permette à un employé de sélectionner un client d’après le
nom de l’entreprise au lieu de l’ID client. Un composant TDBLookupListBox
affichant le nom de toutes les entreprises dans CustomersTable permettra à un
utilisateur de sélectionner le nom de l’entreprise dans la liste et de placer CustNo
sur le bon de commande.
Indicateur
d’enregistrement
Vous pouvez utiliser le bouton à points de suspension pour ouvrir des fiches
contenant des vues plus détaillées des données de la colonne. Par exemple, dans
une table affichant la synthèse des factures émises, vous pouvez intégrer un
bouton à points de suspension dans la colonne des totaux permettant d’afficher
une fiche contenant les éléments d’une facture précise ou le montant de la TVA,
etc. Pour les champs graphiques, vous pouvez utiliser ce bouton pour afficher
une fiche contenant l’image.
Pour doter une colonne d’un bouton à points de suspension :
1 Sélectionnez la colonne dans la boîte liste Colonnes.
2 Choisissez cbsEllipsiscomme valeur de la propriété ButtonStyle.
3 Ecrivez un gestionnaire d’événement OnEditButtonClick.
Pour afficher les champs composites comme s’ils étaient aplanis, attribuez la
valeur false à la propriété ObjectView de l’ensemble de données. L’ensemble
de données stocke les champs composites sous la forme d’un ensemble de
champs séparés et la grille reflète cette organisation en attribuant une colonne
à chaque composante.
• Elle peut afficher des champs composites dans une seule colonne, indiquant
ainsi qu’ils constituent un seul champ. Vous pouvez alors étendre et réduire la
colonne en cliquant sur la flèche dans la barre de titre du champ ou en
définissant la propriété Expanded de la colonne :
• Lorsqu’une colonne est étendue, chaque champ enfant apparaît dans sa
propre sous-colonne et une barre de titre correspondante apparaît sous la
barre de titre du champ parent. La hauteur de la barre de titre de la grille
augmente : la première ligne fournit le nom du champ composite et la
seconde indique ses différentes composantes. Les champs qui ne sont pas
composites apparaissent avec des barres de titre extra hautes. Cette
extension se poursuit pour les composantes qui sont elles-mêmes des
champs composites (par exemple, une table détail imbriquée dans une
autre) et la hauteur de la barre de titre augmente en conséquence.
• Lorsque le champ est réduit, seule la colonne apparaît avec une chaîne non
modifiable des champs enfants, séparés par des virgules.
Pour afficher un champ composite dans une colonne étendue ou réduite,
attribuez la valeur true à la propriété ObjectView de l’ensemble de données.
L’ensemble de données stocke le champ composite sous la forme d’un champ
composant unique qui contient un ensemble de sous-champs imbriqués. La
grille reflète cette organisation dans une colonne qui peut être étendue ou
réduite.
La figure suivante montre une grille contenant un champ ADT et un champ
tableau. La propriété ObjectView de l’ensemble de données a pour valeur false
afin que chaque champ enfant dispose d’une colonne.
Figure 19.2 Contrôle TDBGrid avec ObjectView défini à false
Champs enfant ADT Champs enfant tableau
Les figures suivantes montrent la grille dotée d’un champ ADT et d’un champ
tableau. La première figure montre les champs réduits. Cet état ne permet pas de
les modifier. La seconde figure montre les champs étendus. Pour étendre et
réduire les champs, cliquez sur la flèche dans leur barre de titre.
Le tableau suivant énumère les propriétés qui affectent l’affichage des champs
ADT et tableau dans un objet TDBGrid :
Remarque Outre des champs ADT et array, certains ensembles de données comprennent
des champs qui font référence à un autre ensemble de données (champs
ensemble de données) ou à un enregistrement appartenant à d’autres champs
ensemble de données (référence). Les grilles orientées données affichent
respectivement ces champs sous les formes Ensemble de données ou Référence.
A l’exécution, un bouton à points de suspension apparaît à droite. Le fait de
cliquer sur ce bouton active une nouvelle fiche dont la grille affiche le contenu
du champ. Dans le cas d’un champ ensemble de données, cette grille affiche
l’ensemble de données correspondant à la valeur du champ. Dans le cas d’un
champ référence, cette grille contient une seule ligne qui affiche l’enregistrement
d’un autre ensemble de données.
Tableau 19.5 Options détaillées des propriétés Options du composant TDBGrid (suite)
Option Utilisation
dgRowSelect true : la barre de sélection occupe toute la largeur de la grille.
false : (valeur par défaut) la sélection d’un champ d’un
enregistrement ne sélectionne que ce champ.
dgAlwaysShowSelection true : (valeur par défaut) la barre de sélection de la grille est
toujours visible, même si un autre contrôle a la focalisation.
false : la barre de sélection n’apparaît dans la grille que si la grille
a la focalisation.
dgConfirmDelete true : (valeur par défaut) demande la confirmation de la
suppression d’enregistrements (Ctrl+Suppr).
false : supprime les enregistrements sans confirmation.
dgCancelOnExit true : (valeur par défaut) annule une insertion en attente lorsque la
focalisation quitte la grille. Cela permet d’éviter des validations
involontaires d’enregistrements vierges ou partiellement vierges.
false : permet à une insertion en attente d’être validée.
dgMultiSelect true : permet aux utilisateurs de sélectionner des lignes non
contiguës en utilisant les touches Ctrl+Maj ou Maj+flèche.
false : (valeur par défaut) ne permet pas à l’utilisateur de
sélectionner plusieurs lignes.
Pour plus d’informations sur les propriétés et les méthodes des grilles de
contrôle de base de données, voir la Référence VCL en ligne.
Utilisation de composants
Chapitre 20
20
d’aide à la décision
Les composants d’aide à la décision permettent de créer des graphes et des
tableaux de références croisées pour visualiser et analyser des données selon
différentes perspectives. Pour plus d’informations sur les références croisées, voir
“Présentation des références croisées” à la page 20-2.
Présentation
Les composants d’aide à la décision apparaissent sur la page Decision Cube de
la palette des composants :
• Le cube de décision, TDecisionCube, est un lieu de stockage de données
multidimensionnelles.
• La source de décision, TDecisionSource, définit l’état actuel du pivot d’une
grille ou d’un graphe de décision.
• La requête de décision, TDecisionQuery, est une forme spécialisée de TQuery
utilisée pour définir les données d’un cube de décision.
• Le pivot de décision, TDecisionPivot, vous permet d’ouvrir et de fermer les
dimensions, ou champs, d’un cube de décision, en appuyant sur des boutons.
• La grille de décision, TDecisionGrid, affiche des données unidimensionnelles ou
multidimensionnelles sous forme d’un tableau.
• Le graphe de décision, TDecisionGraph, affiche les champs en provenance
d’une grille de décision sous forme d’un graphe dynamique, qui change
lorsque les dimensions des données sont modifiées.
La figure suivante montre tous les composants d’aide à la décision placés dans
une fiche au moment de la conception.
Pivot de décision
Grille de décision
Graphe de décision
Pour créer une fiche avec des tableaux et des graphes de données
multidimensionnelles, suivez ces étapes :
1 Créez une fiche.
2 Ajoutez ces composants à la fiche et utilisez l’inspecteur d’objets pour les lier
comme indiqué :
• un ensemble de données, habituellement TDecisionQuery (pour plus de
détails, reportez-vous à “Création d’ensembles de données de décision avec
l’éditeur de requête de décision” à la page 20-6) ou TQuery ;
• un cube de décision, TDecisionCube, lié à l’ensemble de données en
définissant la propriété DataSet du cube de décision par le nom de
l’ensemble de données ;
• une source de décision, TDecisionSource, liée au cube de décision en
définissant la propriété DecisionCube de la source de décision par le nom du
cube de décision.
3 Ajoutez un pivot de décision, TDecisionPivot, et liez-le à la source de décision
dans l’inspecteur d’objets en définissant la propriété DecisionSource du pivot
par le nom de la source de décision. Le pivot de décision est facultatif mais
utile ; il permet au développeur de fiches et à l’utilisateur final de changer les
dimensions affichées dans les grilles ou les graphes de décision en appuyant
sur des boutons.
Dans son orientation par défaut (horizontale), les boutons de gauche du pivot
de décision correspondent aux champs de gauche de la grille de décision (les
lignes) ; les boutons de droite correspondent aux champs du haut de la grille
de décision (les colonnes).
Vous pouvez déterminer l’endroit où apparaissent les boutons du pivot de
décision en définissant sa propriété GroupLayout par xtVertical, xtLeftTop ou
xtHorizontal (la valeur par défaut). Pour plus d’informations sur les propriétés
du pivot de décision, reportez-vous à “Utilisation de pivots de décision” à la
page 20-10.
4 Ajoutez un ou plusieurs graphes et/ou grilles de décision, liés à la source de
décision. Pour plus de détails, reportez-vous à “Création et utilisation de
grilles de décision” à la page 20-11 et “Création et utilisation de graphes de
décision” à la page 20-14.
5 Utilisez l’éditeur de requête de décision ou la propriété SQL de
TDecisionQuery (ou TQuery) pour spécifier les tables, les champs et les calculs
récapitulatifs à afficher dans la grille ou dans le graphe. Le dernier champ de
SQL SELECT peut être un champ récapitulatif. Les autres champs de SELECT
doivent être des champs GROUP BY. Pour en savoir plus, reportez-vous à
“Création d’ensembles de données de décision avec l’éditeur de requête de
décision” à la page 20-6.
6 Définissez la propriété Active de la requête de décision (ou d’un autre
composant ensemble de données) à true.
moyennes, l’agrégat peut être utilisé pour tous les champs. N’utilisez COUNT(*)
que dans les cas où aucun des champs ne peut contenir de valeurs vierges ou si
l’opérateur COUNT n’est pas disponible pour tous les champs.
Ces informations apparaissent dans les boîtes situées sur le côté droit de
l’éditeur :
• Pour modifier le nom d’une dimension ou d’un champ récapitulatif
apparaissant sur le pivot, la grille ou le graphe de décision, entrez un
nouveau nom dans la boîte de saisie Nom affichée.
• Pour savoir si le champ sélectionné est une dimension ou un champ
récapitulatif, lisez le texte se trouvant dans la boîte de saisie Type. Si
l’ensemble de données est un composant TTable, vous pouvez utiliser Type
pour spécifier si le champ sélectionné est une dimension ou un champ
récapitulatif.
• Pour désactiver ou activer la dimension ou le champ récapitulatif sélectionné,
modifiez le paramétrage de la boîte liste déroulante Type actif : Actif, Si
besoin ou Inactif. Désactiver une dimension ou la définir par Si besoin
économise de la mémoire.
• Pour modifier le format de cette dimension ou de ce champ récapitulatif,
entrez une chaîne de formatage dans la boîte de saisie Format.
• Pour afficher cette dimension ou ce champ récapitulatif par Année, Trimestre
ou Mois, changez le paramétrage de la boîte liste déroulante Groupage. Dans
la boîte liste Groupage, vous pouvez placer la dimension ou le récapitulatif
sélectionné dans un état “perforé” permanent. Cela peut être utile pour
économiser de la mémoire lorsqu’une dimension a de nombreuses valeurs.
Pour plus d’informations, voir “Considérations relatives au contrôle de la
mémoire” à la page 20-21.
• Pour déterminer le point de départ des intervalles, commencez par choisir la
valeur adaptée de regroupement dans la liste déroulante Groupage puis entrez
la valeur de départ de l’intervalle dans la liste déroulante Valeur initiale.
Propriétés et événements
Voici les propriétés et les événements spéciaux qui contrôlent l’aspect et le
comportement des sources de décision :
• La propriété ControlType de TDecisionSource indique si les boutons du pivot de
décision doivent agir comme des cases à cocher (sélections multiples) ou des
boutons radio (sélections mutuellement exclusives).
• Les propriétés SparseCols et SparseRows de TDecisionSource indiquent si les
colonnes ou les lignes sans valeur doivent être affichées ; si true, les colonnes
ou les lignes vides sont affichées.
• TDecisionSource possède les événements suivants :
• OnLayoutChange se produit lorsque l’utilisateur effectue des pivotements ou
des perforations qui réorganisent les données.
• OnNewDimensions se produit lorsque les données elles-mêmes sont
modifiées, par exemple lorsque les champs récapitulatifs ou les dimensions
sont modifiés.
• OnSummaryChange se produit lorsque la valeur récapitulative en cours est
modifiée.
• OnStateChange se produit quand le cube de décision est activé ou désactivé.
• OnBeforePivot se produit lorsque les modifications sont validées mais pas
encore reflétées par l’interface utilisateur. Les développeurs ont la
possibilité d’effectuer les changements, par exemple de capacité ou de l’état
du pivot, avant que l’utilisateur de l’application ne puisse voir le résultat
de son action.
• OnAfterPivot est déclenché après une modification de l’état du pivot. Les
développeurs peuvent intercepter des informations à ce moment.
Pour plus d’informations sur ce qui apparaît dans un graphe de décision, voir la
section suivante, “Affichage du graphe de décision”.
Pour créer un graphe de décision, voir la section précédente, “Création de
graphes de décision”.
Pour connaître les propriétés des graphes de décision et savoir comment changer
l’aspect et le comportement des graphes de décision, voir “Personnalisation du
graphe de décision” à la page 20-17.
Par défaut, les séries sont représentées par des barres d’histogramme qui
peuvent avoir jusqu’à 16 couleurs. Vous pouvez modifier le type et les propriétés
du modèle pour créer un nouveau modèle par défaut. Lorsque vous utilisez le
pivot pour faire passer la source de décision par différents états, le modèle est
utilisé pour créer de façon dynamique la série de chaque nouvel état. Pour avoir
plus de détails sur les modèles, voir “Définition des modèles de graphe de
décision par défaut” à la page 20-18.
Pour personnaliser une série individuelle, suivez les instructions de
“Personnalisation des séries d’un graphe de décision” à la page 20-19.
Vous trouverez dans l’aide en ligne la description des autres onglets de la page
Séries.
• toutes les valeurs, pour basculer entre l’affichage dans les grilles de
décision des récapitulations seulement ou des récapitulations plus les autres
valeurs.
• à partir de la liste des catégories disponibles, une catégorie à “forer” pour
connaître les valeurs détail.
• Cliquer avec le bouton gauche sur un bouton de dimension pour ouvrir ou
fermer cette dimension.
• Faire glisser les boutons de dimension depuis la partie lignes vers la partie
colonnes et réciproquement ; ils peuvent ensuite les placer à côté des boutons
existant dans cette partie ou sur l’icône de lignes ou de colonnes.
est en cours, une exception est déclenchée. Pour éviter d’appeler StartTransaction,
vous pouvez vérifier la propriété InTransaction :
if (!Database1->InTransaction)
Database1->StartTransaction();
TSQLConnection utilise également la méthode StartTransaction dans une version
qui offre davantage de contrôle. Notamment, StartTransaction accepte un
descripteur de transaction qui permet de gérer plusieurs transactions simultanées
et de spécifier le niveau d’isolation des transactions pour chaque transaction.
(Pour plus d’informations sur les niveaux de transaction, voir “Spécification du
niveau d’isolation des transactions” à la page 21-10.) Pour gérer plusieurs
transactions simultanées, attribuez au champ TransactionID du descripteur de
transaction une valeur unique. TransactionID peut prendre n’importe quelle
valeur, sous réserve qu’elle soit unique (c’est-à-dire non conflictuelle avec une
transaction en cours). Suivant le serveur, les transactions démarrées par
TSQLConnection peuvent être imbriquées (comme dans le cas d’une connexion
ADO) ou se chevaucher.
TTransactionDesc TD;
TD.TransactionID = 1;
TD.IsolationLevel = xilREADCOMMITTED;
SQLConnection1->StartTransaction(TD);
Par défaut, dans le cas des transactions se chevauchant, la première transaction
devient inactive lorsque la seconde démarre, bien que vous puissiez différer la
validation ou l’annulation de la première. Si vous utilisez TSQLConnection avec
une base de données InterBase, vous pouvez identifier chaque ensemble de
données dans votre application avec une transaction active particulière, en
définissant sa propriété TransactionLevel. En d’autres termes, après le démarrage
d’une seconde transaction, vous pouvez continuer à utiliser les deux transactions
simultanément, en associant simplement un ensemble de données à la transaction
qui vous intéresse.
Remarque Contrairement à TADOConnection, TSQLConnection et TDatabase ne reçoivent pas
d’événements au démarrage des transactions.
InterBase Express offre davantage de contrôle que TSQLConnection en utilisant un
composant transaction distinct au lieu de démarrer les transactions au moyen du
composant connexion. Vous pouvez, toutefois, utiliser TIBDatabase pour démarrer
une transaction par défaut :
if (!IBDatabase1->DefaultTransaction->InTransaction)
IBDatabase1->DefaultTransaction->StartTransaction();
Vous pouvez obtenir des transactions se chevauchant à l’aide de deux
composants transaction séparés. Chaque composant transaction possède un
ensemble de paramètres qui permettent de configurer les propriétés de la
transaction. Ces paramètres vous permettent de spécifier le niveau d’isolation,
ainsi que d’autres propriétés de la transaction.
une action sur des données mais ne renvoyant pas d’ensemble de résultat sont
les suivantes : INSERT, DELETE et UPDATE.
La syntaxe de la méthode Execute dépend du type de connexion :
• Dans le cas de TDatabase, Execute possède quatre paramètres : une chaîne
AnsiString qui spécifie une instruction SQL unique à exécuter, un objet
TParams qui fournit toutes les valeurs de paramètre de l’instruction, une
valeur booléenne qui indique si l’instruction doit être placée en mémoire cache
en vue d’un appel ultérieur et un pointeur vers un curseur BDE pouvant être
renvoyé (il est recommandé d’indiquer NULL).
• Dans le cas de TADOConnection, il existe deux versions de la méthode Execute.
La première possède une valeur WideString qui spécifie l’instruction SQL et
un second paramètre qui désigne un ensemble d’options qui déterminent si
l’instruction est exécutée de façon asynchrone et si elle renvoie des
enregistrements. Cette première syntaxe renvoie une interface pour les
enregistrements renvoyés. La seconde syntaxe possède une valeur WideString
qui spécifie l’instruction SQL, un deuxième paramètre qui renvoie le nombre
d’enregistrements affectés par l’exécution de l’instruction et un troisième qui
désigne des options, telles que l’exécution ou non de l’instruction de façon
asynchrone. Aucune des syntaxes ne permet la transmission de paramètres.
• Dans le cas de TSQLConnection, Execute possède trois paramètres : une chaîne
AnsiString qui spécifie une instruction SQL unique à exécuter, un objet
TParams qui fournit les valeurs de paramètre de cette instruction et un
pointeur qui peut recevoir un objet TCustomSQLDataSet créé pour renvoyer les
enregistrements NULL.
Remarque Execute ne peut exécuter qu’une instruction SQL en même temps. A la différence
des utilitaires de script SQL, un seul appel d’Execute ne permet pas d’exécuter
plusieurs instructions SQL. Pour ce faire, appelez Execute autant de fois que
nécessaire.
Il est relativement facile d’exécuter une instruction ne comprenant aucun
paramètre. Par exemple, le code suivant exécute une instruction CREATE TABLE
(DDL) sans aucun paramètre sur un composant TSQLConnection :
void __fastcall TDataForm::CreateTableButtonClick(TObject *Sender)
{
SQLConnection1->Connected = true;
AnsiString SQLstmt = "CREATE TABLE NewCusts " +
"( " +
" CustNo INTEGER, " +
" Company CHAR(40), " +
" State CHAR(2), " +
" PRIMARY KEY (CustNo) " +
")";
SQLConnection1->Execute(SQLstmt, NULL, NULL);
}
Pour utiliser des paramètres, vous devez créer un objet TParams. Pour chaque
valeur de paramètre, utilisez la méthode TParams::CreateParam afin d’ajouter un
objet TParam. Ensuite, utilisez les propriétés de TParam pour décrire le paramètre
et définir sa valeur.
Ce processus est illustré dans l’exemple suivant, qui utilise TDatabase pour
exécuter une instruction INSERT. L’instruction INSERT possède un paramètre
unique nommé :StateParam. Un objet TParams (appelé stmtParams) est créé afin de
fournir la valeur “CA” pour ce paramètre.
void __fastcall TForm1::INSERT_WithParamsButtonClick(TObject *Sender)
{
AnsiString SQLstmt;
TParams *stmtParams = new TParams;
try
{
Database1->Connected = true;
stmtParams->CreateParam(ftString, "StateParam", ptInput);
stmtParams->ParamByName("StateParam")->AsString = "CA";
SQLstmt = "INSERT INTO ’Custom.db’ ";
SQLstmt += "(CustNo, Company, State) ";
SQLstmt += "VALUES (7777, ’Robin Dabank Consulting’, :StateParam)";
Database1->Execute(SQLstmt, stmtParams, false, NULL);
}
__finally
{
delete stmtParams;
}
}
Si l’instruction SQL comprend un paramètre mais que vous ne fournissez pas
d’objet TParam pour indiquer sa valeur, l’instruction SQL peut générer une
erreur lors de son exécution (cela dépend du type de la base de données
utilisée). Si un objet TParam est fourni alors qu’aucun paramètre ne lui
correspond dans l’instruction SQL, une exception est déclenchée lorsque
l’application tente d’utiliser le TParam.
Obtention de métadonnées
Tous les composants connexion de base de données peuvent extraire du serveur
de bases de données des listes de métadonnées, bien que le type des
métadonnées extraites est variable. Les méthodes qui extraient les métadonnées
remplissent une liste de chaînes avec les noms de différentes entités disponibles
sur le serveur. Vous pouvez alors utiliser ces informations pour, par exemple,
permettre aux utilisateurs de sélectionner une table dynamiquement à
l’exécution.
Vous pouvez utiliser un composant TADOConnection pour extraire les
métadonnées des tables et procédures stockées disponibles sur le stockage de
données ADO. Vous pouvez alors utiliser ces informations pour, par exemple,
permettre aux utilisateurs de sélectionner une table ou procédure stockée
dynamiquement à l’exécution.
Tableau 22.1 Valeurs possibles pour la propriété State des ensembles de données
Valeur Etat Signification
dsInactive Inactif L’ensemble de données est fermé. Ses données sont
indisponibles.
dsBrowse Visualisation L’ensemble de données est ouvert. Ses données peuvent être
vues mais pas modifiées. C’est l’état par défaut d’un
ensemble de données ouvert.
dsEdit Edition L’ensemble de données est ouvert. La ligne en cours peut être
modifiée. (non supporté par les ensembles de données
unidirectionnels)
Tableau 22.1 Valeurs possibles pour la propriété State des ensembles de données (suite)
Valeur Etat Signification
dsInsert Insertion L’ensemble de données est ouvert. Une nouvelle ligne peut
être insérée. (non supporté par les ensembles de données
unidirectionnels)
dsSetKey Indexation L’ensemble de données est ouvert. Active la définition de
(SetKey) portées et de valeurs clé pour les opérations portant sur des
portées et les opérations GotoKey. (non supporté par tous les
ensembles de données)
dsCalcFields Champs L’ensemble de données est ouvert. Indique qu’un événement
calculés OnCalcFields est en cours. Interdit toute modification de
(CalcFields) champ non calculé.
dsCurValue CurValue L’ensemble de données est ouvert. Indique que la propriété
CurValue des champs est lue par un gestionnaire
d’événement qui répond aux erreurs en appliquant des mises
à jour en mémoire cache.
dsNewValue NewValue L’ensemble de données est ouvert. Indique que la propriété
NewValue des champs est lue par un gestionnaire
d’événement qui répond aux erreurs en appliquant des mises
à jour en mémoire cache.
dsOldValue OldValue L’ensemble de données est ouvert. Indique que la propriété
OldValue des champs est lue par un gestionnaire
d’événement qui répond aux erreurs en appliquant des mises
à jour en mémoire cache.
dsFilter Filtrage L’ensemble de données est ouvert. Indique qu’une opération
de filtrage est en cours. Un ensemble de données restreint
peut être visualisé, sans qu’aucune donnée ne puisse être
changée. (non supporté par les ensembles de données
unidirectionnels)
dsBlockRead Lecture de L’ensemble de données est ouvert. Les contrôles orientés
bloc données ne sont pas mis à jour et les événements ne sont pas
déclenchés lorsque l’enregistrement en cours est modifié.
dsInternalCalc Calcul L’ensemble de données est ouvert. Un événement
interne OnCalcFields est en cours pour des valeurs calculées stockées
avec l’enregistrement. (uniquement pour les ensembles de
données client)
dsOpening Ouverture L’ensemble de données est dans le processus d’ouverture,
mais n’a pas fini. Cet état arrive quand l’ensemble de
données est ouvert pour une lecture asynchrone.
TDataSet définit deux propriétés booléennes qui donnent des indications utiles
pour parcourir les enregistrements d’un ensemble de données.
Eof
Quand la valeur de Eof est true, cela indique que le curseur se trouve sans
équivoque sur la dernière ligne de l’ensemble de données. Eof passe à true
quand une application :
• Ouvre un ensemble de données vide.
• Réussit à appeler la méthode Last de l’ensemble de données.
• Appelle la méthode Next de l’ensemble de données et que son exécution
échoue (car le curseur se trouve déjà sur la dernière ligne de l’ensemble de
données).
• Appelle SetRange sur une portée ou un ensemble de données vide.
Eof vaut false dans tous les autres cas ; vous devez supposer que Eof vaut false
sauf si l’une des conditions ci-dessus est vérifiée et si vous avez testé directement
la valeur de la propriété.
Le test sur Eof se fait généralement dans une condition de boucle pour contrôler
le processus itératif sur tous les enregistrements d’un ensemble de données. Si
vous ouvrez un ensemble de données contenant plusieurs enregistrements (ou si
vous appelez First) Eof vaut false. Pour parcourir un à un les enregistrements
d’un ensemble de données, vous devez créer une boucle qui avance sur chaque
enregistrement en appelant Next, et se termine quand Eof vaut true. Eof reste à
false jusqu’à ce que vous appeliez Next alors que le curseur se trouve déjà sur le
dernier enregistrement.
L’exemple suivant montre l’une des façons de programmer une boucle de
traitement d’enregistrements pour un ensemble de données appelé CustTable :
CustTable->DisableControls();
try
{
for (CustTable->First(); !CustTable->Eof; CustTable->Next())
(
// Le traitement de l’enregistrement se fait ici
ƒ
}
}
__finally
{
CustTable->EnableControls();
}
Conseil Cet exemple montre aussi comment désactiver puis réactiver des contrôles
visuels, orientés données, rattachés à l’ensemble de données. Si vous désactivez
les contrôles visuels pendant la durée de l’itération sur l’ensemble de données,
le traitement sera accéléré car votre application n’a pas à mettre à jour le contenu
des contrôles au fur et à mesure de l’évolution de l’enregistrement en cours. Une
fois l’itération achevée, les contrôles doivent être réactivés pour être mis à jour
en fonction de la nouvelle ligne en cours. Notez que l’activation de contrôles
visuels a lieu dans la clause __finally d’une instruction try...__finally. Cela
garantit que les contrôles ne resteront pas désactivés, même si une exception
termine le traitement de la boucle de façon prématurée.
Bof
Quand la valeur de Bof est true, cela indique que le curseur se trouve sans
équivoque sur la première ligne de l’ensemble de données. Bof est mis à true
lorsqu’une application :
• Ouvre un ensemble de données.
• Appelle la méthode First de l’ensemble de données.
• Appelle la méthode Prior de l’ensemble de données et que son exécution
échoue (car le curseur se trouve déjà sur la première ligne de l’ensemble de
données).
• Appelle SetRange sur une portée ou un ensemble de données vide.
Bof prend la valeur false dans tous les autres cas ; vous devez supposer que Bof
vaut false sauf si l’une des conditions ci-dessus est vérifiée et si vous avez testé
directement la valeur de la propriété.
Comme Eof, Bof peut se trouver dans une condition de boucle pour contrôler un
processus itératif sur des enregistrements d’un ensemble de données. L’exemple
suivant montre l’une des façons de programmer une boucle de traitement
d’enregistrements pour un ensemble de données appelé CustTable: :
CustTable->DisableControls(); // accélère le traitement et empêche les
// rafraîchissements écran
try
{
while (!CustTable->Bof) // boucle jusqu’à ce que Bof devienne true
(
// Le traitement de l’enregistrement se fait ici
ƒ
CustTable->Prior();
// Bof vaut false en cas de réussite ; bof vaut true si Prior échoue sur le
// premier enregistrement
}
}
__finally
{
CustTable->EnableControls();
}
Marquage d’enregistrements
Outre la possibilité de se déplacer d’un enregistrement à un autre dans un
ensemble de données (ou de se déplacer selon un nombre déterminé
d’enregistrements), il est possible de marquer un emplacement particulier dans
un ensemble de données de façon à y revenir rapidement le moment voulu.
TDataSet introduit une fonction de marquage constituée d’une propriété Bookmark
et de cinq méthodes de définition de signets.
TDataSet implémente des méthodes virtuelles de gestion des signets. Bien que ces
méthodes garantissent que chaque objet ensemble de données dérivé de TDataSet
renvoie une valeur si une méthode de signet est appelée, les valeurs renvoyées
sont simplement des valeurs par défaut qui n’indiquent pas la position en cours.
Les descendants de TDataSet ont des niveaux de support de signets différents.
Les ensembles de données dbExpress ne supportent pas les signets. Les
ensembles de données ADO peuvent prendre en charge les signets, en fonction
des tables de la base de données sous-jacente. Les ensembles de données BDE,
InterBase express et client prennent toujours en charge les signets.
La propriété Bookmark
La propriété Bookmark indique quel est le signet en cours dans votre application.
Bookmark est une chaîne qui identifie le signet en cours. Tout nouveau signet
ajouté devient le signet en cours.
La méthode GetBookmark
Pour créer un signet, vous devez déclarer une variable de type TBookmark dans
votre application, puis appeler GetBookmark pour allouer un espace de stockage à
la variable et définir sa valeur par un emplacement particulier dans l’ensemble
de données. Le type TBookmark est un pointeur (void *).
La méthode CompareBookmarks
Vous pouvez aussi appeler CompareBookmarks pour voir si un signet sur lequel
vous voulez vous déplacer est différent d’un autre signet ou du signet en cours.
Si les deux signets font référence au même enregistrement (ou si tous les deux
sont NULL), CompareBookmarks renvoie 0.
La méthode FreeBookmark
FreeBookmark restitue la mémoire allouée à un signet lorsqu’il n’est plus
nécessaire. Vous devez également appeler FreeBookmark avant de réutiliser un
signet existant.
Création de filtres
Les deux méthodes suivantes permettent de créer un filtre pour un ensemble de
données :
• Spécifiez des conditions de filtre dans la propriété Filter. Filter est
particulièrement utile pour créer et appliquer des filtres à l’exécution.
• Ecrivez un gestionnaire d’événement OnFilterRecord pour les conditions de
filtre simples ou complexes. Avec OnFilterRecord, les conditions de filtre sont
spécifiées en mode conception. A la différence de la propriété Filter, qui se
limite à une seule chaîne contenant une logique de filtre, l’événement
OnFilterRecord peut utiliser la logique des branchements et des boucles pour
créer des conditions de filtre multiniveaux et complexes.
Lorsque vous créez des filtres en utilisant la propriété Filter, votre application
peut créer, modifier et appliquer des filtres dynamiquement (en réponse à des
saisies utilisateur, par exemple). L’inconvénient est que les conditions de filtre
doivent pouvoir s’exprimer dans une seule chaîne texte, ne peuvent pas utiliser
des constructions à base de branchements ou de boucles, et que leurs valeurs ne
peuvent être ni testées ni comparées à des valeurs ne figurant pas encore dans
l’ensemble de données.
La puissance de l’événement OnFilterRecord réside dans la possibilité pour un
filtre d’être complexe et variable, d’être basé sur plusieurs lignes de code
utilisant des constructions de branchements et de boucles, et de pouvoir tester et
comparer les valeurs de l’ensemble de données avec des valeurs figurant à
l’extérieur de l’ensemble de données, comme le texte d’une zone de saisie. Son
inconvénient est que le filtre doit être défini en mode conception et qu’il ne peut
pas être modifié en réponse à des saisies utilisateur. Vous pouvez toutefois créer
plusieurs gestionnaires de filtres et permuter de l’un à l’autre en réponse à
certaines conditions d’application.
Les sections suivantes décrivent comment créer des filtres en utilisant la
propriété Filter et le gestionnaire d’événement OnFilterRecord.
Vous pouvez aussi créer une chaîne à partir de texte codé en dur et de données
saisies par l’utilisateur dans un contrôle :
Dataset1->Filter = AnsiString(“State = ‘”) + Edit1->Text + “‘”;
Les enregistrements vierges ne s’affichent que s’ils sont explicitement inclus dans
le filtre :
Dataset1->Filter = “State <> ‘CA’ or State = BLANK”;
Remarque Après avoir spécifié une valeur pour la propriété Filter, pour appliquer le filtre à
l’ensemble de données, définissez la propriété Filtered par true.
Les opérateurs logiques et de comparaison suivants permettent de comparer les
valeurs des champs à des littéraux et à des constantes :
Par exemple, les instructions suivantes définissent un filtre qui ignore les
différences majuscules/minuscules lors de la comparaison des valeurs d’un
champ State :
TFilterOptions FilterOptions;
FilterOptions->Clear();
FilterOptions << foCaseInsensitive;
Table1->FilterOptions = FilterOptions;
Table1->Filter = “State = ’CA’”;
Tableau 22.7 Méthodes des ensembles de données pour éditer des données
Méthode Description
Edit Met l’ensemble de données à l’état dsEdit s’il n’est pas déjà à l’état dsEdit ou
dsInsert.
Append Emet les données en suspens, déplace le curseur à la fin de l’ensemble de
données, puis met ce dernier à l’état dsInsert.
Insert Emet les données en suspens, puis met l’ensemble de données à l’état dsInsert.
Post Tente d’émettre l’enregistrement nouveau ou modifié vers la base de données. Si
l’opération réussit, l’ensemble de données est mis à l’état dsBrowse ; dans le cas
contraire, son état en cours reste inchangé.
Cancel Annule l’opération en cours et met l’ensemble de données à l’état dsBrowse.
Delete Supprime l’enregistrement en cours et met l’ensemble de données à l’état
dsBrowse.
Modification d’enregistrements
Un ensemble de données doit être en mode dsEdit pour que l’application puisse
modifier des enregistrements. Dans votre code, vous pouvez utiliser la méthode
Edit pour basculer un ensemble de données en mode dsEdit si la propriété en
lecture seule CanModify de l’ensemble de données vaut true.
Quand un ensemble de données passe en mode dsEdit, il reçoit d’abord un
événement BeforeEdit. Une fois le passage en mode édition réussi, l’ensemble de
données reçoit un événement AfterEdit. En général, ces événements sont utilisés
pour mettre à jour l’interface utilisateur afin qu’elle indique l’état en cours de
l’ensemble de données. Si l’ensemble de données ne peut passer en mode édition
pour une raison ou pour une autre, un événement OnEditError survient, grâce
auquel vous pouvez informer l’utilisateur du problème ou essayer de corriger la
situation qui a empêché l’ensemble de données de passer en mode édition.
Dans les fiches de votre application, certains contrôles orientés données pourront
mettre automatiquement votre ensemble de données à l’état dsEdit si
• La propriété ReadOnly du contrôle vaut false (la valeur par défaut).
• La propriété AutoEdit de la source de données du contrôle vaut true et
• La propriété CanModify de l’ensemble de données vaut true.
Remarque Même si un ensemble de données est à l’état dsEdit, la modification
d’enregistrements peut échouer pour les bases de données SQL si l’utilisateur de
votre application ne dispose pas des droits d’accès SQL appropriés.
Quand un ensemble de données se trouve en mode dsEdit, l’utilisateur peut
modifier toutes les valeurs de champ de l’enregistrement qui apparaît dans les
contrôles orientés données d’une fiche. Les contrôles orientés données, pour
lesquels la modification est activée automatiquement, appellent Post quand
l’utilisateur accomplit une action qui change la position du curseur (comme le
déplacement vers un autre enregistrement dans une grille).
Si vous avez mis un composant navigateur dans votre fiche, l’utilisateur peut
annuler les modifications en cliquant sur le bouton Annuler du navigateur.
L’annulation des modifications renvoie l’ensemble de données à l’état dsBrowse.
Dans votre code, vous devez valider ou annuler les modifications en appelant les
méthodes appropriées. Les modifications sont validées par l’appel de Post. Vous
les annulez en appelant Cancel. Les méthodes Edit et Post sont souvent utilisées
conjointement. Par exemple,
Table1->Edit();
Table1->FieldValues[“CustNo”] = 1234;
Table1->Post();
Dans l’exemple précédent, la première ligne du fragment de code place
l’ensemble de données en mode dsEdit. La ligne suivante affecte la chaîne 1234
au champ CustNo de l’enregistrement en cours. Pour finir, la dernière ligne écrit
(émet) l’enregistrement modifié. Si les mises à jour ne sont pas en mémoire
cache, les modifications sont écrites en retour dans la base de données. Si les
mises à jour sont en mémoire cache, les modifications sont écrites dans un
tampon temporaire, où elles restent jusqu’à ce que la méthode ApplyUpdates de
l’ensemble de données soit appelée.
Insertion d’enregistrements
Insert ouvre un nouvel enregistrement vide avant l’enregistrement en cours, puis
positionne le curseur sur ce nouvel enregistrement de façon à que les valeurs de
champ puissent être entrées par l’utilisateur ou par le code de votre application.
Quand une application Post (ou ApplyUpdates si vous utilisez les mises à jour en
mémoire cache), le nouvel enregistrement inséré peut être écrit comme suit dans
le journal des modifications :
• Pour les tables Paradox et dBASE indexées, l’enregistrement est inséré dans
l’ensemble de données à une position déterminée par l’index.
• Pour les tables Paradox et dBASE non indexées, l’enregistrement est inséré
dans l’ensemble de données à sa position actuelle.
• Pour les bases de données SQL, l’emplacement physique de l’insertion est
spécifique à l’implémentation. Si la table est indexée, l’index est mis à jour
avec les données du nouvel enregistrement.
Suppression d’enregistrements
Utilisez la méthode Delete pour supprimer l’enregistrement en cours d’un
ensemble de données actif. Quand la méthode Delete est appelée,
1 L’ensemble de données reçoit un événement BeforeDelete.
2 L’ensemble de données tente de supprimer l’enregistrement en cours.
3 L’ensemble de données revient à l’état dsBrowse.
4 L’ensemble de données reçoit un événement AfterDelete.
Si vous voulez empêcher la suppression dans le gestionnaire d’événement
BeforeDelete, vous pouvez appeler la procédure globale Abort :
void __fastcall TForm1::TableBeforeDelete (TDataSet *Dataset)
{
if (MessageBox(0, "Supprimer cet enregistrement ?", "CONFIRM", MB_YESNO) != IDYES)
Abort();
}
Si Delete échoue, elle génère un événement OnDeleteError. Si le gestionnaire
d’événement OnDeleteError ne peut pas corriger le problème, l’ensemble de
données reste dans l’état dsEdit. Si Delete réussit, l’ensemble de données revient à
l’état dsBrowse et l’enregistrement suivant celui qui est supprimé devient
l’enregistrement en cours.
Si les mises à jour sont en mémoire cache, l’enregistrement supprimé n’est enlevé
de la table de la base de données sous-jacente que si vous appelez ApplyUpdates.
Si vous avez doté vos fiches d’un composant navigateur, les utilisateurs pourront
supprimer l’enregistrement en cours en cliquant sur le bouton d’effacement.
Dans votre code, vous devez appeler explicitement Delete pour supprimer
l’enregistrement en cours.
Pour une fiche, vous pouvez permettre à l’utilisateur d’annuler les opérations de
modification, d’insertion, et d’ajout en incluant le bouton Annuler dans un
composant navigateur associé à l’ensemble de données, ou bien le code de votre
propre bouton d’annulation.
les champs que vous ne voulez pas changer. Si vous ne fournissez pas un
nombre de valeurs correspondant au nombre de champs d’un enregistrement,
SetFields leur affecte la valeur NULL. Les valeurs NULL écrasent les valeurs
existantes de ces champs.
Par exemple, supposons qu’une base de données dispose d’une table COUNTRY
avec les colonnes Name, Capital, Continent, Area et Population. Si un composant
TTable appelé CountryTable a été lié à la table COUNTRY, l’instruction suivante
insérera un enregistrement dans la table COUNTRY :
CountryTable->InsertRecord(ARRAYOFCONST((“Japan”, “Tokyo”, “Asia”)));
Cette instruction ne spécifie aucune valeur pour Area et Population, des valeurs
NULL leur sont donc affectées. La table est indexée sur Name, l’enregistrement
est donc inséré à la position alphabétique de “Japan”.
Pour mettre à jour l’enregistrement, l’application peut utiliser le code suivant :
TLocateOptions SearchOptions;
SearchOptions->Clear();
SearchOptions << loCaseInsensitive;
if (CountryTable->Locate(“Name”, “Japan”, SearchOptions))
{
CountryTable->Edit();
CountryTable->SetFields(ARRAYOFCONST(((void *)NULL, (void *)NULL, (void *)NULL,
344567, 164700000)));
CountryTable->Post();
}
Ce code affecte des valeurs aux champs Area et Population, avant de les
enregistrer dans la base de données. Les trois pointeurs NULL agissent comme
marqueurs de remplissage des trois premières colonnes pour indiquer que leur
contenu actuel doit être préservé.
Attention Quand vous utilisez des pointeurs NULL avec SetFields afin de laisser intacte la
valeur de certains champs, il faut transtyper les NULL en void *. Si vous utilisez
un NULL comme paramètre sans effectuer le transtypage, vous affectez une
valeur vierge au champ.
Champs calculés
En utilisant l’éditeur de champs, vous pouvez définir des champs calculés pour
vos ensembles de données. Quand un ensemble de données contient des champs
calculés, vous fournissez le code calculant les valeurs de ces champs dans un
gestionnaire d’événement OnCalcFields. Pour des détails sur la définition des
champs calculés en utilisant l’éditeur de champs, voir “Définition d’un champ
calculé” à la page 23-8.
La propriété AutoCalcFields détermine quand OnCalcFields est appelé. Si
AutoCalcFields vaut true, OnCalcFields est appelé quand :
• Un ensemble de données est ouvert.
• L’ensemble de données passe en mode édition.
Outre les ensembles de données faisant clairement partie d’une de ces trois
catégories, quelques descendants de TDataSet appartiennent à plusieurs
catégories :
• TADODataSet et TSQLDataSetpossèdent une propriété CommandType qui vous
permet de spécifier s’ils représentent une table, une requête ou une procédure
stockée. Les propriétés et les méthodes sont presque les mêmes que celles des
ensembles de données de type requête, bien que TADODataSet vous permette
de spécifier un index comme dans les ensembles de données de type table.
• TClientDataSet représente les données d’un autre ensemble de données. De ce
fait, il peut représenter une table, une requête et une procédure stockée.
TClientDataSet se comporte pratiquement comme un ensemble de données de
type table puisqu’il supporte les index. Mais, il possède aussi quelques
fonctionnalités des requêtes et des procédures stockées : la gestion des
paramètres et la possibilité de s’exécuter sans renvoyer d’ensemble de
résultats.
• D’autres ensembles de données client (TBDEClientDataSet et
TSQLClientDataSet) possèdent une propriété CommandType qui vous permet de
spécifier s’ils représentent une table, une requête ou une procédure stockée.
Les propriétés et méthodes sont comme TClientDataSet, y compris le support
des paramètres, des index, et la possibilité de s’exécuter sans renvoyer
d’ensemble de résultats.
• TIBDataSet peut représenter à la fois des requêtes et des procédures stockées.
En fait, il peut représenter plusieurs requêtes et procédures stockées
simultanément, sans qu’il y ait des propriétés différentes pour chacune.
Pour plus d’informations sur l’utilisation des composants connexion aux bases
de données, voir chapitre 21, “Connexion aux bases de données”.
3 Définissez la propriété TableName par le nom de la table de la base de
données. Vous pouvez sélectionner des tables dans une liste déroulante si
vous avez déjà identifié un composant connexion aux bases de données.
4 Placez un composant source de données dans le module de données ou sur la
fiche, et définissez sa propriété DataSet par le nom de l’ensemble de données.
Le composant source de données est utilisé pour transmettre un ensemble de
résultats à afficher entre l’ensemble de données et les composants orientés
données.
GotoKeyet FindKey sont des fonctions booléennes qui, en cas de succès, placent le
curseur sur un enregistrement correspondant et renvoient true. Si la recherche
n’aboutit pas, le curseur n’est pas déplacé et ces fonctions renvoient false.
GotoNearest et FindNearest provoquent toujours le repositionnement du curseur
sur la première correspondance exacte trouvée ou, si aucune correspondance
n’est trouvée, sur le premier enregistrement supérieur au critère de recherche
spécifié.
données comprend trois colonnes et si vous voulez effectuer une recherche sur la
première colonne seulement, vous devez donner KeyFieldCount la valeur 1.
En ce qui concerne les ensembles de données de type table avec des clés
multicolonnes, vous ne pouvez rechercher les valeurs que dans des colonnes
contiguës, en commençant par la première. Par exemple, pour une clé portant
sur trois colonnes, vous pouvez rechercher des valeurs dans la première colonne,
puis dans la première et la seconde, ou bien dans la première, la seconde et la
troisième, mais pas seulement dans la première et la troisième.
Spécification de portées
Deux moyens s’excluant mutuellement permettent de spécifier une portée :
• Spécifiez le début et la fin séparément en utilisant SetRangeStart et
SetRangeEnd.
• Spécifier les valeurs des deux extrémités simultanément en utilisant SetRange.
puisque toutes les valeurs sont supérieures à une valeur NULL. Par contre, si le
texte entré dans EndVal a une valeur NULL, aucun enregistrement ne sera inclus,
puisqu’aucun ne peut être inférieur à cette valeur.
Pour un index à plusieurs colonnes, vous pouvez spécifier une valeur de départ
pour tous les champs de l’index ou pour certains de ces champs. Si aucune
valeur n’est fournie pour l’un des champs utilisé dans l’index, une valeur NULL
est affectée au champ lors de l’application de la portée. Si vous essayez de
définir une valeur pour un champ ne figurant pas dans l’index, l’ensemble de
données déclenche une exception.
Conseil Pour commencer au début de l’ensemble de données, n’appelez pas
SetRangeStart.
Pour mettre fin à la spécification du début de la portée, appelez SetRangeEnd ou
appliquez ou annulez la portée. Pour plus d’informations sur l’application et
l’annulation des portées, voir “Application ou annulation d’une portée” à la
page 22-40.
• TableName : CUSTOMER
• Name : CustomersTable
3 Définissez les propriétés du deuxième composant TTable comme suit :
• DatabaseName : BCDEMOS
• TableName : ORDERS
• Name : OrdersTable
4 Définissez les propriétés du premier composant TDataSource comme suit :
• Name : CustSource
• DataSet : CustomersTable
5 Définissez les propriétés du deuxième composant TDataSource comme suit :
• Name : OrdersSource
• DataSet : OrdersTable
6 Placez deux composants TDBGrid sur une fiche.
7 Choisissez Fichier|Inclure l’en-tête d’unité pour indiquer que la fiche doit
utiliser le module de données.
8 Donnez à la propriété DataSource de la première grille la valeur
“CustSource”, et donnez à la propriété DataSource de la deuxième grille la
valeur “OrdersSource”.
9 Définissez la propriété MasterSource de OrdersTable par “CustSource”. Cela lie
la table CUSTOMER (la table maître) à la table ORDERS (la table détail).
10 Double-cliquez dans la zone de la valeur de la propriété MasterFields dans
l’inspecteur d’objets pour appeler le concepteur de liaisons de champs afin de
définir les propriétés suivantes :
• Dans le champ Index disponibles, choisissez CustNo pour lier les deux
tables sur le champ CustNo.
• Sélectionnez CustNo dans les deux listes de champs Champs détail et
Champs maître.
• Cliquez sur Ajouter pour ajouter cette condition de jointure. Dans la liste
Champs joints,
“CustNo -> CustNo” apparaît.
• Cliquez sur OK pour valider vos sélections et quitter le concepteur de
liaisons de champs.
11 Définissez les propriétés Active de CustomersTable et de OrdersTable par true
pour afficher les données dans les grilles de la fiche.
12 Compilez l’application et exécutez-la.
Si vous lancez l’application maintenant, vous pouvez constater que les tables
sont liées et que quand vous vous déplacez sur un nouvel enregistrement de la
table CUSTOMER, seuls apparaissent les enregistrements de la table ORDERS
appartenant au client en cours.
Création de tables
TTable et TIBTable vous permettent tous deux de créer la table de base de
données sous-jacente sans utiliser SQL. De même, TClientDataSet vous permet de
créer un ensemble de données quand vous ne travaillez pas avec un fournisseur
d’ensemble de données. En utilisant TTable et TClientDataSet, vous pouvez créer
la table pendant la conception ou pendant l’exécution. TIBTable vous permet de
créer des tables uniquement à l’exécution.
Avant de créer la table, vous devez définir des propriétés pour spécifier la
structure de la table que vous créez.
Remarque Vous ne pouvez pas définir d’index pour la nouvelle table si vous utilisez des
composants champ persistant au lieu d’objets définition de champ.
Pour créer la table pendant la conception, cliquez avec le bouton droit sur
l’ensemble de données et choisissez Créer table (TTable) ou Créer ensemble de
données (TClientDataSet). Cette commande n’apparaît pas dans le menu
contextuel tant que n’avez pas spécifié toutes les informations nécessaires.
Pour créer la table à l’exécution, appelez la méthode CreateTable (TTable et
TIBTable) ou la méthode CreateDataSet (TClientDataSet).
Remarque Vous pouvez établir les définitions pendant la conception, puis appeler la
méthode CreateTable (ou CreateDataSet) à l’exécution pour créer la table.
Cependant, pour faire cela vous devrez indiquer que les définitions spécifiées à
l’exécution seront enregistrées avec le composant ensemble de données. (par
défaut, les définitions de champs et d’index sont générées de façon dynamique à
l’exécution). Spécifiez que les définitions doivent être enregistrées avec
l’ensemble de données en définissant sa propriété StoreDefs par true.
Conseil Si vous utilisez TTable, vous pouvez pré-charger les définitions de champs et
d’index d’une table existante pendant la conception. Définissez les propriétés
DatabaseName et TableName pour spécifier la table existante. Cliquez avec le
bouton droit sur le composant table et choisissez Mettre à jour la définition de
table. Cela définit automatiquement les valeurs des propriétés FieldDefs et
IndexDefs pour décrire les champs et les index de la table existante. Ensuite,
réinitialisez DatabaseName et TableName pour spécifier la table que vous voulez
créer, en annulant toutes les demandes de renommer la table existante.
Remarque Quand vous créez des tables Oracle8, vous ne pouvez pas créer de champs
objets (champs ADT, champs de tableaux et champs d’ensembles de données).
Le code suivant crée une nouvelle table à l’exécution et l’associe à l’alias
BCDEMOS. Avant de créer la nouvelle table, il vérifie que le nom de la table
fourni ne correspond pas au nom d’une table existante :
TTable *NewTable = new TTable(Form1);
NewTable->Active = false;
NewTable->DatabaseName = “BCDEMOS”;
NewTable->TableName = Edit1->Text;
NewTable->TableType = ttDefault;
NewTable->FieldDefs->Clear();
TFieldDef *NewField = NewTable->FieldDefs->AddFieldDef(); // définit le premier champ
NewField->DataType = ftInteger;
NewField->Name = Edit2->Text;
NewField = NewTable->FieldDefs->AddFieldDef(); // définit le deuxième champ
NewField->DataType = ftString;
NewField->Size = StrToInt(Edit3->Text);
NewField->Name = Edit4->Text;
NewTable->IndexDefs->Clear();
TIndexDef *NewIndex = NewTable->IndexDefs->AddIndexDef(); // ajoute un index
NewIndex->Name = “PrimaryIndex”;
NewIndex->Fields = Edit2->Text;
NewIndex->Options << ixPrimary << ixUnique;
// Vérifie maintenant l’existence préalable de cette table
bool CreateIt = (!NewTable->Exists);
if (!CreateIt)
if (Application->MessageBox((AnsiString(“Remplacer la table “) + Edit1->Text +
AnsiString(“ ?”)).c_str(),
“Table Exists”, MB_YESNO) == IDYES)
CreateIt = true;
if (CreateIt)
NewTable->CreateTable(); // crée la table
Suppression de tables
TTable et TIBTable vous permettent de supprimer des tables de la base de
données sous-jacente sans utiliser SQL. Pour supprimer une table à l’exécution,
appelez la méthode DeleteTable de l’ensemble de données. Par exemple,
l’instruction suivante supprime la table sous-jacente d’un ensemble de données :
CustomersTable->DeleteTable();
Attention Quand vous supprimez une table avec DeleteTable, la table et toutes ses données
disparaissent.
Si vous utilisez TTable, vous pouvez aussi supprimer des tables pendant la
conception : cliquez avec le bouton droit sur le composant table et sélectionnez
Supprimer une table dans le menu contextuel. L’option de menu Supprimer une
table n’est présente que si le composant table représente une table de base de
données existante (les propriétés DatabaseName et TableName spécifient une table
existante).
Pour plus d’informations sur l’utilisation des composants connexion aux bases
de données, voir chapitre 21, “Connexion aux bases de données”.
3 Spécifiez une instruction SQL dans la propriété SQL de l’ensemble de données
et, éventuellement, spécifiez les paramètres de l’instruction. Pour plus
d’informations, voir “Spécification de la requête” à la page 22-49 et
“Utilisation de paramètres dans les requêtes” à la page 22-51.
4 Si les données de la requête doivent être utilisées avec des contrôles de
données visuels, ajoutez un composant source de données au module de
données et définissez sa propriété DataSet par l’ensemble de données de type
requête. Le composant source de données suit les résultats de la requête (que
l’on appelle ensemble de résultats) que les composants orientés données
affichent. Connectez les composants orientés données à la source de données à
l’aide de leurs propriétés DataSource et DataField.
5 Activez le composant requête. Pour les requêtes qui renvoient un ensemble de
résultats, utilisez la propriété Active ou la méthode Open. Pour exécuter des
requêtes qui effectuent seulement une action sur une table et ne renvoient
aucun ensemble de résultats, utilisez la méthode ExecSQL à l’exécution. Si
vous prévoyez d’exécuter la requête plusieurs fois, vous pouvez appeler
Prepare pour initialiser la couche d’accès aux données et les valeurs des
paramètres de liaison dans la requête. Pour plus d’informations sur la
préparation d’une requête, voir “Préparation des requêtes” à la page 22-55.
Spécification de la requête
Pour les véritables ensembles de données de type requête, vous utilisez la
propriété SQL pour spécifier l’instruction SQL à exécuter par l’ensemble de
données. Certains ensembles de données, comme TADODataSet, TSQLDataSet, et
les ensembles de données client, utilisent une propriété CommandText pour faire
la même chose.
La plupart des requêtes qui renvoient des enregistrements sont des commandes
SELECT. Généralement, elles définissent les champs à inclure, les tables dans
lesquelles les sélectionner, les conditions qui limitent les enregistrements à
inclure, l’ordre de l’ensemble de données résultant. Par exemple :
SELECT CustNo, OrderNo, SaleDate
FROM Orders
WHERE CustNo = 1225
ORDER BY SaleDate
Les requêtes qui ne renvoient pas d’enregistrements contiennent des instructions
qui utilisent des instructions DDL (langage de définition des données) ou DML
(langage de manipulation des données) autres que les instructions SELECT (Par
exemple, les commandes INSERT, DELETE, UPDATE, CREATE INDEX et
ALTER TABLE ne renvoient aucun enregistrement). Le langage utilisé dans les
commandes est spécifique au serveur mais généralement conforme au standard
SQL-92 du langage SQL.
La commande SQL que vous exécutez doit être acceptable pour le serveur que
vous utilisez. Les ensembles de données n’évaluent pas la commande SQL et ne
l’exécutent pas. Ils transmettent simplement la commande au serveur pour son
exécution. Dans la plupart des cas, la commande SQL doit être constituée d’une
seule instruction SQL complète, même si cette instruction peut être aussi
complexe que nécessaire (par exemple, une instruction SELECT avec une clause
WHERE qui utilise plusieurs opérateurs logiques imbriqués comme AND et OR).
Certains serveurs supportent également la syntaxe “batch” qui autorise plusieurs
instructions ; si votre serveur supporte cette syntaxe, vous pouvez entrer
plusieurs instructions pour spécifier la requête.
Les instructions SQL utilisées par les requêtes peuvent être textuelles ou peuvent
contenir des paramètres à remplacer. Les requêtes qui utilisent des paramètres
sont appelées requêtes paramétrées. Quand vous utilisez des requêtes paramétrées,
les valeurs réelles affectées aux paramètres sont insérées dans la requête avant
d’exécuter cette dernière. L’utilisation des requêtes paramétrées est très souple,
car vous pouvez, à l’exécution, changer la vue d’un utilisateur et accéder aux
données à la volée, sans avoir à modifier l’instruction SQL. Pour plus
d’informations sur les requêtes paramétrées, voir “Utilisation de paramètres dans
les requêtes” à la page 22-51.
représentation visible des tables et des champs d’une base de données. Pour
utiliser le constructeur SQL, sélectionnez le composant requête, cliquez avec le
bouton droit pour appeler le menu contextuel et choisissez l’éditeur de requêtes
graphique. Pour apprendre à utiliser le constructeur de requêtes, ouvrez-le et
faites appel à son aide en ligne.
Comme la propriété SQL est un objet TStrings, vous pouvez charger le texte de
la requête à partir d’un fichier, en appelant la méthode TStrings::LoadFromFile :
MyQuery->SQL->LoadFromFile("custquery.sql");
Vous pouvez aussi utiliser la méthode Assign de la propriété SQL pour copier le
contenu d’un objet liste de chaînes dans la propriété SQL. La méthode Assign
efface automatiquement le contenu en cours de la propriété SQL avant de copier
la nouvelle instruction :
MyQuery->SQL->Assign(Memo1->Lines);
Avant que l’ensemble de données puisse exécuter la requête, vous devez fournir
une valeur pour chaque paramètre figurant dans le texte de la requête. TQuery,
TIBQuery, TSQLQuery et les ensembles de données client utilisent la propriété
Params pour stocker ces valeurs. TADOQuery utilise à la place la propriété
Parameters. Params (ou Parameters) est une collection d’objets paramètre (TParam
ou TParameter), où chaque objet représente un seul paramètre. Quand vous
spécifiez le texte de la requête, l’ensemble de données génère cet ensemble
d’objets paramètre et (selon le type de l’ensemble de données) initialise les
propriétés qu’il peut déduire de la requête.
Remarque Vous pouvez supprimer la génération automatique des objets paramètre en
réponse au changement du texte de la requête, en définissant la propriété
ParamCheck par false. C’est utile pour les instructions DDL (langage de définition
des données) contenant des paramètres qui font partie de l’instruction DDL et ne
sont pas des paramètres de la requête. Par exemple, l’instruction DDL pour créer
une procédure stockée peut définir des paramètres faisant partie de cette
procédure stockée. En définissant ParamCheck par false, vous empêchez ces
paramètres d’être pris par erreur pour les paramètres de la requête.
Les valeurs de paramètres doivent être liées à l’instruction SQL avant sa
première exécution. Les composants requête le font pour vous automatiquement
si vous n’appelez pas explicitement la méthode Prepare avant l’exécution d’une
requête.
Conseil C’est une bonne habitude de programmation de fournir aux paramètres des
noms de variable correspondant aux noms des colonnes avec lesquelles ils sont
associés. Par exemple, si un nom de colonne est “Number,” alors le paramètre
qui lui correspond peut être “:Number”. L’utilisation de noms correspondants est
particulièrement importante si l’ensemble de données utilise une source de
données pour obtenir les valeurs des paramètres d’un autre ensemble de
données. Ce processus est décrit dans “Etablissement de relations maître/détail
en utilisant des paramètres” à la page 22-54.
Quand vous utilisez la propriété Params (objets TParam), vous pouvez inspecter
ou modifier ce qui suit :
• La propriété DataType indique le type de données de la valeur du paramètre.
Pour certains ensembles de données, cette valeur peut être correctement
initialisée. Si l’ensemble de données ne peut pas déduire le type, DataType
vaut ftUnknown, et vous devez la modifier et indiquer le type de la valeur du
paramètre.
La propriété DataType indique le type de données logique du paramètre. En
général, ces types de données sont conformes aux types de données du
serveur. Pour avoir la correspondance entre les types logiques et les types de
données du serveur, consultez la documentation du mécanisme d’accès aux
données ((BDE, dbExpress, InterBase).
• La propriété ParamType indique le type du paramètre sélectionné. Pour les
requêtes, elle est toujours initialisée à ptInput, car les requêtes ne peuvent
contenir que des paramètres d’entrée. Si la valeur de ParamType est
ptUnknown, changez-la en ptInput.
• La propriété Value spécifie la valeur du paramètre sélectionné. Vous pouvez
laisser vide cette Value si votre application fournit les valeurs des paramètres
au cours de l’exécution.
Quand vous utilisez la propriété Parameters (objets TParameter), vous pouvez
inspecter ou modifier ce qui suit :
• La propriété DataType indique le type de données de la valeur du paramètre.
Pour certains types de données, vous pouvez ajouter d’autres informations :
• La propriété NumericScale indique le nombre de décimales des paramètres
numériques.
• La propriété Precision indique le nombre total de chiffres des paramètres
numériques.
• La propriété Size indique le nombre de caractères des paramètres chaîne.
• La propriété Direction indique le type du paramètre sélectionné. Pour les
requêtes, elle est toujours initialisée à pdInput, car les requêtes ne peuvent
contenir que des paramètres d’entrée.
• La propriété Attributes indique le type des valeurs que le paramètre acceptera.
Attributes peut être défini par une combinaison de psSigned, psNullable et
psLong.
• La propriété Value spécifie la valeur du paramètre sélectionné. Vous pouvez
laisser vide cette Value si votre application fournit les valeurs des paramètres
au cours de l’exécution.
De façon générale, pour accéder à une procédure stockée sur un serveur, vous
devez faire ceci :
1 Placez le composant approprié dans un module de données ou sur une fiche,
et attribuez à sa propriété Name une valeur unique appropriée à votre
application.
2 Identifiez le serveur de base de données qui définit la procédure stockée.
Chaque ensemble de données de type procédure stockée fait cela
différemment, mais, en général, il faut spécifier un composant de base de
données :
• Pour TStoredProc, spécifiez un composant TDatabase ou un alias BDE en
utilisant la propriété DatabaseName.
• Pour TADOStoredProc, spécifiez un composant TADOConnection en utilisant
la propriété Connection.
• Pour TSQLStoredProc, spécifiez un composant TSQLConnection en utilisant la
propriété SQLConnection.
• Pour TIBStoredProc, spécifiez un composant TIBConnection en utilisant la
propriété Database.
Pour plus d’informations sur l’utilisation des composants connexion aux bases
de données, voir chapitre 21, “Connexion aux bases de données”.
3 Spécifiez la procédure stockée à exécuter. Pour la plupart des ensembles de
données de type procédure stockée, vous le faites en définissant la propriété
StoredProcName. La seule exception est TADOStoredProc, qui dispose à la place
d’une propriété ProcedureName.
4 Si la procédure stockée renvoie un curseur à utiliser avec des contrôles de
données visuels, ajoutez un composant source de données au module de
données et définissez sa propriété DataSet par l’ensemble de données de type
procédure stockée. Connectez les composants orientés données à la source de
données à l’aide de leurs propriétés DataSource et DataField.
5 Fournissez les valeurs des éventuels paramètres de la procédure stockée. Si le
serveur ne fournit pas d’information sur tous les paramètres des procédures
stockées, vous devez fournir des informations supplémentaires sur les
paramètres d’entrée, comme les noms et les types de données de ces
paramètres. Pour plus d’informations sur l’utilisation des paramètres des
procédures stockées, voir “Utilisation de paramètres avec les procédures
stockées” à la page 22-59.
6 Exécutez la procédure stockée. Pour les procédures stockées qui renvoient un
curseur, utilisez la propriété Active ou la méthode Open. Pour exécuter des
procédures stockées qui ne renvoient pas de résultat ou renvoient uniquement
des paramètres de sortie, utilisez la méthode ExecProc à l’exécution. Si vous
prévoyez d’exécuter la procédure stockée plusieurs fois, vous pouvez appeler
Prepare pour initialiser la couche d’accès aux données et les valeurs des
paramètres de liaison dans la procédure stockée. Pour plus d’informations sur
la préparation d’une procédure stockée, voir “Exécution de procédures
stockées qui ne renvoient pas d’ensemble de résultats” à la page 22-62.
7 Traitez les éventuels résultats. Ces résultats peuvent être renvoyés sous forme
de paramètres de résultat et de sortie, ou bien sous forme d’un ensemble de
résultats qui remplit l’ensemble de données de type procédure stockée.
Certaines procédures stockées renvoient plusieurs curseurs. Pour plus de
détails sur la façon d’accéder aux curseurs supplémentaires, voir “Lecture de
plusieurs ensembles de résultats” à la page 22-63.
Même si vous n’avez pas besoin d’ajouter les objets paramètre individuels à
l’exécution, vous pouvez accéder à chacun d’eux en affectant des valeurs aux
paramètres d’entrée et en récupérant les valeurs des paramètres de sortie. Vous
pouvez utiliser la méthode ParamByName de l’ensemble de données, pour accéder
aux paramètres individuels par leur nom. Par exemple, le code suivant définit la
valeur d’un paramètre d’entrée/sortie, exécute la procédure stockée et récupère
la valeur renvoyée :
SQLDataSet1->ParamByName("IN_OUTVAR")->AsInteger = 103;
SQLDataSet1->ExecSQL();
int Result = SQLDataSet1->ParamByName("IN_OUTVAR")->AsInteger;
Manipulation Chapitre 23
23
des composants champ
Ce chapitre décrit les propriétés, les événements et les méthodes communes
à l’objet TField et ses descendants. Les composants champ représentent les
différents champs (colonnes) des ensembles de données. Ce chapitre décrit
également comment utiliser les composants champ pour contrôler l’affichage
et l’édition des données dans des applications.
Les composants champ sont toujours associés à un ensemble de données.
Vous n’utilisez jamais un objet TField directement dans vos applications. Au lieu
de cela, chaque composant champ de votre application est un descendant de
TField spécifique au type de données d’une colonne d’un ensemble de données.
Les composants champ fournissent des contrôles orientés données tels que
TDBEdit et TDBGrid afin d’accéder aux données d’une colonne particulière
de l’ensemble de données associé.
D’une façon générale, un composant champ représente les caractéristiques d’une
colonne, ou d’un champ, d’un ensemble de données (comme le type de données
ou la taille du champ). Il représente également les caractéristiques d’affichage
du champ, comme l’alignement, le format d’affichage et le format d’édition.
Par exemple, un composant TFloatField est doté de quatre propriétés qui affectent
directement l’apparence des données :
Champs persistants
Par défaut, les champs des ensembles de données sont des champs dynamiques.
Leurs propriétés et leur disponibilité sont automatiquement définies et ne
peuvent pas être modifiées. Pour contrôler les propriétés et les événements d’un
champ, vous devez créer des champs persistants.
Grâce aux champs persistants, vous pouvez :
• définir ou modifier les caractéristiques d’affichage ou d’édition du champ à la
conception ou à l’exécution ;
• créer de nouveaux champs, tels que des champs de référence, des champs
calculés et des champs agrégés, dont les valeurs sont basées sur les champs
d’un ensemble de données ;
• valider les entrées de données ;
• retirer des composants champ de la liste des composants persistants pour
empêcher votre application d’accéder à des colonnes particulières d’une base
de données sous-jacente ;
• définir de nouveaux champs pour remplacer des champs existants, d’après les
colonnes de la table ou de la requête sous-jacente d’un ensemble de données.
Au moment de la conception vous pouvez, ce qui est conseillé, utiliser l’éditeur
de champs pour créer des listes persistantes de composants champ utilisés par
les ensembles de données de votre application. Ces listes sont stockées dans
votre application et ne changent pas, même si la structure de la base de données
sous-jacente d’un ensemble de données est modifiée. Il est ensuite possible de
créer des gestionnaires d’événements pour ces champs de façon à ce qu’ils
puissent répondre aux modifications de données et aux validations de saisies.
Remarque Lorsque vous créez les champs persistants d’un ensemble de données, seuls ceux
sélectionnés sont disponibles pour votre application en mode conception et à
l’exécution. Pendant la phase de conception, vous pouvez toujours utiliser
l’éditeur de champs de façon à ajouter ou supprimer des champs persistants
pour un ensemble de données.
La totalité des champs utilisés dans un ensemble de données sont soit persistants
soit dynamiques. Il est impossible de combiner les deux types de champs au sein
du même ensemble de données. Si vous avez créé des champs persistants pour
un ensemble de données, vous devrez tous les supprimer pour revenir à des
champs dynamiques. Pour plus d’informations sur les champs dynamiques, voir
“Composants champ dynamique” à la page 23-2.
Remarque L’une des principales utilisations des champs persistants est de contrôler l’aspect
et l’affichage des données. Vous pouvez également contrôler l’aspect des
colonnes dans les grilles orientées données. Pour savoir comment gérer l’aspect
des colonnes dans les grilles, reportez-vous à “Création d’une grille
personnalisée” à la page 19-19.
La boîte groupe Définition de la référence ne s’utilise que pour créer des champs de
référence. Elle est décrite dans “Définition d’un champ de référence” à la page 23-10.
2 Dans la boîte de dialogue Nouveau champ, entrez dans la zone de saisie Nom
le nom d’un champ existant de la table de la base de données. N’entrez pas
un nouveau nom de champ car vous spécifiez ici le nom d’un champ existant
dont le nouveau champ va dériver ses données.
3 Choisissez un nouveau type de données dans la boîte à options Type. Celui-ci
doit être différent de celui du champ que vous remplacez. Il n’est pas possible
de remplacer un champ chaîne d’une taille donnée par un champ chaîne
d’une autre taille. Même si le type de données doit être différent il doit
néanmoins être compatible avec le type de données réel du champ de la table
sous-jacente.
4 Le cas échéant, entrez la taille du champ dans la zone de saisie
correspondante. Cela ne s’applique qu’aux champs de type TStringField,
TBytesField et TVarBytesField.
5 Sélectionnez Données dans la boîte groupe Type de champ.
6 Choisissez OK. La boîte de dialogue Nouveau champ se referme, le nouveau
champ remplace celui que vous avez spécifié à l’étape 1 et la déclaration de
composant dans l’en-tête du module de données ou de la fiche est mise à
jour.
Pour éditer les propriétés ou les événements associés au composant champ,
sélectionnez le nom du composant dans la boîte liste de l’éditeur de champs,
puis éditez ses propriétés ou événements avec l’inspecteur d’objets. Pour plus de
détails sur l’édition des propriétés et des événements d’un composant champ,
reportez-vous à “Définition des événements et des propriétés des champs
persistants” à la page 23-13.
nombre de clés de référence. Pour spécifier plusieurs champs, entrez leur nom
directement. Séparez leur nom par des points-virgules.
8 Dans la liste déroulante Champ résultat, choisissez un champ de l’ensemble
de données de référence à renvoyer comme valeur du champ de référence que
vous êtes en train de créer.
Lorsque vous concevez et exécutez votre application, les valeurs des champs de
référence sont déterminées avant celles des champs calculés. Il est possible de
créer des champs calculés basés sur des champs de référence mais il est
impossible de créer des champs de référence basés sur des champs calculés.
Vous pouvez affiner à l’aide de la propriété LookupCache la façon dont les
champs de référence sont déterminés. Cette propriété détermine si les valeurs
d’un champ de référence sont placées en mémoire cache lors de la première
ouverture d’un ensemble de données ou si elles sont référencées dynamiquement
à chaque modification de l’enregistrement en cours dans l’ensemble de données.
Mettez LookupCache à true pour cacher les valeurs d’un champ de référence
lorsque la propriété LookupDataSet ne risque aucune modification et que le
nombre de valeurs de référence est faible. La mise en mémoire cache des valeurs
de référence permet d’accélérer les performances, car les valeurs de référence
relatives à chaque ensemble de valeurs de la propriété LookupKeyFields sont
préchargées à l’ouverture de l’ensemble de données. En cas de modification de
l’enregistrement en cours dans l’ensemble de données, l’objet champ peut
localiser sa valeur (Value) dans la mémoire cache, plutôt que d’accéder à
LookupDataSet. Cette amélioration des performances est appréciable si l’ensemble
de données de référence (LookupDataSet) est sur un réseau présentant des temps
d’accès lents.
Conseil Vous pouvez utiliser une mémoire cache de référence pour proposer les valeurs
de référence par programme au lieu d’utiliser un ensemble de données
secondaire. Vérifiez que la propriété LookupDataSet vaut NULL. Utilisez ensuite
la méthode Add de la propriété LookupList pour la remplir avec les valeurs de
référence. Affectez la valeur true à la propriété LookupCache. Le champ utilise la
liste de référence spécifiée sans redéfinir ses valeurs avec celles d’un ensemble de
données de référence.
Si chaque enregistrement de l’ensemble de données (DataSet) comporte des
valeurs différentes pour KeyFields, le temps nécessaire à la localisation des
valeurs dans le cache peut être supérieur aux gains de temps obtenus grâce au
placement en mémoire cache. Plus le nombre de valeurs distinctes dans KeyFields
est élevé, plus le temps de traitement passé à localiser des valeurs dans la
mémoire cache augmente.
Si LookupDataSet risque de changer, le fait de placer des valeurs de référence en
mémoire cache peut provoquer des résultats erronés. Appelez RefreshLookupList
pour mettre à jour les valeurs dans la mémoire cache. RefreshLookupList régénère
la propriété LookupList qui contient la valeur de la propriété LookupResultField de
chaque ensemble de valeurs LookupKeyFields.
Si LookupCache est définie à l’exécution, appelez RefreshLookupList pour initialiser
la mémoire cache.
Remarque Si vous supprimez tous les composants champ persistants d’un ensemble de
données, l’ensemble de données recommence à utiliser des composants champ
dynamiques pour chaque colonne de la table de base de données sous-jacente.
Toutes les propriétés ne sont pas disponibles pour l’ensemble des composants
champ. Par exemple, un composant champ de type TStringField ne peut pas
avoir les propriétés Currency, MaxValue ou DisplayFormat et un composant de
type TFloatField ne peut pas avoir de propriété Size.
Alors que le rôle de la plupart des propriétés est évident, certaines comme
Calculated nécessitent des étapes de programmation supplémentaires. D’autres,
comme DisplayFormat, EditFormat et EditMask sont reliées entre elles ; leur
configuration doit être coordonnée. Pour plus de détails sur l’utilisation des
propriétés DisplayFormat, EditFormat et EditMask, voir “Contrôle ou dissimulation
de la saisie utilisateur” à la page 23-17.
Utilisation des formats par défaut pour les champs numériques, date
et heure
C++Builder fournit des routines intégrées d’affichage et d’édition ainsi qu’un
formatage par défaut intelligent pour les composants TFloatField, TCurrencyField,
TBCDField, TFMTBCDField, TIntegerField, TSmallIntField, TWordField, TDateField,
TDateTimeField, TTimeField et TSQLTimeStampField. Vous n’avez donc rien à faire
pour utiliser ces routines.
visuels. OnValidate est utile pour valider la saisie de données dans votre
application avant de renvoyer les valeurs à un serveur de base de données.
Pour écrire un gestionnaire d’événement pour un composant champ :
1 Sélectionnez le composant.
2 Sélectionnez la page Evénements dans l’inspecteur d’objets.
3 Double-cliquez sur la colonne des valeurs du gestionnaire d’événement pour
ouvrir la fenêtre de code source correspondante.
4 Créez ou éditez le code du gestionnaire.
Cette méthode fonctionne bien pour les valeurs chaîne, mais elle peut nécessiter
un surcroît de programmation pour pouvoir gérer les conversions d’autres types
de données. Heureusement, les composants champ ont des propriétés intégrées
leur permettant de le faire.
Remarque Vous pouvez également utiliser des Variants pour accéder aux valeurs des
champs et les définir. Pour plus de détails sur l’utilisation des variants pour
accéder aux valeurs des champs et les définir, reportez-vous à “Accès à des
valeurs par la propriété par défaut d’un ensemble de données” à la page 23-22.
AsFloat
AsCurrency AsDateTime
AsVariant AsString AsInteger AsBCD AsSQLTimeStamp AsBoolean
TStringField Oui N/D Oui Oui Oui Oui
TWideStringField Oui Oui Oui Oui Oui Oui
TIntegerField Oui Oui N/D Oui
TSmallIntField Oui Oui Oui Oui
TWordField Oui Oui Oui Oui
TLargeintField Oui Oui Oui Oui
TFloatField Oui Oui Oui Oui
TCurrencyField Oui Oui Oui Oui
TBCDField Oui Oui Oui Oui
TFMTBCDField Oui Oui Oui Oui
TDateTimeField Oui Oui Oui Oui
TDateField Oui Oui Oui Oui
TTimeField Oui Oui Oui Oui
TSQLTimeStampField Oui Oui Oui Oui
TBooleanField Oui Oui
TBytesField Oui Oui
TVarBytesField Oui Oui
TBlobField Oui Oui
TMemoField Oui Oui
TGraphicField Oui Oui
TVariantField N/D Oui Oui Oui Oui Oui
TAggregateField Oui Oui
Dans les autres cas, la conversion est totalement impossible, toute tentative
provoquant une exception.
La conversion a toujours lieu avant l’affectation. Par exemple, l’instruction ci-
dessous convertit la valeur de CustomersCustNo en chaîne et affecte celle-ci au
texte d’un contrôle de saisie :
Edit1->Text = CustomersCustNo->AsString;
A l’inverse, l’instruction suivante affecte le texte d’un contrôle de saisie au
champ CustomersCustNo en tant qu’entier :
MyTableMyField->AsInteger = StrToInt(Edit1->Text);
Utilisation de contraintes
Les composants champ des ensembles de données ou des ensembles de données
BDE peuvent utiliser des contraintes SQL importées du serveur. De plus, vos
applications peuvent créer et utiliser des contraintes personnalisées appliquées à
ces ensembles de donnés localement par rapport à votre application. Toutes les
contraintes sont des règles ou des conditions qui imposent une limite à la portée
ou à l’intervalle des valeurs que le champ peut stocker.
apparaît au moment où les violations sont détectées (sinon, les messages d’erreur
affichés proviennent du serveur).
A partir de ces champs persistants, vous pouvez accéder simplement aux champs
enfants d’un champ ADT par nom :
CityEdit->Text = CustomerAddrCity->AsString;
Bien que les champs persistants représentent la façon la plus facile d’accéder aux
champs enfants ADT, il est impossible de les utiliser si la structure de l’ensemble
de données est inconnue lors de la conception. Lorsque vous accédez à des
champs enfants ADT sans utiliser de champs persistants, vous devez attribuer la
valeur true à la propriété ObjectView de l’ensemble de données.
Lorsque les données d’un champ référence sont modifiées, c’est en fait les
données référencées qui sont modifiées.
Pour affecter une valeur à un champ référence, vous devez d’abord utiliser une
instruction SELECT pour sélectionner la référence dans la table et ensuite lui
attribuer la valeur. Par exemple :
Architecture BDE
Avec le BDE, votre application utilise une variante de l’architecture générale de
base de données décrite dans “Architecture des bases de données” à la page 18-6.
En plus des éléments de l’interface utilisateur, de la source de données et des
Utilisation de TTable
TTable encapsule toute la structure et les données d’une table de base de données
sous-jacente. Elle implémente toutes les fonctionnalités de base introduites par
TDataSet, ainsi que toutes les caractéristiques spéciales typiques des ensembles de
données de type table. Avant d’étudier les possibilités uniques offertes par
TTable, vous devriez vous familiariser avec les caractéristiques communes des
bases de données décrites dans “Présentation des ensembles de données” à la
page 22-1, y compris la section sur les ensembles de données de type table qui
commence page 22-29.
Comme TTable est un ensemble de données BDE, elle doit êtreassociée avec une
base de données et une session. “Association d’un ensemble de données avec les
connexions de bases de données et de session” à la page 24-3 décrit la façon de
former ces associations. Une fois l’ensemble de données associé avec une base de
données et une session, vous pouvez le lier à une table particulière en
définissant la propriété TableName et, si vous utilisez une table Paradox, dBASE,
FoxPro ou ASCII délimité par des virgules, la propriété TableType.
Remarque La table doit être fermée quand vous modifiez son association à une base de
données, une session ou à une autre table, ou quand vous définissez la propriété
TableType. Cependant, avant de fermer la table pour modifier ces propriétés,
validez ou annulez toute modification en cours. Si les mises à jour en mémoire
cache sont activées, appelez la méthode ApplyUpdates pour écrire les
modifications validées dans la base de données.
Les composants TTable offrent un support unique aux tables des bases de
données locales (Paradox, dBASE, FoxPro, ASCII délimité par des virgules). De
plus, les composants TTable peuvent bénéficier du support du BDE pour les
opérations groupées (opérations consistant à ajouter, mettre à jour, supprimer ou
copier des groupes entiers d’enregistrements). Ce support est décrit dans
“Importation des données d’une autre table” à la page 24-8.
Tableau 24.1 Types de tables reconnues par le BDE d’après les extensions
Extension Type de table
Pas d’extension Paradox
.DB Paradox
.DBF dBASE
.TXT Texte ASCII
Si votre table locale Paradox, dBASE ou ASCII utilise les extensions décrites dans
le tableau précédent, vous pouvez laisser TableType sur ttDefault. Sinon, votre
application doit définir TableType pour indiquer le type réel de la table. Le
tableau suivant indique les valeurs que vous pouvez assigner à TableType :
Après avoir ajouté des fichiers d’index .MDX ou .NDX, les noms des index
individuels du fichier d’index sont accessibles et modifiables par la propriété
IndexName. Les repères d’index sont aussi listés en utilisant la méthode
GetIndexNames et en inspectant les définitions d’index à travers les objets
TIndexDef dans la propriété IndexDefs. Les fichiers .NDX correctement listés sont
automatiquement mis à jour lorsque des données sont ajoutées, modifiées ou
supprimées dans la table (qu’un index donné soit ou non utilisé dans la
propriété IndexName).
Dans l’exemple ci-dessous, le fichier d’index ANIMALS.MDX est affecté à la
propriété IndexFiles du composant table AnimalsTable, et le repère d’index
“NAME” est affecté à sa propriété IndexName :
AnimalsTable->IndexFiles->Add(“ANIMALS.MDX”);
AnimalsTable->IndexName = "NAME";
Une fois le fichier d’index spécifié, les index MDX ou NDX fonctionnent comme
n’importe quel autre index. Spécifier un nom d’index trie les données de la table
et rend l’index disponible pour les recherches, les portées et (pour les index
MDX) les liaisons maître-détail. Voir “Utilisation d’ensembles de données de type
table” à la page 22-29 pour plus de détail sur l’utilisation d’index.
En utilisant des index .NDX dBASE III PLUS avec les composants TTable, deux
considérations particulières sont à prendre en compte. La première est que les
fichiers .NDX ne peuvent pas être utilisés comme base pour les liaisons maître-
détail. La seconde est que lors de l’activation d’un index .NDX avec la propriété
IndexName, vous devez inclure l’extension .NDX dans le nom de l’index dans la
valeur de la propriété :
Table1->IndexName = "ByState.NDX";
TVarRec vr = ("NE");
Table1->FindKey(&vr, 0);
Par exemple, le code suivant met à jour tous les enregistrements de la table en
cours avec les enregistrements de la table Customer qui possèdent les mêmes
valeurs pour les champs de l’index en cours :
Table1->BatchMove(“CUSTOMER.DB”, batUpdate);
BatchMove renvoie le nombre d’enregistrements importés avec succès.
Attention L’importation d’enregistrements en utilisant le mode batCopy écrase les
enregistrements existants. Pour préserver ces derniers, utilisez plutôt batAppend.
BatchMove n’effectue que certaines opérations groupées supportées par le BDE.
D’autres fonctions sont disponibles par le composant TBatchMove. Si vous devez
déplacer une grosse masse de données dans les tables, utilisez TBatchMove au
lieu d’appeler la méthode de table BatchMove. Pour plus d’informations sur
l’utilisation de TBatchMove, voir “Utilisation de TBatchMove” à la page 24-55.
Utilisation de TQuery
TQuery représente une unique instruction en DDL (Data Definition Language) ou
DML (Data Manipulation Language), par exemple une commande SELECT,
INSERT, DELETE, UPDATE, CREATE INDEX ou ALTER TABLE. Le langage
utilisé dans les commandes est spécifique au serveur, mais se conforme
généralement au standard SQL-92. TQuery implémente toutes les fonctionnalités
de base introduites par TDataSet, ainsi que toutes les spécificités des ensembles
de données de type requête. Avant d’étudier les caractéristiques particulières de
TQuery, familiarisez-vous avec les fonctions communes des bases de données
décrites au chapitre 22, “Présentation des ensembles de données”, y compris la
section sur les ensembles de données de type requête qui commence page 22-48.
base de données Sybase comprenant une table ORDERS. Une requête simple sur
ces deux tables pourrait s’écrire :
SELECT Customer.CustNo, Orders.OrderNo
FROM ”:Oracle1:CUSTOMER”
JOIN ”:Sybase1:ORDERS”
ON (Customer.CustNo = Orders.CustNo)
WHERE (Customer.CustNo = 1503)
Dans une requête hétérogène, au lieu de spécifier la base de données à l’aide
d’un alias, vous pouvez utiliser un composant TDatabase. Configurez TDatabase
afin qu’il pointe sur la base de données, affectez à la propriété
TDatabase::DatabaseName une valeur arbitraire mais unique, et utilisez ensuite
cette valeur dans l’instruction SQL au lieu d’un nom d’alias BDE.
Utilisation de TStoredProc
TStoredProc représente une procédure stockée. Elle implémente toutes les
fonctionnalités introduites par TDataSet, ainsi que la plupart des fonctionnalités
spéciales typiques des ensembles de données de type procédure stockée. Avant
d’étudier les caractéristiques particulières de TStoredProc, familiarisez-vous avec
les fonctions communes des bases de données décrites au chapitre 22,
“Présentation des ensembles de données”, y compris la section sur les ensembles
de données de type procédure stockée qui commence en page 22-57.
Puisque TStoredProc est un ensemble de données BDE, il doit être associé à une
base de données et une session. Voir “Association d’un ensemble de données
avec les connexions de bases de données et de session” à la page 24-3 pour
savoir comment former de telles associations. Une fois l’ensemble de données
associé à une base de données et une session, vous pouvez le lier à une
procédure stockée particulière en définissant la propriété StoredProcName.
TStoredProc diffère des autres ensembles de données de type procédure stockée
par les points suivants :
• Il vous donne un plus grand contrôle sur la façon de lier les paramètres.
• Il fournit la gestion des procédures stockées surchargées Oracle.
Si Overload a pour valeur zéro (valeur par défaut), il n’y a pas de redéfinition. Si
Overload a pour valeur 1, le composant procédure stockée exécute la première
procédure stockée qu’il trouve sur le serveur Oracle ayant le nom redéfini ; si
Overload a pour valeur 2, il exécute la seconde, et ainsi de suite.
Remarque Les procédures stockées redéfinies peuvent prendre des paramètres d’entrée et
de sortie différents. Voir la documentation de votre serveur Oracle pour plus
d’informations.
toute valeur déjà affectée à AliasName est effacée pour éviter tout conflit
potentiel entre le nom du pilote que vous spécifiez et le nom du pilote faisant
partie de l’alias BDE identifié par AliasName.
DatabaseName vous permet de fournir votre propre nom pour une connexion de
base de données. Ce nom s’ajoute alors à AliasName ou DriverName, et est local à
votre application. DatabaseName peut être un alias BDE ou, pour les fichiers
Paradox et dBASE, un chemin d’accès qualifié. Comme AliasName, DatabaseName
apparaît ensuite dans les listes déroulantes pour les composants ensemble de
données afin de vous permettre de les lier aux composants base de données.
Au moment de la conception, pour spécifier un alias BDE, affecter un pilote BDE
ou créer un alias BDE local, double-cliquez sur un composant base de données
pour appeler l’éditeur de propriétés de bases de données.
Vous pouvez entrer un DatabaseName dans la zone de saisie Nom de l’éditeur de
propriétés. Vous pouvez entrer un nom d’alias BDE existant dans la boîte à
options Nom d’alias pour la propriété Alias, ou choisir un alias existant dans la
liste déroulante. La boîte à options Nom de pilote vous permet de saisir le nom
d’un pilote BDE existant pour la propriété DriverName, mais vous pouvez aussi
en choisir un dans la liste déroulante des pilotes existants.
Remarque L’éditeur de propriétés de bases de données vous permet aussi de visualiser et
de définir les paramètres de connexion BDE, et de définir l’état des propriétés
LoginPrompt et KeepConnection. Pour plus d’informations sur les paramètres de
connexion, voir “Définition des paramètres d’alias BDE” ci-dessous. Pour plus
d’informations sur LoginPrompt, voir “Contrôle de la connexion au serveur” à la
page 21-4. Pour plus d’informations sur KeepConnection, voir “Ouverture d’une
connexion avec TDatabase” à la page 24-17.
Utilisation d’ODBC
Une application peut utiliser les sources de données ODBC (par exemple,
Btrieve). Une connexion par pilote ODBC requiert :
• Un pilote ODBC fourni par le vendeur.
• Microsoft ODBC Driver Manager.
• L’utilitaire d’administration BDE.
Pour configurer un alias BDE pour une connexion par pilote ODBC, utilisez
l’utilitaire d’administration BDE. Pour plus d’informations, voir le fichier d’aide
en ligne de l’utilitaire d’administration BDE.
pouvez utiliser pour gérer tous vos composants session. Pour plus d’informations
sur la gestion de sessions multiples, voir “Gestion de sessions multiples” à la
page 24-32.
Vous pouvez placer sans risque des composants session dans des modules de
données. Cependant, si vous mettez un module de données contenant un ou
plusieurs composants session dans le référentiel d’objets, assurez-vous que la
propriété AutoSessionName a pour valeur true pour éviter tout conflit d’espace
d’appellation quand les utilisateurs en héritent.
Important Ne définissez pas PrivateDir sur le répertoire racine d’un disque. Utilisez toujours
un sous-répertoire.
Tableau 24.4 Méthodes informatives de bases de données pour les composants session
Méthode Action
GetAliasDriverName Récupère le pilote BDE pour un alias de base de données spécifié.
GetAliasNames Récupère la liste des alias BDE d’une base de données.
GetAliasParams Récupère la liste des paramètres de l’ alias BDE spécifié d’une base de
données.
GetConfigParams Récupère les informations de configuration à partir du fichier de
configuration BDE.
GetDatabaseNames Récupère la liste des alias BDE et les noms de tous les composants
TDatabase en cours d’utilisation.
GetDriverNames Récupère le nom de tous les pilotes BDE actuellement installés.
GetDriverParams Récupère la liste des paramètres pour le pilote BDE spécifié.
GetStoredProcNames Récupère les noms de toutes les procédures stockées pour la base de
données spécifiée.
GetTableNames Récupère les noms de toutes les tables correspondant au modèle
spécifié pour la base de données spécifiée.
GetFieldNames Récupère les noms de tous les champs de la table spécifiée d’une base
de données spécifiée.
Remarque Créer des sessions supplémentaires est facultatif, à moins qu’une application
n’exécute des requêtes simultanées sur une base de données, ou qu’elle soit
multithread.
Pour permettre la création dynamique d’un composant session à l’exécution,
suivez les étapes ci-dessous :
1 Déclarez une variable TSession.
2 Instanciez une nouvelle session avec l’opérateur new.Cet opérateur appelle le
constructeur TSession pour créer et initialiser une nouvelle session. Le
constructeur définit une liste vide de composants base de données pour la
session, définit la propriété KeepConnections à true, et ajoute la session à la liste
des sessions maintenue par le composant liste de sessions de l’application.
3 Définissez la propriété SessionName de la nouvelle session à un nom unique.
Cette propriété est utilisée pour associer les composants base de données à la
session. Pour plus d’informations sur la propriété SessionName, voir
“Affectation d’un nom à une session” à la page 24-31.
4 Activez la session et ajustez ses propriétés si nécessaire.
Vous pouvez aussi créer et ouvrir des sessions avec la méthode OpenSession de
TSessionList. L’emploi de OpenSession est plus sûr que celui de l’opérateur new,
parce que OpenSession ne crée la session que si elle n’existe pas déjà. Pour plus
d’informations sur OpenSession, voir “Gestion de sessions multiples” à la
page 24-32.
Le code suivant crée un nouveau composant session, lui affecte un nom et ouvre
la session pour les opérations de bases de données qui suivent (non présentées
ici). Après usage, la session est détruite par un appel à la méthode Free.
Remarque Ne détruisez jamais la session par défaut.
TSession *SecondSession = new TSession(Form1);
try
{
SecondSession->SessionName = "SecondSession";
SecondSession->KeepConnections = false;
SecondSession->Open();
ƒ
}
__finally
{
delete SecondSession;
};
sont appliqués au lieu des nouveaux, afin de les restaurer dans leur état
antérieur.
Les transactions locales sont plus limitées que les transactions sur les serveurs
SQL ou les pilotes ODBC. En particulier, les restrictions suivantes
s’appliquent aux transactions locales :
• La récupération automatique en cas de problème n’est pas fournie.
• Les instructions de définition de données ne sont pas supportées.
• Les transactions ne peuvent pas être effectuées sur des tables temporaires.
• Le niveau TransIsolation doit être défini à tiDirtyRead.
• Pour Paradox, les transactions locales ne peuvent être effectuées que sur les
tables comportant des index valides. Il est impossible d’annuler les
modifications sur des tables Paradox qui n’ont pas d’index.
• Un nombre limité d’enregistrements peut être verrouillé et modifié. Avec les
tables Paradox, vous êtes limité à 255 enregistrements. Avec dBASE la limite
est de 100.
• Les transactions ne peuvent être effectuées sur le pilote ASCII BDE.
• Fermer un curseur sur une table durant une transaction annule celle-ci sauf si :
• Plusieurs tables sont ouvertes.
• Le curseur est fermé sur une table dans laquelle aucune modification n’a
été effectuée.
Tableau 24.6 Propriétés, méthodes et événements pour les mises à jour en mémoire cache
Sur ensembles
de données BDE
(ou TDatabase) Sur TBDEClientDataSet Fonction
CachedUpdates Inutile pour les ensembles de Détermine si les mise à jour en
données clients, qui pratiquent mémoire cache sont activées pour
toujours la mise en mémoire l’ensemble de données.
cache des mises à jour.
UpdateObject Utilise un gestionnaire Spécifie l’objet mise à jour pour mettre
d’événement à jour les ensembles de données en
BeforeUpdateRecord, ou, si l’on lecture seule.
emploie TClientDataSet, utilise
la propriété UpdateObject sur
l’ensemble de données BDE
source.
UpdatesPending ChangeCount Indique si le cache local contient des
enregistrements modifiés qu’il faut
appliquer à la base de données.
UpdateRecordTypes StatusFilter Indique le type d’enregistrements mis à
jour à rendre visibles en appliquant les
mises à jour en mémoire cache.
UpdateStatus UpdateStatus Indique si un enregistrement est
inchangé, modifié, inséré ou supprimé.
OnUpdateError OnReconcileError Un événement pour la gestion des
erreurs de mise à jour, enregistrement
par enregistrement.
OnUpdateRecord BeforeUpdateRecord Un événement pour le traitement des
mises à jour, enregistrement par
enregistrement.
ApplyUpdates ApplyUpdates Applique à la base de données les
ApplyUpdates enregistrements du cache local.
(base de données)
CancelUpdates CancelUpdates Supprime toutes les mises à jour en
attente du cache local, sans les
appliquer.
CommitUpdates Reconcile Efface le cache des mises à jour après
le succès de l’application des mises à
jour.
FetchAll GetNextPacket Copie les enregistrements de bases de
(et PacketRecords) données dans le cache local pour
modification et mise à jour.
RevertRecord RevertRecord Annule les mises à jour de
l’enregistrement en cours si elles ne
sont pas encore appliquées.
Pour une vue d’ensemble du processus de mises à jour en mémoire cache, voir
“Présentation de l’utilisation d’un cache pour les mises à jour” à la page 27-19.
Remarque Même si vous utilisez un ensemble de données client pour placer les mises à
jour en mémoire cache, lisez la section sur les objets mise à jour, page 24-45.
Vous pouvez utiliser les objets mise à jour dans le gestionnaire d’événement
BeforeUpdateRecord de TBDEClientDataSet ou TDataSetProvider pour appliquer les
mises à jour depuis des procédures stockées ou des requêtes multitables.
Important Pour appliquer les mises à jour depuis une procédure stockée ou une requête
SQL qui ne renvoie pas un ensemble de résultats dynamique, vous devez utiliser
TUpdateSQL pour spécifier comment effectuer les mises à jour. Pour les mises à
jour de jointures (requêtes impliquant plusieurs tables), vous devez fournir un
objet TUpdateSQL pour chaque table impliquée, et vous devez utiliser le
gestionnaire d’événement OnUpdateRecord pour invoquer ces objets afin
d’effectuer les mises à jour. Consultez “Utilisation d’objets mise à jour pour
mettre à jour un ensemble de données” à la page 24-45 pour plus de détails.
Application des mises à jour en mémoire cache avec une base de données
Pour appliquer les mises à jour présentes en mémoire cache à un ou plusieurs
ensembles de données dans le contexte d’une connexion de base de données,
appelez la méthode ApplyUpdates du composant base de données. Le code
suivant applique les mises à jour à l’ensemble de données CustomersQuery en
réponse à un événement clic de bouton :
void __fastcall TForm1::ApplyButtonClick(TObject *Sender)
{
// pour les bases de données locales Paradox, dBASE et FoxPro
// définir TransIsolation à DirtyRead
if (!Database1->IsSQLBased && Database1->TransIsolation != tiDirtyRead)
Database1->TransIsolation = tiDirtyRead;
Database1->ApplyUpdates(&CustomersQuery,0);
}
La séquence ci-dessus écrit les mises à jour en mémoire cache dans la base de
données dans le contexte d’une transaction générée automatiquement. En cas de
succès, elle valide la transaction, puis les mises à jour présentes en mémoire
cache. En cas d’échec, elle annule la transaction et laisse le cache de mise à jour
inchangé. Dans ce dernier cas, vous devez gérer les erreurs de mises à jour en
mémoire cache par le biais de l’événement OnUpdateError de l’ensemble de
données. Pour plus d’informations sur la gestion des erreurs de mise à jour, voir
“Gestion des erreurs de mise à jour en mémoire cache” à la page 24-43.
Le principal avantage à appeler la méthode ApplyUpdates d’un composant base
de données est que vous pouvez mettre à jour tous les composants ensemble de
données associés à la base de données. Les deux arguments de la méthode
ApplyUpdates d’une base de données sont un tableau de TDBDataSet, et l’indice
du dernier ensemble de données dans le tableau. Pour appliquer les mises à jour
pour plusieurs ensembles de données, créez un tableau local de pointeurs sur les
ensembles de données. Par exemple, le code suivant applique les mises à jour
pour deux requêtes :
TDBDataSet* ds[] = {CustomerQuery, OrdersQuery};
if (!Database1->IsSQLBased && Database1->TransIsolation != tiDirtyRead)
Database1->TransIsolation = tiDirtyRead;
Database1->ApplyUpdates(ds,1);
cours. Ces actions peuvent comprendre une validation spéciale des données, la
mise à jour d’autres tables, des substitutions spéciales de paramètres ou
l’exécution de multiples objets mise à jour. Un gestionnaire d’événement
OnUpdateRecord donne un meilleur contrôle sur le processus de mise à jour.
Voici le code squelette d’un gestionnaire d’événement OnUpdateRecord :
void __fastcall TForm1::DataSetUpdateRecord(TDataSet *DataSet,
TUpdateKind UpdateKind, TUpdateAction &UpdateAction)
{
// effectuer les mises à jour ici...
}
Le paramètre DataSet spécifie l’ensemble de données ayant des mises à jour en
mémoire cache.
Le paramètre UpdateKind indique le type de mise à jour qui doit être effectué sur
l’enregistrement en cours. UpdateKind peut prendre les valeurs ukModify, ukInsert
et ukDelete. Si vous utilisez un objet mise à jour, vous devez lui passer ce
paramètre lors de l’application de la mise à jour. Vous pouvez aussi avoir besoin
d’inspecter ce paramètre si votre gestionnaire effectue un traitement spécial selon
le type de mise à jour.
Le paramètre UpdateAction indique si vous avez appliqué la mise à jour.
UpdateAction peut prendre les valeurs uaFail (valeur par défaut), uaAbort, uaSkip,
uaRetry, uaApplied. Si votre gestionnaire d’événement applique la mise à jour
avec succès, donnez à ce paramètre la valeur uaApplied avant de sortir. Si vous
décidez de ne pas mettre à jour l’enregistrement en cours, donnez-lui la valeur
uaSkip pour préserver les modifications en mémoire cache non appliquées. Si
vous ne changez pas la valeur de UpdateAction, toute l’opération de mise à jour
de l’ensemble de données est annulée et une exception est déclenchée. Vous
pouvez supprimer le message d’erreur (et déclencher une exception silencieuse)
en donnant à UpdateAction la valeur uaAbort.
En plus de ces paramètres, vous utiliserez les propriétés OldValue et NewValue
pour le composant champ associé à l’enregistrement en cours. OldValue donne la
valeur originale du champ telle que récupérée de la base de données. Elle peut
servir à localiser l’enregistrement de base de données à mettre à jour. NewValue
est la valeur modifiée dans la mise à jour que vous essayez d’appliquer.
Important Un gestionnaire d’événement OnUpdateRecord, comme un gestionnaire
d’événement OnUpdateError ou OnCalcFields, ne doit jamais appeler les méthodes
qui modifient l’enregistrement en cours d’un ensemble de données.
L’exemple suivant illustre comment utiliser ces paramètres et propriétés. Il
emploie un composant TTable nommé UpdateTable pour appliquer les mises à
jour. En pratique, il est plus facile d’utiliser un objet mise à jour, mais l’emploi
d’une table illustre plus clairement les possibilités.
void __fastcall TForm1::EmpAuditUpdateRecord(TDataSet *DataSet,
TUpdateKind UpdateKind, TUpdateAction &UpdateAction)
{
if (UpdateKind == ukInsert)
{
TVarRec values[2];
if (E->ClassNameIs("EDBEngineError"))
{
EDBEngineError *pDBE = (EDBEngineError *)E;
if (pDBE->Errors[pDBE->ErrorCount - 1]->ErrorCode == DBIERR_KEYVIOL)
UpdateAction = uaSkip; // violation de clé, ignorer cet enregistrement
}
}
Remarque Si une erreur survient durant l’application des mises à jour en mémoire cache,
une exception est déclenchée et un message d’erreur est affiché. A moins que
ApplyUpdates ne soit appelé dans une construction try...catch, un message
d’erreur affiché depuis votre gestionnaire d’événement OnUpdateError peut
provoquer un double affichage par votre application du même message d’erreur.
Pour éviter la duplication du message d’erreur, définissez UpdateAction à uaAbort
pour désactiver l’affichage des messages d’erreur générés par le système.
Les objets mise à jour fournissent une liaison automatique des paramètres pour
les paramètres qui référencent les valeurs originales et modifiées des champs de
l’ensemble de données. Vous insérez donc normalement des paramètres avec des
noms spécialement formatés quand vous composez les instructions SQL. Pour
plus d’informations sur l’utilisation de ces paramètres, voir “Substitution de
paramètres dans les instructions SQL de mise à jour” à la page 24-48.
y est déjà affichée dans la zone mémo Texte SQL. Vous pouvez éditer
l’instruction selon vos désirs.
Important Gardez à l’esprit que les instructions SQL générées sont des points de départ
pour la création d’instructions de mise à jour. Il peut être nécessaire de les
modifier pour qu’elles s’exécutent correctement. Par exemple, si vous travaillez
sur des données contenant des valeurs NULL, il faut modifier la clause WHERE
comme ceci :
WHERE field IS NULL
plutôt que d’utiliser la variable champ générée. Testez chaque instruction
directement avant de l’accepter.
Utilisez les boutons radio Type d’instruction pour basculer d’une instruction
générée à une autre et les éditer.
Pour accepter les instructions et les associer avec les propriétés SQL du
composant mise à jour, cliquez sur OK.
jour à l’ensemble de données, vous devez associer chaque objet mise à jour à un
ensemble de données en affectant à sa propriété DataSet le nom de l’ensemble de
données.
Conseil Quand vous utilisez plusieurs objets mise à jour, vous pouvez utiliser
TBDEClientDataSet au lieu de TClientDataSet avec un fournisseur externe.
La raison est qu’il n’est pas nécessaire de définir la propriété UpdateObject de
l’ensemble de données source.
La propriété DataSet des objets mise à jour n’est pas disponible dans l’inspecteur
d’objets à la conception. Vous ne pouvez définir cette propriété qu’à l’exécution.
UpdateSQL1->DataSet = Query1;
L’objet mise à jour utilise cet ensemble de données pour obtenir les valeurs de
champs originales et modifiées pour la substitution de paramètres et, s’il s’agit
d’un ensemble de données BDE, pour identifier la session et la base de données
à utiliser lors de l’application des mises à jour. Pour que la substitution de
paramètres fonctionne correctement, la propriété DataSet de l’objet mise à jour
doit être l’ensemble de données qui contient les valeurs de champs mises à jour.
Lors de l’utilisation d’un ensemble de données BDE pour mettre en mémoire
cache les mises à jour, il s’agit de l’ensemble de données BDE lui-même. Lors de
l’utilisation d’un ensemble de données client, c’est un ensemble de données client
qui est fourni en paramètre au gestionnaire d’événement BeforeUpdateRecord.
Quand l’objet mise à jour n’a pas été affecté à la propriété UpdateObject de
l’ensemble de données, ses instructions SQL ne sont pas automatiquement
exécutées quand vous appelez ApplyUpdates. Pour mettre à jour les
enregistrements, vous devez appeler manuellement l’objet mise à jour depuis un
gestionnaire d’événement OnUpdateRecord (si vous utilisez le BDE pour placer les
mises à jour en mémoire cache) ou BeforeUpdateRecord (si vous utilisez un
ensemble de données client). Dans ce gestionnaire d’événement, vous devez au
moins entreprendre les actions suivantes :
• Si vous utilisez un ensemble de données client pour placer les mises à jour en
mémoire cache, vous devez vous assurer que les propriétés DatabaseName et
SessionName des objets mise à jour sont définies comme les propriétés
DatabaseName et SessionName de l’ensemble de données source.
• Le gestionnaire d’événement doit appeler la méthode ExecSQL ou Apply de
l’objet mise à jour. Cela invoque l’objet mise à jour pour chaque
enregistrement nécessitant une mise à jour. Pour plus d’informations sur
l’exécution des instructions de mise à jour, voir “Exécution des instructions
SQL” ci-dessous.
• Affectez au paramètre UpdateAction du gestionnaire d’événement la valeur
uaApplied (OnUpdateRecord) ou au paramètre Applied la valeurtrue
(BeforeUpdateRecord).
Si vous le désirez, vous pouvez effectuer une validation ou une modification des
données, ou d’autres opérations qui dépendent de la mise à jour de chaque
enregistrement.
Attention Si vous appelez la méthode ExecSQL ou Apply d’un objet mise à jour dans un
gestionnaire d’événement OnUpdateRecord, assurez-vous de ne pas définir la
propriété UpdateObject de l’ensemble de données à cet objet mise à jour. Sinon, le
résultat sera une seconde tentative d’application de la mise à jour de chaque
enregistrement.
Utilisation de TBatchMove
TBatchMove encapsule les fonctionnalités du moteur de bases de données (BDE)
qui permettent de dupliquer un ensemble de données, d’ajouter à un ensemble
de données des enregistrements d’un autre, de mettre à jour des enregistrements
d’un ensemble de données avec ceux d’un autre, et de supprimer dans un
ensemble de données les enregistrements qui correspondent à ceux d’un autre
ensemble de données. TBatchMove sert le plus souvent à :
• Charger les données d’un serveur dans une source de données locale afin de
les analyser ou d’effectuer d’autres opérations.
• Transférer, dans le cadre d’une opération d’upsizing, une base de données de
bureau dans des tables stockées sur un serveur distant.
Un composant action groupée peut créer sur la destination des tables
correspondant aux tables source, en établissant une correspondance automatique
entre les noms de colonnes et les types de données.
Ajout d’enregistrements
Pour ajouter des données, l’ensemble de données destination doit représenter
une table existante. Durant l’opération d’ajout, le BDE convertit si nécessaire les
données à des tailles et des types de données appropriés à l’ensemble de
données destination. Si la conversion n’est pas possible, une exception est
déclenchée et les données ne sont pas ajoutées.
Suppression d’enregistrements
Pour supprimer des données dans l’ensemble de données destination, celui-ci
doit représenter une table existante et doit avoir un index qui permet d’établir la
correspondance entre les enregistrements. Si les champs de l’index primaire sont
utilisés pour établir les correspondances, les enregistrements pour lesquels des
champs indexés dans l’ensemble de données destination correspondent à des
champs indexés dans l’ensemble de données source sont supprimés dans la table
destination.
Lorsque vous déplacez des données entre des tables de types différents, un
composant action groupée traduit les types de données conformément aux types
de serveurs de l’ensemble de données. Consultez l’aide en ligne du BDE pour
obtenir les dernières tables de mappage entre types de serveurs.
Remarque Pour exécuter une action groupée sur des données en direction d’une base de
données sur un serveur SQL, vous devez avoir installé ce serveur de bases de
données et une version de C++Builder proposant le pilote SQL Link approprié,
ou utiliser ODBC si les pilotes ODBC adéquats des tiers sont installés.
Dictionnaire de données
Quand vous utilisez le BDE pour accéder aux données, votre application doit
accéder au dictionnaire de données. Celui-ci fournit une zone de stockage
personnalisable, indépendante de vos applications, où vous pouvez créer des
ensembles d’attributs de champs étendus qui décrivent le contenu et l’apparence
des données.
Par exemple, si vous développez fréquemment des applications financières, vous
pouvez créer des ensembles d’attributs de champs spécialisés décrivant différents
formats d’affichage monétaire. Quand vous créez des ensembles de données pour
votre application à la conception, plutôt que d’utiliser l’inspecteur d’objets pour
définir manuellement les champs monétaires de chaque ensemble de données,
vous pouvez associer ces champs à un ensemble d’attributs de champs étendus
dans le dictionnaire de données. L’usage de ce dernier assure une apparence
homogène des données dans et entre les applications que vous créez.
En environnement client/serveur, le dictionnaire de données peut résider sur un
serveur distant pour un partage supplémentaire des informations.
Pour apprendre comment créer des ensembles d’attributs de champs étendus
dans l’éditeur de champs à la conception et comment les associer aux champs
des ensembles de données de votre application, voir “Création des ensembles
Paramètre Description
Provider Le nom d’un fournisseur ADO local à utiliser pour la connexion.
Data Source Le nom du stockage de données.
File name Le nom d’un fichier contenant les informations de connexion.
Remote Provider Le nom d’un fournisseur ADO qui réside sur une machine distante.
Remote Server Le nom du serveur distant lors de l’utilisation d’un fournisseur distant.
Connexions asynchrones
Utilisez la propriété ConnectOptions pour que la connexion soit asynchrone.
L’utilisation de connexions asynchrones permet à votre application de poursuivre
son traitement sans attendre leur ouverture définitive.
Par défaut, ConnectionOptions a la valeur coConnectUnspecified qui laisse le serveur
décider du meilleur type de connexion. Pour imposer explicitement une
connexion asynchrone, initialisez ConnectOptions à coAsyncConnect.
Les deux exemples de code suivants active et désactive des connexions
asynchrones dans le composant connexion spécifié :
void __fastcall TForm1::AsyncConnectButtonClick(TObject *Sender)
{
ADOConnection1->Close();
ADOConnection1->ConnectOptions = coAsyncConnect;
ADOConnection1->Open();
}
Autres événements
Les composants connexion ADO introduisent deux événements supplémentaires
qui permettent de répondre aux notifications provenant de l’objet connexion
ADO sous-jacent :
• L’événement OnExecuteComplete se produit après que le composant connexion
exécute une commande sur le stockage de données (par exemple, après l’appel
de la méthode Execute). OnExecuteComplete indique si l’exécution a réussi.
• L’événement OnInfoMessage se produit lorsque l’objet connexion sous-jacent
fournit des informations détaillées après l’exécution d’une opération. Le
gestionnaire d’événement OnInfoMessage reçoit l’interface d’un objet Error
ADO qui contient les informations détaillées et un code d’état indiquant si
l’opération a réussi.
Tableau 25.4 Comparaison des mises à jour en mémoire cache d’un ensemble de données client et ADO
Ensemble
de données
ADO TClientDataSet Description
LockType Inutilisé : les ensembles de Spécifie si l’ensemble de données est ouvert en
données client placent mode mise à jour groupée.
toujours les mises à jour en
mémoire cache.
CursorType Inutilisé : les ensembles de Spécifie le degré d’isolation de l’ensemble de
données client manipulent données ADO par rapport aux modifications
toujours une photographie présentes sur le serveur.
mémorisée des données.
RecordStatus UpdateStatus Indique la mise à jour qui a éventuellement
affecté la ligne en cours. RecordStatus fournit
davantage d’informations que UpdateStatus.
FilterGroup StatusFilter Spécifie les types d’enregistrements disponibles.
FilterGroup fournit davantage d’informations.
UpdateBatch ApplyUpdates Applique les mises à jour en mémoire cache au
serveur de base de données. A la différence de
ApplyUpdates, UpdateBatch permet de limiter les
types de mises à jour à appliquer.
CancelBatch CancelUpdates Ne prend pas en compte les mises à jour en
attente et rétablit les valeurs initiales. A la
différence de CancelUpdates, CancelBatch permet
de limiter les types de mises à jour à annuler.
Application des mises à jour groupées dans les tables des bases
Pour appliquer les mises à jour en attente qui n’ont pas déjà été appliquées ou
annulées, appelez la méthode UpdateBatch. Pour les lignes dont le contenu a
changé et qui sont appliquées, les modifications sont placées dans les tables de
base sur lesquelles l’ensemble d’enregistrement est basé. Une ligne du cache
marqué pour la suppression entraîne la suppression de la ligne correspondante
de la table de la base. Une insertion d’enregistrement (l’enregistrement existe
dans le cache mais pas dans la table de la base) est ajoutée à la table de la base.
Pour les lignes modifiées, les colonnes des lignes correspondantes des tables de
la base sont modifiées pour adopter les nouvelles valeurs de colonnes présentes
dans le cache.
UpdateBatch accepte un paramètre : une valeur TAffectRecords. Si une valeur autre
que arAll est transmise, seul un sous-ensemble des modifications en attente est
appliqué. L’exemple suivant n’applique que la ligne en cours :
ADODataSet1->UpdateBatch(arCurrent);
Utilisation de TADODataSet
TADODataSet est un ensemble de données polyvalent qui permet de manipuler
les données d’un stockage de données ADO. A la différence des autres
composants ensemble de données ADO, TADODataSet n’est pas un ensemble de
données de type table, de type requête ou de type procédure stockée. Par contre,
il peut fonctionner comme l’un des types suivants :
• Comme un ensemble de données de type table, TADODataSet permet de
représenter toutes les lignes et colonnes d’une seule table de base de données.
Pour l’utiliser à cet effet, attribuez à la propriété CommandType la valeur
cmdTable et à la propriété CommandText le nom de la table. TADODataSet gère
les tâches de type table suivantes :
• Affectation d’index pour trier des enregistrements ou constituer la base de
recherches à partir d’enregistrements. Outre les propriétés et méthodes
d’index standard décrites dans “Tri des enregistrements avec des index” à
la page 22-30, vous pouvez utiliser la propriété Sort de TADODataSet pour
effectuer des tris à partir d’index temporaires. Les recherches basées sur les
index effectuées à l’aide de la méthode Seek utilisent l’index en cours.
Spécification de la commande
Spécifiez les commands d’un composant TADOCommand à l’aide de la propriété
CommandText. Comme TADODataSet, TADOCommand vous permet de spécifier la
commande de différentes manières, en fonction de la propriété CommandType.
CommandType peut prendre les valeurs suivantes : cmdText (si la commande est
une instruction SQL), cmdTable (si c’est un nom de table) et cmdStoredProc (si la
commande spécifie le nom d’une procédure stockée). A la conception,
sélectionnez la valeur appropriée dans la liste proposée par l’inspecteur d’objet.
A l’exécution, affectez une valeur de type TCommandType à la propriété
CommandType.
ADOCommand1->CommandText = "AddEmployee";
ADOCommand1->CommandType = cmdStoredProc;
...
méthode Execute). Une commande est dite en attente si la méthode Execute a été
appelée mais n’est pas encore achevée ou n’a pas dépassé le délai limite.
Une commande dépasse le délai limite si elle n’est pas terminée ou annulée dans
l’intervalle, en secondes, imparti par la propriété CommandTimeout. Par défaut, les
commandes disposent d’un délai de 30 secondes.
à jour les données en faisant appel à une commande SQL UPDATE, ou leur
conférer la prise en charge conventionnelle de l’édition en recourant à un
ensemble de données client dbExpress ou en connectant l’ensemble de
données à un ensemble de données client (voir “Connexion à un autre
ensemble de données” à la page 18-12).
• Il n’y a pas de support des filtres, car ceux-ci doivent fonctionner avec
plusieurs enregistrements, ce qui nécessite la mise en tampon. Si vous essayez
de filtrer un ensemble de données unidirectionnel, une exception est
déclenchée. Pour imposer des limites aux données à afficher, il vous faut
utiliser la commande SQL qui définit les données pour l’ensemble de données.
• Il n’y a pas de support des champs de référence, qui nécessitent un tampon
pour les enregistrements multiples contenant des valeurs de référence. Si vous
définissez un champ de référence sur un ensemble de données unidirectionnel,
il ne fonctionnera pas correctement.
Malgré ces limites, les ensembles de données unidirectionnels offrent un moyen
puissant d’accéder aux données. Ils représentent le mécanisme d’accès aux
données le plus rapide et sont très simples à utiliser et à déployer.
Configuration de TSQLConnection
Afin de décrire une connexion de base de données de façon suffisamment
détaillée pour que TSQLConnection puisse l’ouvrir, vous devez identifier le pilote
à utiliser et un ensemble de paramètres de connexion transmis au pilote.
Identification du pilote
Le pilote est identifié par la propriété DriverName, qui correspond au nom d’un
pilote dbExpress installé, tel que INTERBASE, ORACLE, MYSQL ou DB2. Le nom
de pilote est associé à deux fichiers :
• Le pilote dbExpress. Celui-ci est une bibliothèque de liaison dynamique portant
un nom tel que dbexpint.dll, dbexpora.dll, dbexpmys.dll ou dbexpdb2.dll.
• La bibliothèque de liaison dynamique fournie par l’éditeur de bases de
données pour la gestion de la partie client.
La relation entre ces deux fichiers et le nom de la base de données est stockée
dans un fichier appelé dbxdrivers.ini, qui est mis à jour lorsque vous installez un
pilote dbExpress. Généralement, vous n’avez pas à vous soucier de ces fichiers car
le composant connexion SQL les recherche dans dbxdrivers.ini lorsqu’il reçoit la
valeur de DriverName. Lorsque vous définissez la propriété DriverName,
TSQLConnection attribue automatiquement aux propriétés LibraryName et
VendorLib les noms des bibliothèques de liaison dynamique associées. Une fois
LibraryName et VendorLib définies, votre application n’est plus dépendante de
dbxdrivers.ini (en d’autres termes, vous n’avez pas besoin de déployer le fichier
dbxdrivers.ini avec votre application sauf si vous définissez la propriété
DriverName à l’exécution.)
Exécution de la commande
Pour exécuter une requête ou une procédure stockée ne renvoyant pas
d’enregistrement, n’utilisez pas la propriété Active ni la méthode Open. En
revanche, utilisez :
• La méthode ExecSQL si l’ensemble de données est une instance de
TSQLDataSet or TSQLQuery.
FixTicket->CommandText = "DELETE FROM TrafficViolations WHERE (TicketID = 1099)";
FixTicket->ExecSQL();
• La méthode ExecProc si l’ensemble de données est une instance
deTSQLStoredProc.
SQLStoredProc1->StoredProcName = "MyCommandWithNoResults";
SQLStoredProc1->ExecProc();
Conseil Si vous exécutez la requête ou la procédure stockée plusieurs fois, il convient de
définir la propriété Prepared par true.
SUSPEND;
END
Le code suivant utilise un TSQLDataSet pour créer cette procédure stockée.
Remarquez l’utilisation de la propriété ParamCheck pour empêcher l’ensemble de
données de confondre les paramètres de la définition de la procédure stockée
(:EMP_NO et :PROJ_ID) avec un paramètre de la requête créant la procédure
stockée.
SQLDataSet1->ParamCheck = false;
SQLDataSet1->CommandType = ctQuery;
SQLDataSet1->CommandText = ”CREATE PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT) RETURNS
(PROJ_ID CHAR(5)) AS BEGIN FOR SELECT PROJ_ID FROM EMPLOYEE_PROJECT WHERE EMP_NO = :EMP_NO
INTO :PROJ_ID DO SUSPEND; END”;
SQLDataSet1->ExecSQL();
Le procédé le plus simple pour obtenir ces métadonnées consiste à utiliser les
méthodes de TSQLConnection. Ces méthodes remplissent une liste de chaînes ou
un objet liste existant avec les noms de tables, de procédures stockées, de
champs ou d’index, ou avec des descripteurs de paramètre. Cette technique
s’apparente à celle que vous utilisez pour remplir des listes avec des
métadonnées pour tout autre composant connexion de base de données. Ces
méthodes sont décrites dans “Obtention de métadonnées” à la page 21-14.
Si vous avez besoin d’informations de schéma plus détaillées, vous pouvez
remplir un ensemble de données unidirectionnel avec des métadonnées. Au lieu
d’une simple liste, l’ensemble de données unidirectionnel est rempli avec des
informations de schéma, dans lesquelles chaque enregistrement représente une
table, une procédure stockée, un index, un champ ou un paramètre unique.
L’appel suivant demande une table listant toutes les tables système (les tables du
serveur qui contiennent des métadonnées) :
SQLDataSet1->SetSchemaInfo(stSysTable, "", "");
Lorsque vous ouvrez l’ensemble de données après cet appel de SetSchemaInfo, il
possède un enregistrement pour chaque table, dont les colonnes fournissent le
nom de table, le type, le nom de schéma, etc. Si le serveur n’utilise pas de tables
système pour stocker les métadonnées (par exemple MySQL), l’ensemble de
données ne contient aucun enregistrement lorsque vous l’ouvrez.
L’exemple précédent n’utilisait que le premier paramètre. Supposons que vous
vouliez obtenir la liste des paramètres utilisés en entrée de la procédure stockée
nommée ‘MyProc’. Supposons également que la personne ayant écrit cette
procédure se soit servie d’un préfixe dans le nom de tous les paramètres pour
indiquer s’il s’agit d’un paramètre en entrée ou en sortie (‘inName’, ‘outValue’,
etc.). Vous pourriez appeler SetSchemaInfo comme suit :
SQLDataSet1->SetSchemaInfo(stProcedureParams, "MyProc", "in%");
L’ensemble de données résultant est une table de paramètres d’entrée dont les
colonnes décrivent les propriétés de chaque paramètre.
Tableau 26.1 Colonnes des tables de métadonnées concernant les tables (suite)
Type
Nom de colonne de champ Contenu
CATALOG_NAME ftString Le nom du catalogue (la base de données) contenant la
table. C’est le même que le paramètre Database pour un
composant de connexion SQL.
SCHEMA_NAME ftString Le nom du schéma identifiant le propriétaire de la table.
TABLE_NAME ftString Le nom de la table. Ce champ détermine l’ordre de tri de
l’ensemble de données.
TABLE_TYPE ftInteger Identifie le type de table. C’est la somme d’un nombre
quelconque des valeurs suivantes :
1 : table
2 : vue
4 : table système
8 : synonyme
16 : table temporaire
32 : table locale.
Tableau 26.2 Colonnes des tables de métadonnées concernant les procédures stockées
Type
Nom de colonne de champ Contenu
RECNO ftInteger Un numéro d’enregistrement identifiant chaque
enregistrement de manière unique.
CATALOG_NAME ftString Le nom du catalogue (la base de données) contenant la
procédure stockée. C’est le même que le paramètre Database
pour un composant de connexion SQL.
SCHEMA_NAME ftString Le nom du schéma identifiant le propriétaire de la
procédure stockée.
PROC_NAME ftString Le nom de la procédure stockée. Ce champ détermine
l’ordre de tri de l’ensemble de données.
PROC_TYPE ftInteger Identifie le type de procédure stockée. C’est la somme d’un
nombre quelconque des valeurs suivantes :
1 : procédure (pas de valeur renvoyée)
2 : fonction (renvoie une valeur)
4 : paquetage
8 : procédure système
IN_PARAMS ftSmallint Le nombre de paramètres d’entrée.
OUT_PARAMS ftSmallint Le nombre de paramètres de sortie.
Tableau 26.5 Colonnes des tables de métadonnées concernant les paramètres (suite)
Type
Nom de colonne de champ Contenu
PROC_NAME ftString Le nom de la procédure stockée contenant le paramètre.
PARAM_NAME ftString Le nom du paramètre. Ce champ détermine l’ordre de tri
de l’ensemble de données.
PARAM_TYPE ftSmallint Identifie le type de paramètre. C’est le même que la
propriété ParamType d’un objet TParam.
PARAM_DATATYPE ftSmallint Le type de données du paramètre. C’est une des
constantes de types de champs logiques définies dans
sqllinks.h.
PARAM_SUBTYPE ftSmallint Un sous-type du type de données du paramètre. C’est
une des constantes de sous-types logiques définies dans
sqllinks.h.
PARAM_TYPENAME ftString Une chaîne décrivant le type de données. C’est la même
que celle contenue dans PARAM_DATATYPE et
PARAM_SUBTYPE, mais sous une forme utilisée par
certaines instructions DDL.
PARAM_PRECISION ftInteger Le nombre maximal de chiffres dans les valeurs en
virgule flottante ou dans les octets (pour les chaînes et
les champs d’octets).
PARAM_SCALE ftSmallint Le nombre de chiffres à droite de la décimale dans les
valeurs en virgule flottante.
PARAM_LENGTH ftInteger Le nombre d’octets nécessaires pour stocker les valeurs
des paramètres.
PARAM_NULLABLE ftSmallint Un booléen indiquant si le paramètre peut être laissé
vierge (0 signifie que le paramètre exige une valeur).
}
Remarque Le gestionnaire d’événement précédent vous permet également d’enregistrer une
liste qui s’avère partielle (contenant moins de 10 entrées) à l’arrêt de
l’application.
Utilisation d’ensembles
Chapitre 27
27
de données client
Les ensembles de données client sont des ensembles de données spécialisés qui
stockent toutes leurs données en mémoire. La manipulation des données stockées
en mémoire est possible grâce à midas.dll. Le format utilisé par les ensembles de
données client pour le stockage des données est auto-contenu et facilement
transportable ; c’est ce qui permet aux ensembles de données client de :
• Lire et écrire dans des fichiers dédiés sur le disque, en agissant comme un
ensemble de données basé sur des fichiers. Les propriétés et méthodes prenant
en charge ce mécanisme sont décrites dans “Utilisation d’un ensemble de
données client avec des données basées sur des fichiers” à la page 27-39.
• Mettre en cache les mises à jour des données d’un serveur de base de
données. Les fonctionnalités des ensembles de données client prenant en
charge les mises à jour en cache sont décrites dans “Utilisation d’un ensemble
de données client pour mettre en cache les mises à jour” à la page 27-18.
• Représenter les données dans la partie client d’une application multiniveau.
Pour fonctionner ainsi, l’ensemble de données client doit fonctionner avec un
fournisseur externe, comme décrit dans “Utilisation d’un ensemble de données
client avec un fournisseur” à la page 27-29. Pour plus d’informations sur ces
méthodes, voir chapitre 29, “Création d’applications multiniveaux”.
• Représenter les données issue d’une source autre qu’un ensemble de données.
Comme un ensemble de données client peut utiliser les données provenant
d’un fournisseur externe, des fournisseurs spécialisés peuvent adapter une
grande variété de sources d’informations pour les faire fonctionner avec des
ensembles de données client. Par exemple, vous pouvez utiliser un fournisseur
XML pour permettre à un ensemble de données client de représenter les
informations contenues dans un document XML.
Que vous utilisiez les ensembles de données client avec des données basées sur
des fichiers, pour mettre en cache les mises à jour, avec des données issues d’un
Tableau 27.1 Support des filtres dans les ensembles de données client
Pris en
charge par
d’autres
Opérateur ensembles
ou fonction Exemple de données Commentaire
Comparaisons
= State = ’CA’ Oui
<> State <> ’CA’ Oui
>= DateArrivée >= ’1/1/1998’ Oui
<= Total <= 100000 Oui
> Pourcentage > 50 Oui
< Champ1 < Champ2 Oui
Tableau 27.1 Support des filtres dans les ensembles de données client (suite)
Pris en
charge par
d’autres
Opérateur ensembles
ou fonction Exemple de données Commentaire
BLANK State <> ’CA’ or State = Oui Les enregistrements
BLANK vierges ne s’affichent que
s’ils sont explicitement
inclus dans le filtre.
IS NULL Champ1 IS NULL Non
IS NOT NULL Champ1 IS NOT NULL Non
Opérateurs
logiques
and State = ’CA’ and Country = Oui
’US’
or State = ’CA’ or State = ’MA’ Oui
not not (State = ’CA’) Oui
Opérateurs
arithmétiques
+ Total + 5 > 100 Dépend du S’applique aux nombres,
pilote aux chaînes ou aux dates
(heures) plus un nombre.
- Champ1 - 7 <> 10 Dépend du S’applique aux nombres,
pilote aux dates ou aux dates
(heures) moins un
nombre.
* Remise * 100 > 20 Dépend du S’applique aux nombres
pilote uniquement.
/ Remise > Total / 5 Dépend du S’applique aux nombres
pilote uniquement.
Fonctions String
Upper Upper(Champ1) = Non
’TOUJOURS’
Lower Lower(Champ1 + Champ2) Non
= ’josp’
Substring Substring(ChampDate,8) = Non La valeur va de la
’1998’ position du second
Substring(ChampDate,1,3) = argument à la fin ou au
’JAN’ nombre de caractères
dans le troisième
argument. Le premier
caractère a la position 1.
Tableau 27.1 Support des filtres dans les ensembles de données client (suite)
Pris en
charge par
d’autres
Opérateur ensembles
ou fonction Exemple de données Commentaire
Trim Trim(Champ1 + Champ2) Non Supprime le troisième
Trim(Champ1, ’-’) argument au début et à
la fin. S’il n’y a pas de
troisième argument,
supprime les espaces.
TrimLeft TrimLeft(ChampString) Non Voir Trim.
TrimLeft(Champ1, ’$’) <> ’’
TrimRight TrimRight(ChampString) Non Voir Trim.
TrimRight(Champ1, ’.’) <> ’’
Fonctions
DateTime
Year Year(ChampDate) = 2001 Non
Month Month(ChampDate) <> 12 Non
Day Day(ChampDate) = 1 Non
Hour Hour(ChampDate) < 16 Non
Minute Minute(ChampDate) = 0 Non
Second Second(ChampDate) = 30 Non
GetDate GetDate - DateField > 7 Non Représente la date et
l’heure en cours.
Date ChampDate = Non Renvoie la partie date
Date(GetDate) d’une valeur date/heure.
Time ChampHeure > Non Renvoie la partie heure
Time(GetDate) d’une valeur date/heure.
Divers
Like Memo LIKE ’%filters%’ Non Fonctionne comme SQL-
92 sans la clause ESC.
Lorsqu’elle est appliquée
à des champs BLOB,
FilterOptions détermine
la prise en compte de
la casse.
In Day(ChampDate) in (1,7) Non Fonctionne comme SQL-
92. Le second argument
est une liste de valeurs
toutes du même type.
* State = ’M*’ Oui Caractère générique pour
les comparaisons
partielles.
Lorsque vous appliquez des portées ou des filtres, l’ensemble de données client
stockera tous les enregistrements en mémoire. La portée ou le filtre détermine
Chaque composant champ possède deux propriétés qui peuvent être utilisées
pour spécifier des contraintes :
• La propriété DefaultExpression définit une valeur par défaut qui est attribuée au
champ si l’utilisateur n’en saisit pas une. Remarquez que si le serveur de base de
données ou l’ensemble de données source attribue aussi une expression par
défaut au champ, celle de l’ensemble de données client est prioritaire car elle est
attribuée avant que la mise à jour ne soit appliquée en retour sur le serveur de
base de données ou dans l’ensemble de données source.
• La propriété CustomConstraint vous permet d’imposer une condition à remplir
pour qu’une valeur de champ puisse être validée. Les contraintes personnalisées
définies de cette façon sont appliquées en plus des contraintes importées du
serveur. Pour plus d’informations sur la manipulation des contraintes
personnalisées sur les composants champ, voir “Création de contrainte
personnalisée” à la page 23-24.
Au niveau de l’enregistrement, vous pouvez spécifier des contraintes à l’aide de
la propriété Constraints de l’ensemble de données client. Constraints est une
collection d’objets TCheckConstraint, dans laquelle chacun d’eux représente une
condition. Utilisez la propriété CustomConstraint d’un objet TCheckConstraint pour
ajouter vos propres contraintes, qui sont vérifiées lorsque vous validez les
enregistrements.
Tri et indexation
L’utilisation d’index présente plusieurs avantages pour vos applications :
• Ils permettent aux ensembles de données client de localiser les données
rapidement.
• Ils permettent d’appliquer des portées pour limiter les enregistrements
disponibles.
• Ils permettent à votre application de définir des relations entre les autres
ensembles de données, telles que des tables de référence ou des liens maître/
détail.
• Ils spécifient l’ordre dans lequel les enregistrements apparaissent.
Si un ensemble de données client représente les données d’un serveur ou utilise
un fournisseur externe, il hérite d’un index et d’un ordre de tri par défaut, basés
sur les données qu’il reçoit. L’index par défaut s’appelle DEFAULT_ORDER. Il
est possible d’utiliser ce classement, mais il est impossible de modifier ou de
supprimer l’index.
En plus de l’index par défaut, l’ensemble de données client gère un deuxième
index, appelé CHANGEINDEX, à partir des enregistrements stockés dans le
journal de modifications (propriété Delta). CHANGEINDEX classe tous les
enregistrements de l’ensemble de données tels qu’ils apparaîtraient si les
modifications de Delta étaient appliquées. CHANGEINDEX est basé sur l’ordre
qu’il a hérité de DEFAULT_ORDER. Comme pour DEFAULT_ORDER, il est
impossible de modifier ou de supprimer l’index CHANGEINDEX.
Vous pouvez utiliser d’autres index existants ou créer vos propres index. Les
sections suivantes décrivent comment créer et utiliser des index avec des
ensembles de données client.
Remarque Vous pouvez également vouloir revoir les documents sur les index dans les
ensembles de données de type table, ce qui s’applique aussi aux ensembles de
données client. Vous trouverez ces informations dans “Tri des enregistrements
avec des index” à la page 22-30 et “Limitation des enregistrements avec des
portées” à la page 22-35.
Spécification d’agrégats
Pour spécifier que vous voulez opérer des calculs synthétiques à partir des
enregistrements d’un ensemble de données client, utilisez la propriété Aggregates.
Aggregates est un ensemble de spécifications d’agrégat (TAggregate). Vous pouvez
ajouter des spécifications d’agrégat à votre ensemble de données client à l’aide
de l’éditeur de collection lors de la conception ou en utilisant la méthode Add de
Aggregates lors de l’exécution. Si vous souhaitez créer des composants champ
pour les agrégats, créez des champs persistants pour les valeurs synthétisées
dans l’éditeur de champs.
Remarque Lorsque vous créez des champs synthétisés, les objets agrégat appropriés sont
automatiquement ajoutés à la propriété Aggregates de l’ensemble de données
client. Ne les ajoutez pas de façon explicite lors de la création des champs
persistants synthétisés. Pour plus de détails sur la création des champs
persistants synthétisés, voir “Définition d’un champ agrégat” à la page 23-12.
Pour chaque agrégat, la propriété Expression indique le calcul synthétique qu’elle
représente. Expression peut contenir une simple expression synthétique telle que
Sum(Champ1)
ou une expression complexe qui combine les informations de plusieurs champs,
telle que
Sum(Qté * Prix) - Sum(MontantPayé)
Les expressions d’agrégat incluent un ou plusieurs opérateurs de synthèse du
tableau suivant :
Les opérateurs de synthèse portent sur des valeurs de champ ou sur des
expressions conçues à partir de valeurs de champ à l’aide des mêmes opérateurs
que ceux utilisés pour la création de filtres. Vous ne pouvez pas, toutefois,
imbriquer des opérateurs de synthèse. Vous pouvez créer des expressions avec
des opérateurs à partir de valeurs synthétisées, ou de valeurs synthétisées et de
constantes. Toutefois, vous ne pouvez pas combiner des valeurs synthétisées et
des valeurs de champ, car de telles expressions sont ambiguës (rien n’indique
quel enregistrement doit fournir la valeur de champ). Ces règles sont illustrées
dans les expressions suivantes :
Sum(Qty * Price) {autorisé — synthèse d’une expression portant sur des champs }
Max(Champ1) - Max(Champ2) {autorisé — expression à partir de synthèses }
Avg(TauxRemise) * 100 {autorisé — expression à partir d’une synthèse et d’une constante }
Min(Sum(Champ1)) {non autorisé — synthèses imbriquées }
Count(Champ1) - Champ2 {non autorisé — expression à partir d’une synthèse et d’un champ }
Le code suivant définit un agrégat maintenu qui indique le montant total des
ventes réalisé par chaque représentant :
Agg->Expression = "Sum(Amount)";
Agg->IndexName = "SalesCust";
Agg->GroupingLevel = 1;
Agg->AggregateName = "Total for Rep";
Pour ajouter un agrégat qui synthétise chaque client pour un représentant donné,
créez un agrégat maintenu de niveau 2.
Une fois qu’un paquet de données est affecté à Data, son contenu est
automatiquement affiché dans les contrôles orientés données connectés à
l’ensemble de données client par un composant source de données.
Lorsque vous ouvrez un ensemble de données client représentant des données
du serveur ou utilisant un composant fournisseur externe, les paquets de
données sont automatiquement affectés à Data.
Lorsque votre ensemble de données client n’utilise pas de fournisseur, vous
pouvez copier les données à partir d’un autre ensemble de données client
comme suit :
ClientDataSet1->Data = ClientDataSet2->Data;
Remarque Lorsque vous copiez la propriété Data d’un autre ensemble de données client,
vous copiez également le journal de modifications, mais la copie ne reflète pas
les filtres ni les portées ayant été appliqués. Pour inclure les filtres ou les
portées, vous devez cloner le curseur de l’ensemble de données source.
Si vous copiez à partir d’un ensemble de données autre qu’un ensemble de
données client, vous pouvez créer un composant fournisseur d’ensembles de
données, le relier à l’ensemble de données source et copier ses données :
TempProvider = new TDataSetProvider(Form1);
TempProvider->DataSet = SourceDataSet;
ClientDataSet1->Data = TempProvider->Data;
delete TempProvider;
Remarque Lorsque vous affectez directement les données à la propriété Data, le nouveau
paquet de données n’est pas fusionné dans les données existantes. Au lieu de
cela, toutes les anciennes données sont remplacées.
Si vous souhaitez fusionner les modifications d’un autre ensemble de données, et
non copier ses données, vous devez utiliser un composant fournisseur. Créez un
fournisseur d’ensembles de données comme dans l’exemple précédent, mais
attachez-le à l’ensemble de données de destination et au lieu de copier la
propriété Data, utilisez la méthode ApplyUpdates :
TempProvider = new TDataSetProvider(Form1);
TempProvider->DataSet = ClientDataSet1;
TempProvider->ApplyUpdates(SourceDataSet->Delta, -1, ErrCount);
delete TempProvider;
l’index en cours, de liens vers une table maître (lorsque l’ensemble de données
source est un ensemble détail), de la propriété ReadOnly et de tout lien vers un
composant connexion ou un fournisseur.
Lorsque Reset et KeepSettings valent false, un ensemble de données client cloné
est ouvert et les paramètres de l’ensemble de données client source sont utilisés
pour définir les propriétés de l’ensemble de données destination. Lorsque Reset
vaut true, les propriétés de l’ensemble de données client destination reçoivent les
valeurs par défaut (aucun index ni filtre, aucune table maître, ReadOnly vaut
false et aucun composant connexion ou fournisseur n’est spécifié). Lorsque
KeepSettings vaut true, les propriétés de l’ensemble de données destination ne
sont pas modifiées.
applique les mises à jour du cache à la base de données en une seule transaction.
Lorsque vous mettez en cache les mises à jour, les changements effectués sur un
ensemble de données (comme émettre des modifications ou supprimer des
enregistrements) sont stockés en local au lieu d’être écrits directement dans la
table sous-jacente à l’ensemble de données. Lorsque les modifications sont
terminées, votre application appelle une méthode qui écrit les modifications du
cache dans la base de données et vide le cache.
Mettre en cache les mises à jour peut minimiser le temps de transaction et
réduire le trafic sur le réseau. Cependant, les données mises en cache sont locales
pour votre application et ne se trouvent plus sous le contrôle des transactions.
Cela signifie que, pendant que vous travaillez sur votre copie des données dans
votre mémoire locale, d’autres applications peuvent être en train de changer les
données dans la table de la base de données sous-jacente. D’autre part, elles ne
peuvent pas voir les modifications que vous effectuez tant que ne validez pas les
mises à jour du cache. De ce fait, les mises à jour en cache ne conviennent pas
aux applications impliquant des données trop versatiles, car vous risqueriez de
créer ou de rencontrer trop de conflits au moment d’intégrer vos modifications
dans la base de données.
Bien que le BDE et ADO fournissent d’autres mécanismes pour cacher les mises
à jour, l’utilisation d’un ensemble de données client offre plusieurs avantages :
• Lorsque des ensembles de données sont liés par des relations maître/détail,
l’application des mises à jour est gérée à votre place. Cela garantit que les
mises à jour dans des ensembles de données multiples liés entre eux sont
effectuées dans le bon ordre.
• Les ensembles de données client vous procurent le meilleur contrôle sur le
processus de mise à jour. Vous pouvez définir des propriétés pour influencer
le SQL généré pour mettre à jour les enregistrements, spécifier la table à
utiliser dans le cas de mise à jour d’enregistrements à partir d’une jointure
multitable, ou même appliquer les mises à jour manuellement à partir d’un
gestionnaire d’événement BeforeUpdateRecord.
• Si des erreurs se produisent pendant l’application au serveur de la base de
données des mises à jour du cache, seuls les ensembles de données client (et
les fournisseurs d’ensembles de données) vous donnent des informations sur
l’enregistrement en cours dans le serveur en plus de la valeur originale (non
modifiée) de votre ensemble de données et de la nouvelle valeur (modifiée) de
la mise à jour qui a échoué.
• Les ensembles de données client vous permettent de spécifier le nombre
d’erreurs de mise à jour que vous pouvez accepter avant l’abandon de la
totalité de la mise à jour.
1 Indiquer les données que vous voulez modifier. La façon dont vous le ferez
dépend du type d’ensemble de données client que vous utilisez :
• Si vous utilisez TClientDataSet, spécifiez le composant fournisseur qui
représente les données que vous voulez modifier. Cela est décrit dans
“Spécification d’un fournisseur” à la page 27-29.
• Si vous utilisez un ensemble de données client associé à un mécanisme
d’accès aux données particulier, vous devez
- Identifier le serveur de base de données en définissant la propriété
DBConnection par un composant de connexion approprié.
- Indiquer les données que vous voulez voir en spécifiant les propriétés
CommandText et CommandType. CommandType indique si CommandText est
une instruction SQL à exécuter, le nom d’une procédure stockée ou le nom
d’une table. Si CommandText est une requête ou une procédure stockée,
utilisez la propriété Params pour extraire les paramètres d’entrée.
- Optionnellement, utilisez la propriété Options pour déterminer si les
ensembles détails imbriqués et les données BLOB doivent figurer dans les
paquets de données ou être extraits séparément, si les types spécifiques
d’édition (insertions, modifications ou suppressions) sont désactivés, si une
même mise à jour peut concerner plusieurs enregistrements du serveur et si
les enregistrements de l’ensemble de données client sont rafraîchis lorsqu’il
applique les mises à jour. Options est identique à la propriété Options du
fournisseur. Par conséquent, vous pouvez définir des options non
pertinentes ou inappropriées. Par exemple, il n’y a pas lieu d’inclure
poIncFieldProps, car l’ensemble de données client n’extrait pas ses données
d’un ensemble de données comportant des champs persistants. De même, il
n’est pas souhaitable d’exclure poAllowCommandText, qui est inclus par
défaut, car cela désactiverait la propriété CommandText, que l’ensemble de
données client utilise pour spécifier quelles données il veut. Pour plus
d’informations sur la propriété Options du fournisseur, voir “Initialisation
des options contrôlant les paquets de données” à la page 28-6.
2 Afficher et modifier les données, permettre l’insertion de nouveaux
enregistrements et la suppression d’enregistrements existants. A la fois la
copie originale de chaque enregistrement et toutes ses modifications sont
stockées en mémoire. Ce processus est décrit dans “Edition des données” à la
page 27-6.
3 Extraire des enregistrements supplémentaires si nécessaire. Par défaut, les
ensembles de données client extraient tous les enregistrements et les stockent
en mémoire. Si un ensemble de données contient beaucoup d’enregistrements,
ou des enregistrements avec des champs BLOB volumineux, vous souhaiterez
probablement modifier ce comportement pour que l’ensemble de données
clients n’extrait que les enregistrements requis pour l’affichage et recommence
l’opération lorsque cela s’avère à nouveau nécessaire. Pour des détails sur la
façon de contrôler le processus d’extraction des enregistrements, voir
“Extraction des données dans l’ensemble de données ou le document source”
à la page 27-31.
Tableau 27.3 Ensembles de données client spécialisés pour les mises à jour en cache
Ensemble de données client Mécanisme d’accès aux données
TBDEClientDataSet Borland Database Engine
TSQLClientDataSet dbExpress
TIBClientDataSet InterBase Express
En outre, vous pouvez mettre en cache les mises à jour en utilisant l’ensemble de
données client générique (TClientDataSet) avec un fournisseur externe et un
ensemble de données source. Pour plus d’informations sur l’utilisation de
TClientDataSet avec un fournisseur externe, voir “Utilisation d’un ensemble de
données client avec un fournisseur” à la page 27-29.
Remarque Les ensembles de données client spécialisés associés à chaque mécanisme d’accès
aux données utilisent en fait un fournisseur et un ensemble de données source.
Mais, et le fournisseur et l’ensemble de données source sont internes par rapport
à l’ensemble de données client.
Le plus simple est d’utiliser un des ensembles de données client spécialisés pour
mettre en cache les mises à jour. Mais, il est parfois préférable d’utiliser
TClientDataSet avec un fournisseur externe :
• Si vous utilisez un mécanisme d’accès aux données n’ayant pas d’ensemble de
données client spécialisé, vous devez utiliser TClientDataSet avec un
composant fournisseur externe. Par exemple, si les données proviennent d’un
document XML ou d’un ensemble de données personnalisé.
• Si vous travaillez avec des tables entre lesquelles a été établie une relation
maître/détail, vous devez utiliser TClientDataSet et le connecter, au moyen
d’un fournisseur, à la table maître de deux ensembles de données source liés
dans une relation maître/détail. L’ensemble de données client voit l’ensemble
détail comme le champ d’un ensemble de données imbriqué. Cette approche
est nécessaire pour permettre l’application des mises à jour des tables maître
et client dans l’ordre correct.
• Si vous voulez coder des gestionnaires d’événements répondant à la
communication entre l’ensemble client et le fournisseur (par exemple, avant et
après que l’ensemble client extrait des enregistrements du fournisseur), vous
devez utiliser TClientDataSet avec un composant fournisseur externe. Les
ensembles de données client spécialisés publient les événements les plus
importants de l’application des mises à jour (OnReconcileError,
BeforeUpdateRecord et OnGetTableName), mais ils ne publient pas les
événements périphériques de la communication entre l’ensemble client et son
fournisseur, car au départ ils ont été prévus pour les applications
multiniveaux.
• Lorsque vous utilisez le BDE, vous pouvez vouloir utiliser un fournisseur
externe et un ensemble de données source si vous avez besoin d’utiliser un
objet mise à jour. Bien qu’il soit possible de coder un objet mise à jour à partir
du gestionnaire d’événement BeforeUpdateRecord de TBDEClientDataSet, il est
plus simple d’affecter la propriété UpdateObject de l’ensemble de données
source. Pour plus d’informations sur l’utilisation des objets mise à jour, voir
“Utilisation d’objets mise à jour pour mettre à jour un ensemble de données”
à la page 24-45.
fournisseur pour agir sur la façon dont sont appliquées les mises à jour. Ces
méthodes sont décrites dans “Comment répondre aux demandes de mise à jour
des clients” à la page 28-9.
Mais, lorsque le fournisseur est interne, ce qui se passe pour tout ensemble de
données client associé à un mécanisme d’accès aux données, vous ne pouvez pas
définir ses propriétés ni fournir de gestionnaire d’événement. Il s’en suit que
l’ensemble de données client publie une propriété et deux événements vous
permettant d’agir sur la façon dont le fournisseur interne applique les mises à
jour.
• UpdateMode détermine les champs utilisés pour rechercher des enregistrements
dans les instructions SQL que génère le fournisseur pour appliquer les mises à
jour. UpdateMode est identique à la propriété UpdateMode du fournisseur. Pour
plus d’informations sur la propriété UpdateMode du fournisseur, voir
“Comment contrôler l’application des mises à jour” à la page 28-11.
• OnGetTableName qui vous permet de fournir au fournisseur le nom de la table
de base de données à laquelle il doit appliquer les mises à jour. Cela permet
au fournisseur de générer les instructions SQL de mise à jour lorsqu’il ne peut
pas identifier la table de la base de données à partir de la procédure stockée
ou de la requête spécifiée par CommandText. Par exemple, si la requête exécute
une jointure multitable qui n’implique des mises à jour que pour une seule
table, la fourniture d’un gestionnaire d’événement OnGetTableName permet au
fournisseur interne d’appliquer correctement les mises à jour.
Le gestionnaire d’événement OnGetTableName reçoit trois paramètres : le
composant fournisseur interne, l’ensemble de données interne ayant extrait les
données du serveur, et un paramètre pour renvoyer le nom de la table à
utiliser dans le SQL généré.
• BeforeUpdateRecord se produit pour chaque enregistrement du paquet delta. Cet
événement permet d’effectuer tout changement de dernière minute avant que
l’enregistrement ne soit inséré, supprimé ou modifié. En outre, il vous permet
d’exécuter vos propres instructions SQL pour appliquer la mise à jour lorsque
le fournisseur n’est pas en mesure de générer une instruction SQL correcte
(c’est par exemple le cas des jointures multitables dans lesquelles plusieurs
tables doivent être mises à jour.)
Le gestionnaire d’événement BeforeUpdateRecord reçoit cinq paramètres : le
composant fournisseur interne, l’ensemble de données interne qui a extrait les
données du serveur, un paquet delta positionné sur l’enregistrement qui va
être mis à jour, une indication de la nature de la mise à jour (insertion,
suppression ou modification), et un paramètre qui renvoie l’indication que le
gestionnaire d’événement a effectué la mise à jour. Tout cela est illustré dans
le gestionnaire d’événement suivant. Pour simplifier, cet exemple suppose que
les instructions SQL sont accessibles en tant que variables globales ne
nécessitant que les valeurs des champs :
void __fastcall TForm1::SQLClientDataSet1BeforeUpdateRecord(TObject *Sender,
TDataSet *SourceDS, TCustomClientDataSet *DeltaDS, TUpdateKind UpdateKind, bool
&Applied)
{
TSQLConnection *pConn := (dynamic_cast<TCustomSQLDataSet *>(SourceDS)->SQLConnection);
char buffer[256];
switch (UpdateKind)
case ukModify:
// premier ensemble de données : met à jour Fields[1], utilise Fields[0]
// dans la clause where
sprintf(buffer, UpdateStmt1, DeltaDS->Fields->Fields[1]->NewValue,
DeltaDS->Fields->Fields[0]->OldValue);
pConn->Execute(buffer, NULL, NULL);
// second ensemble de données : met à jour Fields[2], utilise Fields[3]
// dans la clause where
sprintf(buffer, UpdateStmt2, DeltaDS->Fields->Fields[2]->NewValue,
DeltaDS->Fields->Fields[3]->OldValue);
pConn->Execute(buffer, NULL, NULL);
break;
case ukDelete:
// premier ensemble de données : utilise Fields[0] dans la clause where
sprintf(buffer, DeleteStmt1, DeltaDS->Fields->Fields[0]->OldValue);
pConn->Execute(buffer, NULL, NULL);
// second ensemble de données : utilise Fields[3] dans la clause where
sprintf(buffer, DeleteStmt2, DeltaDS->Fields->Fields[3]->OldValue);
pConn->Execute(buffer, NULL, NULL);
break;
case ukInsert:
// premier ensemble de données : valeurs de Fields[0] et Fields[1]
sprintf(buffer, UpdateStmt1, DeltaDS->Fields->Fields[0]->NewValue,
DeltaDS->Fields->Fields[1]->NewValue);
pConn->Execute(buffer, NULL, NULL);
// second ensemble de données : valeurs de Fields[2] et Fields[3]
sprintf(buffer, UpdateStmt2, DeltaDS->Fields->Fields[2]->NewValue,
DeltaDS->Fields->Fields[3]->NewValue);
pConn->Execute(buffer, NULL, NULL);
break;
}
empaqueter les données ou appliquer des mises à jour. Si vous voulez qu’il
représente des données issues d’un ensemble de données source ou d’un
document XML, vous devez associer l’ensemble client avec un composant
fournisseur externe.
La façon dont vous associez TClientDataSet à un fournisseur dépend de l’endroit
où se trouve le fournisseur : dans la même application que l’ensemble de
données client ou sur un serveur d’applications distant exécuté sur un autre
système.
• Si le fournisseur se trouve dans la même application que l’ensemble de
données client, vous pouvez associer l’ensemble de données à un fournisseur
en choisissant celui-ci dans la liste déroulante de la propriété ProviderName
dans l’inspecteur d’objets. Ce procédé fonctionne sous réserve que le
fournisseur possède le même Owner que l’ensemble de données client.
L’ensemble de données client et le fournisseur possèdent le même Owner s’ils
sont placés dans la même fiche ou dans le même module de données. Pour
utiliser un fournisseur local possédant un Owner différent, vous devez établir
l’association à l’exécution à l’aide de la méthode SetProvider de l’ensemble de
données client.
Si vous envisagez de passer à un fournisseur distant ou si vous voulez faire
directement appel à l’interface IAppServer, vous pouvez définir la propriété
RemoteServer par un composant TLocalConnection. Si vous utilisez
TLocalConnection, l’instance TLocalConnection gère la liste des tous les
fournisseurs locaux par rapport à votre application, et les appels IAppServer de
l’ensemble de données client. Si vous n’utilisez pas TLocalConnection,
l’application crée un objet caché pour gérer les appels IAppServer de
l’ensemble de données client.
• Si le fournisseur se trouve sur un serveur d’applications distant, outre la
propriété ProviderName, vous devez spécifier un composant qui connecte
l’ensemble de données client au serveur d’applications. Voici deux propriétés
pouvant gérer cette tâche : RemoteServer, qui spécifie le nom d’un composant
connexion à partir duquel obtenir une liste de fournisseurs, ou
ConnectionBroker, qui spécifie un courtier ou agent centralisé fournissant un
niveau d’indirection supplémentaire entre l’ensemble client et le composant
connexion. Le composant connexion et le composant courtier, lorsqu’il est
utilisé, se trouvent dans le même module de données que l’ensemble de
données client. Le composant connexion établit et maintient la connexion au
serveur d’applications, c’est pourquoi il est parfois appelé “le courtier ou
l’agent des données”. Pour plus d’informations, voir “Structure de
l’application client” à la page 29-5.
Après avoir spécifié en mode conception la propriété RemoteServer ou
ConnectionBroker, vous pouvez sélectionner un fournisseur dans la liste
déroulante de la propriété ProviderName dans l’inspecteur d’objets. Cette liste
contient les fournisseurs locaux (appartenant à la même fiche ou au même
module de données) et les fournisseurs distants accessibles par le biais du
composant connexion.
Extractions incrémentales
En changeant la propriété PacketRecords, vous pouvez demander que l’ensemble
de données client lise les données en fragments plus petits. PacketRecords spécifie
la quantité d’enregistrements à extraire à la fois et le type des enregistrements à
renvoyer. Par défaut, PacketRecords vaut -1, ce qui signifie que tous les
enregistrements disponibles sont extraits à la fois, que ce soit à la première
ouverture de l’ensemble de données client ou lorsque l’application appelle
explicitement GetNextPacket. Lorsque PacketRecords vaut -1, l’ensemble de données
client n’extrait pas de données supplémentaires après la première extraction des
données, car il dispose de tous les enregistrements disponibles.
Pour extraire les enregistrements par petits lots, affectez à PacketRecords une
valeur correspondant au nombre d’enregistrements voulu. Par exemple,
l’instruction suivante fixe la taille de chaque paquet de données à dix
enregistrements :
ClientDataSet1->PacketRecords = 10;
Ce processus d’extraction d’enregistrements par petits lots est appelé “extraction
incrémentale”. Les ensembles de données client utilisent l’extraction incrémentale
lorsque PacketRecords est supérieur à zéro.
Pour lire chaque lot d’enregistrements, l’ensemble de données client appelle
GetNextPacket. Les paquets extraits sont ajoutés à la fin des données se trouvant
déjà dans l’ensemble de données client. GetNextPacket renvoie le nombre
d’enregistrements extraits. Si la valeur renvoyée est équivalente à la valeur de
PacketRecords, c’est que tous les enregistrements disponibles n’ont pas été traités.
Si la valeur renvoyée est supérieure à 0 mais inférieure à PacketRecords, c’est que
le dernier enregistrement a été atteint durant l’opération d’extraction. Si
GetNextPacket renvoie 0, c’est qu’il n’y a plus aucun enregistrement à extraire.
Attention L’extraction incrémentale ne fonctionne pas si les données sont extraites d’un
fournisseur distant situé sur un serveur d’applications sans état. Voir “Gestion
des informations d’état dans les modules de données distants” à la page 29-21,
pour plus d’informations sur l’utilisation de l’extraction incrémentale avec les
modules de données distants sans état.
Remarque La propriété PacketRecords peut aussi être utilisée pour extraire des informations
métadonnées sur l’ensemble de données source. Pour extraire des informations
métadonnées, PacketRecords doit valoir 0.
Extraction à la demande
L’extraction automatique d’enregistrements est contrôlée par la propriété
FetchOnDemand. Lorsque FetchOnDemand vaut true (la valeur par défaut),
l’ensemble de données client lit automatiquement les enregistrements en fonction
des besoins. Pour empêcher l’extraction automatique des enregistrements, mettez
FetchOnDemand à false. Si FetchOnDemand est à false, l’application doit appeler
explicitement GetNextPacket pour extraire des enregistrements.
Par exemple, les applications qui doivent représenter des ensembles de données
très volumineux accessibles en lecture seulement peuvent désactiver
FetchOnDemand afin que les ensembles de données client n’essaient pas de
charger plus de données que la mémoire ne peut en contenir. Entre les
extractions, l’ensemble de données client libère sa mémoire cache à l’aide de la
méthode EmptyDataSet. Cette approche, toutefois, ne fonctionne pas très bien
lorsque le client doit renvoyer les mises à jour au serveur.
Le fournisseur contrôle si les enregistrements figurant dans les paquets de
données comprennent des données BLOB et des ensembles de données détail
imbriqués. Si le fournisseur exclut cette information des enregistrements, la
propriété FetchOnDemand oblige l’ensemble de données client à extraire
automatiquement les données BLOB et les ensembles de données détail au fur et
à mesure des besoins. Si FetchOnDemand vaut false et si le fournisseur ne
contient pas de données BLOB ni d’ensembles de données détail avec les
enregistrements, vous devez appeler explicitement la méthode FetchBlobs ou
FetchDetails pour extraire ces informations.
filtre, les enregistrements sont encore en mémoire cache mais considérés comme
non disponibles.
Le nom de chaque paramètre doit correspondre à un nom de champ. Lorsque
vous utilisez TClientDataSet, ce sont les noms des champs du composant TTable
ou TSQLTable associé au fournisseur. Lorsque vous utilisez TSQLClientDataSet ou
TBDEClientDataSet, ce sont les noms des champs de la table sur le serveur de
base de données. L’ensemble client ne contient alors que les enregistrements dont
les valeurs dans les champs équivalents correspondent à celles des paramètres.
Par exemple, supposons une application qui affiche les commandes d’un seul
client. Lorsque l’utilisateur identifie le client, l’ensemble de données client définit
sa propriété Params pour inclure un paramètre unique nommé CustID, dont la
valeur identifie le client dont les commandes doivent être affichées. Quand
l’ensemble de données client demande les données de l’ensemble de données
source, il transmet la valeur de ce paramètre. Le fournisseur n’envoie ensuite que
les enregistrements concernant le client identifié. Ceci est beaucoup plus efficace
que la solution dans laquelle tous les enregistrements de commande sont
envoyés par le fournisseur à l’application client puis filtrés à l’aide de l’ensemble
de données client.
les paquets delta envoyés par les ensembles de données client lors de la mise à
jour des enregistrements. Dans ce cas, l’ensemble de données client peut ne
jamais exploiter ces informations que le fournisseur s’envoie à lui-même.
Quand vous ajoutez des informations personnalisées dans l’événement
OnGetDataSetProperties, chaque attribut individuel (appelé parfois un “paramètre
optionnel”) est spécifié en utilisant un tableau Variant contenant trois éléments :
le nom (une chaîne), la valeur (un Variant) et un indicateur booléen indiquant si
les informations doivent être placées dans les paquets delta lorsque le client
applique les mises à jour. Ajoutez plusieurs attributs en créant un tableau
Variant de tableaux Variant. Par exemple, le gestionnaire d’événement
OnGetDataSetProperties suivant envoie deux valeurs : l’heure à laquelle les
données ont été fournies et le nombre total d’enregistrements dans l’ensemble de
données source. Seule l’heure à laquelle les données ont été fournies est
renvoyée quand les ensembles de données client appliquent les mises à jour :
void __fastcall TMyDataModule1::Provider1GetDataSetProperties(TObject *Sender, TDataSet
*DataSet, out OleVariant Properties)
{
int ArrayBounds[2];
ArrayBounds[0] = 0;
ArrayBounds[1] = 1;
Properties = VarArrayCreate(ArrayBounds, 1, varVariant);
Variant values[3];
values[0] = Variant("TimeProvided");
values[1] = Variant(Now());
values[2] = Variant(true);
Properties[0] = VarArrayOf(values,2);
values[0] = Variant("TableSize");
values[1] = Variant(DataSet->RecordCount);
values[2] = Variant(false);
Properties[1] = VarArrayOf(values,2);
}
Quand l’ensemble de données client applique les mises à jour, l’heure à laquelle
les enregistrements ont été initialement fournis peut être lue dans l’événement
OnUpdateData du fournisseur :
void __fastcall TMyDataModule1::Provider1UpdateData(TObject *Sender, TCustomClientDataSet
*DataSet)
{
Variant WhenProvided = DataSet->GetOptionalParam("TimeProvided");
...
}
un événement BeforeUpdateRecord que vous pouvez utiliser pour filtrer avant que
les modifications ne soient appliquées. Si une erreur se produit lors de la
résolution d’un enregistrement, le fournisseur reçoit un événement OnUpdateError
dans lequel il peut résoudre l’erreur. Généralement, il se produit des erreurs car
la modification viole une contrainte du serveur ou parce qu’un enregistrement a
été modifié avec une autre application après sa lecture par le fournisseur, mais
avant la demande de l’ensemble de données client d’appliquer la mise à jour.
Les erreurs de mise à jour peuvent être traitées par le fournisseur d’ensemble de
données ou l’ensemble de données client. Lorsque le fournisseur fait partie d’une
application multiniveau, il doit gérer toutes les erreurs de mise à jour qui ne
nécessitent pas d’interaction avec l’utilisateur pour être résolues. Quand le
fournisseur ne peut résoudre une condition d’erreur, il stocke une copie
temporaire de l’enregistrement posant problème. Quand le traitement des
enregistrements est terminé, le fournisseur renvoie à l’ensemble de données client
le nombre d’erreurs ayant eu lieu et copie les enregistrements non résolus dans
un paquet de données résultat qu’il renvoie à l’ensemble de données client pour
que celui-ci termine la réconciliation.
Les gestionnaires d’événements de tous les événements du fournisseur reçoivent
les mises à jour sous la forme d’un ensemble de données client. Si le gestionnaire
d’événement ne traite que certains types de mise à jour, vous pouvez filtrer
l’ensemble de données en vous basant sur le type de mise à jour des
enregistrements. Le filtrage des enregistrements évite au gestionnaire
d’événement de parcourir des enregistrements qu’il n’utilise pas. Pour filtrer
l’ensemble de données client d’après le type de mise à jour de ses
enregistrements, définissez sa propriété StatusFilter.
Remarque Les applications doivent proposer des fonctions supplémentaires quand les mises
à jour sont dirigées vers un ensemble de données qui représente plusieurs tables.
Pour des détails sur la manière de procéder, voir “Application des mises à jour à
des ensembles de données représentant plusieurs tables” à la page 28-14.
que représente l’enregistrement en cours dans le paquet delta. Elle peut prendre
l’une des valeurs énumérées dans le tableau suivant :
Vous pouvez avoir besoin d’un contrôle encore plus précis. Par exemple, dans
l’instruction précédente, vous pouvez empêcher que le champ EMPNO ne soit
modifié en le retirant de la clause UPDATE et enlever les champs TITLE et
DEPT de la clause WHERE pour empêcher des conflits de mise à jour quand
d’autres applications ont modifié les données. Pour spécifier la clause dans
laquelle un champ spécifique apparaît, utilisez la propriété ProviderFlags.
ProviderFlags est un ensemble qui peut inclure les valeurs du tableau suivant :
quand même les champs utilisés pour rechercher des enregistrements et les
champs actualisés.
Important Avant que le fournisseur ne puisse transférer aux ensembles de données client
les informations relatives aux contraintes, il doit lire ces informations sur le
serveur de bases de données. Pour importer les contraintes de bases de données
du serveur, utilisez l’explorateur SQL pour importer les contraintes du serveur
de base de données et les expressions par défaut dans le dictionnaire de
données. Les contraintes et les expressions par défaut du dictionnaire de données
sont automatiquement proposées aux ensembles de données BDE.
Il est parfois nécessaire de ne pas appliquer les contraintes du serveur aux
données envoyées à un ensemble de données client. Ainsi quand un ensemble de
données client reçoit les données en paquets et autorise la modification locale
des données avant la lecture de tous les enregistrements, il peut être nécessaire
de désactiver certaines des contraintes du serveur qui risquent d’être déclenchées
à cause d’un ensemble de données temporairement incomplet. Pour empêcher la
réplication des contraintes du fournisseur par l’ensemble de données client,
affectez la valeur false à Constraints. De toute façon, les ensembles de données
client peuvent désactiver ou activer les contraintes en utilisant les méthodes
DisableConstraints et EnableConstraints. Pour davantage d’informations sur
l’activation et la désactivation des contraintes par les ensembles de données
client, voir “Gestion des contraintes liées au serveur” à la page 27-35.
Remarque Vous pouvez ajouter vos propres propriétés et méthodes à la nouvelle interface.
Pour plus d’informations, voir “Extension de l’interface du serveur
d’applications” à la page 29-18.
Vous devez spécifier le modèle threading dans l’expert Module de données
distant. Vous pouvez choisir Thread Unique, Thread Appartement, Thread Libre
ou Les deux.
• Si vous choisissez Thread Unique, COM fait en sorte qu’une seule requête
client soit traitée à un moment donné. Aucune requête client ne peut entrer en
conflit avec une autre.
• Si vous choisissez Thread Appartement, COM fait en sorte que toute instance
de votre module de données distant traite une seule requête à un moment
donné. Lorsque vous écrivez du code dans une bibliothèque Thread
Appartement, vous devez prévenir les conflits de thread si vous utilisez des
variables globales ou des objets non contenus dans le module de données
distant. C’est le modèle recommandé si vous utilisez des ensembles de
données BDE. (Veuillez noter que vous aurez besoin d’un composant session
dont la propriété AutoSessionName vaut true pour gérer les problèmes de
threading sur les ensembles de données BDE.)
• Si vous choisissez Thread Libre, votre application peut recevoir des requêtes
client simultanées sur plusieurs threads. Vous devez faire en sorte que votre
application soit compatible avec les threads. Comme plusieurs clients peuvent
simultanément accéder à votre module de données distant, vous devez
protéger vos données d’instance (propriétés, objets contenus, etc.) ainsi que les
variables globales. C’est le modèle recommandé si vous utilisez des ensembles
de données ADO.
• Si vous choisissez Les deux, votre bibliothèque fonctionne de la même façon
que lorsque vous choisissez Thread Libre, à la différence que tous les rappels
(appels vers les interfaces client) sont automatiquement sérialisés.
• Si vous choisissez Neutre, le module de données distant peut recevoir des
appels simultanés dans des threads séparés, comme dans le modèle Thread
Libre, mais COM s’assure qu’il n’y a pas deux threads accédant à la même
méthode au même moment.
Configuration de TSoapDataModule
Pour ajouter un composant TSoapDataModule dans votre application, choisissez
Fichier|Nouveau|Autre et sélectionnez Module de données serveur SOAP dans
la page WebServices de la boîte de dialogue Nouveaux éléments. L’expert
Module de données SOAP apparaît.
Vous devez fournir un nom de classe pour votre module de données SOAP. Il
s’agit du nom de base d’un descendant de TSoapDataModule que votre
application crée. Par exemple, si vous spécifiez le nom de classe MyDataServer,
l’expert crée une nouvelle unité déclarant TMyDataServer, un descendant de
TSoapDataModule. Cette nouvelle classe hérite d’une implémentation de
IAppServer et de IAppServerSOAP de TSoapDataModule.Au contraire des autres
modules de données distants, les modules de données SOAP n’implémentent pas
d’interface personnalisée descendant de IAppServer ou de IAppServerSOAP. Cela
provient des différences dans la façon dont les applications service Web
ventillent les appels entrants à ces interfaces. En revanche, vous pouvez ajouter
de nouvelles interfaces à votre application en utilisant l’expert Ajouter un service
Web.
Remarque Pour utiliser TSoapDataModule, le nouveau module de données doit avoir été
ajouté à une application service Web. L’interface IAppServerSOAP est une
interface invocable, recensée dans le code de démarrage de la nouvelle unité.
Cela permet au composant invocateur dans le module Web principal de faire
suivre tous les appels entrants à votre module de données.
Remarque Si vous voulez que votre serveur d’applications réponde aux clients écrits à
l’aide de Kylix 2 ou de Delphi 6 (avant la mise à niveau du patch 2), vous devez
ajouter du code pour recenser l’interface IAppServer. Localisez le code de
démarrage qui recense IAppServerSOAP. Immediatement après cet appel de
recensement, ajoutez un appel à la fonction globale RegDefIAppServerInvClass, qui
recense le module de données en tant qu’implémentation pour IAppServer.
Quand vous ajoutez une interface COM, vos modifications sont ajoutées au code
source de l’unité et dans le fichier de la bibliothèque de types (.TLB).
Remarque Vous devez enregistrer explicitement le fichier TLB en choisissant Rafraîchir dans
l’éditeur de bibliothèque de types et en sauvegardant ensuite les modifications
depuis l’EDI.
Une fois que vous avez effectué un ajout à l’interface de votre classe
d’implémentation, localisez les propriétés et les méthodes ajoutées à
l’implémentation de votre classe. Ajoutez du code pour terminer cette
implémentation en remplissant le corps des nouvelles méthodes.
Les applications client appellent les extensions de votre interface à l’aide de la
propriété AppServer de leur composant connexion. Pour plus d’informations sur
la procédure à suivre, voir “Appel des interfaces serveur” à la page 29-31.
{
TClientDataSet *pDS = dynamic_cast<TClientDataSet *>(Sender);
if (!pDS->Active)
return;
OwnerData = pDS->Tag;
}
• Enfin, sur le serveur, le fournisseur utilise la dernière valeur de CUST_NO
envoyée comme valeur minimale dans la requête :
TRemoteDataModule1::DataSetProvider1BeforeGetRecords(TObject *Sender, OleVariant
&OwnerData)
{
if (!VarIsEmpty(OwnerData))
{
TDataSetProvider *pProv = dynamic_cast<TDataSetProvider *>(Sender);
TSQLDataSet *pDS = (dynamic_cast<TSQLDataSet *>(pProv->DataSet);
pDS->Params->ParamValues["MinVal"] = OwnerData;
pDS->Refresh(); // oblige la requête à se réexécuter
}
}
Une fois que les propriétés qui représentent les modules de données distants
enfant ont été ajoutées au module de données distant principal, les applications
client n’ont pas besoin d’établir de connexions distinctes à chaque module de
données distant sur le serveur d’applications. En effet, elles partagent une
connexion unique au module de données distant parent, qui répartit ensuite les
messages parmi les modules de données “enfant”. Etant donné que chaque
application client utilise la même connexion pour chaque module de données
distant, les modules de données distants peuvent partager une connexion de
base de données unique, ce qui permet d’économiser les ressources. Pour plus
d’informations sur la partage d’une connexion unique par les applications enfant,
voir “Connexion à un serveur d’applications qui utilise plusieurs modules de
données” à la page 29-32.
Si votre application client peut choisir parmi plusieurs serveurs, vous pouvez
utiliser la propriété ObjectBroker au lieu de spécifier la valeur de ComputerName.
Pour plus d’informations, voir “Courtage de connexions” à la page 29-29.
Si vous fournissez le nom d’un ordinateur hôte ou d’un serveur introuvable, le
composant connexion DCOM déclenche une exception lorsque vous essayez
d’ouvrir la connexion.
Courtage de connexions
Si votre application client peut choisir parmi plusieurs serveurs basés sur COM,
vous pouvez utiliser un courtier d’objets pour localiser un système serveur
disponible. Le courtier d’objets gère une liste de serveurs disponibles pour le
composant connexion. Lorsque le composant connexion a besoin de se connecter
à un serveur d’applications, il demande au courtier d’objets un nom d’ordinateur
(ou une adresse IP, un nom d’hôte, une URL). Le courtier fournit un nom puis le
composant connexion établit la connexion. Si le nom fourni ne fonctionne pas
(par exemple si le serveur n’est pas opérationnel), le courtier fournit un autre
nom et répète l’opération jusqu’à ce que la connexion soit établie.
Une fois que le composant connexion a établi une connexion avec un nom fourni
par le courtier, il enregistre ce nom en tant que valeur de la propriété appropriée
(ComputerName, Address, Host, RemoteHost ou URL). Si le composant connexion
ferme la connexion puis a besoin de l’ouvrir à nouveau, il utilise cette valeur de
propriété et ne demande un nouveau nom au courtier que si la connexion
échoue.
Pour utiliser un courtier d’objets, spécifiez la propriété ObjectBroker de votre
composant connexion. Lorsque la propriété ObjectBroker est initialisée, le
composant connexion n’enregistre pas la valeur de ComputerName, Address, Host,
RemoteHost ou URL.
Connexion au serveur
Pour localiser le serveur d’applications et vous y connecter, vous devez d’abord
initialiser les propriétés du composant connexion pour identifier le serveur
d’applications. Ce processus est décrit dans “Connexion au serveur
d’applications” à la page 29-25. Avant d’ouvrir la connexion, tous les ensembles
de données client qui utilisent le composant connexion pour communiquer avec
le serveur d’applications doivent l’indiquer en initialisant leur propriété
RemoteServer.
La connexion est automatiquement ouverte lorsque les ensembles de données
client essaient d’accéder au serveur d’applications. Par exemple, l’initialisation à
true de la propriété Active de l’ensemble de données client ouvre la connexion,
pour autant que la propriété RemoteServer ait été définie.
Si vous ne liez aucun ensemble de données client au composant connexion, vous
pouvez ouvrir la connexion en initialisant à true la propriété Connected du
composant connexion.
Avant d’établir une connexion à un serveur d’applications, un composant
connexion génère un événement BeforeConnect. Vous pouvez exécuter des actions
particulières avant de vous connecter en les codant dans un gestionnaire
BeforeConnect. Après avoir établi une connexion, le composant connexion génère
un événement AfterConnect où vous pouvez également exécuter toute action
nécessaire.
n’achève pas la réponse (ne définit pas le paramètre Handled par true), le
courtier XML envoie une réponse qui redirige le navigateur sur le document
ayant généré le paquet delta.
5 S’il y a des erreurs de mise à jour, le courtier XML reçoit un événement
OnGetErrorResponse. Vous pouvez utiliser cet événement pour tenter de
résoudre les erreurs ou pour générer une page Web qui les décrit à
l’utilisateur final. Si le gestionnaire de l’événement OnGetErrorResponse
n’achève pas la réponse (ne définit pas le paramètre Handled par true), le
courtier XML appelle un générateur de contenu particulier, appelé le
ReconcileProducer, pour générer le contenu du message de réponse.
6 Enfin, le courtier XML reçoit un événement AfterDispatch, où vous pouvez
effectuer toutes les actions voulues avant de renvoyer une réponse au
navigateur Web.
Joe,
Ci-joint la spécification de la gestion du nouveau composant XML dans
C++Builder. C’est une bonne solution à notre application inter-entreprises.
Le schedule du projet est également joint. Te semble-t’il raisonnable ?
Dave.
</content>
<attachment attachfile="XMLSpec.txt"/>
<attachment attachfile="Schedule.txt"/>
</body>
</email>
Une correspondance naturelle entre ce document et un ensemble de données
consisterait à mapper chaque message sur un enregistrement unique.
L’enregistrement contiendrait des champs pour le nom et l’adresse de
l’expéditeur. Comme un message électronique peut avoir plusieurs destinataires,
le destinataire (<to>) serait mappé sur un ensemble de données imbriqué. De
même, la liste cc serait mappée sur un ensemble de données imbriqué. La ligne
de sujet serait mappée sur un champ de type chaîne de caractères tandis que le
message lui-même (<content>) serait probablement mappé sur un champ mémo.
Les noms des fichiers joints seraient mappés sur un ensemble de données
imbriqué, car un message peut avoir plusieurs fichiers joints. Par conséquent,
le message électronique ci-dessus serait mappé sur un ensemble de données
comme suit :
Name Address
Joe Engineer jengineer@MyCo.Com
Name Address
Robin Smith rsmith@MyCo.Com
Leonard Devon ldevon@MyCo.Com
Attachfile
XMLSpec.txt
Schedule.txt
sur des champs dont le type de données reflète le type des données pouvant
apparaître comme valeurs. Les attributs d’une balise (comme l’attribut AttachFile
de la balise de pièce jointe) sont également mappés sur des champs.
Notez que les balises du document XML n’apparaissent pas toutes dans
l’ensemble de données correspondant. Par exemple, l’élément <head>...<head/>
ne possède pas d’élément correspondant dans l’ensemble de données résultant.
Généralement, seuls les éléments qui ont des valeurs, les éléments qui peuvent
être répétés ou les attributs d’une balise sont mappés sur les champs (y compris
les champs d’un ensemble de données imbriqué) d’un ensemble de données. Un
nœud père du document XML qui est mappé sur un champ dont la valeur est
composée à partir des valeurs des nœuds fils constituerait toutefois une
exception à cette règle. Par exemple, un document XML peut contenir un
ensemble de balises de la forme
<FullName>
<Title> Mr. </Title>
<FirstName> John </FirstName>
<LastName> Smith </LastName>
</FullName>
qui peuvent être mappées sur un champ d’ensemble de données unique avec la
valeur
Mr. John Smith
Utilisation de XMLMapper
L’utilitaire mappeur XML, xmlmapper.exe, vous permet de définir des mappages
(ou correspondances) de trois manières :
• A partir d’un schéma (ou d’un document) XML existant vers un ensemble de
données client que vous définissez. Cette méthode est utile lorsque vous
souhaitez créer une application de base de données pour manipuler des
données pour lesquelles vous disposez déjà d’un schéma XML.
• A partir d’un paquet de données existant vers un nouveau schéma XML que
vous définissez. Cette méthode est utile lorsque vous souhaitez présenter des
informations de bases de données existantes dans XML, par exemple pour
créer un nouveau système de communication inter-entreprise.
• Entre un schéma XML existant et un paquet de données existant. Cette
méthode est utile lorsque vous disposez d’un schéma XML et d’une base de
données qui décrivent tous deux les mêmes informations et que vous
souhaitez les faire travailler ensemble.
Après avoir défini le mappage, vous pouvez générer les fichiers de
transformation pour la conversion des documents XML en paquets de données et
vice-versa. Notez que seul le fichier de transformation est directionnel : un même
mappage peut être utilisé pour générer à la fois la transformation de XML vers
le paquet de données et du paquet de données vers XML.
Remarque Le mappeur XML se base sur deux .DLL (midas.dll et msxml.dll). Assurez-vous
que ces .DLL sont toutes deux installées avant d’essayer d’utiliser
Spécification de la transformation
Il existe deux méthodes pour spécifier la transformation qui convertit le
document XML en paquet de données :
• Utilisez la propriété TransformationFile pour indiquer un fichier de
transformation créé à l’aide de xmlmapper.exe.
• Utilisez la propriété TransformationDocument si vous disposez d’une interface
IDOMDocument pour la transformation.
arguments : une chaîne XML à partir de laquelle extraire les valeurs des
paramètres, et le nom d’un fichier de transformation pour traduire ce code XML
en paquet de données. SetParams utilise le fichier de transformation pour
convertir la chaîne XML en paquet de données, puis extrait les valeurs des
paramètres de ce paquet de données.
Remarque Vous pouvez outrepasser l’un quelconque de ces arguments si vous souhaitez
spécifier le document ou la transformation d’une autre manière. Il vous suffit de
définir l’une des propriétés avec TransformSetParams pour indiquer les paramètres
ou la transformation à utiliser pour les convertir, puis d’affecter à l’argument
que vous souhaitez outrepasser une chaîne vide lorsque vous appelez SetParams.
Pour des détails sur les propriétés que vous pouvez utiliser, consultez
“Conversion de documents XML en paquets de données” à la page 30-7.
Après avoir configuré TransformGetData et spécifié les éventuels paramètres
d’entrée, vous pouvez appeler la méthode GetDataAsXml pour récupérer le code
XML. GetDataAsXml envoie les valeurs de paramètres en cours au fournisseur,
récupère un paquet de données, le convertit en document XML puis renvoie ce
document sous forme de chaîne de caractères. Vous pouvez enregistrer cette
chaîne dans un fichier :
XMLTransformClient1->ProviderName = "Provider1";
XMLTransformClient1->TransformGetData->TransformationFile = "CustTableToCustXML.xtr";
XMLTransformClient1->TransFormSetParams->SourceXmlFile = "InputParams.xml";
XMLTransformClient1->SetParams("", "InputParamsToDP.xtr");
AnsiString XML = XMLTransformClient1->GetDataAsXml();
TFileStream pXMLDoc = new TFileStream("Customers.xml", fmCreate || fmOpenWrite);
__try
{
pXMLDoc->Write(XML.c_str(), XML.Length());
}
__finally
{
delete pXMLDoc;
}
• Le nombre d’erreurs de mise à jour qui peuvent être tolérées sans que
l’opération de mise à jour ne soit abandonnée. Si le nombre d’enregistrements
qui ne peuvent pas être insérés ou supprimés est inférieur à ce paramètre,
ApplyUpdates renvoie le nombre d’erreurs réelles. Si le nombre
d’enregistrements qui ne peuvent pas être insérés ou supprimés est égal à ce
paramètre, l’opération de mise à jour tout entière est annulée et aucune mise à
jour n’est effectuée.
L’appel suivant transforme le document XML Customers.xml en paquet delta et
applique toutes les mises à jour quel que soit le nombre d’erreurs :
StringList1->LoadFromFile("Customers.xml");
nErrors = ApplyUpdates(StringList1->Text, "CustXMLToInsert.xtr", -1);
III
Ecriture d’applications Internet
Partie III
Sur les clients CORBA, le stub agit comme proxy pour un objet qui peut être
implémenté par le même processus, un autre processus ou une autre machine
(un autre service). Le client interagit avec le stub comme il le ferait avec tout
autre objet.
Toutefois, à la différence de la plupart des objets, le stub gère les appels
d’interfaces en appelant le logiciel ORB installé sur la machine client. L’ORB
VisiBroker utilise un Smart Agent (osagent) qui s’exécute quelque part dans le
réseau local. Le Smart Agent est un service d’annuaire distribué dynamique qui
localise un serveur disponible fournissant la mise en oeuvre réelle de l’objet.
Sur le serveur CORBA, le logiciel ORB transmet les appels d’interfaces à un
squelette généré automatiquement. Le squelette communique avec le logiciel ORB
par l’intermédiaire du Basic Object Adaptor (BOA). Il utilise le BOA pour
recenser l’objet auprès du Smart Agent, indique la portée de l’objet (s’il peut être
utilisé sur des machines distantes) et indique quand les objets sont instanciés et
prêts à répondre aux clients.
Stubs et squelettes
La base d’un objet distribué avec CORBA est son interface. L’interface est
similaire à une définition de classe mais elle ne contient pas d’informations
d’implémentation. Vous définissez des interfaces en utilisant le langage de
définition d’interface CORBA (IDL). Vous pouvez alors ajouter les définitions
d’interface au projet avec un fichier IDL. Pour davantage d’informations sur les
fichiers IDL, les stubs et les squelettes, voir le guide du programmeur VisiBroker.
Pour davantage d’informations sur l’utilisation des fichiers dans C++Builder, voir
“Définition d’interfaces d’objets” à la page 31-5.
Lors de la compilation du fichier IDL, C++Builder génère deux fichiers .cpp.
Le fichier client qui contient l’implémentation de la classe stub. L’autre, le fichier
serveur contient l’implémentation du squelette de classe. Les stubs et les
squelettes fournissent le mécanisme qui permet aux applications CORBA
d’effectuer le marshaling des appels d’interfaces. Le Marshaling :
• Accueille une instance d’objet dans le processus du serveur et met ce pointeur
à la disposition du code du processus client.
• Transfère les arguments d’un appel d’interface tels qu’ils sont transmis par le
client et les place dans l’espace du processus de l’objet distant.
Quand l’application client appelle les méthodes d’un objet CORBA, elle pousse
les arguments dans la pile et appelle l’objet stub. Le stub écrit les arguments
dans un tampon de marshaling et transmet l’appel à l’objet distant dans une
structure. Le squelette serveur dépouille cette structure, empile les arguments et
appelle l’implémentation de l’objet. Fondamentalement, le squelette recrée l’appel
du client dans son propre espace d’adressage.
Pour générer les classes stub et squelette, compilez simplement le fichier IDL.
Vous pouvez compiler ce fichier en choisissant Projet|Compiler unité quand le
fichier IDL est affiché dans l’éditeur de code ou cliquez avec le bouton droit de
la souris sur le fichier IDL dans le gestionnaire de projet et choisissez Compiler.
Le compilateur IDL génère deux nouveaux fichiers qui apparaissent dans
l’éditeur de code et le gestionnaire de projet. Ces fichiers sont :
• Le fichier serveur (xxx_s.cpp). Ce fichier contient l’implémentation des classes
squelette.
• Le fichier client (xxx_c.cpp). Ce fichier contient l’implémentation des classes
stub.
La page CORBA des options de projet vous permet d’influencer la manière dont
sont générées les classes stub et squelette à partir du fichier IDL. Vous pouvez,
par exemple, spécifier si vous voulez uniquement inclure l’unité serveur générée
dans le projet ou spécifier si vous voulez ajouter les classes Tie si votre serveur
utilise le modèle de délégation (décrit dans “Utilisation du modèle de
délégation” à la page 31-9). Ces options affectent la compilation de tous les
fichiers IDL inclus dans le projet en cours.
Les objets qui acceptent les appels de clients CORBA doivent porter un nom,
sinon les clients ne peuvent pas les trouver. Les objets transitoires (créés en
réponse à des appels des clients et renvoyés comme référence) n’ont pas besoin
de porter de nom.
#endif
Vous pouvez ajouter à cette classe les données et méthodes membre
supplémentaires dont a besoin votre implémentation. Par exemple :
#ifndef Interface1ServerH
#define Interface1ServerH
#include "account_s.hh"
//---------------------------------------------------------------------------
class AccountImpl: public _sk_Account
{
protected:
CORBA::float _bal;
public:
void Initialize(CORBA::float startbal); // non disponible pour les clients
AccountImpl(const char *object_name=NULL);
CORBA::float balance();
};
#endif
Ces méthodes et propriétés supplémentaires sont utilisables dans l’application
serveur mais ne sont pas exposées aux clients.
Dans le fichier .cpp généré, remplissez le corps de la classe d’implémentation
afin de disposer d’un objet CORBA fonctionnel :
AccountImpl::AccountImpl(const char *object_name):
_sk_Account(object_name)
{
}
CORBA::float AccountImpl::balance()
{
return _bal;
};
void Initialize(CORBA::float startbal) // non disponible pour les clients
{
_bal = startbal;
}
Remarque Depuis votre serveur CORBA, vous pouvez écrire du code qui interagit avec le
BOA. Par exemple, en utilisant le BOA vous pouvez temporairement masquer
(désactiver) des objets serveur et les réactiver ultérieurement. Pour davantage
d’informations sur l’écriture de code interagissant avec le BOA, voir le guide du
programmeur VisiBroker.
dans l’application serveur, il ne faut pas travailler directement avec une instance
d’objet. Il faut plutôt obtenir une référence à l’objet CORBA et la manipuler.
Vous pouvez obtenir la référence d’objet CORBA de deux manières, selon que
vous voulez utiliser la liaison à l’avance (statique) ou la liaison retardée
(dynamique).
Pour utiliser la liaison à l’avance, vous pouvez utiliser l’expert objet CORBA en
choisissant Edition|Utiliser un objet CORBA. L’utilisation de la liaison à l’avance
est plus rapide que l’utilisation de la liaison dynamique, et elle présente d’autres
avantages tels que le contrôle des types lors de la compilation et le complément
de code.
Il est toutefois des cas où vous ne savez pas jusqu’à l’exécution quel objet
(interface) vous souhaitez utiliser. Pour ces cas, vous pouvez utiliser la liaison
dynamique. La liaison dynamique utilise un objet CORBA générique, qui
transmet les requêtes au serveur en utilisant un type CORBA particulier appelé
un Any.
• Que ce soit une application Windows ou une application console, l’expert peut
ajouter une propriété à une classe existante dans l’unité de votre choix ou
créer une nouvelle classe pour y inclure une propriété pour l’instance de stub.
Indépendamment du mécanisme adopté, l’expert ajoute les fichiers en-tête
nécessaires et génère le code liant la variable ou la propriété stub à l’objet
serveur CORBA. Par exemple, le code suivant instancie le stub d’une interface de
serveur appelée MyServerObj dans la fonction main() d’une application console :
#include <corba.h>
#include <condefs.h>
#include “MyServerObj_c.hh”
#pragma argsused
int main(int argc, char* argv[])
{
try
{
// Initialise l’ORB
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
MyServerObj_var TheObject = MyServerObj::_bind("InstanceName");
}
catch(const CORBA::Exception& e)
{
cerr << e << endl;
return(1);
}
return 0;
}
Attention Si vous copiez le code qui lie un objet serveur dans une autre partie de votre
application, assurez-vous que la variable stub est une variable locale ou la
donnée membre d’une classe. L’utilisation de variables stub globales est
périlleuse car il est possible qu’elles ne libèrent pas leur compteur de références
CORBA avant la libération de la variable orb. Si vous devez utiliser une variable
globale stub, pensez à annuler la liaison en initialisant la variable à NULL avant
la libération de orb.
Si votre application client ne contient que l’unité client générée (BaseName_c),
vous ne pouvez pas utiliser l’expert objet CORBA pour lier les objets du serveur.
Vous devez alors générer le code vous même. Vous pouvez également écrire
votre propre code de liaison pour tirer profit des options de liaison VisiBroker.
Vous pouvez, par exemple, indiquer un serveur spécifique, désactiver la tentative
automatique de renouer la connexion avec le serveur si la connexion CORBA
est perdue, etc. Pour davantage d’informations sur l’écriture de code de liaison
avec les objets du serveur, voir la documentation VisiBroker.
puis décoder cette information sur le serveur, son utilisation est plus lente que
celle d’une classe stub.
Pour utiliser DII dans une application client, vous devez
1 Créer un objet CORBA générique fonctionnant comme un objet stub, si ce
n’est que son implémentation ne contient pas le code du marshaling des
requêtes. Il faut spécifier l’identificateur de référentiel de l’objet afin
d’indiquer l’objet qui doit recevoir les requêtes :
CORBA::Object_var diiObj;
try
{
diiObj = orb->bind("IDL:ServerObj:1.0");
} catch (const CORBA::Exception& E)
{
// gère l’exception de liaison.
}
2 Puis, utilisez l’objet CORBA générique pour créer un objet requête pour une
méthode spécifique de l’objet représenté par l’objet CORBA générique :
CORBA::Request_var req = diiObj->_request("methodName");
3 Ensuite, ajoutez les arguments attendus par la méthode. Les arguments sont
ajoutés à une liste de type CORBA::NVList_ptr. Chaque argument est de type
CORBA::Any, similaire à un Variant. Le type CORBA::Any est nécessaire car
une liste de valeurs nommées (CORBA::NVList) doit gérer toute liste
d’arguments qui peut contenir des valeurs de types quelconques.
CORBA::Any arg;
arg <<= (const char *)"argvalue";
CORBA::NVList_ptr arguments = req->arguments();
arguments->add_value("arg1", arg, CORBA::ARG_IN);
4 Il est alors possible d’appeler la requête :
req->invoke();
5 Enfin, testez les erreurs et récupérez le résultat :
if (req->env()->exception())
// gère les exceptions
else
{
CORBA::Any_ptr pRetVal = req->result()->value();
CORBA::float val;
Any_ptr >>= val;
}
Pour davantage d’informations sur l’utilisation de l’appel dynamique d’interface,
voir le guide du programmeur VisiBroker.
présenter sous la forme de pages HTML transférées via HTTP. Les pages sont
généralement interprétées sur la machine client par une application de navigation
Web, qui affiche ces pages sous une forme adaptée au système de l’utilisateur.
La première étape de la conception d’une application serveur Web consiste
à choisir l’architecture que vous souhaitez utiliser, à savoir WebBroker ou
WebSnap. Ces deux architectures ont de nombreuses caractéristiques
en commun :
• Gestion des applications serveur Web de type CPI et DSO Apache. Celles-ci
sont décrites à la section “Types d’applications serveur Web” à la page 32-7.
• Gestion multithread permettant aux requêtes client entrantes d’être traitées
dans des threads distincts.
• Mise en mémoire cache des modules Web pour de meilleurs temps de
réponse.
• Développement multi-plate-forme. Vous pouvez facilement migrer votre
application serveur Web entre les systèmes d’exploitation Windows et Linux.
Votre code source sera compilé sur les deux plates-formes.
Les composants WebBroker et WebSnap gèrent tous deux l’ensemble du
mécanisme de transfert des pages. Comme WebSnap se base sur WebBroker, elle
intègre toutes les fonctions de cette architecture. WebSnap offre en revanche un
ensemble d’outils de génération de pages beaucoup plus puissant. En outre, les
applications WebSnap vous permettent d’utiliser des scripts côté serveur pour
faciliter la génération des pages au moment de l’exécution. WebBroker ne
dispose pas de cette fonctionnalité. Ses outils ne sont pas aussi complets et
beaucoup moins intuitifs que ceux de WebSnap. Si vous développez une
nouvelle application serveur Web, l’architecture WebSnap est probablement
mieux adaptée que WebBroker.
Les principales différences entre ces deux technologies sont présentées dans le
tableau suivant :
Terminologie et normes
La majorité des protocoles contrôlant l’activité Internet sont définis dans des
documents Request for Comment (RFC) gérés par le comité IETF (Internet
Engineering Task Force), comité chargé de l’ingénierie et du développement des
protocoles Internet. Plusieurs documents RFC vous apporteront des précisions
utiles pour le développement d’applications Internet :
• Le document RFC822, “Standard for the format of ARPA Internet text
messages”, décrit la structure et le contenu des en-têtes de messages.
• Le document RFC1521, “MIME (Multipurpose Internet Mail Extensions) Part
One : Mechanisms for Specifying and Describing the Format of Internet
Message Bodies,” décrit la méthode utilisée pour encapsuler et transporter des
messages multiparties et multiformats.
• Le document RFC1945, “Hypertext Transfer Protocol — HTTP/1.0”, décrit une
méthode de transfert utilisée pour distribuer des documents hypermédias
collaboratifs.
Le comité IETF propose une bibliothèque des documents RFC sur son site Web
www.ietf.cnri.reston.va.us
URI et URL
L’URL est un sous-ensemble de l’URI (Uniform Resource Identifier) défini dans
le document de norme HTTP RFC1945. Les applications serveur Web génèrent
fréquemment un contenu à partir de plusieurs sources ; le résultat final ne réside
pas alors à un emplacement précis, mais il est créé si nécessaire. Les URI
peuvent décrire des ressources n’ayant pas d’emplacement défini.
un nom, comme “Host” suivi d’une valeur chaîne. Soit par exemple, la requête
HTTP suivante :
GET /art/gallery.dll/animals?animal=dog&color=black HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/3.0b4Gold (WinNT; I)
Host: www.TSite.com:1024
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
La première ligne identifie la requête comme un GET. Un message de requête
GET demande à l’application serveur Web de renvoyer le contenu associé à
l’URI suivant le mot GET (ici /art/gallery.dll/animals?animal=doc&color=black).
La dernière partie de la première ligne indique que le client utilise la norme
HTTP 1.0.
La deuxième ligne est l’en-tête Connection, qui indique que la connexion ne doit
pas être fermée tant que la requête n’a pas été traitée. La troisième ligne est l’en-
tête User-Agent, qui donne des informations sur le programme générant la
demande. La ligne suivante définit l’en-tête Host et indique le nom et le port de
l’hôte sur le serveur contacté pour établir la connexion. La dernière ligne est l’en-
tête Accept, qui énumère les types de données que le client accepte en réponse.
ISAPI et NSAPI
Une application serveur Web ISAPI ou NSAPI est une DLL qui est chargée par
le serveur Web. Les informations de requête client sont transmises à la DLL sous
forme de structure et évaluées par l’application ISAPI/NSAPI, qui crée les objets
requête et réponse appropriées. Chaque message de requête est automatiquement
géré dans un thread d’exécution distinct.
CGI autonome
Une application serveur Web CGI autonome est une application console qui
reçoit les informations de requête client sur l’entrée standard et transmet les
résultats au serveur sur la sortie standard. Ces données sont évaluées par
l’application CGI, qui crée les objets requête et réponse appropriés. Chaque
message de requête est traité par une instance distincte de l’application.
WinCGI autonome
Une application serveur Web WinCGI autonome est une application Windows
qui reçoit les informations de requête client à partir d’un fichier de configuration
(INI) créé par le serveur et écrit les résultats dans un fichier que le serveur
retransmet au client. Le fichier INI est évalué par l’application serveur Web, qui
crée les objets requête et réponse appropriés. Chaque message de requête est
traité par une instance distincte de l’application.
Apache
Les applications serveur Web Apache sont des DLL chargées par le serveur Web.
Les informations de requête client sont transmises à la DLL sous forme de
structure et évaluées par l’application de serveur Web Apache, qui crée les objets
requête et réponse appropriés. Chaque message de requête est automatiquement
traité dans un thread d’exécution distinct.
être exécutée au moins une fois pour se recenser. Si vous ne trouvez toujours
pas votre application dans la liste déroulante, essayez d’actualiser la page
Web. (Il arrive que le navigateur Web place cette page en mémoire cache,
vous empêchant ainsi de voir les modifications les plus récentes.)
6 Une fois votre application sélectionnée dans la liste déroulante, cliquez sur
le bouton de démarrage. Cela démarre votre application dans le débogueur
d’application Web, qui vous donne des détails sur les messages de requête et de
réponse échangés entre votre application et le débogueur d’application Web.
33
Utilisation de l’agent Web
Chapitre 33
Les composants agent Web (placés dans l’onglet Internet de la palette des
composants) vous permettent de créer des gestionnaires d’événements qui sont
associés à une URL spécifique. Une fois le traitement achevé, il est possible de
construire par programme des documents HTML ou XML et de les transférer au
client. Vous pouvez utiliser les composants agent Web pour le développement
d’applications multiplates-formes.
Souvent, le contenu des pages Web provient de bases de données. Vous pouvez
utiliser des composants Internet pour gérer automatiquement les connexions aux
bases de données, en permettant à une seule DLL de gérer simultanément
plusieurs connexions de bases de données adaptées aux threads.
Les sections suivantes de ce chapitre expliquent comment utiliser les composants
agent Web pour créer une application serveur Web.
Module Web
Le module Web (TWebModule) est un descendant de TDataModule ; il s’utilise de
la même façon pour offrir un contrôle centralisé pour les règles de gestion et les
composants non visuels dans l’application Web.
Ajoutez tout générateur de contenu que votre application utilise pour générer les
messages de réponse. Il peut s’agir de générateurs de contenu intégrés, tels que
TPageProducer, TDataSetPageProducer, TDataSetTableProducer, TQueryTableProducer
et TInetXPageProducer ou de descendants de TCustomContentProducer que vous
avez créés vous-même. Si votre application génère des messages de réponse
incluant des données extraites d’une base de données, vous pouvez ajouter des
composants d’accès aux données ou des composants particuliers pour écrire un
serveur Web qui fait office de client dans une application de bases de données
multiniveaux.
Le module Web ne se contente pas de stocker les composants non visuels et des
règles de gestion : il fait aussi office de répartiteur en associant les messages de
requête HTTP reçus aux éléments d’action qui génèrent les réponses à ces
requêtes.
Vous avez peut-être déjà un module de données paramétré avec les composants
non visuels et les règles de gestion que vous souhaitez utiliser dans votre
application Web. Vous pouvez alors remplacer le module Web par ce module de
données : il suffit de supprimer le module Web généré automatiquement et de le
remplacer par votre module de données. Ajoutez ensuite un composant
TWebDispatcher à votre module de données pour qu’il puisse répartir les
messages de requête vers les éléments d’action, comme le ferait un module Web.
Si vous voulez modifier la façon dont les éléments d’action sont choisis pour
Répartiteur Web
Si vous utilisez un module Web, il agit comme un répartiteur Web. Si vous
utilisez un module de données existant, vous devez lui ajouter un composant
(TWebDispatcher). Le répartiteur gère un ensemble d’éléments d’action qui savent
comment répondre à certains types de messages de requête. Lorsque l’application
répartiteur appelle l’élément d’action par défaut. Il n’est pas nécessaire que cet
élément d’action corresponde à l’URL de destination ou à la méthode de requête.
Si le répartiteur atteint la fin de la liste d’actions (y compris l’éventuelle action
par défaut) et qu’aucune action n’a été déclenchée, rien n’est retourné au
serveur. Le serveur met alors fin à la connexion avec le client.
Si la requête est traitée par les éléments d’action, le répartiteur génère un
événement AfterDispatch. Ceci représente la dernière possibilité pour votre
application de vérifier que la réponse a été générée et de faire les modifications
requises.
Eléments d’action
Chaque élément d’action (TWebActionItem) effectue une tâche précise en réponse
à un type spécifique de message de requête.
Les éléments d’action peuvent répondre entièrement à une requête ou n’y
répondre que partiellement et laisser d’autres éléments d’action finir le travail.
Les éléments d’action peuvent envoyer le message de réponse HTTP pour la
requête, ou simplement préparer une partie de la réponse, que d’autres éléments
d’action termineront. Si une réponse est complétée par les éléments d’action mais
non envoyée, l’application serveur Web envoie le message de réponse.
URL de destination
Le répartiteur compare la valeur de la propriété PathInfo d’un élément d’action à
celle de la propriété PathInfo du message de requête. La valeur de cette propriété
doit être le chemin d’accès à l’URL pour toutes les requêtes que l’élément
d’action est prêt à gérer. Par exemple dans cette URL
http://www.TSite.com/art/gallery.dll/mammals?animal=dog&color=black
si la partie /gallery.dll indique l’application serveur Web, le chemin d’accès est
/mammals
Utilisez les informations de chemin d’accès pour indiquer où votre application
Web doit rechercher des informations au moment de traiter des requêtes ou pour
subdiviser votre serveur Web en sous-services logiques.
d’action par défaut. Vous pouvez ainsi vous assurer que l’élément d’action par
défaut n’est appelé qu’en dernier recours en mettant sa propriété Enabled à false.
L’élément d’action par défaut doit être prêt à gérer toute requête détectée, même
si ce n’est qu’en retournant un code d’erreur signalant une URI ou une valeur de
propriété MethodType non valide. Si l’élément d’action par défaut ne peut pas
traiter la requête, aucune réponse n’est transmise au client Web.
Attention Si vous modifiez la propriété Default d’une action lors de l’exécution, vous
risquez d’obtenir des résultats imprévisibles pour la requête active. Si la
propriété Default d’une action ayant déjà été déclenchée passe à true, cette action
ne sera pas réévaluée et le répartiteur ne la déclenchera pas lorsqu’il atteindra la
fin de la liste d’actions.
Envoi de la réponse
Un gestionnaire d’événement OnAction peut renvoyer la réponse au client Web à
l’aide des méthodes de l’objet TWebResponse. Cependant, si aucun élément
d’action n’envoie la réponse au client, elle sera envoyée par l’application serveur
Web si le dernier élément d’action ayant analysé la requête indique que la
requête a été traitée.
La propriété Method peut indiquer toute autre méthode que le client Web
demande au serveur.
Il n’est pas nécessaire que l’application serveur Web fournisse une réponse pour
toutes les valeurs possibles de la propriété Method. Le standard HTTP exige
cependant qu’elle sache répondre aux requêtes GET et HEAD.
Description du contenu
Plusieurs propriétés décrivent le contenu de la réponse. ContentType fournit le
type de support de la réponse, ContentVersion le numéro de version de ce
support. ContentLength indique la longueur de la réponse. Si le contenu est codé
(par compression des données, par exemple), indiquez-le dans la propriété
ContentEncoding. Si le contenu provient d’une autre URI, indiquez-le dans la
propriété DerivedFrom. Si la valeur du contenu tient compte de la date, utilisez
les propriétés LastModified et Expires pour indiquer si le contenu est toujours
valide. La propriété Title peut fournir des informations descriptives sur
le contenu.
Envoi de la réponse
Si vous êtes sûr que le traitement du message de requête est terminé, vous
pouvez envoyer une réponse directement depuis le gestionnaire
d’événementOnAction. L’objet réponse offre deux méthodes d’envoi de réponses :
SendResponse et SendRedirect. Appelez SendResponse pour envoyer une réponse
Modèles HTML
Un modèle HTML est une suite de commandes HTML et de balises HTML
transparentes. Une balise HTML transparente est au format :
<#Nom_de_balise Param1=Valeur1 Param2=Valeur2 ...>
Les crochets (< et >) définissent la portée de la balise. Le signe “#” vient
immédiatement après le crochet ouvrant, sans espace entre les deux. Il indique
au générateur de page que la chaîne qui suit est une balise HTML transparente.
Le nom de la balise suit immédiatement le signe dièse, sans espace entre les
deux. Le nom de la balise peut être tout identificateur valide ; il identifie le type
de conversion représenté par la balise.
Après un nom de balise, une balise HTML transparente peut parfois comporter
des paramètres fournissant des informations sur la conversion à effectuer.
Chaque paramètre est au format Paramètre=Valeur. Aucun espace ne doit figurer
entre le nom du paramètre, le signe égal et la valeur. Les paramètres sont
séparés par des espaces.
Les crochets (< et >) rendent la balise transparente pour les navigateurs HTML
qui ne reconnaissent pas la syntaxe “#Nom_de_balise”.
Bien que vous puissiez créer vos propres balises HTML transparentes pour
représenter tout type d’informations traitées par votre générateur de page,
plusieurs noms de balises associés à des valeurs du type de données TTag sont
mis à votre disposition. Ces noms de balise prédéfinis corrrespondent aux
commandes HTML susceptibles de varier d’un message de réponse à l’autre.
Ils sont décrits dans le tableau suivant :
Nom Valeur
de la balise de TTag La balise est convertie en :
Link tgLink Lien hypertexte. Le résultat est une séquence HTML
commençant par la balise <A> et se terminant par </A>.
Image tgImage Graphique. Le résultat est une balise HTML <IMG>.
Table tgTable Tableau HTML. Le résultat est une séquence HTML
commençant par la balise <TABLE> et se terminant par la
balise </TABLE>.
ImageMap tgImageMap Graphique contenant des zones sensibles. Le résultat est
une séquence HTML commençant par la balise <MAP> et
se terminant par </MAP>.
Object tgObject Objet ActiveX incorporé. Le résultat est une séquence
HTML commençant par la balise <OBJECT> et se
terminant par la balise </OBJECT>.
Embed tgEmbed DLL compatible Netscape. Le résultat est une séquence
HTML commençant par la balise <EMBED> et se
terminant par la balise </EMBED>.
Tout autre nom de balise est associé à tgCustom. Le générateur de page n’offre
aucun traitement spécifique des noms de balises prédéfinis. Ils sont simplement
fournis pour aider vos applications à structurer le processus de conversion des
tâches les plus fréquentes.
Remarque Les noms de balises prédéfinis tiennent compte de la différence entre majuscules
et minuscules.
propriétés pour désigner le modèle, vous pouvez générer les commandes HTML
converties en appelant la méthode Content.
Vous pouvez également appeler la méthode ContentFromString pour convertir
directement un modèle HTML composé d’une seule chaîne Ansi passée dans un
paramètre, ou appeler la méthode ContentFromStream pour lire le modèle HTML
depuis un flux. Ainsi, par exemple, vous pourriez placer vos modèles HTML
dans un champ mémo d’une base de données et, à l’aide de la méthode
ContentFromStream, obtenir les commandes HTML converties en lisant le modèle
depuis un objet TBlobStream.
placés entre des images des mois précédent et suivant, puis du calendrier lui-
même. L’image finale aurait l’aspect suivant :
liste d’utilisateurs permet de gérer des utilisateurs, des mots de passe et des
droits d’accès.
L’expert application Web permet de générer rapidement une application
personnalisée avec les composants dont vous avez besoin. L’expert module de
page Web vous permet de créer un module définissant une nouvelle page de
votre application. L’expert module de données Web vous permet de créer un
conteneur pour des composants réutilisés dans votre application Web.
Les vues de module de page affichent le résultat d’un script côté serveur sans
avoir à exécuter l’application. Vous pouvez visualiser le code HTML généré dans
un navigateur incorporé en utilisant l’onglet Prévisualiser ou au format texte en
utilisant l’onglet Résultat HTML. L’onglet Script HTML affiche la page avec le
script côté serveur utilisé pour générer le code HTML pour la page.
Les sections suivantes de ce chapitre décrivent la manière d’utiliser les
composants WebSnap pour créer une application serveur Web.
Modules Web
Les modules Web sont les éléments constitutifs de base d’une application
WebSnap. Chaque application serveur WebSnap doit avoir au moins un module
Web. Selon les besoins, il est possible d’en ajouter plus. Il existe quatre types de
modules Web :
• Les modules de page d’application Web (objets TWebAppPageModule)
• Les modules de page d’application Web (objets TWebAppDataModule)
• Les modules de page Web (objets TWebPageModule)
• Les modules de données Web (objets TWebDataModule)
Les modules de page Web et les modules de page d’application Web fournissent
un contenu pour les pages Web. Les modules de données Web et les modules de
données d’application Web agissent comme des conteneurs pour les composants
partagés de votre application ; ils ont le même objectif dans les applications
WebSnap que les modules de données ordinaires dans les applications C++
Builder classiques. Vous pouvez inclure un nombre quelconque de pages ou de
modules de données Web dans votre application serveur.
Vous pouvez vous interroger sur le nombre de modules Web dont votre
application a besoin. Chaque application WebSnap a besoin d’un (et un seul)
module d’application Web d’un certain type. Au delà, vous pouvez ajouter
autant de pages ou de modules de données Web que vous avez besoin.
Pour les modules de page Web, un bon principe de base consiste à en utiliser un
par style de page. Si vous avez l’intention de mettre en œuvre une page capable
d’utiliser le format d’une page existante, vous n’avez pas besoin d’un nouveau
module de page Web. Des modifications d’un module de page existant peuvent
suffire. Si la page est très différente de vos modules existants, vous souhaiterez
probablement créer un nouveau module. Par exemple, supposons que vous
tentiez de construire un serveur pour gérer des ventes par correspondance en
ligne. Les pages qui décrivent les produits disponibles pourraient toutes partager
le même module de page Web, puisque les pages peuvent toutes contenir les
mêmes types d’informations de base en utilisant la même disposition. Une fiche
de commande, par contre, exigerait probablement un module de page Web
différent, puisque le format et la fonction d’une fiche de commande sont
différents de ceux d’une page de description d’article.
Les règles sont différentes pour les modules de données Web. Les composants
qui peuvent être partagés par de nombreux modules Web différents devraient
être placés dans un module de données Web pour simplifier l’accès partagé.
Vous pouvez également placer les composants qui peuvent être utilisés par de
nombreuses applications Web différentes dans leur propre module de données
Web. Vous faciliterez ainsi le partage de ces éléments entre applications.
Naturellement, si aucune de ces circonstances ne s’applique, vous pourriez
choisir de ne pas utiliser du tout de modules de données Web. Utilisez-les de la
même manière que vous utiliseriez les modules de données classiques, et laissez-
vous guider par votre jugement et votre expérience.
Les modules d’application Web agissent comme conteneurs pour les composants
qui exécutent des fonctions pour toute l’application — comme l’acheminement
des requêtes, la gestion des sessions et la maintenance des listes d’utilisateurs.
Si vous êtes déjà familiarisé avec l’architecture WebBroker, vous pouvez vous
représenter les modules d’application Web comme similaires aux objets
TWebApplication. Les modules d’application Web contiennent également la
fonctionnalité d’un module Web classique, page ou données, selon le type du
module d’application Web. Votre projet ne peut contenir qu’un seul module
d’application Web. Vous n’en aurez de toute façon jamais besoin de plusieurs ;
vous pouvez ajouter des modules Web classiques à votre serveur pour fournir
les quelques fonctionnalités supplémentaires voulues.
Utilisez le module d’application Web pour les fonctionnalités les plus
fondamentales de votre application serveur. Si votre serveur gère une page
d’accueil d’une quelconque sorte, vous pouvez souhaiter adopter pour votre
module d’application Web un TWebAppPageModule au lieu d’un
TWebAppDataModule, de manière à ne pas avoir à créer de module de page Web
supplémentaire pour cette page.
Nom de page
Les modules de page Web ont un nom de page qui sert à référencer la page dans
une requête HTTP ou dans la logique de l’application. Une fabrique dans l’unité
du module de page Web spécifie le nom de page pour le module de page Web.
Modèle de générateur
La plupart des générateurs de page utilisent un modèle. Généralement, les
modèles HTML contiennent du code HTML statique mélangé à des balises
transparentes ou à du script exécuté côté serveur. Quand les générateurs de page
créent leur contenu, ils remplacent les balises transparentes par les valeurs
appropriées et exécutent les scripts côté serveur pour générer le code HTML
affiché dans le navigateur du client. (XSLPageProducer constitue une exception.
Il utilise des modèles XSL, qui contiennent du code XSL et non HTML. Les
modèles XSL ne gèrent pas les balises transparentes ou les scripts serveur.)
Les modules de page Web peuvent avoir un fichier modèle associé qui sera géré
comme une partie de l’unité. Un fichier modèle géré apparaît dans le
gestionnaire de projet et utilise le même nom et le même emplacement que le
fichier de service de l’unité. Si le module de page Web n’a pas de fichier modèle
associé, les propriétés du composant générateur de page spécifient le modèle.
Adaptateurs
Les adaptateurs définissent une interface de script pour votre application
serveur. Ils vous permettent d’insérer du code en langage script dans une page
et de récupérer des informations en appelant les adaptateurs depuis le code
script. Vous pouvez, par exemple, utiliser un adaptateur pour définir les champs
de données à afficher dans une page HTML. Une page HTML à script peut alors
contenir du contenu HTML et des instructions en script qui récupèrent la valeur
de ces champs. Ce système est similaire aux balises transparentes utilisées dans
les applications WebBroker. Les adaptateurs prennent également en charge les
actions qui exécutent des commandes. Par exemple, cliquer sur un lien
hypertexte ou soumettre une fiche HTML peut lancer des actions d’adaptateur.
Les adaptateurs simplifient la tâche de création dynamique de pages HTML.
En utilisant des adaptateurs dans votre application, vous pouvez inclure un
script orienté objet qui prend en charge la logique conditionnelle et les boucles.
Sans adaptateurs et script côté serveur, vous devrez écrire beaucoup plus de
logique de génération HTML dans des gestionnaires d’événements C++.
L’utilisation d’adaptateurs peut réduire de manière importante le temps de
développement.
Voir “Scripts côté serveur dans WebSnap” page 34-34 et “Répartition des
requêtes et des réponses” page 34-38, pour plus de détails sur les scripts.
Quatre types de composants adaptateur peuvent être utilisés pour créer le
contenu de la page : les champs, les actions, les erreurs et les enregistrements.
Champs
Les champs sont des composants que le générateur de page utilise pour
récupérer des données de votre application afin d’en afficher le contenu dans
une page Web. Les champs peuvent également servir à récupérer une image.
Dans ce cas, le champ renvoie l’adresse de l’image écrite dans la page Web.
Quand une page affiche son contenu, une requête est envoyée à l’application
serveur Web, qui demande au répartiteur d’adaptateur de rechercher l’image
réelle à partir du composant champ.
Actions
Les actions sont des composants qui exécutent des commandes pour
l’adaptateur. Quand un générateur de page génère sa page, le langage de script
appelle les composants action d’adaptateur pour renvoyer le nom de l’action
ainsi que tous les paramètres nécessaires à l’exécution de la commande. Par
exemple, soit un bouton d’une fiche HTML destiné à supprimer une ligne d’une
table. Il renvoie dans la requête HTTP le nom de l’action associé au bouton et un
paramètre indiquant le numéro de la ligne. Le répartiteur d’adaptateur recherche
le composant action ainsi nommé et lui transmet le numéro de ligne comme
paramètre de l’action.
Erreurs
Les adaptateurs gèrent une liste des erreurs qui se produisent lors de l’exécution
d’une action. Les générateurs de page peuvent accéder à cette liste afin de les
afficher dans la page Web renvoyée par l’application à l’utilisateur final.
Enregistrements
Certains composants adaptateur, comme TDataSetAdapter, représentent plusieurs
enregistrements. L’adaptateur propose alors une interface de script qui permet de
parcourir les enregistrements. Certains adaptateurs gèrent la pagination et ne
permettent de parcourir que les enregistrement de la page en cours.
Générateurs de page
Les générateurs de page permettent de produire un contenu pour un module de
page Web. Ils offrent les fonctionnalités suivantes :
• Ils génèrent du contenu HTML.
• Ils peuvent référencer un fichier externe en utilisant la propriété HTMLFile ou
une chaîne interne avec la propriété HTMLDoc.
• S’ils sont utilisés avec un module de page Web, le modèle peut être un fichier
associé à une unité.
• Ils génèrent dynamiquement du code HTML qui peut être inséré dans le
modèle en utilisant des balises transparentes ou des scripts actifs. Les balises
transparentes s’utilisent de la même manière que dans une application
WebBroker. Pour en savoir plus sur l’utilisation des balises transparentes,
consultez “Conversion des balises HTML transparentes” à la page 33-16.
La gestion des scripts actifs vous permet d’incorporer du code JScript ou
VBScript dans la page HTML.
La méthode WebSnap pour utiliser les générateurs de page est la suivante.
Lorsque vous créez un module de page Web, vous devez choisir un type de
générateur de page dans l’expert de module de page Web. Vous disposez de
nombreux choix, mais la plupart des développeurs WebSnap prototypent leurs
pages en utilisant un générateur de page d’adaptateur, TAdapterPageProducer. Le
générateur de page d’adaptateur vous permet de construire une page Web
prototype en utilisant un processus analogue au modèle de composant standard.
Vous ajoutez un type de fiche, une fiche d’adaptateur, au générateur de page
d’adaptateur. Lorsque vous en avez besoin, vous pouvez ajouter des composants
d’adaptateur (tels que des grilles d’adaptateur) à la fiche d’adaptateur. En
utilisant les générateurs de page d’adaptateur, vous pouvez créer des pages Web
d’une manière semblable à la technique standard C++Builder pour la
construction d’interfaces utilisateur.
Il existe certaines circonstances où le passage d’un générateur de page
d’adaptateur à un générateur de page classique est plus approprié. Par exemple,
une partie de la fonction d’un générateur de page d’adaptateur consiste à
générer dynamiquement un script dans un modèle de page lors de l’exécution.
Vous pouvez décider qu’un script statique vous aidera à optimiser votre serveur.
De plus, les utilisateurs qui ont de l’expérience avec les scripts peuvent vouloir
apporter directement des modifications dans le script. Dans ce cas, un générateur
de page classique doit être utilisé pour éviter des conflits entre le script
dynamique et le script statique. Pour en savoir plus sur la manière de passer à
un générateur de page classique, voir “Conception HTML avancée” à la
page 34-25.
Vous pouvez aussi utiliser des générateurs de page comme vous les utiliseriez
dans les applications WebBroker, en associant le générateur à un élément
d’action de répartiteur Web. L’utilisation des modules de page Web offre les
avantages suivants :
• La possibilité de prévisualiser la disposition des pages sans avoir à exécuter
l’application.
• L’association entre un nom de page et un module permet au répartiteur de
page d’appeler automatiquement le générateur de page.
Pour chacun des composants ci-dessus, les types de composants listés sont les
types par défaut livrés avec C++Builder. Les utilisateurs peuvent créer leur
propres types de composants ou utiliser des composants proposés par des tiers.
Didacticiel WebSnap
Ce didacticiel fournit des instructions étape par étape sur la construction d’une
application WebSnap. L’application WebSnap illustre la manière d’utiliser les
composants HTML WebSnap pour concevoir une application permettant de
modifier le contenu d’une table. Suivez les instructions du début à la fin. Si vous
souhaitez faire une pause, vous pouvez utiliser à tout moment Fichier|Tout
enregistrer pour enregistrer votre projet.
Comme les éléments du module ne sont pas visuels, l’endroit où ils apparaissent
dans le module importe peu. Il importe surtout que votre module contienne les
composants représentés sur la figure.
défaut est 20. Vous pouvez redéfinir la valeur par défaut dans n’importe quelle
session donnée en modifiant sa propriété TimeoutMinutes.
Pages de connexion
Votre application a bien sûr également besoin d’une page de connexion. Les
utilisateurs entrent leur nom d’utilisateur et leur mot de passe pour
l’authentification, soit en essayant d’accéder à une page restreinte, soit avant une
telle tentative. L’utilisateur peut également spécifier la page à afficher lorsque
l’authentification est terminée. Si le nom d’utilisateur et le mot de passe
correspondent à un utilisateur de la liste des utilisateurs Web, l’utilisateur
acquiert les droits d’accès appropriés et il est dirigé vers la page spécifiée sur la
page de connexion. Si l’utilisateur n’est pas authentifié, la page de connexion
peut être affichée à nouveau (action par défaut) ou une autre action peut se
produire.
Heureusement, WebSnap facilite la création d’une page de connexion simple en
utilisant un module de page Web et le générateur de page d’adaptateur. Pour
créer une page de connexion, commencez par créer un nouveau module de page
Web. Choisissez Fichier|Nouveau|Autre pour afficher la boîte de dialogue
Nouveaux éléments, puis sélectionnez Module de page WebSnap sur l’onglet
WebSnap. Sélectionnez AdapterPageProducer comme type de générateur de
page. Complétez les autres options comme vous le souhaitez. Login est
généralement un nom approprié pour la page de connexion.
Vous devez maintenant ajouter les champs les plus fondamentaux de la page de
connexion : un champ nom d’utilisateur, un champ mot de passe, une boîte de
sélection pour choisir la page affichée à l’utilisateur après la connexion, et un
bouton de connexion qui valide la page et authentifie l’utilisateur. Pour ajouter
ces champs :
1 Ajoutez un composant LoginFormAdapter (que vous pouvez trouver sur
l’onglet WebSnap de la palette des composants) au module de page Web que
vous venez de créer.
2 Double-cliquez sur le composant AdapterPageProducer pour afficher une fenêtre
d’éditeur de page Web.
3 Cliquez avec le bouton droit de la souris sur AdapterPageProducer dans le volet
supérieur gauche et sélectionnez Nouveau composant. Dans la boîte de
dialogue Ajout de composant Web, sélectionnez AdapterForm puis cliquez sur
OK.
4 Ajoutez un AdapterFieldGroup à l’AdapterForm. (Cliquez avec le bouton droit
de la souris sur AdapterForm dans le volet supérieur gauche et sélectionnez
Nouveau composant. Dans la boîte de dialogue Ajout de composant Web,
sélectionnez AdapterFieldGroup puis cliquez sur OK.)
5 Affichez maintenant l’inspecteur d’objets et affectez à la propriété Adapter de
votre AdapterFieldGroup votre LoginFormAdapter. Les champs UserName,
Password et NextPage devraient apparaître automatiquement dans l’onglet
Explorateur de l’éditeur de page Web.
évalué par l’application serveur Web, on parle de script côté serveur par
opposition au script côté client qui est évalué par le navigateur.
Cette section offre une vue générale conceptuelle d’un script côté serveur et de la
manière dont il est utilisé par des applications WebSnap. L’annexe ”Référence de
scripts côté serveur WebSnap” contient des informations beaucoup plus détaillées
sur les objets script ainsi que leurs propriétés et méthodes. Vous pouvez la
considérer comme une référence de l’API pour les scripts côté serveur, similaire
aux descriptions d’objets pour C++Builder qui se trouvent dans les fichiers
d’aide. L’annexe contient également des exemples détaillés de scripts qui vous
montrent exactement comment le script peut être utilisé pour générer des
pages HTML.
Bien que le script côté serveur soit un élément précieux de WebSnap, il n’est pas
essentiel que vous utilisiez des scripts dans vos applications WebSnap. Les
scripts sont utilisés pour la génération HTML et rien d’autre. Ils vous permettent
d’insérer des données d’application dans une page HTML. En fait, presque
toutes les propriétés exposées par les adaptateurs et d’autres objets orientés
script sont en lecture seule. Le script côté serveur n’est pas utilisé pour modifier
des données d’application, qui sont encore gérées par des composants et des
gestionnaires d’événements écrits en Pascal ou C++.
Il existe d’autres façons d’insérer des données d’application dans une page
HTML. Vous pouvez utiliser les balises transparentes de WebBroker, ou une
autre solution basée sur des balises, si vous le souhaitez. Par exemple, plusieurs
projets dans le dossier C++ Builder Examples\WebSnap utilisent XML et XSL à
la place d’un script. Sans script, cependant, vous êtes obligé d’écrire la majeure
partie de votre logique de génération HTML en C++, ce qui augmente le temps
de développement.
Le script utilisé dans WebSnap est orienté objet et prend en charge la logique
conditionnelle et les boucles, ce qui peut considérablement simplifier vos tâches
de génération de page. Par exemple, vos pages peuvent inclure un champ de
données qui peut être modifié par certains utilisateurs mais pas par d’autres.
Avec le script, il est possible de placer dans vos pages modèle une logique
conditionnelle qui affiche une zone de saisie pour les utilisateurs autorisés et un
texte simple pour les autres. Avec une approche basée sur des balises, vous
devez programmer une telle prise de décision dans votre code source générant
du HTML.
Scripts actifs
WebSnap utilise les scripts actifs pour implémenter les scripts serveur. Le script
actif est une technologie créée par Microsoft qui autorise l’utilisation d’un
langage de script par des objets d’application via des interfaces COM. Microsoft
fournit deux langages de script, VBScript et JScript. La gestion d’autres langages
est proposée par d’autres fournisseurs.
Moteur de script
La propriété ScriptEngine du générateur de page identifie le moteur de script
actif qui doit évaluer les scripts placés dans un modèle. Elle est définie pour
prendre en charge JScript par défaut, mais elle peut également prendre en charge
d’autres langages de script (comme VBScript).
Remarque Les adaptateurs de WebSnap sont conçus pour produire du JScript. Vous devez
fournir votre propre logique de génération de script pour les autres langages de
script.
Blocs de script
Les blocs de script, qui apparaissent dans les modèles HTML, sont délimités par
<% et %>. Le moteur de script évalue tout texte placé à l’intérieur d’un bloc de
script. Le résultat est intégré au contenu du générateur de page. Le générateur
de page écrit le texte hors d’un bloc de script après avoir traduit les balises
transparentes incorporées. Les blocs de script peuvent également contenir du
texte, ce qui permet de définir le texte en sortie à l’aide de conditions ou de
boucles. Par exemple, le bloc JScript suivant génère une liste de cinq lignes
numérotées :
<ul>
<% for (i=0;i<5;i++) { %>
<li>Item <%=i %></li>
<% } %>
</ul>
Le délimiteur <%= est un raccourci de Response.Write.
Création de scripts
Les développeurs peuvent profiter des caractéristiques de WebSnap pour générer
des scripts automatiquement.
Experts modèles
Lors de la création d’une nouvelle application WebSnap ou d’un module de
page, les experts WebSnap proposent une zone Modèle qui permet de
sélectionner le contenu initial d’un modèle de module de page. Par exemple, le
modèle Défaut génère du code JScript qui, à son tour, affiche le titre de
l’application, le nom de la page et des liens vers les pages publiées.
TAdapterPageProducer
TAdapterPageProducer produit des formulaires et des tableaux en générant du
HTML et du code JScript. Le code JScript généré appelle les objets adaptateurs
pour récupérer la valeur des champs, les paramètres des champs image et les
paramètres d’action.
Objets de script
Les objets de script sont des objets qui peuvent être référencés par des
commandes de script. Pour que des objets soient accessibles par script, vous
devez recenser une interface IDispatch avec l’objet dans le moteur de script actif.
Les objets suivants sont disponibles pour les scripts :
Composants répartiteur
Les composants répartiteur dans le module d’application Web contrôlent le flux
de l’application. Les répartiteurs déterminent comment traiter certains types de
messages de requête HTTP en analysant la requête HTTP.
Le composant répartiteur d’adaptateur (TAdapterDispatcher) recherche un champ
de contenu ou un champ de requête qui identifie un composant action
d’adaptateur ou un composant d’adaptateur de champ image. Si le répartiteur
d’adaptateur trouve un composant, il lui transmet le contrôle.
Le composant répartiteur Web (TWebDispatcher) gère une collection d’éléments
action (de type TWebActionItem) sachant gérer certains types de messages de
requête HTTP. Le répartiteur Web recherche un élément action correspondant à
la requête. S’il en trouve un, il transmet le contrôle à cet élément action.
Requêtes d’action
Les objets de requête d’action sont responsables de la décomposition de la
requête HTTP afin d’obtenir les informations nécessaires à l’exécution d’une
action d’adaptateur.
Requête d’image
L’objet requête d’image est responsable de la décomposition de la requête HTTP
afin d’obtenir les informations dont le champ image d’adaptateur a besoin pour
générer une image. Les informations représentées par la requête d’image sont :
• Nom du composant. Identifie le composant champ d’adaptateur.
• Paramètres de requête d’image. Identifient les paramètres nécessaires.
Par exemple, l’objet TDataSetAdapterImageField a besoin de valeurs clés pour
l’identification de l’enregistrement contenant l’image.
Réponse d’image
L’objet réponse d’image contient l’objet TWebResponse. Les champs d’adaptateur
répondent à une requête d’adaptateur en écrivant une image dans l’objet
réponse Web.
La figure suivante montre comment les champs d’adaptateur d’image répondent
à une requête.
Utilisation de TXMLDocument
Le composant TXMLDocument sert de point de départ à l’utilisation d’un
document XML. Les étapes suivantes décrivent la manière d’utiliser
TXMLDocument pour manipuler directement un document XML :
1 Ajoutez un composant TXMLDocument dans votre fiche ou votre module de
données. TXMLDocument apparaît sur la page Internet de la palette des
composants.
enfant sont des nœuds feuille, ou nœuds terminaux. Le texte qu’ils contiennent
apparaît comme valeur de chaque nœud feuille.
Remarque Cette division en nœuds peut varier selon la manière dont l’implémentation de
DOM génère les nœuds pour un document XML. En particulier, un analyseur
DOM traite tous les éléments balisés comme des nœuds internes. Des nœuds
supplémentaires (de type nœud texte) sont créés pour les valeurs des nœuds
name, price, symbol et shares. Ces nœuds texte apparaissent alors comme des
enfants des nœuds name, price, symbol et shares.
Pour accéder à chaque nœud, utilisez une interface IXMLNode, en partant du
nœud racine, qui soit la valeur de la propriété DocumentElement du composant
document XML.
NewStock->Attributes[WideString("exchange")] = "NASDAQ";
_di_IXMLNode ValueNode = NewStock->AddChild(WideString("name"));
ValueNode->Text = WideString("Cisco Systems");
ValueNode = NewStock->AddChild(WideString("price"));
ValueNode->Text = WideString("62.375");
ValueNode = NewStock->AddChild(WideString("symbol"));
ValueNode->Text = WideString("CSCO");
ValueNode = NewStock->AddChild(WideString("shares"));
ValueNode->Text = WideString("25");
Une version redéfinie de AddChild vous permet de spécifier l’URI de l’espace de
nommage dans lequel le nom de balise est défini.
Vous pouvez supprimer des nœuds enfant en utilisant les méthodes de la
propriété ChildNodes. ChildNodes est une interface IXMLNodeList qui gère les
enfants d’un nœud. Vous pouvez utiliser sa méthode Delete pour supprimer un
nœud enfant unique identifié par sa position ou par son nom. Par exemple, le
code suivant supprime la dernière cotation énumérée dans le document
précédent :
_di_IXMLNode StockList = XMLDocument1->DocumentElement;
StockList->ChildNodes->Delete(StockList->ChildNodes->Count - 1);
6 Une fois spécifié le code que l’expert doit générer pour chaque nœud, passez
à la troisième page. Cette page vous permet de choisir certaines options
globales contrôlant la manière dont l’expert génère le code, de prévisualiser le
code qui sera généré et de demander à conserver vos options pour des
utilisations ultérieures.
• Pour prévisualiser le code généré par l’expert, sélectionnez une interface
dans la liste Récapitulatif des liaisons et visualisez la définition d’interface
dans la zone Prévisualisation du code.
• Utilisez la zone Paramètres de liaison des données pour indiquer comment
l’expert doit enregistrer vos choix. Vous pouvez stocker vos choix comme
annotations dans un fichier schéma associé au document (le fichier schéma
spécifié dans la première page de la boîte de dialogue) ou vous pouvez
nommer un fichier schéma autonome utilisé uniquement par l’expert.
7 Quand vous choisissez Terminer, l’expert Liaison de données génère une
nouvelle unité définissant les interfaces et les classes d’implémentation pour
tous les types de nœuds de votre document XML. De plus, il crée une
fonction globale qui attend un objet TXMLDocument et renvoie l’interface sur
le nœud racine de la hiérarchie de données.
Les composants qui gèrent les services Web sont disponibles sous Windows et
Linux, et vous pouvez donc les utiliser comme base pour des applications
distribuées multi-plates-formes. Il n’y a pas de runtime client particulier à
installer comme c’est le cas pour des applications distribuées utilisant CORBA.
Comme cette technologie repose sur des messages HTTP, elle a l’avantage d’être
disponible sur diverses machines. La gestion des services Web repose sur
l’architecture des applications de serveur Web (Web Broker).
Les applications de services Web publient des informations sur les interfaces
disponibles et sur la manière de les appeler à l’aide d’un document WSDL (Web
Service Definition Language). Côté serveur, votre application peut publier un
document WSDL décrivant votre service Web. Côté client, un expert ou un
utilitaire en ligne de commande peut importer un document WSDL publié afin
de vous proposer les définitions d’interfaces et les informations de connexion
dont vous avez besoin. Si vous possédez déjà un document WSDL qui décrit le
service Web que vous voulez implémenter, vous pouvez aussi générer le code
côté serveur lors de l’importation du document WSDL.
Par exemple, le code suivant définit une interface invocable contenant deux
méthodes pour coder et décoder des valeurs numériques :
__interface INTERFACE_UUID("{C527B88F-3F8E-1134-80e0-01A04F57B270}") IEncodeDecode :
public IInvokable
{
public:
virtual double __stdcall EncodeValue(int Value) = 0 :
virtual int __stdcall DecodeValue(double Value) = 0 :
};
Remarque Dans cet exemple, notez l’utilisation de __interface dans la déclaration. Il ne
s’agit pas d’un véritable mot clé, mais plutôt d’une macro utilisée par convention
pour les interfaces. Elle établit une correspondance avec le mot clé class. La
macro INTERFACE_UUID affecte un identificateur unique global (GUID) à
l’interface. Remarquez que la classe d’interface contient uniquement des
méthodes virtuelles pures.
Pour qu’une application service Web puisse utiliser cette interface invocable, elle
doit être recensée dans le registre d’invocation. Sur le serveur, l’entrée du
registre d’invocation permet aux composants invocateur (THTTPSOAPCppInvoker)
d’identifier la classe d’implémentation à utiliser pour l’exécution des appels de
l’interface. Dans les applications client, une entrée du registre d’invocation
permet aux objets interfacés distants (THTTPRio) de rechercher les informations
identifiant l’interface invocable et fournit des informations sur la manière de
l’appeler.
Généralement, votre client ou serveur de service Web crée le code de définition
des interfaces invocables en important un document WSDL ou en utilisant
l’expert de service Web. Par défaut, lorsque l’importateur WSDL ou l’expert de
service Web génère une interface, la définition est ajoutée au fichier d’en-tête
avec le même nom que le service Web. Le fichier .cpp correspondant contient le
code permettant de recenser l’interface (ainsi qu’une classe d’implémentation si
vous êtes en train d’écrire un serveur). Pour l’interface décrite ci-dessus, ce code
de recensement a l’apparence suivante :
static void RegTypes()
{
InvRegistry()->RegisterInterface(__delphirtti(IEncodeDecode), "", "");
}
#pragma startup RegTypes 32
Les interfaces de services Web doivent posséder un espace de nommage pour
identifier toutes les interfaces dans tous les services Web possibles. L’exemple
précédent ne fournit pas d’espace de nommage pour l’interface. Lorsque vous ne
fournissez pas explicitement un espace de nommage, le registre d’invocation en
génère automatiquement un à votre place. Cet espace de nommage est créé à
partir d’une chaîne qui identifie de manière unique l’application (la variable
AppNamespacePrefix), le nom de l’interface et le nom de l’unité dans laquelle elle
est définie. Si vous ne souhaitez pas utiliser l’espace de nommage généré
automatiquement, vous pouvez en spécifier un explicitement en utilisant un
deuxième paramètre lors de l’appel à RegisterInterface.
Remarque N’essayez pas d’utiliser le fichier d’en-tête qui définit une interface invocable à la
fois dans les applications client et dans les applications serveur. Cela peut
facilement conduire à des incohérences dans les espaces de nommage, car
lorsque l’en-tête est inclus dans un autre fichier source, le nom de l’unité devient
le nom du fichier source d’inclusion, ce qui change le nom de l’espace de
nommage généré. Par conséquent, les applications client doivent importer le
service Web en utilisant un document WSDL.
public:
__published:
__property MyEnumType __propType = {read=__instanceType };
};
Dans ce cas, la classe MyEnumType_TypeInfoHolder est définie pour extraire les
informations de type à partir d’un type énuméré nommé MyEnumType. Elle
possède une seule propriété publiée, __propType, dont le type est le type
énuméré que vous souhaitez recenser. Après avoir défini la classe holder, vous
pouvez obtenir les informations de type pour le type énuméré en appelant la
fonction globale GetClsMemberTypeInfo. Le code suivant illustre la manière de
recenser un type énuméré à partir de sa classe holder :
void RegTypes()
{
RemTypeRegistry()->RegisterXSInfo(
GetClsMemberTypeInfo(__classid(MyEnumType_TypeInfoHolder), "__propType"),
MyNameSpace, "MyEnumType");
}
RegisterClsMemberTypeInfo possède deux paramètres : les informations de type de
la classe holder et le nom de la propriété publiée du type dont vous souhaitez
extraire les informations de type. Si la classe holder possède une seule propriété
publiée (comme dans l’exemple précédent), vous pouvez omettre le deuxième
paramètre.
Cette technique d’utilisation d’une classe holder doit également être utilisée si
votre type est déclaré au moyen d’une instruction typedef établissant une
correspondance avec un type scalaire C++ prédéfini. (Un type scalaire C++
prédéfini est l’un des types énumérés dans “Utilisation de types non scalaires
dans des interfaces invocables” à la page 36-4, à l’exception de ceux qui sont des
classes émulant les types Pascal Objet.) Par conséquent, étant donné le type
suivant :
typedef int CardNumber;
vous devez créer une classe holder telle que :
class CardNumberType_TypeInfoHolder : public TObject {
CardNumber __instanceType;
public:
__published:
__property CardNumber __propType = {read=__instanceType };
};
puis la recenser comme suit :
RemTypeRegistry()->RegisterXSInfo(GetClsMemberTypeInfo(
__classid(CardNumber_TypeInfoHolder), "__propType"),
MyNameSpace, "CardNumber");
Pour tout autre type déclaré à l’aide d’une instruction typedef, appelez
RegisterXSInfo s’il établit une correspondance avec une classe de tableau
dynamique et RegisterXSClass s’il établit une correspondance avec une classe.
Pour plus d’informations sur le recensement des tableaux dynamiques et des
classes, voir “Recensement des types non scalaires” à la page 36-5.
Remarque Vous devez essayer d’éviter les instructions typedef qui établissent une
correspondance entre plusieurs types et le même type sous-jacent.
Les informations de type accessibles à l’exécution pour ces dernières ne sont pas
différentes.
Après la définition d’une classe distante, celle-ci doit être recensée avec le
registre des types distants, comme décrit dans “Recensement des types non
scalaires” à la page 36-5. Ce recensement se produit automatiquement sur les
serveurs lorsque vous recensez l’interface qui utilise la classe. Côté client, le code
permettant de recenser la classe est automatiquement généré lorsque vous
importez le document WSDL qui définit le type.
Conseil Il est judicieux d’implémenter et de recenser les descendants de TRemotable dans
une unité distincte du reste de votre application serveur, y compris des unités
qui déclarent et recensent les interfaces invocables. De cette manière, vous
pouvez utiliser le type pour plusieurs interfaces.
L’un des problèmes qui se posent lors de l’utilisation de descendants de
TRemotable concerne les moments de leur création et de leur destruction.
Logiquement, l’application serveur doit créer sa propre instance locale de ces
objets, car l’instance de l’appelant se trouve dans un espace de processus
distinct. Pour gérer cela, les applications de service Web créent un contexte de
données pour les requêtes entrantes. Le contexte des données persiste tant que le
serveur traite la requête, et il est libéré lorsque tous les paramètres de sortie sont
rassemblés dans un message de retour. Lorsque le serveur crée des instances
locales d’objets distants, il les ajoute au contexte des données et ces instances
sont ensuite libérées avec le contexte des données. Dans certains cas, vous
pouvez préférer empêcher la libération d’une instance d’objet distant après un
appel de méthode. Par exemple, si l’objet contient des informations d’état, il peut
s’avérer plus efficace d’avoir une seule et même instance pour tous les appels de
messages. Pour empêcher la libération de l’objet distant avec le contexte des
données, modifiez sa propriété DataContext.
vers votre application, ainsi que la propriété MethodType pour indiquer l’en-
tête de méthode des messages de requête.
• Un publieur WSDL (TWSDLHTMLPublish). Le publieur WSDL publie un
document WSDL décrivant vos interfaces et la manière de les appeler. Le
document WSDL indique aux clients la manière d’appeler votre application de
service Web. Pour plus de détails sur l’utilisation du publieur WSDL, voir
“Génération de documents WSDL pour une application de service Web” à la
page 36-17.
Le répartiteur SOAP et le publieur WSDL sont des composants à auto-
répartition. Cela signifie qu’ils se recensent automatiquement eux-mêmes avec le
module Web pour transmettre les requêtes entrantes adressées en utilisant les
informations de chemin spécifiées dans leurs propriétés WebDispatch. Si vous
cliquez avec le bouton droit de la souris sur le module Web, vous pouvez voir
qu’en plus de ces composants auto-répartis, il possède une action Web unique
nommée DefaultHandler.
DefaultHandler est l’action par défaut. Cela signifie que si le module Web reçoit
une requête pour laquelle il ne peut pas trouver de gestionnaire (pas de
possibilité d’établir de correspondance avec les informations de chemin), il
transmet ce message à l’action par défaut. DefaultHandler génère une page Web
qui décrit votre service Web. Pour modifier l’action par défaut, modifiez le
gestionnaire d’événement OnAction de cette action.
Pour changer l’URL, utilisez l’administrateur WSDL. Vous devez tout d’abord
activer l’administrateur. Pour ce faire, initialisez la propriété AdminEnabled du
composant TWSDLHTMLPublish à true. Ensuite, lorsque vous utiliserez votre
navigateur pour afficher la liste des documents WSDL, il contiendra également
un bouton permettant de les administrer. Utilisez l’administrateur WSDL pour
spécifier les emplacements (URL) où vous avez déployé votre application de
service Web.
37
Utilisation des sockets
Chapitre 37
Services et ports
La plupart des services standard sont associés, par convention, à des numéros de
ports précis. Nous étudierons plus tard ces numéros de ports. Pour l’instant,
considérez le numéro de port comme un code numérique pour ce service.
Si vous implémentez un service standard à utiliser dans des applications
multiplates-formes, les objets socket Linux fournissent des méthodes de recherche
de numéro de port pour le service. Si vous offrez un service nouveau, vous
pouvez spécifier son numéro de port dans un fichier /etc/services. Voir votre
documentation Linux, pour davantage d’informations sur la configuration d’un
fichier de services.
Connexions client
Les connexions client connectent un socket client sur le système local à un socket
serveur sur un système distant. Les connexions client sont lancées par le socket
client. En premier lieu, le socket client doit décrire le socket serveur auquel il
souhaite se connecter. Le socket client recherche ensuite le socket serveur et,
lorsqu’il l’a trouvé, demande une connexion. Le socket serveur peut ne pas
établir immédiatement la connexion. Les sockets serveur gèrent une file d’attente
des demandes de clients et établissent la connexion lorsqu’ils le peuvent. Lorsque
le socket serveur accepte la connexion du client, il envoie au socket client une
description complète du socket serveur auquel il se connecte et la connexion est
finalisée par le client.
Connexions d’écoute
Les sockets serveur ne localisent pas les clients : ils génèrent des “demi-
connexions” passives qui restent à l’écoute des requêtes des clients. Les sockets
serveur associent une file d’attente à leurs connexions d’écoute ; la file d’attente
enregistre les requêtes de connexion lorsqu’elles lui parviennent. Lorsque le
socket serveur accepte une demande de connexion client, il forme un nouveau
socket pour se connecter au client pour que la connexion d’écoute reste ouverte
afin d’accepter d’autres requêtes de clients.
Connexions serveur
Les connexions serveur sont formées par des sockets serveur lorsque le socket
d’écoute accepte une requête du client. La description du socket serveur ayant
effectué la connexion au client est envoyée au client lorsque le serveur accepte la
connexion. La connexion est établie lorsque le socket client reçoit cette
description et effectue véritablement la connexion.
Une description complète d’une connexion par socket inclut les adresses du
socket à chaque extrémité de la connexion. Vous pouvez décrire l’adresse de
chaque extrémité du socket en fournissant l’hôte ou l’adresse IP et le numéro
de port.
Avant de faire une connexion par socket, vous devez décrire complètement les
sockets formant ses extrémités. Certaines informations sont disponibles sur le
système exécutant votre application. Par exemple, il n’est pas nécessaire de
décrire l’adresse IP locale d’un socket client car elle est dans le système
d’exploitation.
Les informations à fournir dépendent du type de socket implémenté. Les sockets
client doivent décrire le serveur auquel ils souhaitent se connecter. Les sockets
serveur d’écoute doivent décrire le port représentant le service qu’ils offrent.
Formation de la connexion
Lorsque les propriétés de votre composant socket client décrivent le serveur
auquel vous souhaitez vous connecter, vous pouvez former la connexion à
l’exécution en appelant la méthode Open. Si vous souhaitez que votre application
forme automatiquement la connexion à son ouverture, mettez la propriété Active
à true lors de la conception, à l’aide de l’inspecteur d’objets.
Fermeture de la connexion
Lorsque vous avez fini de communiquer avec une application serveur sur la
connexion socket, vous pouvez fermer la connexion en appelant la méthode
Close. La connexion peut également être fermée depuis le serveur. Si c’est le cas,
vous en êtes informé par un événement OnDisconnect.
Désignation du port
Pour que votre socket serveur puisse écouter les requêtes de connexion client,
vous devez spécifier un port d’écoute. Vous pouvez spécifier ce port à l’aide de
la propriété LocalPort. Si votre application serveur offre un service standard
associé par convention à un numéro de port précis, vous pouvez aussi spécifier
le nom du service à l’aide de la propriété LocalPort. Il est recommandé d’utiliser
plutôt le nom du service car il est facile de faire des fautes de saisie en entrant
le numéro de port.
Evénements d’erreurs
Les sockets client et serveur génèrent un événement OnError lorsqu’ils reçoivent
un message d’erreur émis par la connexion. Vous pouvez écrire un gestionnaire
d’événement OnError pour répondre à ces messages d’erreur. Le gestionnaire
d’événement reçoit des informations sur :
• l’objet socket ayant reçu la notification d’erreur ;
• ce que le socket tentait de faire lorsque l’erreur s’est produite ;
• le code d’erreur fourni par le message d’erreur.
Vous pouvez répondre à l’erreur dans le gestionnaire d’événement et mettre le
code d’erreur à 0 pour empêcher le socket de déclencher une exception.
Evénements client
Lorsqu’un socket client ouvre une connexion, les événements suivants se
produisent :
• Le socket est paramétré et initialisé pour la notification d’événements.
• Un événement OnCreateHandle se produit une fois que le serveur et le serveur
socket sont créés. A ce moment, l’objet socket accessible par la propriété
Handle peut fournir des informations sur le serveur ou client socket qui sera à
l’autre extrémité de la connexion. Ceci est la première possibilité d’obtenir le
numéro de port utilisé pour la connexion, qui peut différer du numéro de
port des sockets d’écoute qui ont accepté la connexion.
• La demande de connexion est acceptée par le serveur et gérée par le socket
client.
• Un événement de notification OnConnect se produit après l’établissement de la
connexion.
Evénements serveur
Les composants socket serveur forment deux types de connexions : les
connexions d’écoute et les connexions aux applications client. Le socket serveur
reçoit des événements lors de la formation de ces deux types de connexions.
Evénements d’écoute
Juste avant que la connexion d’écoute soit formée, l’événement OnListening se
produit. Vous pouvez utiliser la propriété Handle pour modifier le socket avant
qu’il ne soit ouvert pour l’écoute. Par exemple, si vous souhaitez restreindre les
adresses IP que le serveur utilise pour les écoutes, vous pouvez le faire dans un
gestionnaire d’événement OnListening.
Connexions bloquantes
Lorsque la connexion est bloquante, votre socket doit initier la lecture ou
l’écriture sur la connexion. Il ne peut pas attendre la notification émanant de la
connexion socket. Utilisez un socket bloquant lorsque votre côté de la connexion
décide du moment où doivent s’effectuer les lectures et les écritures.
Pour les sockets client, initialisez la propriété BlockMode à bmBlocking pour former
une connexion bloquante. En fonction de ce dont est capable votre application
client, il peut être recommandé de créer un nouveau thread d’exécution pour les
lectures ou les écritures, de telle sorte que votre application puisse continuer
l’exécution du code dans d’autres threads tout en attendant la fin des lectures ou
des écritures sur la connexion.
Pour les sockets serveur, mettez la propriété BlockMode à bmBlocking ou à
bmThreadBlocking pour former une connexion bloquante. Etant donné que les
connexions bloquantes interrompent l’exécution de tout autre code lorsque le
socket attend que des informations soient écrites ou lues sur la connexion, les
composants de socket serveur génèrent toujours un nouveau thread d’exécution
pour chaque connexion client lorsque BlockMode est à bmThreadBlocking. Quand
BlockMode est à bmBlocking, l’exécution du programme est bloqué jusqu’à ce
qu’une nouvelle connexion soit établie.
IV
Développement d’applications COM
Partie IV
Extensions de COM
COM a évolué et a été étendu au-delà des services COM de base. COM sert de
fondement à d’autres technologies, comme l’Automation, les contrôles ActiveX,
les documents Active et les annuaires Active. Pour plus de détails, voir
“Extensions de COM” à la page 38-10.
En outre, si vous travaillez dans un environnement distribué important, vous
pouvez créer des objets COM transactionnels. Avant Windows 2000, ces objets ne
faisaient pas partie de COM, mais s’exécutaient dans l’environnement Microsoft
Transaction Server (MTS). Avec l’arrivée de Windows 2000, cette gestion est
intégrée dans COM+. Les objets transactionnels sont décrits en détail dans le
chapitre 44, “Création d’objets MTS ou COM+”.
C++Builder fournit des experts permettant d’implémenter facilement des
applications qui incorporent toutes ces technologies dans l’environnement
C++Builder. Pour plus de détails, voir “Implémentation des objets COM à l’aide
d’experts” à la page 38-20.
Interface COM Le moyen par lequel un objet expose ses services aux clients.
Un objet COM fournit une interface pour chaque ensemble de
méthodes. Attention : les propriétés COM ne sont pas identiques
aux propriétés des objets VCL. Les propriétés COM utilisent
toujours des méthodes d’accès en lecture/écriture, et elles ne
sont pas déclarées en utilisant le mot clé __property.
Serveur COM Un module, EXE, DLL ou OCX, contenant le code d’un objet
COM. Les implémentations d’objets résident sur les serveurs.
Un objet COM implémente une ou plusieurs interfaces.
Client COM Le code appelant les interfaces afin d’obtenir du serveur les
services demandés. Les clients savent ce qu’ils veulent obtenir
du serveur (via l’interface) ; les clients ne savent pas comment
en interne le serveur fournit les services. C++Builder facilite le
processus de création de client en vous permettant d’installer
des serveurs COM (tel qu’un document Word ou une diapositive
PowerPoint) en tant que composants sur la palette de
composants. Cela vous permet de vous connecter au serveur et
de vous lier à ses événements en utilisant l’inspecteur d’objets.
Interfaces COM
Les clients COM communiquent avec des objets par le biais d’interfaces COM. Les
interfaces sont des groupes de routines, liées par la logique ou par la sémantique,
qui assurent la communication entre le fournisseur d’un service (objet serveur) et
ses clients. Voici la représentation standard d’une interface COM :
Figure 38.1 Une interface COM
Par exemple, tout objet COM doit implémenter l’interface de base, IUnknown. Via
une routine appelée QueryInterface de IUnknown, les clients peut demander les
autres interfaces implémentées par le serveur.
Les objets peuvent avoir plusieurs interfaces, où chacune implémente une
fonctionnalité. L’interface est le moyen de mettre à disposition du client le
service fourni par l’objet, sans lui donner les détails de l’implémentation sur la
façon dont ce service est fourni.
Les aspects majeurs des interfaces COM sont les suivants :
• Une fois publiées, les interfaces sont immuables ; c’est-à-dire qu’elles ne
changent plus. Une interface permet d’accéder à un ensemble précis de
Les clients obtiennent des pointeurs sur d’autres interfaces via la méthode
QueryInterface de IUnknown. QueryInterface connaît chaque interface de l’objet
serveur et peut donner au client un pointeur vers l’interface demandée. Lorsqu’il
reçoit un pointeur vers une interface, le client est assuré de pouvoir appeler
n’importe quelle méthode de l’interface.
Les objets contrôlent leur propre durée de vie grâce aux méthodes AddRef et
Release de IUnknown, qui sont de simples méthodes de décompte de références.
Serveurs COM
Un serveur COM est une application ou une bibliothèque qui fournit des
services à une application ou bibliothèque client. Un serveur COM est constitué
d’un ou de plusieurs objets COM, un objet COM étant un ensemble de
propriétés (données membre ou contenu) et de méthodes (fonctions membre).
Les clients ne savent pas comment l’objet COM effectue son service ;
l’implémentation de l’objet est encapsulée. Un objet met ses services à disposition
par le biais de ses interfaces comme décrit précédemment.
En outre, les clients n’ont pas besoin de savoir où réside l’objet COM. COM
fournit un accès transparent quel que soit l’emplacement de l’objet.
Quand il demande un service à un objet COM, le client transmet un
identificateur de classe (CLSID) à COM. Un CLSID est juste un GUID qui
référence un objet COM. COM utilise ce CLSID, recensé dans le registre système,
pour localiser l’implémentation appropriée du serveur. Une fois le serveur
localisé, COM amène le code en mémoire, et fait instancier par le serveur une
instance de l’objet pour le client. Ce processus est géré indirectement par un
objet spécial appelé un fabricant (basé sur les interfaces) qui crée sur demande
des instances d’objet.
Au minimum, un serveur COM doit effectuer ceci :
• Recenser des entrées dans le registre système pour associer le module serveur
à l’identificateur de classe (CLSID).
• Implémenter un objet fabricant de classe, qui fabrique un autre objet à partir
d’un CLSID particulier.
• Exposer le fabricant d’objet à COM.
• Fournir un mécanisme de déchargement grâce auquel un serveur qui ne sert
pas de client pourra être supprimé de la mémoire.
Remarque Les experts de C++Builder automatisent la création des objets et des serveurs
COM comme décrit dans “Implémentation des objets COM à l’aide d’experts” à
la page 38-20.
Comme illustré dans la figure suivante, pour les serveurs en processus, les
pointeurs sur les interfaces de l’objet sont dans le même espace processus que le
client, et COM fait des appels directs dans l’implémentation de l’objet.
Figure 38.3 Serveurs en processus
Remarque Cela n’est pas toujours vrai avec COM+. Quand le client appelle un objet dans
un contexte différent, COM+ intercepte l’appel afin qu’il se comporte comme
l’appel d’un serveur hors processus (voir plus bas) même si le serveur est en
La différence entre les serveurs hors processus et serveurs distants est le type de
communication inter-processus utilisé. Le proxy utilise COM pour communiquer
avec un serveur hors processus et COM distribué (DCOM) pour communiquer
avec une machine distante. DCOM transfère de manière transparente une
demande d’objet local dans l’objet distant s’exécutant sur une autre machine.
Remarque Pour les appels de procédure distantes, DCOM utilise le protocole RPC fourni
par l’environnement de calcul distribué (DCE) de Open Source. Pour la sécurité
distribuée, DCOM utilise le protocole de sécurité NT LAN Manager (NTLM).
Pour les services d’annuaire, DCOM utilise DNS (Domain Name System).
Le mécanisme du marshaling
Le marshaling est le mécanisme qui permet à un client de faire des appels aux
fonctions de l’interface d’objets distants qui se trouvent dans un autre processus
ou sur une autre machine. Le marshaling
• Prend un pointeur d’interface dans le processus du serveur et rend un
pointeur de proxy disponible au code dans le processus du client.
• Prend les arguments d’un appel à l’interface passés depuis le client et les
place dans l’espace processus de l’objet distant.
Pour tout appel à l’interface, le client met les arguments sur une pile et émet un
appel à une fonction via le pointeur d’interface. Si l’appel à l’objet n’est pas en
processus, il est passé au proxy. Celui-ci compresse les arguments dans un
paquet de marshaling et transmet la structure à l’objet distant. Le stub de l’objet
décompresse le paquet, place les arguments sur la pile et appelle
l’implémentation de l’objet. L’objet recrée l’appel du client dans son propre
espace d’adressage.
Le type de marshaling dépend de l’interface implémentée par l’objet COM.
Les objets peuvent utiliser le mécanisme de marshaling standard fourni par
l’interface IDispatch. C’est un mécanisme de marshaling générique qui permet la
communication via un appel standard à une procédure distante (RPC). Pour plus
de détails sur l’interface IDispatch, voir “Interfaces d’Automation” à la
page 41-13. Quand l’objet n’implémente pas IDispatch, s’il se limite lui-même aux
types compatibles Automation et s’il a une bibliothèque de types recensée, COM
fournit automatiquement la gestion du marshaling.
Les applications qui ne se limitent pas eux-mêmes aux types compatibles
automation ou recensent une bibliothèque de types doivent fournir leur propre
marshaling. Le marshaling est fourni par le biais d’une implémentation de
l’interface IMarshal, ou en utilisant une DLL proxy/stub générée séparément.
C++Builder ne prend pas en charge la génération automatique des DLL
proxy/stub.
Agrégation
Dans certains cas, un objet serveur peut utiliser un autre objet COM pour
effectuer certaines de ces fonctions. Par exemple, un objet de gestion de stock
peut utiliser un objet commande séparé pour gérer les commandes des clients.
Si l’objet de gestion de stock veut présenter une interface de commande au client,
il y a un problème. Même si le client ayant une interface stock peut appeler
QueryInterface pour obtenir l’interface commande, quand l’objet commande a été
créé, il ne connaît pas l’objet gestion de stock et ne peut lui renvoyer une
interface stock en réponse à un appel de QueryInterface. Un client qui a l’interface
commande ne peut revenir dans l’interface stock.
Pour éviter ce problème, certains objets COM gèrent l’agrégation. Quand l’objet
gestion de stock crée une instance de l’objet commande, il lui transmet une copie
de sa propre interface IUnknown. L’objet commande peut ensuite utiliser cette
interface IUnknown et gérer les appels de QueryInterface qui demandent une
interface, comme l’interface stock, qu’il ne gère pas. Quand cela se produit, les
deux objets pris ensemble s’appellent un agrégat. L’objet commande est appelé
l’objet interne (ou objet contenu) de l’agrégat et l’objet stock est appelé l’objet
externe.
Remarque Pour pouvoir se comporter comme objet externe d’un agrégat, un objet COM
doit créer l’objet interne en utilisant l’API Windows CoCreateInstance ou
CoCreateInstanceEx, en lui transmettant comme paramètre un pointeur IUnknown
que l’objet interne peut utiliser pour les appels de QueryInterface. Vous pouvez
également instancier un objet TComInterface et utiliser sa méthode CreateInstance à
cet effet.
Les objets qui se comportent comme objet interne d’un agrégat proposent deux
implémentations de l’interface IUnknown : une implémentation qui délègue les
appels QueryInterface qu’il ne peut gérer au IUnknown contrôleur de l’objet
externe et une implémentation qui renvoie une erreur quand elle reçoit un appel
QueryInterface qu’elle ne peut gérer. Les experts C++Builder créent
automatiquement des objets qui contiennent la gestion du comportement des
objets internes.
Clients COM
Les clients peuvent toujours interroger les interfaces d’un objet COM pour
déterminer ce qu’il est capable de faire. Tous les objets COM permettent aux
clients de demander les interfaces connues. De plus, si le serveur gère l’interface
IDispatch, les clients peuvent demander au serveur des informations sur les
méthodes gérées par le serveur. Les objets serveurs n’ont pas d’attentes
concernant l’utilisation de ses objets par le client. De même, les clients n’ont pas
besoin de savoir comment (ou même si) un objet fournit les services ; ils s’en
remettent simplement sur les objets serveurs pour fournir les services qu’ils
annoncent via leurs interfaces.
Il y a deux types de clients COM : les contrôleurs et les conteneurs. Un
contrôleur lance le serveur et interagit avec lui via son interface. Il demande des
services de l’objet COM ou il le pilote comme processus distinct. Les conteneurs
accueillent des contrôles visuels ou des objets qui apparaissent dans l’interface
utilisateur du conteneur. Ils utilisent des interfaces prédéfinies pour négocier les
problèmes d’affichage avec les objets serveur. Il est impossible d’avoir une
relation conteneur sur DCOM ; par exemple, les contrôles visuels qui
apparaissent dans l’interface utilisateur du conteneur doivent être localisés
localement. En effet, les contrôles sont supposés se dessiner eux-mêmes, ce qui
nécessite qu’ils puissent accéder aux ressources GDI locales.
C++Builder facilite le développement d’un contrôleur Automation en permettant
d’importer la bibliothèque de types ou un contrôle ActiveX dans un composant
enveloppe de telle manière que les objets serveur apparaissent comme les autres
composants VCL. Pour des détails sur ce processus, voir chapitre 40, “Création
de clients COM”.
Extensions de COM
COM a été initialement conçu pour fournir une fonctionnalité de communication
de base et permettre l’enrichissement de cette fonctionnalité via des extensions.
COM lui-même a étendu sa fonctionnalité première en définissant des ensembles
spécialisés d’interfaces couvrant des besoins spécifiques.
Le diagramme page suivante montre les relations entre les extensions de COM et
la façon dont elles dérivent de COM.
Documents
Contrôles ActiveX
OLE
Activation in-situ
(édition visuelle)
Liaison
Automation
Services MTS
ou
COM+
Incorporation
Informations
de type
COM
Les objets COM peuvent être visuels ou non visuels. Certains s’exécutent dans le
même espace processus que leurs clients ; d’autres peuvent s’exécuter dans des
processus différents ou sur des machines distantes si les objets assurent le
marshaling. Le tableau suivant récapitule les types d’objets COM que vous
pouvez créer, s’ils sont visuels, les espaces processus dans lesquels ils peuvent
s’exécuter, le marshaling qu’ils fournissent et s’ils ont besoin d’une bibliothèque
de types.
Serveurs Automation
L’Automation désigne la capacité d’une application à contrôler par programme
les objets d’une autre application, comme une macro qui peut manipuler
plusieurs applications à la fois. Le client d’un objet Automation est appelé
contrôleur Automation, et l’objet serveur manipulé est appelé objet Automation.
L’Automation peut être utilisée sur des serveurs en processus, locaux ou distants.
L’Automation présente deux caractéristiques :
• L’objet Automation définit un ensemble de propriétés et de commandes, et
décrit ses capacités via les descriptions de type. Pour ce faire, il doit disposer
d’un moyen de fournir des informations sur les interfaces de l’objet, les
méthodes des interfaces et les arguments de ces méthodes. Généralement, ces
informations se trouvent dans des bibliothèques de types. Le serveur
Automation peut aussi générer des informations dynamiquement quand elles
lui sont demandées via son interface IDispatch interface (voir plus bas).
• Les objets Automation rendent ces méthodes accessibles pour que d’autres
applications puissent les utiliser. Pour cela, ils implémentent l’interface
IDispatch. C’est par le biais de cette interface qu’un objet peut exposer toutes
ses méthodes et propriétés. Et c’est par le biais de la méthode primaire de
cette interface que les méthodes de l’objet peuvent être appelées, une fois
qu’elles ont été identifiées grâce aux informations de type.
Les développeurs utilisent souvent l’Automation pour créer et utiliser des objets
OLE non visuels qui s’exécutent dans n’importe quel espace processus, car
l’interface Automation IDispatch automatise le processus de marshaling. En
revanche, l’Automation limite les types que vous pouvez utiliser.
Pour obtenir une liste de types compatibles avec les bibliothèques de types en
général, et d’interfaces Automation en particulier, voir “Types autorisés” à la
page 39-13.
Pour plus d’informations sur l’écriture d’un serveur Automation, voir chapitre 41,
“Création de serveurs COM simples”.
Contrôles ActiveX
ActiveX est une technologie qui permet aux composants COM, particulièrement
aux contrôles, d’être plus compacts et efficaces. Cela est particulièrement
important pour les contrôles conçus pour des applications Intranet qui
nécessitent leur téléchargement par le client avant de les utiliser.
Les contrôles ActiveX sont des contrôles visuels qui s’exécutent uniquement
comme des serveurs en processus et qui peuvent s’intégrer dans une application
conteneur ActiveX. Ce ne sont pas des applications complètes par eux-mêmes,
vous pouvez les voir comme des contrôles OLE préfabriqués qui sont
réutilisables dans diverses applications. Les contrôles ActiveX ont une interface
utilisateur apparente et reposent sur l’utilisation d’interfaces prédéfinies pour
négocier les entrées/sorties et les questions d’affichage avec le conteneur hôte.
Les contrôles ActiveX utilisent l’Automation pour exposer leurs propriétés,
méthodes et événements. Leurs fonctionnalités incluent la capacité à déclencher
des événements, la liaison aux sources de données et la gestion de licence.
Les contrôles ActiveX s’utilisent parfois dans un site Web comme objets
interactifs placés dans une page Web. Ainsi, ActiveX est devenu un standard
particulièrement destiné à des contenus interactifs pour le Web, y compris
l’utilisation de documents ActiveX employés pour visualiser des documents non
HTML via un navigateur Web. Pour plus d’informations sur la technologie
ActiveX, voir le site Web de Microsoft.
Les experts de C++Builder facilitent la création des contrôles ActiveX. Pour plus
d’informations sur la création et l’utilisation de ces types d’objets, voir
chapitre 43, “Création d’un contrôle ActiveX”.
Documents Active
Les documents Active (appelés auparavant documents OLE) sont un ensemble de
services COM supportant la liaison et l’incorporation, le glisser-déplacer et
l’édition visuelle. Les documents Active intègrent de façon transparente des
données ou des objets de différents formats, par exemple des clips sonores, des
feuilles de calcul, du texte et des images.
Contrairement aux contrôles ActiveX, les documents Active ne sont pas limités
aux serveurs en processus ; ils peuvent être utilisés dans des applications inter-
processus.
A la différence des objets Automation, qui ne sont presque jamais visuels, les
objets document Active peuvent être visuellement actifs dans une autre
application. Ils sont associés à deux types de données : les données de
représentation utilisées pour l’affichage visuel à l’écran ou sur un périphérique
de sortie, et les données natives utilisées pour modifier l’objet.
Les objets document Active peuvent être des conteneurs ou des serveurs de
documents. Bien que C++Builder ne fournisse pas d’expert pour créer
automatiquement des documents Active, vous pouvez utiliser la classe
TOleContainer de la VCL pour supporter la liaison et l’incorporation dans les
documents Active existants.
Vous pouvez aussi utiliser TOleContainer comme base d’un conteneur de
document Active. Pour créer des objets pour les serveurs de documents Active,
utilisez une des classes de base COM de la VCL et implémentez les interfaces
appropriées à ce type d’objet, en fonction des services que l’objet doit gérer. Pour
plus d’informations sur la création et l’utilisation de serveurs de documents
Active, voir le site Web Microsoft.
Remarque Bien que la spécification des documents Active contienne une gestion intégrée du
marshaling des applications à processus croisé, les documents Active ne
s’exécutent pas sur des serveurs distants car les types qu’ils utilisent (handles de
fenêtre, de menu, etc.) sont spécifiques à un système sur une machine donnée.
Objets transactionnels
C++Builder utilise le terme “objets transactionnels” pour désigner des objets qui
exploitent les services de transaction, la sécurité et la gestion des ressources
proposées par MTS (pour les versions de Windows antérieures à Windows 2000)
ou COM+ (pour Windows 2000 et plus). Ces objets sont conçus pour travailler
dans des environnements distribués importants.
Les services de transaction garantissent la fiabilité assurant que des activités sont
toujours achevées ou annulées (le serveur ne s’arrête jamais en ayant fait la
moitié d’une activité). Les services de sécurité vous permettent d’exposer
différents niveaux de services à différentes classes de clients. La gestion des
ressources permet à un objet de répondre à davantage de clients en regroupant
les ressources et en ne gardant des objets actifs que s’ils sont utilisés. Pour
permettre au système de proposer ces services, l’objet doit implémenter
Bibliothèques de types
Les bibliothèques de types offrent un moyen d’obtenir davantage d’informations
de type sur un objet que les interfaces de l’objet. Les bibliothèques de types
contiennent les informations nécessaires sur les objets et leurs interfaces, comme
les interfaces associées à tels objets (étant donné le CLSID), les fonctions membre
de chaque interface et les arguments requis par ces fonctions.
Vous pouvez obtenir les informations de type en interrogeant une instance d’un
objet pendant qu’elle s’exécute ou, en chargeant et en lisant les bibliothèques de
types. Grâce à ces informations, vous pouvez implémenter un client qui utilise
un objet souhaité, en sachant exactement les fonctions membre dont vous avez
besoin, et ce qu’il faut passer à ces fonctions.
Les clients des serveurs Automation, des contrôles ActiveX et des objets
transactionnels s’attendent à disposer de ces informations de type. Tous les
experts C++Builder génèrent automatiquement une bibliothèque de types. Vous
pouvez voir ou modifier ces informations de type en utilisant l’éditeur de
bibliothèques de types comme décrit au chapitre 39, “Utilisation des
bibliothèques de types”.
Cette section décrit le contenu d’une bibliothèque de types, comment la créer,
quand l’utiliser et comment y accéder. Pour les développeurs souhaitant partager
des interfaces à travers divers langages, la section se termine par des suggestions
sur l’utilisation des outils de gestion de bibliothèques de types.
Interface Description
ITypeLib Fournit des méthodes pour accéder à la description d’une bibliothèque de
types.
ITypeLib2 Augmente ITypeLib pour inclure la gestion des chaînes de documentation, les
données personnalisées et des statistiques sur la bibliothèque de types.
ITypeInfo Fournit la description de chaque objet d’une bibliothèque de types. Par
exemple, un navigateur utilise cette interface pour extraire des informations
sur les objets de la bibliothèque de types.
ITypeInfo2 Augmente ITypeInfo pour accéder à des informations supplémentaires de la
bibliothèque de types, comme les méthodes d’accès aux éléments de données
personnalisés.
ITypeComp Fournit un moyen rapide d’accéder aux informations dont le compilateur a
besoin lors de la liaison avec une interface.
Comme le montre la figure 38.8, pour les objets contrôles ActiveX et fiches
ActiveX, l’expert implémente toutes les interfaces requises par les contrôles
ActiveX : IUnknown, IDispatch, IOleObject, IOleControl, etc.
Figure 38.8 Interfaces d’un contrôle ActiveX
Tableau 38.2 Experts C++Builder qui implémentent des objets COM, Automation et ActiveX
Expert Interfaces implémentées Ce que fait l’expert
serveur COM IUnknown (et IDispatch Exporte les routines nécessaires pour gérer le
si vous sélectionnez une recensement du serveur, le recensement des
interface par défaut qui classes, le chargement et le déchargement du
descend de IDispatch) serveur et l’instanciation des objets.
Crée et gère les fabricants de classes pour les
objets implémentés sur le serveur.
Fournit les entrées de registre pour l’objet
spécifiant le modèle de thread sélectionné.
Fournit, si c’est demandé, une gestion par le
serveur de la génération d’événements.
Déclare les méthodes qui implémentent
l’interface sélectionnée et fournit un squelette
d’implémentation que vous devez compléter.
Fournit une bibliothèque de types
Vous permet de sélectionner une interface
arbitraire qui est recensée dans la
bibliothèque de types et de l’implémenter.
Pour cela, vous devez utiliser une
bibliothèque de types.
serveur IUnknown, IDispatch Effectue les actions d’un expert serveur COM
Automation (décrit plus haut) plus :
Implémente l’interface que vous spécifiez,
double ou de répartition.
objet Active IUnknown, IDispatch, Effectue les actions d’un expert objet
Server (IASPObject) Automation (décrit plus haut) et génère
facultativement une page .ASP qui peut être
chargée dans un navigateur Web. Vous laisse
dans l’éditeur de bibliothèques de types pour
que vous puissiez modifier les propriétés et
les méthodes de l’objet, si nécessaire.
Restitue les éléments intrinsèques ASP sous
la forme de propriétés afin de pouvoir
disposer facilement d’informations sur
l’application ASP et le message HTTP qui l’a
démarrée.
contrôle IUnknown, IDispatch, Effectue les actions de l’expert Automation
ActiveX IPersistStreamInit, (décrites plus haut) plus :
IOleInPlaceActiveObject, Génère une CoClasse d’implémentation qui
IPersistStorage, IViewObject, correspond au contrôle VCL sur lequel est
IOleObject, IViewObject2, basé le contrôle ActiveX et qui implémente
IOleControl, toutes les interfaces ActiveX.
IPerPropertyBrowsing,
IOleInPlaceObject, Vous laisse dans l’éditeur de code source
ISpecifyPropertyPages pour que vous puissiez modifier la classe
d’implémentation.
Tableau 38.2 Experts C++Builder qui implémentent des objets COM, Automation et ActiveX (suite)
Expert Interfaces implémentées Ce que fait l’expert
ActiveForm Mêmes interfaces que Effectue les actions de l’expert contrôle
contrôle ActiveX ActiveX, plus :
Crée un descendant de TActiveForm qui prend
la place de la classe VCL préexistante dans
l’expert contrôle ActiveX. Cette nouvelle
classe vous permet de concevoir la fiche
active de la même manière que vous
concevez une application Windows.
objet IUnknown, IDispatch, Ajoute une nouvelle unité au projet en cours
transactionnel IObjectControl contenant la définition de l’objet MTS ou
COM+. Il insère des GUID propriétaires dans
la bibliothèque de types afin que C++Builder
puisse installer correctement l’objet et vous
laisse dans l’éditeur de bibliothèque de types
pour que vous puissiez définir l’interface que
l’objet expose aux clients. Vous devez
installer l’objet séparément après l’avoir
généré.
page de IUnknown, IPropertyPage Crée une nouvelle page de propriétés que
propriétés vous pouvez concevoir dans le concepteur de
fiche.
objet événement Aucune par défaut Crée un objet événement COM+ que vous
COM+ pouvez définir en utilisant l’éditeur de
bibliothèque de types. A la différence des
autres experts, l’expert objet événement
COM+ ne crée pas d’unité d’implémentation
car les objets événement n’ont pas
d’implémentation (elle est fournie par les
souscripteurs d’événements des clients).
COM+ Aucune par défaut Crée un objet souscripteur COM+ qui
implémente l’interface de l’événement choisi.
bibliothèque de Aucune par défaut Crée une nouvelle bibliothèque de types et
types l’associe au projet actif.
bibliothèque Aucune par défaut Crée une nouvelle DLL ActiveX ou serveur
ActiveX COM et expose les fonctions d’exportation
nécessaires.
Si vous voulez, vous pouvez ajouter d’autres objets COM (ou refaire une
implémentation existante). Pour ajouter un nouvel objet, il est plus simple
d’utiliser l’expert une seconde fois. En effet, l’expert met en place l’association
entre la bibliothèque de types et une classe d’implémentation, ainsi les
modifications effectuées dans l’éditeur de bibliothèques de types sont
automatiquement appliquées à l’unité d’implémentation.
Unité _TLB Cette unité (fichiers .cpp et .h) reflète le contenu de la bibliothèques de
types pour son utilisation par l’application. Elle contient toutes les déclarations
dont l’application a besoin pour utiliser les éléments définis dans la
bibliothèque de types. Même si vous pouvez ouvrir ce fichier dans l’éditeur de
code, vous ne devez jamais le modifier : il est géré automatiquement par
l’éditeur de bibliothèques de types et vos modifications seraient écrasées par
l’éditeur de bibliothèques de types. Pour plus de détails sur le contenu de ce
fichier, voir “Code généré par l’importation des informations d’une
bibliothèque de types” à la page 40-5.
Ces éléments sont illustrés dans le tableau suivant qui présente l’éditeur de
bibliothèques de types affichant les informations de type pour un objet COM
nommé cyc.
Figure 39.1 L’éditeur de bibliothèques de types
Barre d’outils
Pages
Barre d’état
Barre d’outils
La barre d’outils de l’éditeur de bibliothèques de types, située en haut, contient
des boutons sur lesquels vous cliquez pour ajouter de nouveaux objets à la
bibliothèque de types.
Le premier groupe de boutons vous permet d’ajouter des éléments à la
bibliothèque de types. Quand vous cliquez sur un bouton de la barre d’outils,
l’icône de cet élément apparaît dans le volet liste des objets. Vous pouvez alors
personnaliser ses attributs dans le volet de droite. Selon le type d’icône
sélectionnée, différentes pages d’informations apparaissent à droite.
Le tableau suivant énumère les éléments qu’il est possible d’ajouter à une
bibliothèque de types :
Icône Signification
Une CoClasse.
Une énumération.
Un alias.
Un enregistrement.
Une union.
Un module.
Quand vous sélectionnez un des éléments listés ci-dessus, dans le volet liste des
objets, le second groupe de boutons affiche les membres autorisés pour cet
élément. Par exemple, quand vous sélectionnez Interface, les icônes de méthode
et de propriété deviennent disponibles dans le second groupe car vous pouvez
ajouter des propriétés et des méthodes à une définition d’interface. Quand vous
sélectionnez une énumération, le second groupe de boutons n’affiche que le
membre constante car c’est le seule membre utilisable pour spécifier les
informations d’un type énumération.
Le tableau suivant énumère les membres qu’il est possible d’ajouter aux éléments
du volet liste des objets :
Icône Signification
Barre d’état
Lors de la modification ou de l’enregistrement d’une bibliothèque de types, les
erreurs de syntaxe, les erreurs de traduction et les avertissements sont affichés
dans le volet barre d’état.
Si, par exemple, vous spécifiez un type non géré par l’éditeur de bibliothèques
de types, vous obtiendrez une erreur de syntaxe. Pour une liste complète des
types gérés par l’éditeur de bibliothèques de types, voir “Types autorisés” à la
page 39-13.
Remarque Pour davantage d’informations sur les diverses options définissables dans les
pages d’informations de type, voir l’aide en ligne de l’éditeur de bibliothèques
de types.
Vous pouvez utiliser chacune des pages d’informations de type pour visualiser
ou modifier les valeurs qu’elles affichent. La plupart des pages organisent les
informations dans un ensemble de contrôles afin que vous puissiez saisir des
valeurs ou les sélectionner sans avoir à connaître la syntaxe des déclarations
correspondantes. Cela évite beaucoup d’erreurs de saisie quand vous spécifiez
une valeur comprise dans un ensemble déterminé. Cependant, vous pouvez
trouver plus efficace de saisir directement la déclaration. Pour ce faire, utilisez la
page Texte.
Tous les éléments des bibliothèques de types disposent d’une page Texte qui
affiche la syntaxe de l’élément. Cette syntaxe utilise un sous-ensemble du
langage Microsoft IDL (Interface Definition). Les modifications effectuées dans les
autres pages de l’élément sont reflétées ici. Si vous ajoutez du code directement
dans la page Texte, les modifications sont reflétées dans les autres pages de
l’éditeur de bibliothèques de types.
L’éditeur de bibliothèques de types génère des erreurs de syntaxe si vous ajoutez
des identificateurs qui ne sont pas gérés par l’éditeur ; l’éditeur ne gère
Interfaces
L’interface décrit les méthodes (et les propriétés exprimées comme fonctions get/
set) d’un objet auquel il faut d’accéder via une table de fonction virtuelle
(vtable). Si une interface est définie comme double, elle hérite de IDispatch, et
votre objet peut fournir à la fois une liaison anticipée par vtable et une liaison à
l’exécution via l’automation OLE. Par défaut, la bibliothèque de types marque
toutes les interfaces ajoutées comme double.
Il est possible d’attribuer des membres aux interfaces : des méthodes et des
propriétés. Elles apparaissent dans le volet liste des objets comme enfant du
nœud interface. Les propriétés des interfaces sont représentées par les méthodes
get et set utilisées pour lire et écrire les données sous-jacentes de la propriété.
Elles sont représentées dans la vue arborescente par des icônes spéciales qui
indiquent leur fonction.
Remarque Si une propriété est spécifiée comme “Ecriture par référence”, cela signifie qu’elle
est transmise comme pointeur et non comme valeur. Certaines applications,
comme Visual Basic, utilisent si possible l’écriture par référence pour optimiser
les performances. Pour passer une propriété uniquement par référence plutôt que
par valeur, utilisez le type de propriété Par référence seulement. Pour
transmettre la propriété par adresse et par valeur, sélectionnez Lecture | Ecriture
| Ecriture par référence. Pour activer ce menu, sélectionnez dans la barre d’outils
la flèche en regard de l’icône de la propriété.
Une fois les propriétés et méthodes ajoutées en utilisant les boutons de la barre
d’outils ou le menu contextuel du volet liste des objets, vous pouvez décrire leur
syntaxe et leurs attributs en sélectionnant la propriété ou la méthode et en
utilisant les pages d’informations de type.
La page Attributs vous permet d’attribuer un nom à la propriété ou méthode et
un identificateur de répartition (afin de pouvoir l’appeler en utilisant IDispatch).
Pour les propriétés, vous pouvez également attribuer un type. La signature de
fonction est créée en utilisant la page Paramètres qui vous permet d’ajouter, de
supprimer ou d’organiser les paramètres, de définir leur type et les modificateurs
et de spécifier le type de retour de la fonction.
Si vous attribuez des propriétés et des méthodes à une interface, elles sont
implicitement attribuées à sa CoClasse associée. C’est pour cela que l’éditeur de
bibliothèques de types ne vous permet pas d’ajouter directement des méthodes
ou des propriétés à une CoClasse.
Dispinterfaces
Les interfaces sont plus fréquemment utilisées que les dispinterfaces pour décrire
les propriétés et méthodes d’un objet. Les dispinterfaces sont accessibles
uniquement au travers d’une liaison dynamique alors que les interfaces peuvent
aussi utiliser une liaison statique grâce à une vtable.
Vous pouvez ajouter des propriétés et méthodes aux dispinterfaces comme pour
les interfaces. Cependant, quand vous créez une propriété pour une
dispinterface, vous ne pouvez spécifier le type de fonction ou le type des
paramètres.
CoClasses
Une CoClasse décrit un objet COM unique qui implémente une ou plusieurs
interfaces. Quand vous définissez une CoClasse, vous devez spécifier l’interface
implémentée qui est celle par défaut pour l’objet et, de manière facultative, la
dispinterface qui est la source par défaut des événements. Il n’est pas possible
d’ajouter directement des propriétés ou méthodes à une CoClasse dans l’éditeur
de bibliothèques de types. Les propriétés et méthodes sont exposées aux clients
par les interfaces, qui sont associées à la CoClasse avec la page Implémente.
Définitions de types
Les énumérations, les alias, les enregistrements et les unions déclarent des types
qui peuvent ensuite être utilisés ailleurs dans la bibliothèque de types.
Les énumérations sont constituées d’une liste de constantes numériques.
Ces constantes sont généralement des valeurs entières au format décimal
ou hexadécimal. Par défaut, la valeur de base est zéro. Vous pouvez ajouter des
constantes à une énumération en la sélectionnant dans le volet liste des objets,
puis en choisissant le bouton Constante de la barre d’outils ou en sélectionnant
la commande Nouveau|Const dans le menu contextuel du volet liste des objets.
Remarque Il est fortement conseillé de spécifier une chaîne d’aide pour les énumérations.
Voici un exemple d’entrée d’un type énumération pour un bouton de souris qui
inclut une chaîne d’aide pour chacun des éléments de l’énumération :
typedef enum TxMouseButton
{
[helpstring("mbLeft”)]
mbLeft = 0,
[helpstring("mbRight)]
mbRight = 1.
[helpstring("mbMiddle)]
mbMiddle = 2
} TxMouseButton;
Un alias définit un alias (un typedef) pour un type. Un alias permet de définir
des types s’utilisant dans d’autres types, par exemple des enregistrements ou des
unions. Associez l’alias au type sous-jacent en spécifiant l’attribut Type dans la
page Attributs.
Un enregistrement est l’équivalent d’une structure record en C. Un
enregistrement est constitué de la liste des membres de la structure, ou champs.
Une union définit une union de style C. Comme un enregistrement, une union
est constituée de la liste des membres de la structure, ou champs. Mais, à la
différence des membres d’un enregistrement, tous les membres d’une union
occupent le même emplacement physique, il n’est donc possible de stocker
qu’une seule valeur logique.
Ajoutez les champs à un enregistrement ou une union en le sélectionnant dans le
volet liste des objets puis en choisissant le bouton Champ de la barre d’outils ou
en utilisant le menu contextuel du volet liste des objets. Chaque champ dispose
d’un nom et d’un type que vous pouvez spécifier en sélectionnant le champ et
en attribuant les valeurs dans la page Attributs. Les enregistrements et les unions
peuvent être définis avec un repère optionnel, comme un struct C.
Les membres peuvent être de n’importe quel type prédéfini. Vous pouvez aussi
spécifier un type en utilisant un alias avant de définir l’enregistrement.
Remarque C++Builder ne gère pas le marshalling des mots clés pour les structures et les
unions comme switch_type, first_is, last_is, etc.
Modules
Un module définit un groupe de fonctions, généralement un ensemble de points
d’entrée de DLL. Vous définissez un module en :
• Spécifiant la DLL qu’il représente dans la page Attributs.
• Ajoutant des méthodes et des constantes en utilisant la barre d’outils ou le
menu contextuel du volet liste des objets. Vous devez ensuite spécifier les
Types autorisés
L’éditeur de bibliothèque de types gère les types IDL suivants dans une
bibliothèque de types. La colonne Compatible Automation spécifie si le type peut
être utilisé par une interface dont l’indicateur Automation ou Dispinterface est
activé. COM utilise automatiquement le marshalling pour les types suivants via
la bibliothèque de types.
Compatible
Type IDL Type variant Automation Description
short VT_I2 Oui Entier signé sur 2 octets
long VT_I4 Oui Entier signé sur 4 octets
single VT_R4 Oui Réel sur 4 octets
double VT_R8 Oui Réel sur 8 octets
CURRENCY VT_CY Oui Monétaire
DATE VT_DATE Oui Date
BSTR VT_BSTR Oui Chaîne binaire
IDispatch VT_DISPATCH Oui Pointeur sur l’interface IDispatch
SCODE VT_ERROR Oui Code d’erreur OLE
VARIANT_BOOL VT_BOOL Oui Vrai = –1, faux = 0
VARIANT VT_VARIANT Oui Pointeur sur un Variant OLE
IUnknown VT_UNKNOWN Oui Pointeur sur l’interface IUnknown
DECIMAL VT_DECIMAL Oui Nombre à virgule sur 16 octets
byte VT_I1 Non* Entier signé sur 1 octet
unsigned char VT_UI1 Oui Entier non signé sur 1 octet
unsigned short VT_UI2 Non* Entier non signé sur 2 octets
unsigned long VT_UI4 Non* Entier non signé sur 4 octets
__int64 VT_I8 Non Réel signé sur 8 octets
uint64 VT_UI8 Non Réel non signé sur 8 octets
int VT_INT Non* Entier dépendant du système
(Win32=Integer)
unsigned int VT_UINT Non* Entier non signé dépendant du
système
void VT_VOID Oui VOID de style C
HRESULT VT_HRESULT Non Code d’erreur 32 bits
SAFEARRAY VT_SAFEARRAY Oui Tableau protégé OLE
LPSTR VT_LPSTR Non Chaîne à zéro terminal
LPWSTR VT_LPWSTR Non Chaîne large à zéro terminal
Outre ces types IDL, toute interface ou type défini dans la bibliothèque ou dans
les bibliothèques référencées peut s’utiliser dans une définition de bibliothèque
de types.
L’éditeur de bibliothèques de types stocke les informations de type dans le
fichier (.TLB) de bibliothèque de types générée sous forme binaire.
Les SafeArray
COM requiert que les tableaux soient transmis via un type de données spécial
appelé SafeArray. Vous pouvez créer et détruire les SafeArrays en appelant des
fonctions COM particulières, et tous les éléments d’un SafeArray doivent être de
types compatibles automation-valides.
Dans l’éditeur de bibliothèques de types, un SafeArray doit spécifier son type de
composant. Par exemple, la ligne suivante de la page Texte déclare une méthode
avec un paramètre SafeArray avec un élément de type long:
HRESULT _stdcall HighlightLines(SAFEARRAY(long) Lines);
Remarque Même si vous devez spécifier le type de l’élément lors de la déclaration d’un
type SafeArray dans l’éditeur de bibliothèques de types, la déclaration du fichier
unité _TLB généré n’indique pas le type de l’élément.
[propget, id(0x00000002)]
HRESULT _stdcall AutoSelect([out, retval] long Value );
[propget, id(0x00000003)]
HRESULT _stdcall AutoSize([out, retval] VARIANT_BOOL Value );
[propput, id(0x00000003)]
HRESULT _stdcall AutoSize([in] VARIANT_BOOL Value );
};
Une fois des membres ajoutés à une interface en utilisant la page Texte de
l’interface, les membres apparaissent comme éléments distincts dans le volet liste
des objets. Chaque membre dispose de ses propres pages Attributs, Indicateurs
et Paramètres. Vous pouvez modifier chaque nouvelle propriété ou méthode en
la sélectionnant dans le volet liste des objets et en utilisant ses pages ou en
effectuant les modifications directement dans la page Texte.
Si l’interface est associée à une CoClasse générée par un expert, vous pouvez
demander à l’éditeur de bibliothèques de types d’appliquer les modifications au
fichier implémentation en utilisant le bouton Rafraîchir de la barre d’outils.
L’éditeur de bibliothèques de types ajoute les nouvelles méthodes à la classe
d’implémentation afin de refléter les nouveaux membres. Vous pouvez ensuite
rechercher les nouvelles méthodes dans le code source de l’unité
d’implémentation et remplir leurs corps afin de compléter l’implémentation.
Une fois un alias ajouté, le nouveau type peut être utilisé par la bibliothèque de
types ou par toute bibliothèque de types qui y fait référence dans sa page
Utilise. Vous pouvez, par exemple, utiliser l’alias comme type d’une propriété ou
d’un paramètre.
40
Création de clients COM
Chapitre 40
Les clients COM sont des applications qui utilisent un objet COM implémenté
par une autre application ou bibliothèque. Les types les plus courants sont les
applications qui contrôlent des serveurs Automation (ce sont les contrôleurs
Automation) et les applications qui accueillent un contrôle ActiveX (ce sont les
conteneurs ActiveX).
Au premier abord, ces deux types de clients COM semblent très différents :
un contrôleur Automation standard lance un serveur EXE externe et émet des
commandes que le serveur traite pour lui. Le serveur Automation est
généralement non visuel et hors processus. D’un autre côté, le client ActiveX
standard accueille un contrôle visuel en l’utilisant comme vous pouvez utiliser
les contrôles de la palette des composants. Les serveurs ActiveX sont toujours
des serveurs en processus.
Cependant, la réalisation de ces deux types de clients COM est étonnamment
similaire : l’application client obtient une interface pour l’objet serveur et en
utilise les propriétés et méthodes. C++Builder simplifie beaucoup cela en vous
permettant d’envelopper la CoClasse serveur dans un composant du client que
vous pouvez même installer dans la palette des composants. Des exemples de
tels composants enveloppe apparaissent dans deux pages de la palette des
composants : des enveloppes ActiveX exemple apparaissent dans la page ActiveX
et des objets Automation exemple apparaissent dans la page Serveurs.
Quand vous écrivez un client COM, vous devez comprendre l’interface que le
serveur expose aux clients, exactement comme vous devez comprendre les
propriétés et méthodes d’un composant de la palette des composants pour
pouvoir l’utiliser dans votre application. Cette interface (ou cet ensemble
d’interfaces) est déterminée par l’application serveur et se trouve généralement
publiée dans une bibliothèque de types. Pour des informations spécifiques sur les
interfaces publiées par une application serveur spécifique, vous devez consulter
la documentation de cette application.
Même si vous ne choisissez pas d’envelopper un objet serveur et de l’installer
dans la palette des composants, vous devez rendre sa définition d’interface
Enveloppes ActiveX
Vous devez toujours utiliser un composant enveloppe pour accueillir des
contrôles ActiveX car le composant enveloppe intègre la fenêtre du contrôle dans
le modèle VCL.
Le contrôle ActiveX hérite de TOleControl des propriétés et méthodes qui vous
permettent d’accéder à l’interface sous-jacente ou d’obtenir des informations sur
le contrôle. Cependant, la plupart des applications n’en n’ont pas besoin.
Vous utilisez à la place le contrôle importé comme vous utiliseriez tout autre
contrôle VCL.
Généralement, les contrôles ActiveX proposent une page de propriétés qui vous
permet de définir leurs propriétés. Les pages de propriétés sont similaires aux
éditeurs que certains composants affichent quand vous double-cliquez dessus
dans le concepteur de fiche. Pour afficher la page de propriétés d’un contrôle
ActiveX, cliquez dessus avec le bouton droit de la souris et choisissez Propriétés.
La manière dont vous utilisez les contrôles ActiveX importés est déterminée par
l’application serveur. Cependant, les contrôles ActiveX utilisent un ensemble
standard de notifications quand ils représentent les données d’un champ de base
de données. Pour davantage d’informations sur la manière d’accueillir des
contrôles ActiveX orientés données, voir “Utilisation de contrôles ActiveX
orientés données” à la page 40-9.
Il est facile de gérer les événements car vous pouvez utiliser l’inspecteur d’objets
pour écrire des gestionnaires d’événements. Toutefois, vous devez faire attention
car les gestionnaires d’événements de votre composant ont des paramètres
légèrement différents de ceux définis pour les événements de la bibliothèque de
types. Les paramètres qui sont des pointeurs d’interface sont généralement
enveloppés en utilisant le modèle TComInterface et n’apparaissent pas comme un
pur pointeur d’interface. L’enveloppe d’interface résultante a un nom de la forme
NomInterfacePtr.
Par exemple, l’exemple de code suivant est le gestionnaire d’événement pour
l’événement OnNewWorkBook de ExcelApplication. Le gestionnaire d’événement
a un paramètre qui fournit l’interface d’une autre CoClasse (ExcelWorkbook).
Cependant, l’interface n’est pas transmise comme un pointeur d’interface
ExcelWorkBook, mais comme un objet ExcelWorkbookPtr.
void _fastcall TForm1::XLappNewWorkbook(TObject *Sender, ExcelWorkbookPtr Wb)
{
ExcelWorkbook1->ConnectTo(Wb);
}
Dans cet exemple, le gestionnaire d’événement affecte le classeur à un composant
ExcelWorkbook (ExcelWorkbook1). Cela illustre la manière de connecter un
composant enveloppe à une interface existante en utilisant la méthode ConnectTo.
La méthode ConnectTo est ajoutée au code généré du composant enveloppe.
Les serveurs qui ont un objet application exposent une méthode Quit pour cet
objet afin de permettre aux clients de terminer la connexion. Généralement Quit
expose des fonctionnalités équivalentes à l’utilisation du menu Fichier pour la
sortie de l’application. Du code pour l’appel de la méthode Quit est généré dans
la méthode Disconnect de votre composant. Il est possible d’appeler la méthode
Quit sans paramètre. Le composant enveloppe a également une propriété
AutoQuit. AutoQuit oblige le contrôleur à appeler Quit quand le composant est
libéré. Si vous voulez déconnecter à un autre moment, ou si la méthode Quit
nécessite des paramètres, vous devez l’appeler explicitement. Quit apparaît
comme méthode publique du composant généré.
WordApplication1->ActiveDocument->PrintOut();
}
}
_ApplicationDisp MyWord;
MyWord.Bind(CLSID_WordApplication);
DocumentsDisp MyDocs = MyWord->Documents;
MyDocs->Open(&FileName);
Connexion à un serveur
Avant de pouvoir piloter un serveur Automation depuis votre application
contrôleur, vous devez obtenir une référence sur une interface qu’il gère.
Généralement, vous vous connectez au serveur via son interface principale. Par
exemple vous vous connectez à Microsoft Word via le composant
WordApplication.
Si l’interface principale est une interface double, vous pouvez utiliser les objets
créateur du fichier NomBibTypes_TLB.h. Les classes de créateur portent le même
nom que la CoClasse sans le préfixe “Co”. Vous pouvez vous connecter à un
serveur situé sur la même machine en appelant la méthode Create ou à un
serveur situé sur une autre machine en utilisant la méthode CreateRemote.
Comme Create et CreateRemote sont des méthodes statiques, vous n’avez pas
besoin d’une instance de la classe de créateur pour les appeler.
pInterface = CoServerClassName.Create();
pInterface = CoServerClassName.CreateRemote("Machine1");
Create et CreateRemote renvoient la classe enveloppe pour l’interface par défaut de
la CoClasse (définie dans NomBibTypes_TLB.h en utilisant le modèle
TComInterface).
Si l’interface par défaut est une interface de répartition, il n’y a pas de classe
créateur générée pour la CoClasse. Vous devez à la place, créer une instance de
la classe enveloppe générée automatiquement pour l’interface par défaut.
Cette classe est définie en utilisant le modèle TAutoDriver, elle a un nom de la
forme NomInterfaceDisp. Appelez ensuite la méthode Bind, en lui transmettant
le GUID de la CoClasse (il y a une constante pour ce GUID définie en haut de
l’unité _TLB).
valeurs possibles, voir “Choix d’un modèle de thread” à la page 41-5. Pour
des informations sur la manière de gérer les threads dans votre application,
voir chapitre 11, “Ecriture d’applications multithreads”.
• Générer le code de support d’événement. Vous devez indiquer si vous voulez
que votre objet génère des événements pour les clients pouvant y répondre.
L’expert peut fournir la gestion des interfaces nécessaires pour générer des
événements et la distribution des appels aux gestionnaires d’événements des
clients. Pour des informations sur le fonctionnement des événements et la
manière de les implémenter, voir “Exposition d’événements aux clients” à la
page 41-11.
• Oleautomation. Si vous voulez vous confiner aux types compatibles
Automation, vous pouvez laisser COM gérer pour vous le marshaling quand
vous ne générez pas un serveur en processus. En indiquant l’interface de
votre objet comme étant OleAutomation dans la bibliothèque de types, vous
permettez à COM de définir pour vous les proxys et stubs et de gérer le
passage de paramètres entre les frontières de processus. Pour davantage
d’informations, voir “Le mécanisme du marshaling” à la page 38-8. Vous ne
pouvez spécifier que l’interface est compatible Automation que si vous créez
une nouvelle interface. Si vous sélectionnez une interface existante, ses
attributs sont déjà spécifiés dans sa bibliothèque de types. Si l’interface de
votre objet n’est pas marquée comme OleAutomation, vous devez soit créer
un serveur en processus ou écrire votre propre code de marshaling.
• Implémenter les interfaces ancêtres : Sélectionnez cette option si vous voulez
que l’expert fournisse les routines stub des interfaces héritées. Trois de ces
interfaces ne seront jamais implémentées par l’expert : IUnknown, IDispatch et
IAppServer. IUnknown et IDispatch ne sont pas implémentées car ATL fournit
sa propre implémentation de ces deux interfaces. IAppServer n’est pas
implémentée car elle est automatiquement implémentée lors de l’utilisation
des ensembles de données client et des fournisseurs d’ensembles de données.
Vous pouvez, si vous le souhaitez, ajouter une description de votre objet COM.
Cette description apparaît pour l’objet dans la bibliothèques de types.
Le tableau suivant énumère les différents modèles de thread que vous pouvez
spécifier.
Remarque Les variables locales sont toujours fiables (sauf celles des callbacks)
indépendamment du modèle de thread. En effet, les variables locales sont
stockées dans la pile et chaque thread dispose de sa propre pile. Les variables
locales des callbacks peuvent n’être pas fiables si vous utilisez le modèle libre.
lequel l’objet a été créé. Cependant votre objet est assuré de ne pas recevoir
d’appels contradictoires.
L’écriture d’un objet utilisant le modèle de thread neutre respecte sensiblement
les même règles que l’écriture d’un objet gérant le modèle de thread apartment,
sauf qu’il n’est pas nécessaire de protéger les données de l’instance des conflits
de threads, elles peuvent être accédées par différentes méthodes de l’interface de
l’objet. Toutes les données d’instance qui ne peuvent être accédées que par une
seule méthode d’interface sont automatiquement adaptées aux threads.
Pour que votre objet génère des événements, vous devez effectuer les opérations
suivantes :
1 Dans l’expert, cochez la case Insérer le code de support d’événement.
L’expert crée un objet qui contient une interface Events en plus de l’interface
par défaut. Cette interface Events a un nom de la forme INomCoClasseEvents.
C’est une interface en sortie (source) : cela signifie que cette interface ne doit
pas être implémentée par votre objet mais par les clients, elle est appelée par
votre objet (vous pouvez le constater en sélectionnant la CoClasse, allez sur la
page Implémente, vous constaterez que la colonne Source indique true pour
l’interface Events). Le GUID de l’interface Events est ajouté à la carte des
points de connexion, qui apparaît sous la carte d’interface dans la déclaration
de l’objet. Pour davantage d’informations sur la carte des points de connexion,
voir la documentation ATL.
Outre l’interface Events, l’expert ajoute des classes de base supplémentaires à
votre objet. Une implémentation de l’interface IConnectionPointContainer
(IConnectionPointContainerImpl) et une classe de base modélisée gèrent le
déclenchement des événements dans les clients (TEvents_NomCoClasse).
Le modèle de cette classe se trouve dans l’en-tête de l’unité _TLB.
2 Dans l’éditeur de bibliothèques de types, sélectionnez l’interface en sortie
Events de votre objet (elle a un nom de la forme INomCoClasseEvents)
3 Cliquez sur le bouton Méthode de la barre d’outils de l’éditeur de
bibliothèques de types. Chaque méthode ajoutée à l’interface Events représente
un gestionnaire d’événement que le client doit implémenter.
4 Dans la page Attributs, spécifiez le nom du gestionnaire d’événement, par
exemple MonEvenement.
5 Dans la barre d’outils, choisissez le bouton Rafraîchir.
L’implémentation de votre objet contient maintenant tout ce qu’il faut pour
accepter les récepteurs d’événements des clients et gérer une liste des
interfaces à appeler quand l’événement se produit. Pour appeler ces interfaces,
vous pouvez appeler la méthode qui déclenche un événement (implémentée
par TEvents_NomCoClasse) pour générer les événements dans les clients. Pour
chaque gestionnaire d’événement, cette méthode porte un nom de la forme
Fire_NomGestionnaireEvenement.
6 A chaque fois que vous avez besoin de déclencher l’événement pour que les
clients soient informés de son occurrence, appelez la méthode qui distribue
l’événement à tous les récepteurs d’événements :
if (EventOccurs) Fire_MonEvenement;
// Appelez la méthode créée pour déclencher des événements.
Interfaces d’Automation
L’expert objet Automation implémente par défaut une interface double ce qui
signifie que l’objet Automation gère :
• La liaison tardive à l’exécution, via son interface IDispatch. Elle est
implémentée comme une interface de répartition ou dispinterface.
• La liaison précoce à la compilation, ce qui s’effectue directement en appelant
l’une des fonctions membre de la table de fonction virtuelle (VTable). C’est ce
que l’on appelle une interface personnalisée.
Remarque Les interfaces générées par l’expert objet COM qui ne descendent pas de
IDispatch ne gèrent que les appels de la VTable.
Interfaces doubles
Une interface double est à la fois une interface personnalisée et une
dispinterface. Elle est implémentée en tant qu’interface VTable COM qui dérive
de IDispatch. Pour les contrôleurs qui accèdent à l’objet uniquement à l’exécution,
la dispinterface est disponible. Pour les objets qui peuvent tirer profit de la
liaison à la compilation, c’est l’interface VTable, la plus efficace, qui est utilisée.
Les interfaces doubles offrent les avantages combinés des interfaces VTable et
des dispinterfaces :
• Pour les contrôleurs Automation qui ne peuvent pas obtenir d’information de
type, la dispinterface fournit l’accès à l’objet à l’exécution.
• Pour les serveurs en processus, vous bénéficiez d’un accès rapide via les
interfaces VTable.
• Pour les serveurs hors processus, COM effectue le marshaling des données à
la fois pour les interfaces VTable et pour les dispinterfaces. COM fournit une
implémentation proxy/stub générique qui peut réaliser le marshaling de
l’interface en fonction des informations contenues dans une bibliothèque de
types. Pour davantage d’informations sur le marshaling, voir “Marshaling des
données” à la page 41-15.
Le diagramme page suivante décrit l’interface IMyInterface d’un objet gérant une
interface double nommée IMyInterface. Les trois premières entrées de la VTable
d’une interface double font référence à l’interface IUnknown, les quatre suivantes
font référence à l’interface IDispatch, les autres sont des entrées COM pour l’accès
direct aux membres de l’interface personnalisée.
Figure 41.1 VTable d’une interface double
Interfaces de répartition
Les contrôleurs Automation sont des clients qui utilisent l’interface COM
IDispatch pour accéder aux objets du serveur COM. Le contrôleur doit d’abord
créer l’objet, puis demander à l’interface IUnknown de l’objet un pointeur sur son
interface IDispatch. IDispatch garde en interne la trace des méthodes et des
propriétés par le biais d’un identificateur de répartition (dispID), qui est un
numéro d’identification propre à chaque membre interface. Grâce à IDispatch, un
contrôleur récupère les informations de type de l’objet pour l’interface de
répartition, puis associe les noms des membres interface aux dispID spécifiques.
Ces dispID sont accessibles à l’exécution et les contrôleurs y accèdent en
appelant la méthode GetIDsOfNames de IDispatch.
Lorsqu’il connaît le dispID, le contrôleur peut appeler la méthode Invoke de
IDispatch pour exécuter le code requis (propriété ou méthode), en regroupant les
paramètres de la propriété ou de la méthode dans l’un des paramètres de la
méthode Invoke. Invoke a une signature fixe définie lors de la compilation, qui lui
permet d’accepter des arguments variés lors de l’appel d’une méthode
d’interface.
L’implémentation de l’objet automation de Invoke doit alors dégrouper les
paramètres, appeler la propriété ou la méthode et gérer les éventuelles erreurs.
Lorsque la propriété ou la méthode revient, l’objet retransmet la valeur renvoyée
au contrôleur.
Cette procédure est appelée liaison différée car le contrôleur se lie à la propriété
ou à la méthode lors de l’exécution de l’application plutôt que lors de sa
compilation.
Remarque C++Builder ne peut créer de CoClasses avec des interfaces de répartition qui ne
soient pas des interfaces doubles. En effet sa gestion de COM repose sur ATL
qui ne gère pas les interfaces de répartition non doubles.
Remarque Lors de l’importation d’une bibliothèque de types, C++Builder requiert des
dispID lors de la génération du code, permettant de cette façon aux classes
enveloppe générées d’appeler Invoke sans appeler GetIDsOfNames. Cela peut
augmenter de manière significative les performances d’exécution des contrôleurs.
Interfaces personnalisées
Les interfaces personnalisées sont des interfaces définies par l’utilisateur qui
permettent aux clients d’appeler les méthodes de l’interface en fonction de leur
ordre dans la VTable et du type des arguments. La VTable contient les adresses
de toutes les propriétés et méthodes qui sont membres de l’objet, y compris les
fonctions membre des interfaces qu’il supporte. Si l’objet ne supporte pas
IDispatch, les entrées correspondant aux membres des interfaces personnalisées
de l’objet suivent immédiatement celles des membres de IUnknown.
Si l’objet possède une bibliothèque de types, vous pouvez accéder à l’interface
personnalisée via sa disposition VTable, que vous pouvez obtenir à l’aide de
l’éditeur de bibliothèques de types. Si l’objet possède une bibliothèque de types
et gère IDispatch, un client peut aussi obtenir les dispID de l’interface IDispatch et
se lier directement à un déplacement de la VTable. L’importateur de la
bibliothèque de types de C++Builder (TLIBIMP) extrait les dispIDs à
l’importation, ce qui évite aux clients qui utilisent les enveloppes de
dispinterfaces d’appeler GetIDsOfNames; ces informations figurent déjà dans le
fichier _TLB. Toutefois, les clients doivent quand même appeler Invoke.
Remarque La première méthode, l’utilisation de IDispatch est uniquement disponible sur les
serveurs Automation. La seconde méthode est automatiquement disponible sur
tous les objets créés par les experts et utilisant une bibliothèque de types.
• Tous les membres d’une interface double doivent passer un HRESULT comme
valeur de retour de fonction.
• Les membres d’une interface duale qui ont besoin de renvoyer d’autres
valeurs doivent spécifier ces paramètres en tant que var ou out, en indiquant
un paramètre de sortie pour renvoyer la valeur de la fonction.
Remarque Une façon d’outrepasser les restrictions des types Automation est d’implémenter
une interface IDispatch distincte et une interface personnalisée. Vous pouvez ainsi
utiliser tous les types d’arguments. Cela signifie que les clients COM ont la
possibilité d’utiliser l’interface personnalisée, à laquelle les contrôleurs
Automation peuvent encore accéder. Mais, dans ce cas, il faut implémenter
manuellement le code de marshaling.
Marshaling personnalisé
Généralement, vous utiliserez le marshaling automatique dans les serveurs hors
processus et distants parce que c’est le plus simple : COM fait le travail à votre
place. Cependant, vous pouvez décider de fournir un marshaling personnalisé si
vous pensez que ses performances seront supérieures. Si sous implémentez votre
propre marshaling personnalisé, vous devez gérer l’interface IMarshal. Pour
davantage d’informations sur cette approche, voir la documentation Microsoft.
Les scripts des pages Active Server et les objets Automation incorporés dans
une page peuvent utiliser les éléments intrinsèques ASP (des objets prédéfinis
qui fournissent des informations sur l’application en cours, les messages HTTP
du navigateur, etc).
Ce chapitre décrit comment créer un objet Active Server en utilisant l’expert
objet Active Server C++Builder. Ce contrôle Automation spécial peut ensuite être
appelé par une page Active Server et lui fournir son contenu.
Voici les étapes de la création d’un objet Active Server :
• Création d’un objet Active Server pour l’application.
• Définition de l’interface d’un objet Active Server.
• Recensement d’un objet Active Server
• Test et débogage d’une application ASP
Vous pouvez, dans l’expert, spécifier comment votre objet y accède en spécifiant
l’option Type d’Active Server :
• Si vous utilisez IIS 3 ou IIS 4, vous pouvez utiliser Méthodes d’événement de
niveau page. Avec ce modèle, votre objet implémente les méthodes
OnStartPage et OnEndPage appelées au chargement/déchargement de la page
Active Server. Quand l’objet est chargé, il obtient automatiquement une
interface IScriptingContext qu’il utilise pour accéder aux éléments intrinsèques
ASP. Ces interfaces sont à leur tour reflétées sous la forme de propriétés
héritées de la classe de base (TASPObject).
Si vous utilisez IIS5 ou plus, utilisez le type Contexte d’objet. Avec ce modèle,
votre objet obtient une interface IObjectContext qu’il utilise pour accéder aux
éléments intrinsèques ASP. Là encore, ces interfaces sont à leur tour reflétées
sous la forme de propriétés héritées de la classe de base (TMTSASPObject).
L’avantage de cette approche tient à ce que l’objet accède à tous les autres
services proposés par IObjectContext. Pour accéder à l’interface IObjectContext,
utilisez la propriété ObjectContext de votre objet Active Server. Pour davantage
d’informations sur les services accessibles via IObjectContext, voir chapitre 44,
“Création d’objets MTS ou COM+”.Vous pouvez demander à l’expert de générer
une page .ASP simple pour accueillir le nouvel objet Active Server. La page
générée contient un script minimaliste (écrit en VBScript) qui crée votre objet
Active Server à partir de son ProgID et indique où vous pouvez appeler ses
méthodes. Ce script appelle Server.CreateObject pour démarrer votre objet
Active Server.
Remarque Même si le script de test généré utilise VBScript, une page Active Server peut
également contenir du code Jscript.
Lorsque vous sortez de l’expert, une nouvelle unité est ajoutée au projet en
cours ; elle contient la définition de l’objet Active Server. De plus, l’expert ajoute
un projet de bibliothèque de types et ouvre l’éditeur de bibliothèque de types.
Vous pouvez alors exposer les propriétés et méthodes de l’interface via la
bibliothèque de type comme indiqué dans “Définition de l’interface d’un objet
COM” à la page 41-10. Quand vous écrivez l’implémentation des propriétés et
méthodes de votre objet, vous pouvez tirer profit des éléments intrinsèques ASP
(décrit ci-dessous) pour obtenir des informations sur l’application ASP et les
messages HTTP qu’elle utilise pour communiquer avec les navigateurs.
Comme tout autre objet Automation, l’objet Active Server implémente une
interface double, qui gère aussi bien la liaison précoce (à la compilation) via la
VTable et la liaison tardive (à l’exécution) via l’interface IDispatch. Pour
davantage d’informations sur les interfaces doubles, voir “Interfaces doubles” à
la page 41-13.
informations partagées par tous les objets Active Server appartenant à une même
application ASP.
Pour simplifier l’accès à ces objets, la classe de base de votre objet Active Server
les présente sous la forme de propriétés. Pour une description complète de ces
objets, reportez-vous à la documentation Microsoft. Les rubriques suivantes vous
en donnent une présentation rapide.
Application
On accède à l’objet Application via une interface IApplicationObject. Il représente
toute l’application ASP, définie comme étant l’ensemble de tous les fichiers .asp
d’un même répertoire virtuel et de ses sous-répertoires. L’objet Application peut
être partagé par plusieurs clients, il propose donc une gestion du verrouillage
que vous devez utiliser pour empêcher des conflits de threads.
IApplicationObject propose les membres suivants :
Request
On accède à l’objet Request via une interface IRequest. Il donne des informations
sur le message de requête HTTP qui a entraîné l’ouverture de la page
Active Server.
Response
On accède à l’objet Response via une interface IResponse. Il vous permet de
spécifier des informations sur le message de réponse HTTP renvoyé au
navigateur client.
IResponse propose les membres suivants :
Session
On accède à l’objet Session via une interface ISessionObject. Il vous permet de
stocker des variables qui subsistent durant toute l’interaction d’un client avec
l’application ASP. Ces variables ne sont donc pas libérées quand le client passe
d’une page à une autre dans l’application ASP mais uniquement quand le client
sort de l’application.
ISessionObject propose les membres suivants :
Server
On accède à l’objet Server via une interface IServer. Il propose divers utilitaires
pour écrire votre application ASP.
IServer propose les membres suivants :
Contrôle VCL
Dans C++Builder, l’implémentation sous-jacente à un contrôle ActiveX est un
contrôle VCL. Quand vous créez un contrôle ActiveX, vous devez commencer
par concevoir ou choisir le contrôle VCL à partir duquel vous aller construire
votre contrôle ActiveX.
Le contrôle VCL sous-jacent doit être un descendant de TWinControl car il doit
disposer d’une fenêtre qui peut être accueillie par l’application hôte. Quand vous
créez une fiche active, cet objet est un descendant de TActiveForm.
Remarque L’expert contrôle ActiveX énumère les descendants TWinControl dans lesquels
vous pouvez choisir pour créer un contrôle ActiveX. Néanmoins, cette liste ne
propose pas tous les descendants TWinControl. Certains contrôles sont répertoriés
comme incompatibles avec ActiveX (en utilisant la procédure RegisterNonActiveX)
et n’apparaissent pas dans cette liste.
Enveloppe ActiveX
Le véritable objet COM est un objet ActiveX qui encaspule le contrôle VCL. Il a
un nom de la forme TVCLClassXImpl, où TVCLClass est le nom de la classe du
contrôle VCL. Ainsi, par exemple, l’enveloppe ActiveX de TButton se nommerait
TButtonXImpl.
La classe enveloppe descend des classes déclarées par la macro
VCLCONTROL_IMPL, qui gèrent les interfaces ActiveX. L’enveloppe ActiveX en
hérite, ce qui lui permet de retransmettre les messages Windows au contrôle
VCL et d’accueillir sa fenêtre dans l’application hôte.
L’enveloppe ActiveX expose les propriétés et méthodes du contrôle VCL aux
clients en utilisant son interface par défaut. L’expert implémente
automatiquement la plupart des propriétés et méthodes de classe enveloppe et
délègue les appels de méthode au contrôle VCL sous-jacent. L’expert fournit
également à la classe enveloppe les méthodes qui déclenchent les événements du
contrôle VCL dans les clients et affecte ces méthodes aux gestionnaires
d’événements du contrôle VCL.
Bibliothèque de types
L’expert contrôle ActiveX génère automatiquement une bibliothèque de types qui
contient les définitions de type pour la classe enveloppe, son interface par défaut
et toutes les définitions de type nécessaires. Ces informations de type permettent
au contrôle d’informer les applications hôtes de ses services. Vous pouvez
visualiser et modifier ces informations en utilisant l’éditeur de bibliothèques de
types. Même si ces informations sont stockées dans un fichier bibliothèque
Page de propriétés
Vous pouvez éventuellement attribuer à votre contrôle ActiveX une page de
propriétés. La page de propriétés permet à l’utilisateur de l’application hôte
(le client) de visualiser et de modifier les propriétés du contrôle. Vous pouvez
regrouper plusieurs propriétés dans une page ou utiliser une page pour proposer
une interface de type boîte de dialogue à une propriété. Pour davantage
d’informations sur la manière de créer des pages de propriétés, voir “Création
d’une page de propriétés pour un contrôle ActiveX” à la page 43-14.
try
{
}
catch(Exception &e)
{
return Error(e.Message.c_str(), IID_IButtonX);
}
return S_OK;
};
STDMETHODIMP TButtonXImpl::set_Caption(BSTR Value)
{
try
{
}
catch(Exception &e)
{
return Error(e.Message.c_str(), IID_IButtonX);
}
return S_OK;
};
Généralement, vous pouvez implémenter ces méthodes par simple délégation au
contrôle VCL associé auquel vous avez accès en utilisant le membre m_VclCtl de
la classe enveloppe :
STDMETHODIMP TButtonXImpl::get_Caption(BSTR* Value)
{
try
{
*Value = WideString(m_VclCtl->Caption).Copy();
}
catch(Exception &e)
{
return Error(e.Message.c_str(), IID_IButtonX);
}
return S_OK;
};
STDMETHODIMP TButtonXImpl::set_Caption(BSTR Value)
{
try
{
m_VclCtl->Caption = AnsiString(Value);
}
catch(Exception &e)
{
return Error(e.Message.c_str(), IID_IButtonX);
}
return S_OK;
};
Dans certains cas, vous avez besoin d’ajouter du code pour convertir les types de
données COM en types natifs C++. L’exemple précédent le fait en utilisant le
transtypage.
Ajout d’événement
Le contrôle ActiveX peut déclencher des événements dans son conteneur de la
même manière qu’un objet automation déclenche des événements dans ses
clients. Ce mécanisme est décrit dans “Exposition d’événements aux clients” à la
page 41-11.
Si le contrôle VCL que vous utilisez comme base pour votre contrôle ActiveX a
des événements publiés, l’expert ajoute automatiquement le traitement de la liste
d’événements client à la classe enveloppe ActiveX et définit la dispinterface de
sortie que les clients doivent implémenter pour répondre aux événements.
Pour pouvoir déclencher des événements dans le conteneur, votre classe
enveloppe ActiveX doit implémenter un gestionnaire d’événement pour
l’événement dans l’objet VCL. Ce gestionnaire d’événement appelle la méthode
Fire_EventName qui est implémentée par la classe TEvents_CoClassName définie
dans l’unité _TLB :
void __fastcall TButtonXImpl::KeyPressEvent(TObject *Sender, char &Key)
{
short TempKey;
TempKey = (short)Key;
Fire_OnKeyPress(&TempKey);
Key = (short)TempKey;
};
Vous devez ensuite affecter ce gestionnaire d’événement au contrôle VCL afin
qu’il soit appelé quand l’événement se produit. Pour ce faire, ajoutez
l’événement à la méthode InitializeControl qui apparaît dans la déclaration de la
classe enveloppe (dans l’en-tête de l’unité d’implémentation) :
void InitializeControl()
{
m_VclCtl->OnClick = ClickEvent;
m_VclCtl->OnKeyPress = KeyPressEvent;
}
Remarque C’est l’application conteneur accueillant votre contrôle ActiveX qui est
responsable de la connexion avec la base de données des propriétés spécifiées
comme orientés données dans la bibliothèque de types. Pour des informations
sur l’écriture d’un tel conteneur avec C++Builder, voir “Utilisation de contrôles
ActiveX orientés données” à la page 40-9.
Utilisez la bibliothèque de types pour activer la liaison de données simple,
1 Dans la barre d’outils, cliquez sur la propriété à lier.
2 Choisissez la page Indicateurs.
3 Sélectionnez les attributs de liaison suivants :
persistent. Si ces propriétés ne sont pas publiées dans le contrôle VCL sous-
jacent, vous devez créer un descendant personnalisé du contrôle VCL qui
redéclare les propriétés comme publiées, et utiliser l’expert contrôle ActiveX pour
créer le contrôle ActiveX à partir de cette classe dérivée.
Actualisation de l’objet
Ajoutez du code à la méthode UpdateObject pour mettre à jour la propriété
quand l’utilisateur modifie les contrôles de la page de propriétés. Vous devez
ajouter du code à la méthode UpdateObject afin de définir la nouvelle valeur des
propriétés du contrôle ActiveX.
Utilisez la propriété OleObject pour accéder au contrôle ActiveX.
Par exemple, le code suivant affecte la propriété EditMask d’un contrôle ActiveX
en utilisant la valeur du contrôle boîte de saisie (InputMask) de la page de
propriétés :
void __fastcall TPropertyPage1::UpdateObject(void)
{
// Mettre à jour OleObject à partir de votre contrôle
OleObject.OlePropertySet<WideString>("EditMask", WideString(InputMast->Text).Copy());
}
Paquets et/ou
fichiers Compression
supplémentaires de fichier CAB Résultat
Non Non Un fichier bibliothèque ActiveX (OCX).
Non Oui Un fichier CAB contenant un fichier bibliothèque
ActiveX.
Oui Non Un fichier INF, un fichier bibliothèque ActiveX et
tous les paquets et/ou fichiers supplémentaires.
Oui Oui Un fichier INF, un fichier CAB contenant un
fichier bibliothèque ActiveX et un fichier CAB
pour chacun des fichiers et paquets
supplémentaires.
Activation juste-à-temps
La capacité d’un objet à être désactivé et réactivé alors que des clients continuent
à lui faire référence est nommée activation juste-à-temps. Vu du client, il existe
une seule instance de l’objet à partir du moment où le client l’a créée et jusqu’au
moment où il la libère. En réalité, il se peut que l’objet ait été désactivé et
réactivé de nombreuses fois. Les objets pouvant être ainsi désactivés, les clients
peuvent continuer de faire référence à un objet pendant un temps indéterminé
sans affecter les ressources du système. Lorsqu’un objet devient désactivé, toutes
les ressources de l’objet sont libérées. Ainsi quand un objet est désactivé, sa
connexion à la base de données est libérée et utilisable par d’autres clients.
Un objet transactionnel est créé à l’état désactivé et ne devient actif qu’à la
réception d’une requête d’un client. Quand l’objet transactionnel est créé, un
objet de contexte est également créé. Cet objet de contexte existe pendant
l’intégralité de la durée de vie de l’objet transactionnel correspondant, pendant
un ou plusieurs cycles de réactivation. L’objet de contexte, accessible via
l’interface IObjectContext permet de conserver une trace de l’objet quand il est
désactivé ou pendant les transactions de coordination.
Les objets transactionnels sont désactivés dès que cela peut se faire sans risque.
C’est la désactivation dès-que-possible. Un objet transactionnel est désactivé
lorsqu’un des événements suivants se produit :
• L’objet demande la désactivation avec SetComplete ou SetAbort : Un objet
appelle la méthode SetComplete de IObjectContext lorsqu’il a terminé son travail
avec succès et qu’il n’a pas besoin de sauver l’état interne de l’objet pour un
prochain appel du client. Un objet appelle SetAbort pour indiquer qu’il ne
peut terminer son travail avec succès et que l’état de l’objet n’a pas besoin
d’être sauvé, c’est-à-dire que l’objet reprend l’état qu’il avait avant la
transaction. Souvent, les objets sont conçus sans état, ce qui signifie que les
objets sont désactivés après le retour de toutes les méthodes.
• Une transaction est validée ou annulée : Lorsqu’une transaction sur un objet
est validée ou annulée, l’objet est désactivé. Parmi ces objets désactivés, les
seuls qui continuent à exister sont ceux à qui des clients hors transaction sont
en train de faire référence. Les prochains appels à ces objets les réactivent et
les font s’exécuter dans la prochaine transaction.
• Le dernier client libère l’objet : Bien sûr, lorsqu’un client libère l’objet, il est
désactivé et l’objet de contexte également.
Remarque Quand vous installez un objet transactionnel sous COM+ depuis l’EDI, vous
pouvez spécifier si l’objet utilise l’activation juste-à-temps en utilisant la page
• Si vous utilisez les composants base de données ADO pour vous connecter à
vos données, le fournisseur de ressources est fourni par ADO.
Remarque Il n’y a pas de fournisseur de ressources prédéfini si vous utilisez les
composants InterbaseExpress pour accéder à vos données.
Pour les modules de données transactionnels distants, les connexions sont
automatiquement intégrées dans des objets transactions et le fournisseur de
ressources peut automatiquement récupérer et réutiliser les connexions.
public:
};
// SHAREDPROPERTYEXAMPLEIMPL : Implémentation de TSharedPropertyExampleImpl
#include <vcl.h>
#pragma hdrstop
#include "SHAREDPROPERTYEXAMPLEIMPL.H"
STDMETHODIMP TSharedPropertyExampleImpl::Activate()
{
static TMtsDll Mts;
HRESULT hr = E_FAIL;
hr = Mts.Get_ObjectContext(&m_spObjectContext);
if (SUCCEEDED(hr))
{
VARIANT_BOOL _false = VARIANT_FALSE;
VARIANT_BOOL _true = VARIANT_TRUE;
CoCreateInstance( CLSID_SharedPropertyGroupManager, NULL, CLSCTX_INPROC_SERVER,
IID_ISharedPropertyGroupManager, (void**)manager);
manager->CreatePropertyGroup(L"Test Group", LockSetGet, Standard, &_false, &PG13);
if ( (PG13->CreateProperty(L"Counter", &_true, &Counter)) == S_OK)
{
Counter->put_Value(TVariant(0));
}
return S_OK;
}
return hr;
}
STDMETHODIMP_(BOOL) TSharedPropertyExampleImpl::CanBePooled()
{
return FALSE;
}
STDMETHODIMP_(void) TSharedPropertyExampleImpl::Deactivate()
{
PG13->Release();
manager->Release();
m_spObjectContext.Release();
}
STDMETHODIMP TSharedPropertyExampleImpl::IncrementCounter()
{
try
{
TVariant temp;
Counter->get_Value(&temp);
temp=(int)temp+1;;
Counter->put_Value(temp);
}
catch(Exception &e)
{
return Error(e.Message.c_str(), IID_ISharedPropertyExample);
}
return S_OK;
};
Regroupement d’objets
Tout comme vous pouvez regrouper des ressources, vous pouvez avec COM+
regrouper des objets. Quand un objet est désactivé, COM+ appelle la méthode
CanBePooled de l’interface, qui indique que l’objet peut être regroupé afin d’être
réutilisé. Si CanBePooled renvoie true, au lieu d’être détruit quand il est désactivé,
l’objet est déplacé dans le groupe d’objets. Il y reste pour une durée limitée
durant laquelle il est disponible si un client en fait la demande. C’est seulement
quand le groupe d’objets est vide qu’une nouvelle instance de l’objet est créée.
Les objets qui renvoient false ou qui ne gèrent pas l’interface IObjectControl sont
détruits quand il sont désactivés.
Le regroupement d’objets n’est pas disponible avec MTS. MTS appelle
CanBePooled comme indiqué, mais le regroupement n’est pas effectué. De ce fait,
quand l’expert crée des objets transactionnels, la méthode CanBePooled générée
renvoie toujours false. Si votre objet est utilisé uniquement avec COM+ et si
vous voulez utiliser le regroupement d’objets, recherchez cette méthode dans
l’unité d’implémentation et modifiez-la pour renvoyer true.
Même si la méthode CanBePooled d’un objet renvoie true, il peut être configuré
afin que COM+ ne le place pas dans le regroupement d’objets. Si vous installez
l’objet transactionnel dans COM+ depuis l’EDI, vous pouvez spécifier si COM+
doit essayer de regrouper l’objet en utilisant la page COM+ de l’éditeur de
bibliothèques de types. Sélectionnez l’objet (la coclasse) dans l’éditeur de
bibliothèques de types, allez sur la page COM+ et cochez ou non la case Pooling
d’objets. Par ailleurs, un administrateur système peut spécifier cet attribut en
utilisant le gestionnaire de composant COM+.
De la même façon, vous pouvez configurer la durée durant laquelle un objet
désactivé reste dans le regroupement d’objets avant d’être libéré. Pour ce faire,
utilisez le paramètre Délai maxi de création dans la page COM+ de l’éditeur de
bibliothèques de types. Ici encore, l’administrateur système peut spécifier cet
attribut en utilisant le gestionnaire de composants COM+.
Attributs transactionnels
Chaque objet transactionnel a un attribut transactionnel stocké dans le catalogue
MTS ou recensé dans COM+.
C++Builder permet de définir l’attribut transactionnel à la conception en utilisant
l’expert objet transactionnel ou l’éditeur de bibliothèques de types.
Chaque attribut transactionnel peut être défini par une des valeurs suivantes :
Remarque Ces modèles de threads sont semblables à ceux définis par les objets COM.
Cependant, comme MTS et COM+ fournissent une meilleure gestion des threads,
Activités
Outre le modèle de thread, les objets transactionnels supporte les accès
simultanés via les activités. Les activités sont enregistrées dans le contexte de
l’objet et l’association entre un objet et une activité ne peut être modifiée. Une
activité comprend l’objet transactionnel créé par le client de base, ainsi que tous
les objets transactionnels créés par cet objet et ses descendants. Ces objets
peuvent être distribués dans un ou plusieurs processus s’exécutant sur un ou
plusieurs ordinateurs.
Par exemple, une application destinée à des médecins peut posséder un objet
transactionnel ajoutant des mises à jour et supprimant des enregistrements dans
plusieurs bases de données médicales, chacune représentée par un objet différent.
Cet objet d’ajout peut utiliser également d’autres objets, comme un objet de
réception qui enregistre la transaction. Il en résulte plusieurs objets
transactionnels qui sont, soit directement, soit indirectement, sous le contrôle du
client de base. Ces objets appartiennent tous à la même activité.
MTS et COM+ suivent le flux d’exécution dans chaque activité, en empêchant
qu’un phénomène de parallélisme n’altère malencontreusement l’état de
l’application. Le résultat de cette fonctionnalité est l’unicité du thread logique
d’exécution pour toute une série d’objets potentiellement distribuables. Grâce à
ce thread logique unique, les applications sont nettement plus faciles à écrire.
Lorsqu’un objet transactionnel est créé à partir d’un contexte existant, en utilisant
soit un objet contexte transactionnel ou un objet contexte, le nouvel objet devient
membre de la même activité. Autrement dit, le nouveau contexte hérite de
l’identificateur d’activité du contexte utilisé pour le créer.
Il ne peut y avoir qu’un seul thread logique d’exécution pour une même activité.
Ce comportement est semblable à celui d’un modèle de thread apartment COM,
mais les objets peuvent être distribués dans plusieurs processus. Lorsqu’un client
de base fait appel à une activité, toutes les autres demandes de travail dans cette
activité (par exemple, celles provenant d’un autre thread client) sont bloquées
jusqu’à ce que le thread d’exécution initial revienne vers le client.
Avec MTS, chaque objet transactionnel appartient à une activité. Avec COM+,
vous pouvez configurer la manière dont l’objet participe aux activités en
initialisant la synchronisation d’appel. Les options suivantes sont disponibles :
Quand vous sortez, l’expert crée un projet contenant une bibliothèque de types
qui définit votre objet événement et son interface. Utilisez l’éditeur de
bibliothèques de types pour définir les méthodes de cette interface. Ces méthodes
sont les gestionnaires d’événements que les clients implémentent pour répondre
aux événements.
Le projet objet événement inclut le fichier projet unité _ATL pour importer les
modèles de classes ATL et l’unité _TLB pour définir les informations de la
bibliothèque de types. Il ne contient aucune unité d’implémentation car les objets
événement COM+ n’ont pas d’implémentation. L’implémentation de l’interface
est à la charge du client. Quand l’objet serveur appelle un objet événement
COM+, COM+ intercepte l’appel et le distribue aux clients recensés. Comme les
objets événement COM+ n’ont pas besoin d’objet implémentation, une fois que vous
avez défini l’interface de l’objet dans l’éditeur de bibliothèques de types, il vous
suffit de compiler le projet et de l’installer dans COM+
COM+ impose certaines restrictions sur les interfaces des objets événement.
L’interface définie dans l’éditeur de bibliothèques de types pour l’objet
événement doit respecter les règles suivantes :
• L’interface de l’objet événement doit dériver de IDispatch.
• Les noms de méthode doivent être uniques pour toutes les interfaces de l’objet
événement.
• Les méthodes de l’interface de l’objet événement doivent toutes renvoyer une
valeur HRESULT.
• Le modificateur de tous les paramètres de méthode doit être [in].
Une fois une telle référence transmise hors du contexte de l’objet, ce n’est plus
une référence valide.
Appeler SafeRef sur une référence déjà sécurisée renvoie la référence sécurisée
inchangée, mais le compteur de références sur l’interface est incrémenté.
Lorsqu’un client appelle QueryInterface sur une référence sécurisée, la référence
renvoyée au client est également sécurisée.
Un objet qui obtient une référence sécurisée doit libérer la référence sécurisée
lorsqu’elle ne lui est plus nécessaire.
Pour plus de détails concernant SafeRef, voir la rubrique SafeRef de la
documentation MTS.
Callbacks
Les objets peuvent faire des callbacks aux clients et aux autres objets
transactionnels. Par exemple, vous pouvez avoir un objet qui crée un autre objet.
L’objet créateur peut transmettre à l’objet créé une référence à lui-même ; l’objet
créé peut ensuite utiliser cette référence pour appeler l’objet qui l’a créé.
Si vous choisissez d’utiliser les callbacks, tenez compte des restrictions suivantes :
• Un callback au client de base ou à un autre paquet nécessite, sur le client, une
sécurité au niveau des accès. De plus, le client doit être un serveur DCOM.
• L’introduction de coupe-feux doit bloquer les callbacks vers le client.
• Le travail effectué par le callback s’exécute dans l’environnement de l’objet qui
est appelé. Il peut faire partie de la même transaction, d’une transaction
différente ou d’aucune transaction.
• Dans MTS, l’objet créateur doit appeler SafeRef et transmettre la référence
renvoyée à l’objet créé en vue de se rappeler lui-même.
COM+ dans lequel vous installez vos objets. Vous pouvez choisir Dans
nouveau paquet ou Dans nouvelle application pour créer un nouveau paquet
MTS ou une nouvelle application COM+ dans lequel installer les objets.
Choisissez Dans un paquet existant ou Dans une application existante pour
installer les objets dans un paquet MTS ou une application COM+ qui
existe déjà.
4 Choisissez OK pour rafraîchir le catalogue, ce qui rend les objets accessibles
lors de l’exécution.
Les paquets MTS peuvent contenir des composants issus de plusieurs DLL, et
des composants issus de la même DLL peuvent être installés dans différents
paquets. Cependant, un même composant ne peut être distribué entre plusieurs
paquets.
De même, des applications COM+ peuvent contenir des composants issus de
plusieurs exécutables et différents composants d’un même exécutable peuvent
être installés dans différentes applications COM+.
Remarque Vous pouvez également installer l’objet transactionnel en utilisant le gestionnaire
de composants COM+ ou l’explorateur MTS. Faites bien attention dans ce cas à
utiliser les mêmes paramètres pour l’objet que ceux apparaissant dans la page
COM+ de l’éditeur de bibliothèques de types. Ces paramètres ne sont pas
appliqués automatiquement si vous n’installez pas l’objet depuis l’EDI.
V
Création de composants
Partie V
personnalisés
Les chapitres de cette partie présentent les concepts nécessaires à la conception
et à l’implémentation de composants personnalisés dans C++Builder.
Bibliothèques de classes
Les composants de C++Builder résident dans deux hiérarchies de classes
appelées 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 suivante présente la relation qui existe entre
les classes sélectionnées qui composent la VCL. La hiérarchie CLX est similaire à
celle de la 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 46, “Programmation orientée objet et écriture des
composants”. Pour obtenir un aperçu des différences entre la VCL et la CLX,
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.
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
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.
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
actions spécifiques, telles des manipulations de la souris ou des frappes au
clavier. Le code qui s’exécute lorsqu’un événement survient est appelé le
gestionnaire de l’événement.
Les événements permettent aux développeurs d’applications de spécifier des
réponses différentes en fonction des actions possibles sans avoir à créer de
nouveaux composants.
Le chapitre 48, “Création d’événements”, explique comment implémenter des
événements standard et comment en définir de nouveaux.
Méthodes
Les méthodes de classes sont des fonctionsqui opèrent sur une classe plutôt que
sur des instances particulières de cette classe. Par exemple, les méthodes
constructeur de composants sont toutes des méthodes de classes. Les méthodes
de composants sont des 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 49, “Création de méthodes”, explique comment ajouter des méthodes
à vos composants.
Remarque Dans la liste déroulante, de nombreux composants sont présentés deux fois
avec des noms d’unité différents, un pour la VCL et l’autre pour la CLX. Les
unités spécifiques à la CLX commencent par Q (telles que QGraphics au lieu
de Graphics). Veillez à dériver à partir du bon composant.
2 Dans Nom de classe, spécifiez le nom de classe de votre nouveau composant.
3 Dans Page de palette, spécifiez la page de la palette dans laquelle vous voulez
installer le composant.
4 Dans Nom de fichier unité, spécifiez le nom de l’unité dans laquelle vous
voulez déclarer la classe du composant.
5 Si l’unité n’est pas dans le chemin de recherche, modifiez ce dernier.
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.
Attention Si vous dérivez un composant d’une classe de la VCL ou de la CLX 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.
C++Builder ne peut pas créer d’instance d’une classe ayant des propriétés ou des
méthodes abstraites.
Lorsque vous avez rempli les champs de l’expert composant, choisissez OK.
C++Builder crée une nouvelle unité composée d’un fichier .cpp et d’un fichier
en-tête associé.
Le fichier .cpp apparaît dans l’éditeur de code. Il contient un constructeur pour
le composant et la fonction Register qui recense le composant, indiquant à
C++Builder quel composant ajouter à la bibliothèque des composants et sur
quelle page de la palette de composants il doit figurer. Le fichier contient
également une instruction include spécifiant le fichier en-tête créé. Par exemple :
#include <vcl.h>
#pragma hdrstop
#include "NewComponent.h"
#pragma package(smart_init);
//---------------------------------------------------------------------------
// ValidCtrCheck est utilisé pour garantir que les composants créés n’ont pas
// de fonctions virtuelles pures.
//
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. “Comment créer un composant ?” à la page 45-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 46-1.
Pour dériver une classe de composant, ajoutez une déclaration de classe au
fichier en-tête.
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
à votre fichier en-tête :
class PACKAGE TNewComponent : public TComponent
{
};
Recensement du composant
Le recensement est une opération simple qui indique à C++Builder 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 52, “Accessibilité des composants au
moment de la conception”.
Pour recenser un composant,
1 Ajoutez une fonction appelée Register au fichier .CPP de l’unité, en la plaçant
à l’intérieur d’un espace de nommage. L’espace de nommage est le nom du
fichier dans lequel se trouve le composant, sans l’extension, tout en
minuscules sauf la première lettre.
//---------------------------------------------------------------------------
extern TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Pour l’instruction #include qui inclut le fichier NEWCTRL.H, il est supposé que
le composant réside dans le répertoire du projet en cours ou dans un répertoire
se trouvant dans le chemin d’inclusion du projet.
Voici le fichier .CPP de l’unité fiche :
#include <vcl\vcl.h>
#pragma hdrstop
#include "TestForm.h"
#include "NewCtrl.h"
//---------------------------------------------------------------------------
#pragma package(smart_init);
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
static inline TNewControl *ValidCtrCheck()
{
return new TNewControl(NULL);
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
NewControl1 = new TNewControl(this);
NewControl1->Parent = this;
NewControl1->Left = 12;
}
//---------------------------------------------------------------------------
namespace Newctrl
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TNewControl)};
RegisterComponents("Exemples", classes, 0);
}
}
Ajout du composant
Pour ajouter des composants à la bibliothèque de composants
1 Choisissez Composant|Installer un composant.
La boîte de dialogue Installation de composant apparaît.
2 Choisissez entre l’installation du nouveau composant dans un paquet existant
ou nouveau en choisissant la page appropriée.
3 Entrez le nom du fichier .CPP contenant le nouveau composant ou choisissez
Parcourir pour rechercher l’unité.
4 Ajustez le chemin de recherche si le fichier .CPP du nouveau composant ne se
trouve pas dans l’emplacement par défaut indiqué.
5 Spécifiez le nom du paquet dans lequel installer le composant ou choisissez
Parcourir pour localiser le paquet.
6 Si le composant est installé dans un nouveau paquet, vous pouvez également
spécifier une description du nouveau paquet.
7 Choisissez OK pour fermer la boîte de dialogue Installation de composants.
Cela compile/reconstruit le paquet et installe le composant dans la palette de
composants.
Remarque Les composants nouvellement installés apparaissent initialement dans la page de
la palette de composants qui a été spécifiée par le concepteur du composant.
Vous pouvez déplacer le composant dans une page différente après son
installation dans la palette en utilisant la boîte de dialogue Composant|
Configurer la palette.
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 int. 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.
Modifier les 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 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 53, “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.
N’oubliez pas d’inclure la macro PACKAGE (définie dans Sysmac.h), qui permet
l’importation et l’exportation de classes.
Une déclaration de composant achevée comprend la déclaration des propriétés,
des données membres et des méthodes avant l’accolade fermante. Mais une
déclaration vide avant l’accolade fermante est également admise et représente un
point de départ pour l’ajout de fonctionnalités supplémentaires à votre
composant.
TTestForm *TestForm;
//---------------------------------------------------------------------------
__fastcall TTestForm::TTestForm(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TTestForm::FormCreate(TObject *Sender)
{
SecretForm->FSecretCode = 13; // le compilateur s’arrête en donnant un message d’erreur
}
Bien qu’un programme utilisant l’unité HideInfo puisse utiliser les classes de type
TSecretForm, il ne peut accéder à la donnée membre FSecretCode dans aucune de
ces classes.
CLX Les noms et les emplacements de certains fichiers d’en-tête sont différents dans
les applications CLX. Par exemple, <vcl\controls.hpp> est <clx\qcontrols.hpp>
dans CLX.
Méthodes standard
Les méthodes d’une classe sont considérées comme standard (non virtuelles) sauf
si vous les déclarez virtuelles ou si elles surchargent une méthode virtuelle d’une
classe de base. Le compilateur peut déterminer l’adresse exacte de la méthode au
moment de la compilation, ce qui constitue la liaison au moment de la
compilation.
Les méthodes standard d’une classe de base sont transmises aux classes dérivées
de celle-ci. Dans l’exemple ci-dessous, un objet de type Derived peut appeler la
méthode Regular() comme si c’était sa propre méthode. Déclarer une méthode
dans une classe dérivée ayant le même nom et les mêmes paramètres qu’une
méthode standard de l’ancêtre de la classe remplace la méthode de l’ancêtre.
Dans notre exemple, lorsque d->AnotherRegular() est appelée, c’est la méthode qui
remplace AnotherRegular() dans la classe Derived qui est appelée.
class Base
{
public:
void Regular();
void AnotherRegular();
virtual void Virtual();
};
class Derived : public Base
{
public:
void AnotherRegular(); // remplace Base::AnotherRegular()
void Virtual(); // surcharge Base::Virtual()
};
void FunctionOne()
{
Derived *d;
d = new Derived;
d->Regular(); // appel de Regular() comme si c’était un membre de Derived
// identique à l’appel de d->Base::Regular()
d->AnotherRegular(); // appel de AnotherRegular() redéfini, ...
// ... en remplacement de Base::AnotherRegular()
delete d;
}
Méthodes virtuelles
Contrairement aux méthodes standard, dont la liaison est effectuée au moment
de la compilation, les méthodes virtuelles sont liées au moment de l’exécution. Le
mécanisme virtuel de C++ permet à une méthode d’être appelée selon le type de
classe utilisé pour invoquer cette méthode.
Dans l’exemple précédent, si vous appelez FunctionTwo() avec un pointeur sur un
objet Derived, la fonction Derived::Virtual() sera appelée. Le mécanisme virtuel
inspecte le type de classe de l’objet transmis à l’exécution et conduit à la
méthode appropriée. Cependant, l’appel de la fonction standard
b->AnotherRegular() appellera toujours Base::AnotherRegular() car l’adresse de
AnotherRegular() a été déterminée au moment de la compilation.
Pour déclarer une nouvelle méthode virtuelle, vous devez faire précéder la
déclaration par le mot réservé virtual.
Lorsque le compilateur rencontre le mot réservé virtual, il crée une entrée dans
la table des méthodes virtuelles de la classe. Cette VMT (virtual method table)
contient les adresses de toutes les méthodes virtuelles d’une classe. Cette table de
références est utilisée à l’exécution pour déterminer que b->Virtual doit appeler
Derived::Virtual(), et non Base::Virtual().
Lorsque vous dérivez une nouvelle classe à partir d’une classe existante, la
nouvelle classe reçoit sa propre VMT, comprenant les entrées des VMT de ses
ancêtres ainsi que les méthodes virtuelles supplémentaires déclarées dans la
nouvelle classe. En outre, la classe descendante peut surcharger toute méthode
virtuelle dont elle hérite.
Classes et pointeurs
Chaque classe (et par conséquent chaque composant) est en fait un pointeur.
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.
47
Création de propriétés
Chapitre 47
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.
• Les données membres utilisées pour stocker les données d’une propriété sont
déclarées private et ne peuvent être accédées qu’à partir du composant
lui-même. Les composants dérivés doivent utiliser la propriété héritée ; ils ne
nécessitent pas un accès direct au stockage interne des données de la
propriété.
• Les identificateurs de ces données membres sont composés de la lettre F
suivie du nom de la propriété. Par exemple, la donnée brute de la propriété
Width définie pour TControl est stockée dans une donnée membre appelée
FWidth.
Le principe qui sous-tend ces conventions est le suivant : seules les méthodes
d’implémentation d’une propriété doivent pouvoir accéder aux données associées
à cette propriété. Si une méthode ou une autre propriété a besoin de changer ces
données, elle doit le faire via la propriété et non directement par un accès aux
données stockées. Cela garantit que l’implémentation d’une propriété héritée
puisse être modifiée sans invalider les composants dérivés.
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 la donnée membrede 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.
class PACKAGE TSampleComponent : public TComponent
{
private: // le stockage interne est privé
bool FReadOnly; // déclare la donnée membre pour contenir la valeur
ƒ
__published: // rendre la propriété disponible à la conception
__property bool ReadOnly = {read=FReadOnly, write=FReadOnly};
};
Méthodes d’accès
Vous pouvez spécifier une méthode d’accès plutôt qu’une donnée membredans
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 :
class PACKAGE TSampleCalendar : public TCustomGrid
{
private:
int __fastcall GetDateElement(int Index); // remarquez le paramètre Index
void __fastcall SetDateElement(int Index, int Value);
public:
__property int Day = {read=GetDateElement, write=SetDateElement, index=3, nodefault};
__property int Month = {read=GetDateElement, write=SetDateElement, index=2, nodefault};
__property int Year = {read=GetDateElement, write=SetDateElement, index=1, nodefault};
};
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 :
int __fastcall TSampleCalendar::GetDateElement(int Index)
{
unsigned short AYear, AMonth, ADay;
int result;
FDate.DecodeDate(&AYear, &AMonth, &Aday); // décompose la date en éléments
switch (Index)
{
case 1: result = AYear; break;
case 2: result = AMonth; break;
case 3: result = ADay; break;
default: result = -1;
}
return result;
}
Voici la méthode write qui définit l’élément date approprié :
void __fastcall TSampleCalendar::SetDateElement(int Index, int Value)
{
unsigned short AYear, AMonth, ADay;
if (Value > 0) // tous les éléments doivent être positifs
{
FDate.DecodeDate(&AYear, &AMonth, &ADay); // obtient les éléments de la date
switch (Index)
{
case 1: AYear = Value; break;
case 2: AMonth = Value; break;
case 3: ADay = Value; break;
default: return;
}
}
FDate = TDateTime(AYear, AMonth, ADay); // code la date modifiée
Refresh();// met à jour le calendrier visible
}
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 47-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.
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 fonction membre 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.
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 une donnée membre appelée FCount.
void __fastcall TMyComponent::SetCount( int Value )
{
if ( Value != FCount )
{
FCount = Value;
Update();
}
break;
default: Result = "Taille inconnue";
}
return Result;
}
FTimer->FreeNotification(this);
}
else // valeur NULL
{
if (FTimer && FTimer->Owner != this)
{
FTimer = new ExtCtrls::TTimer(this);
FTimer.SetSubComponent(true);
FTimer->FreeNotification(this);
}
}
}
}
Notez que la méthode de définition de propriété ci-dessus a appelé la méthode
FreeNotification du composant affecté à la propriété. Cet appel garantit que le
composant représentant la valeur de la propriété envoie une notification s’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 redéfinissant la méthode Notification,
comme suit :
void __fastcall TDemoComponent::Notification(Classes::TComponent *AComponent,
Classes::TOperation Operation)
{
TComponent::Notification(AComponent, Operation); { appelle la méthode héritée }
if ((Operation == opRemove) && (AComponent == (TComponent *)FTimer))
FTimer = NULL;
}
• Détermination du stockage
• Initialisation après chargement
• Stockage et chargement des propriétés non publiées
stockage en mémoire est 0. Par défaut, les nombres valent donc 0, les booléens
false, les pointeurs NULL, etc. En cas de doute, affectez une valeur dans la
méthode du constructeur.
Le code suivant montre la déclaration d’un composant qui attribue une valeur
par défaut à la propriété Align, ainsi que l’implémentation du constructeur du
composant qui affecte cette valeur. Dans notre exemple, le nouveau composant
est un cas particulier du composant volet standard utilisé en tant que barre
d’état dans une fenêtre. Il doit donc implicitement s’aligner sur la bordure
inférieure de son propriétaire.
class PACKAGE TMyStatusBar : public TPanel
{
public:
virtual __fastcall TMyStatusBar(TComponent* AOwner);
__published:
__property Align = {default=alBottom};
};
Le constructeur du composant TMyStatusBar se trouve dans le fichier .CPP :
__fastcall TMyStatusBar::TMyStatusBar (TComponent* AOwner)
: TPanel(AOwner)
{
Align = alBottom;
}
Détermination du stockage
Vous pouvez choisir si C++Builder 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étermine dynamiquement le stockage de la
propriété.
Pour contrôler le stockage par C++Builder d’une propriété :
1 Ajoutez un signe égal (=) après le nom de la propriété.
2 Après le signe égal, ajoutez des accolades ({}).
3 A l’intérieur des accolades, tapez le mot clé stored, suivi de true, false ou du
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 :
class PACKAGE TSampleComponent : public TComponent
{
protected:
bool __fastcall StoreIt();
public:
ƒ
__published:
48
Création d’événements
Chapitre 48
TNotifyEvent FOnClick;
ƒ
protected:
__property TNotifyEvent OnClick = {read=FOnClick, write=FOnClick};
ƒ
};
Pour en savoir davantage sur TNotifyEvent et sur les autres types d’événements,
voir la prochaine section, “Les types d’événements sont des types de closures”.
Comme pour toute autre propriété, vous pouvez définir ou modifier la valeur d’un
événement au moment de l’exécution. L’avantage principal des événements
implémentés sous la forme de propriétés est que l’utilisateur de composant peut lui
associer un gestionnaire au moment de la conception à l’aide de l’inspecteur
d’objets.
Dans un cas comme celui-là, l’utilisateur doit définir le gestionnaire suivant pour
gérer les frappes de touche :
void __fastcall TForm1::Edit1KeyPress(TObject *Sender, Char &Key)
{
Key = UpCase(Key);
}
Vous pouvez également utiliser des arguments passés par référence pour
permettre à l’utilisateur de surcharger la gestion par défaut.
Comme les événements standard de TControl, les événements des contrôles fenêtrés
disposent de méthodes correspondantes. Les événements de touches standard
présentés ci-dessus répondent à toutes les frappes de touches normales.
VCL 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 51, “Gestion des messages et des notifications
système”, pour plus d’informations sur l’écriture de gestionnaires de messages.
Par exemple, pour créer un composant qui rende visible en mode conception
l’événement OnClick, ajoutez les lignes suivantes à la déclaration de classe
du composant.
class PACKAGE TMyControl : public TCustomControl
{
ƒ
__published:
__property OnClick; // Rend OnClick disponible dans l’inspecteur d’objets
};
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.
CLX Pour les applications CLX, voir “Réponse aux notifications du système à l’aide
de CLX” à la page 51-11.
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 closureet 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.
Le fait de rassembler tous les appels à un événement en un seul endroit vous
permet d’être sûr qu’un programmeur, qui dérive un nouveau composant à
partir du vôtre, pourra personnaliser la gestion de l’événement en surchargeant
cette méthode sans avoir à parcourir votre code pour repérer les endroits où
l’événement est appelé.
Deux autres considérations sont à prendre en compte concernant l’appel de
l’événement :
• Les gestionnaires vides doivent être valides.
• Les utilisateurs peuvent surcharger la gestion par défaut.
Un gestionnaire vide doit produire le même effet qu’un gestionnaire absent. Aussi,
le code pour appeler le gestionnaire d’événement dans une application doit
ressembler à ceci :
if (OnClick)
OnClick(this);
// exécute la gestion par défaut
Il ne doit en aucun cas ressembler à ceci :
if (OnClick)
OnClick(this);
else
// exécute la gestion par défaut
49
Création de méthodes
Chapitre 49
Graphiques et composants
Chapitre 50
50
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. C++Builder 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 C++Builder. Toutefois, vous vous
rendrez vite compte que l’utilisation de l’encapsulation C++Builder des fonctions
graphiques est un moyen plus efficace et plus rapide de créer des graphiques.
CLX Les fonctions GDI sont particulières à Windows et ne s’appliquent pas aux
applications CLX ou multiplates-formes. 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
les pinceaux et les fontes. Après avoir tracé vos images, vous devez remettre
le contexte de périphérique dans son état initial avant de le restituer.
Pour vous épargner la gestion de vos graphiques à un niveau détaillé,
C++Builder fournit une interface à la fois simple et complète : il s’agit de la
propriété Canvas des composants. Le canevas garantit qu’un contexte de
périphérique valide est disponible et restitue le contexte lorsqu’il est inutilisé.
Il dispose également de propriétés spécifiques pour représenter la fonte, le
crayon et le pinceau en cours.
Le canevas gère toutes ces ressources à votre place et vous n’avez donc pas le
souci de créer, de sélectionner ou de restituer les éléments comme le handle d’un
crayon. Vous n’avez qu’à indiquer au canevas le crayon à utiliser et il se charge
du reste.
L’un des avantages de laisser C++Builder gérer les ressources graphiques à votre
place est que C++Builder peut mettre en mémoire cache les ressources en vue
d’un usage ultérieur, ce qui accélère considérablement les opérations répétitives.
Par exemple, supposons qu’un programme crée, utilise puis restitue un outil
crayon d’un certain type plusieurs fois de suite, vous devez répéter ces étapes
chaque fois que vous l’utilisez. Comme C++Builder stocke en mémoire cache les
ressources graphiques, il y a une forte probabilité qu’un outil que vous utilisez
de façon répétitive se trouve dans la mémoire cache. Aussi, au lieu de recréer
l’outil en question, C++Builder se contentera de réutiliser celui qui existe déjà.
Par exemple, vous pouvez imaginer une application avec des dizaines de fiches
ouvertes et des centaines de contrôles. Chacun de ces contrôles peut présenter
une ou plusieurs propriétés TFont. Comme cela peut générer des centaines ou
des milliers d’instances d’objets TFont, la plupart des applications n’utiliseront
que deux ou trois handles de fontes grâce à un cache de fontes.
Voici deux exemples montrant à quel point le code C++Builder manipulant des
graphiques peut être simple. Le premier utilise les fonctions GDI standard pour
dessiner une ellipse jaune bordée de bleu comme le ferait d’autres outils de
développement. Le second utilise un canevas pour dessiner la même ellipse dans
une application écrite avec C++Builder.
Voici le code ObjectWindows :
void TMyWindow::Paint(TDC& PaintDC, bool erase, TRect& rect)
{
HPEN PenHandle, OldPenHandle;
HBRUSH BrushHandle, OldBrushHandle;
PenHandle = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
OldPenHandle = SelectObject(PaintDC, PenHandle);
BrushHandle = CreateSolidBrush(RGB(255, 255, 0));
OldBrushHandle = SelectObject(PaintDC, BrushHandle);
Ellipse(10, 20, 50, 50);
SelectObject(OldBrushHandle);
DeleteObject(BrushHandle);
SelectObject(OldPenHandle);
DeleteObject(PenHandle);
)
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 VCL, offre un accès de bas niveau au GDI
Windows.
Le tableau suivant 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 C++Builder :
• 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 :
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Image1->Picture->LoadFromFile("c:\\windows\\athena.bmp");
}
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.
LRESULT MyWndProc( HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam )
{
switch( Message )
{
HANDLE_MSG( hwnd, WM_KEYDOWN, MyKeyDownHandler );
ƒ
}
Ce style de décomposition des messages rend plus évidente la répartition des
messages entre les différents gestionnaires. Vous pouvez également donner des
noms significatifs aux paramètres de votre fonction gestionnaire. Il est plus facile
de comprendre une fonction dont un paramètre s’appelle nVirtKey, qui est la
valeur de wParam dans un message WM_KEYDOWN.
Les méthodes WndProc vérifient les conditions spéciales qui peuvent affecter le
traitement et “interceptent”, s’il le faut, les messages non souhaités. Par exemple,
lorsque vous faites glisser un composant, celui-ci ignore les événements du clavier,
et la méthode WndProc de TWinControl ne transmet ces événements que si
l’utilisateur ne fait pas glisser le composant. Enfin, WndProc appelle Dispatch, une
méthode non virtuelle héritée de TObject, qui détermine la méthode à appeler pour
gérer le message.
Dispatch utilise le champ de données Msg de l’enregistrement du message pour
déterminer comment répartir le message particulier. Si le composant définit un
gestionnaire pour ce message, Dispatch appelle cette méthode. Si aucun gestionnaire
n’est défini, Dispatch appelle DefaultHandler.
Le composant TControl définit des plages entières de messages liés à la souris qu’il
filtre lorsqu’un utilisateur fait glisser puis lâche un contrôle. Une méthode WndProc
surchargée peut agir par deux moyens :
• Elle peut filtrer des plages entières de messages au lieu de spécifier un
gestionnaire pour chacun d’eux.
• Elle peut inhiber totalement la répartition des messages de façon à ce que les
gestionnaires ne soient jamais appelés.
Voici une partie d’une méthode WndProc pour un TControl telle qu’elle est
implémentée dans la VCL du Pascal Objet :
procedure TControl.WndProc(var Message: TMessage);
begin
ƒ
if (Message.Msg >= WM_MOUSEFIRST) and (Message.Msg <= WM_MOUSELAST) then
if Dragging then { gestion spécifique d’une opération glisser }
DragMouseMsg(TWMMouse(Message))
else
ƒ { gestion normale des autres opérations }
end;
ƒ { autrement gestion normale }
end;
à 1 024. Lorsque vous déclarez vos propres messages, vous devez donc toujours
débuter par un numéro supérieur.
La constante WM_APP représente le numéro de départ pour les messages définis
par l’utilisateur. Lorsque vous définissez un identificateur de message, utilisez
WM_APP.
Notez que certains contrôles Windows standard utilisent des messages compris
dans la plage des messages utilisateur. Entre autres contrôles, il y a les boîtes
liste, les boîtes à options, les boîtes de saisie et les boutons de commande. Si
vous dérivez un composant à partir de l’un d’eux et si vous voulez lui associer
un nouveau message, vérifiez le contenu du fichier MESSAGES.HPP pour voir
quels messages Windows sont déjà définis pour ce contrôle.
Le code suivant définit deux messages utilisateur :
#define MY_MYFIRSTMESSAGE (WM_APP + 400)
#define MY_MYSECONDMESSAGE (WM_APP + 401)
• Vous pouvez savoir quel contrôle notifier, mais ne pas connaître son type.
Comme vous ne connaissez pas le type du contrôle cible, vous ne pouvez
utiliser aucune de ses méthodes spécialisées, mais tous les contrôles offrant
des fonctionnalités de gestion des messages, vous pouvez toujours lui envoyer
un message. Si le contrôle dispose d’un gestionnaire pour le message que
vous envoyez, il répondra de façon appropriée. Sinon, il ignorera le message
envoyé et renverra 0.
Pour appeler la méthode Perform, vous n’avez pas besoin de créer une structure
message. Il suffit de passer comme paramètres l’identificateur du message,
WParam et LParam. Perform renvoie le message résultant.
Remarque Les méthodes de chaque objet intercepteur sont déclarées dans l’unité Qt.
Consultez qt.hpp pour voir les méthodes disponibles pour un objet intercepteur
donné. 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 Pascal Objet puisse accéder
aux méthodes depuis l’objet intercepteur C++.
TWidgetControl::HookEvents();
}
Tableau 51.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 suivant
contient la liste de ces méthodes.
Tableau 51.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 quand 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.
switch (QEvent_type(Event))
{
case QEventType_Resize:
case QEventType_FocusIn:
case QEventType_FocusOut:
UpdateMask();
}
return retval;
}
Ecriture de la fonctionRegister
Dans la fonction Register d’une unité contenant des composants, vous devez
recenser chaque composant que vous voulez ajouter à la palette des composants.
Si l’unité contient plusieurs composants, vous pouvez les recenser en une
seule fois.
Pour recenser un composant, appelez la fonction RegisterComponents pour
chacune des pages de la palette auxquelles vous souhaitez ajouter des
composants. RegisterComponents nécessite trois informations importantes :
1 Spécification des composants
2 Spécification de la page de palette
3 Utilisation de la fonction RegisterComponents
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 C++Builder 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.
Les rubriques de propriété, d’événement et de méthode doivent inclure une
note de bas de page K qui indique le nom de la propriété, de l’événement et
Tableau 52.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
Closure (événement) GetMethodValue SetMethodValue
Type ordinal GetOrdValue SetOrdValue
Chaîne GetStrValue SetStrValue
Lorsque vous surchargez une méthode GetValue, appelez l’une des méthodes
“Get”. Lorsque vous surchargez SetValue, appelez l’une des méthodes “Set”.
Les méthodes Edit utilisent les mêmes méthodes “Get” et “Set” utilisées dans les
méthodes GetValue et SetValue ; une méthode Edit appelle à la fois une méthode
“Get” et une méthode “Set”. Comme l’éditeur est spécifique du type, il est
habituellement inutile de convertir les valeurs des propriétés en chaînes.
L’éditeur traite généralement la valeur telle qu’elle a été récupérée.
Lorsque l’utilisateur clique sur le bouton ‘...’ à côté de la propriété, ou double-
clique sur la colonne des valeurs, l’inspecteur d’objets appelle la méthode Edit de
l’éditeur de propriétés.
Pour votre implémentation de la méthode Edit, suivez ces étapes :
1 Construisez l’éditeur que vous utilisez pour cette propriété.
2 Lisez la valeur en cours et attribuez-la à la propriété en utilisant
une méthode “Get”.
3 Lorsque l’utilisateur sélectionne une nouvelle valeur, attribuez cette valeur
à la propriété en utilisant une méthode “Set”.
4 Détruisez l’éditeur.
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 :
virtual __fastcall TPropertyAttributes TColorProperty::GetAttributes()
{
return TPropertyAttributes() << paMultiSelect << paDialog << paValueList << paRevertable;
}
Catégories de propriété
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
fait apparaître une boîte de dialogue. GetVerb possède un paramètre unique pour
indiquer l’index de la commande.
Le code suivant surcharge les méthodes GetVerbCount et GetVerb pour ajouter
deux commandes au menu contextuel.
int __fastcall TMyEditor::GetVerbCount(void)
{
return 2;
}
System::AnsiString __fastcall TMyEditor::GetVerb(int Index)
{
switch (Index)
{
case 0: return “&DoThis ...”; break;
case 1: return “Do&That”; break;
}
}
Remarque Veillez à ce que votre méthode GetVerb renvoie une valeur pour chaque index
possible indiqué par GetVerbCount.
Modification Chapitre 53
53
d’un composant existant
Le moyen le plus simple de créer un composant consiste à le dériver d’un
composant qui réalise la presque totalité des fonctions souhaitées et lui apporter
ensuite quelques modifications. L’exemple de ce chapitre modifie le composant
mémo standard pour créer un mémo qui présente un fond jaune. Les autres
chapitres de cette partie décrivent la création de composants plus complexes.
Le processus de base est toujours le même, mais les composants plus complexes
requièrent davantage d’étapes pour la personnalisation de la nouvelle classe.
La modification d’un composant existant se fait en deux étapes :
• Création et recensement du composant
• Modification de la classe composant
Remarque Cet exemple suppose que vous créez le composant manuellement, sans l’expert
composant. Si vous utilisez l’expert, un constructeur est automatiquement ajouté
à TYellowMemo.
Surcharge 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 constructeur
du composant définit les valeurs des propriétés. Quand un composant est chargé
depuis un fichier fiche, l’application définit toutes les propriétés qui ont été
modifiées lors de la conception.
Remarque Lorsque vous surchargez un constructeur, le nouveau constructeur doit appeler le
constructeur reçu en héritage avant toute autre action. Pour plus d’informations,
voir “Surcharge des méthodes” à la page 46-10.
Dans notre exemple, votre nouveau composant doit surcharger le constructeur
transmis en héritage par TMemo en attribuant la valeur clYellow à la propriété
Color. Pour ce faire, ajoutez la déclaration du constructeur surchargé à la
déclaration de la classe, puis écrivez le nouveau constructeur dans la partie .CPP
de l’unité :
class PACKAGE TYellowMemo : public TMemo
{
public:
virtual __fastcall TYellowMemo(TComponent* Owner); // déclaration du constructeur
__published:
__property Color;
};
__fastcall TYellowMemo::TYellowMemo(TComponent* Owner)
: TMemo(Owner) // l’implémentation du constructeur...
// commence par appeler le constructeur pour TMemo
{
Color = clYellow; // colore le composant en jaune
}
Remarque Si vous avez créé le composant à l’aide de l’expert composant, il vous suffit
d’ajouter Color = clYellow; au constructeur existant.
Vous pouvez maintenant installer le nouveau composant dans la palette des
composants puis l’ajouter dans une fiche. Notez que la propriété Color est
maintenant initialisée à clYellow.
• Recensez TSampleShape sur la page Exemples (ou une autre page dans CLX)
de la palette des composants.
Le fichier en-tête que vous obtenez doit ressembler à ceci :
//---------------------------------------------------------------------------
#ifndef ShapesH
#define ShapesH
//---------------------------------------------------------------------------
#include <sysutils.hpp>
#include <controls.hpp>
#include <classes.hpp>
#include <forms.hpp>
//---------------------------------------------------------------------------
class PACKAGE TSampleShape : public TGraphicControl
{
private:
protected:
public:
__published:
};
//---------------------------------------------------------------------------
#endif
Le fichier .CPP doit ressembler à ceci :
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Shapes.h"
//---------------------------------------------------------------------------
#pragma package(smart_init);
//---------------------------------------------------------------------------
// ValidCtrCheck est utilisé pour garantir que les composants créés n’ont pas
// de fonctions virtuelles pures.
//
CLX Les noms et les emplacements de certains fichiers d’en-tête sont différents
pour les applications CLX. Par exemple, <vcl\controls.hpp> est <clx\qcontrols.hpp>
dans CLX.
Déclaration de la propriété
Généralement, pour déclarer une propriété, vous déclarez une donnée membre
privée pour stocker les données de la propriété puis vous spécifiez les méthodes
pour lire et/ou é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 une donnée membre
contenant la forme courante, puis à déclarer une propriété qui lit cette donnée
membre et l’écrit via un appel de méthode.
ƒ
};
Dans le fichier SHAPES.CPP, affectez la méthode StyleChanged aux événements
OnChange des classes du crayon et du pinceau dans le constructeur
TSampleShape :
__fastcall TSampleShape::TSampleShape(TComponent* Owner) : TGraphicControl(Owner)
{
Width = 65;
Height = 65;
FBrush = new TBrush();
FBrush->OnChange = StyleChanged;
FPen = new TPen();
FPen->OnChange = StyleChanged;
}
Incluez l’implémentation de la méthode StyleChanged :
void __fastcall TSampleShape::StyleChanged( TObject* Sender)
{
Invalidate(); // repaints the component
}
Ces modifications faites, le composant se redessine pour refléter tout changement
du crayon ou du pinceau.
Remarque Si vous avez créé le composant à l’aide de l’expert composant, le fichier en-tête
déclarera également un nouveau constructeur et le fichier CALSAMP.CPP
débutera comme un constructeur. Si le constructeur est absent, vous pouvez
l’ajouter ultérieurement.
CLX Les noms et les emplacements de certains fichiers d’en-tête sont différents
pour les applications CLX. Par exemple, <vcl\controls.hpp> est <clx\qcontrols.hpp>
dans CLX.
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. C++Builder
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
{
FDate = Value; // définit la nouvelle valeur de la date
Refresh(); // met à jour l’image sur l’écran
}
switch (Index)
{
case 1: AYear = Value; break;
case 2: AMonth = Value; break;
case 3: ADay = Value; break;
default: return;
}
}
FDate = TDateTime(AYear, AMonth, ADay); // code la date modifiée
Refresh(); // mise à jour du calendrier visible
}
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.
Pour remplir les cellules avec les numéros de jour appropriés, procédez de la
façon suivante :
1 Ajoutez à la classe une donnée membre décalage de mois, ainsi qu’une
méthode pour mettre à jour la valeur de cette donnée membre :
class PACKAGE TSampleCalendar : public TCustomGrid
{
private:
int FMonthOffset; // stocke le décalage
ƒ
protected:
virtual void __fastcall UpdateCalendar(void);
ƒ
};
void __fastcall TSampleCalendar::UpdateCalendar(void)
{
unsigned short AYear, AMonth, ADay;
TDateTime FirstDate; // date du premier jour du mois
if ((int)FDate != 0) // ne calcule le décalage que si la date est valide
{
FDate.DecodeDate(&AYear, &AMonth, &ADay); // récupère les éléments de la date
FirstDate = TDateTime(AYear, AMonth, 1); // date du premier jour du mois
FMonthOffset = 2 - FirstDate.DayOfWeek(); // génère le décalage dans la grille
}
Refresh(); // toujours repeindre le contrôle
}
2 Ajoutez les instructions au constructeur et aux méthodes SetCalendarDate et
SetDateElement qui appellent la nouvelle méthode de mise à jour à chaque
changement de date :
__fastcall TSampleCalendar::TSampleCalendar(TComponent *Owner)
: TCustomGrid(Owner)
{
ƒ
UpdateCalendar();
}
void __fastcall TSampleCalendar::SetCalendarDate(TDateTime Value)
{
FDate = Value; // existait déjà
UpdateCalendar(); // appelait précédemment Refresh
}
void __fastcall TSampleCalendar::SetDateElement(int Index, int Value)
{
ƒ
FDate = TDateTime(AYear, AMonth, ADay); // existait déjà
UpdateCalendar(); // appelait précédemment Refresh
}
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 :
int __fastcall TSampleCalendar::DayNum(int ACol, int ARow)
{
int result = FMonthOffset + ACol + (ARow - 1) * 7; // calcule le jour pour cette cellule
Notez que vous réutilisez la variable ADay précédemment définie lors du décodage
de la date.
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 surcharger la
méthode Click de la grille.
Lorsque vous surchargez 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.
void __fastcall TSampleCalendar::Click()
{
int TempDay = DayNum(Col, Row); // récupère le numéro du jour de la cellule cliquée
if (TempDay != -1) Day = TempDay; // change le jour s’il est valide
}
protected:
virtual void __fastcall Change();
__published:
__property TNotifyEvent OnChange = {read=FOnChange, write=FOnChange};
ƒ
}
2 Ecrivez la méthode Change :
void __fastcall TSampleCalendar::Change()
{
if(FOnChange != NULL) FOnChange(this);
}
3 Ajoutez les instructions appelant Change à la fin des méthodes SetCalendarDate
et SetDateElement :
void __fastcall TSampleCalendar::SetCalendarDate(TDateTime Value)
{
FDate = Value;
UpdateCalendar();
Change(); // seule nouvelle instruction
}
void __fastcall TSampleCalendar::SetDateElement(int Index, int Value)
{
ƒ // instructions définissant des valeurs d’éléments
FDate = TDateTime(AYear, AMonth, ADay);
UpdateCalendar();
Change(); // ceci est nouveau
}
Les applications qui utilisent le composant calendrier peuvent maintenant répondre
aux changements en associant des gestionnaires à l’événement OnChange.
protected:
virtual bool __fastcall SelectCell(long ACol, long ARow);
public:
ƒ
virtual void __fastcall UpdateCalendar();
ƒ
};
bool __fastcall TDBCalendar::SelectCell(long ACol, long ARow)
{
if (!FUpdating && FReadOnly) return false; // sélection impossible si accès en
// lecture seule
return TSampleCalendar::SelectCell(ACol, ARow); // sinon, utilise la méthode héritée
}
void __fastcall TDBCalendar::UpdateCalendar()
{
FUpdating=true; // définit l’indicateur pour permettre
// les modifications
try
{
TSampleCalendar::UpdateCalendar(); // mise à jour normale
}
catch(...)
{
FUpdating = false;
throw;
}
FUpdating = false; // toujours effacer l’indicateur
}
Le calendrier n’autorise toujours pas les modifications directes de l’utilisateur
mais les modifications de la date effectuées via les propriétés de date sont prises
en compte. Vous disposez maintenant d’un contrôle en lecture seulement tout à
fait opérationnel. Vous voilà prêt à ajouter les fonctionnalités servant à scruter
les données.
FDataLink->Control = NULL;
FDataLink->OnUpdateData = NULL;
delete FDataLink;
}
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.
FDataLink->OnUpdateData = NULL;
FDataLink->OnDataChange = NULL; // détache le gestionnaire avant de...
delete FDataLink; // ... détruire l’objet lien aux données
}
Vous avez maintenant un contrôle de parcours des données.
//---------------------------------------------------------------------------
class PACKAGE TAboutBoxDlg : public TComponent
{
private:
protected:
public:
__published:
};
//---------------------------------------------------------------------------
#endif
Le fichier .CPP de l’unité doit ressembler à ceci :
#include <vcl\vcl.h>
#pragma hdrstop
#include "AboutDlg.h"
//---------------------------------------------------------------------------
#pragma package(smart_init);
//---------------------------------------------------------------------------
static inline TAboutBoxDlg *ValidCtrCheck()
{
return new TAboutBoxDlg(NULL);
}
//---------------------------------------------------------------------------
namespace AboutDlg {
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TAboutBoxDlg)};
RegisterComponents("Exemples", classes, 0);
}
}
Remarque Si vous avez utilisé l’expert composant pour élaborer ce composant, un
constructeur sera également ajouté à TAboutDlg.
CLX Les noms et les emplacements de certains fichiers d’en-tête sont différents
pour les applications CLX. Par exemple, <vcl\controls.hpp> est <clx\qcontrols.hpp>
dans 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.
protected:
public:
__published:
__property int Year = {read=FYear, write=FYear}; // la propriété et son stockage
};
S’agissant de votre boîte A propos de, vous devez disposer de quatre propriétés
de type string pour le nom du produit, les informations de version, les
informations de copyright et les commentaires éventuels. Le fichier
ABOUTDLG.H doit ressembler à ceci :
class PACKAGE TAboutBoxDlg : public TComponent
{
private:
int FYear;
String FProductName, FVersion, FCopyright, FComments;
protected:
public:
__published:
__property int Year = {read=FYear, write=FYear};
__property String ProductName = {read=FProductName, write=FProductName};
__property String Version = {read=FVersion, write=FVersion};
__property String Copyright = {read=FCopyright, write=FCopyright};
__property String Comments = {read=FComments, write=FComments};
};
Si vous installez votre composant dans la palette des composants et si vous le
placez dans une fiche, vous pourrez définir les propriétés, et ces valeurs
apparaîtront de façon permanente dans la fiche. Ainsi, lors de l’exécution de la
boîte de dialogue qu’il enveloppe, le composant pourra les utiliser.
}
catch(...)
{
Result = false; // en cas d’échec, affecte la valeur false à Result
}
DialogBox->Free(); // libère la fiche
}
En pratique, il y a davantage de code dans le gestionnaire d’exception. Plus
spécifiquement, avant l’appel à ShowModal, le composant enveloppe doit définir
certaines propriétés de la boîte de dialogue en fonction de ses propres propriétés
d’interface. A l’inverse, quand ShowModal rend la main, le composant enveloppe
définit certaines de ses propriétés d’interface en fonction du résultat de
l’exécution de la boîte de dialogue.
Dans le cas de la boîte A propos de, vous devez utiliser les quatre propriétés
d’interface du composant enveloppe pour définir le contenu des libellés de la
boîte de dialogue. Comme cette dernière ne renvoie aucune information à
l’application, il n’y a rien de particulier à faire après l’appel à ShowModal.
Modifiez la méthode Execute du composant enveloppe de la boîte A propos de
pour qu’elle ressemble à ce qui suit dans le fichier ABOUTDLG.CPP :
bool __fastcall TAboutBoxDlg::Execute()
{
AboutBox = new TAboutBox(Application); // construit la boîte A propos
bool Result;
try
{
if (ProductName == ““) // si le nom du produit est vide...
}
AboutBox->Free(); // restitue la boîte A propos de
return Result == IDOK; // compare Result à IDOK et renvoie une valeur
booléenne
}
Dans l’en-tête du fichier ABOUTDLG.H, dans la partie public de la classe
TAboutDlg, ajoutez la déclaration de la méthode Execute :
class PACKAGE TAboutDlg : public TComponent
{
public:
virtual bool __fastcall Execute();
};
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.
5 Dans le gestionnaire d’événements, entrez la ligne de code suivante :
AboutBoxDlg1->Execute();
6 Exécutez l’application.
Lorsque la fiche principale apparaît, cliquez sur le bouton de commande.
La boîte A propos de s’affiche avec l’icône projet par défaut et Project1 comme
titre. Choisissez OK pour fermer la boîte de dialogue.
Vous pouvez pousser plus loin le test du fonctionnement du composant en
définissant les différentes propriétés du composant A propos de et en exécutant
une nouvelle fois l’application.
58
Extensions de l’EDI
Chapitre 58
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 (classes abstraites) 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 15, “Utilisation des paquets et des composants”) et le
recensement des composants (chapitre 52, “Accessibilité des composants au
moment de la conception”). Il est également conseillé de lire chapitre 13,
“Gestion en langage C++ de VCL et CLX”, en particulier la section “Héritage et
interfaces” à la page 13-2 pour davantage d’informations sur les interfaces de
style Delphi.
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
• Installation d’une DLL expert
interfaces OTA, il est possible d’écrire une DLL qui ne dépend pas d’une
version spécifique de l’EDI.
L’API Tools contient deux types d’interfaces : celles que le programmeur doit
implémenter et celles qui sont implémentées par l’EDI. La plupart des interfaces
rentrent dans cette dernière catégorie : ces interfaces définissent les possibilités de
l’EDI mais masquent l’implémentation réelle. 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 58-19.
• 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 davantage
d’informations, voir la section “Création de fiches et de projets” à la
page 58-15.
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 davantage d’informations, voir la section
“Utilisation des fichiers et des éditeurs” à la page 58-13.
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).
l’expert. Cependant, COM exige plus que ce qui est nécessaire des simples
interfaces Pascal Objet. En utilisant judicieusement les classes de base et avec un
peu de copier-coller, il est plus facile d’éviter l’utilisation des experts COM et
garder des implémentations simples. Vous pouvez, par exemple, faciliter
l’implémentation de QueryInterface grâce à une simple macro :
#define QUERY_INTERFACE(T, iid, obj) \
if ((iid) == __uuidof(T)) { \
*(obj) = static_cast<T*>(this); \
static_cast<T*>(*(obj))->AddRef(); \
return S_OK; \
}
Utilisez cette macro comme suit :
HRESULT __stdcall MyWizard::QueryInterface(const GUID& iid, void* obj)
{
QUERY_INTERFACE(IOTAMenuWizard, iid, obj);
QUERY_INTERFACE(IOTAWizard, iid, obj);
return inherited::QueryInterface(iid, obj);
}
Vous devez également surcharger toutes les fonctions membre de IOTAWizard et
des classes dérivées que vous utilisez. La plupart des fonctions des diverses
interfaces de l’expert se comprennent d’elles-mêmes. L’EDI appelle les fonctions
de votre expert pour décider comment présenter l’expert à l’utilisateur et
comment exécuter l’expert quand l’utilisateur y fait appel.
Une fois terminée l’écriture de la classe de l’expert, l’étape suivante est
l’installation de l’expert.
ressource contenant une ressource bitmap 16 par 16. Ajoutez le code suivant au
constructeur de l’expert :
_di_INTAServices services;
BorlandIDEServices->Supports(services);
// Ajoute une image à la liste d’images.
Graphics::TBitmap* bitmap(new Graphics::TBitmap());
bitmap->LoadFromResourceName(reinterpret_cast<unsigned>(HInstance), "Bitmap1");
int image = services->AddMasked(bitmap, bitmap->TransparentColor,
"Tempest Software.intro wizard image");
delete bitmap;
Remarquez le type de HInstance qui étant incorrect doit être transtypé dans le
type attendu par LoadFromResourceID. Assurez vous également de charger la
ressource en utilisant le nom ou l’identificateur spécifié dans le fichier ressource.
Ajoutez le fichier ressource au paquet en utilisant la directive #pragma resource.
Vous devez choisir une couleur qui sera interprétée comme la couleur de fond
de l’image. Si vous ne voulez pas utiliser de couleur de fond, choisissez une
couleur n’existant pas dans le bitmap.
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.
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
// IInterface
virtual HRESULT __stdcall QueryInterface(const GUID&, void**);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
private:
long ref_count;
const AnsiString creator_type;
};
La plupart des membres de Creator renvoient zéro ou des chaînes vides.
Les méthodes booléennes renvoient true, sauf GetExisting qui renvoie false.
La méthode la plus intéressante est GetOwner qui renvoie un pointeur sur le
module du projet en cours ou 0 s’il n’y a pas de projet. Il n’y a pas de moyen
simple de déterminer le projet ou le groupe de projets en cours. Il faut à la place
utiliser GetOwner pour parcourir tous les modules ouverts. Si un groupe de
projets est trouvé, ce doit être le seul groupe de projets ouvert, donc GetOwner
renvoie son projet en cours. Sinon la fonction renvoie le premier module de
projet trouvé ou 0 s’il n’y a pas de projet ouvert.
_di_IOTAModule __fastcall Creator::GetOwner()
{
// Renvoie le projet en cours.
_di_IOTAProject result = 0;
_di_IOTAModuleServices svc = interface_cast<IOTAModuleServices>(BorlandIDEServices);
for (int i = 0; i < svc->ModuleCount; ++i)
begin
_di_IOTAModule module = svc->Modules[i];
_di_IOTAProject project;
_di_IOTAProjectGroup group;
if (module->Supports(project)) {
// Mémoriser le premier module de projet.
if (result == 0)
result = project;
} else if (module->Supports(group)) {
// Trouve le groupe de projets et renvoie son projet actif.
result = group->ActiveProject;
break;
}
}
return result;
}
Le créateur renvoie 0 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 File 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 Filesimple, le créateur génère la chaîne, la
classe File se contenant de la transmettre.
class File : public IOTAFile {
public:
__fastcall File(const AnsiString source);
"T%f *%f;\n"
"//-----------------------------------------------------------------\n"
"__fastcall T%m::T%m(TComponent* Owner)\n"
" : T%a(Owner)\n"
"{\n"
"}\n"
"//----------------------------------------------------------------\n";
return new File(expand(form_source, ModuleIdent, FormIdent,
AncestorIdent));
}
Le code source contient des chaînes de la forme %m et %y. Elles sont similaires
aux contrôles des fonctions printf ou Format, mais elles sont développées par la
fonction expand de l’expert. Plus précisément, %m est développé pour donner
l’identificateur du module ou de l’unité, %f pour donner le nom de la fiche et
%a le nom de l’ancêtre. Remarquez comment le nom de la fiche est utilisé dans
le nom du type de la fiche en ajoutant un T majuscule. Certains spécificateurs de
format supplémentaires simplifient la génération du bloc de commentaire : %d
pour la date, %u pour l’utilisateur et %y pour l’année. L’écriture de la fonction
expand est sans rapport avec l’API Tools, elle est laissée au lecteur à titre
d’exercice.
NewIntfSource ressemble à NewImplSource mais elle génère le fichier interface (.h).
La dernière étape consiste à créer deux experts fiche : un qui utilise sUnit comme
type de créateur et l’autre utilisant sForm. Pour proposer un avantage
supplémentaire à l’utilisateur, vous pouvez utiliser INTAServices pour ajouter un
élément au menu Fichier|Nouveau permettant d’appeler chaque expert. Le
gestionnaire d’événement OnClick de l’élément de menu peut appeler la fonction
Execute de l’expert.
Certains experts ont besoin d’activer ou de désactiver des éléments de menu en
fonction de ce qui se passe dans l’EDI. Ainsi, un expert qui archive un projet
dans un système de contrôle du code source doit désactiver sa commande
Archiver s’il n’y a pas de fichier ouvert dans l’EDI. Vous pouvez ajouter cette
fonctionnalité à votre expert en utilisant les notificateurs, décrits dans la section
suivante.
// IOTAModuleNotifier
virtual bool __fastcall CheckOverwrite();
virtual void __fastcall ModuleRenamed(const AnsiString NewName);
// IOTANotifier
void __fastcall AfterSave();
void __fastcall BeforeSave();
void __fastcall Destroyed();
void __fastcall Modified();
protected:
// IInterface
virtual HRESULT __stdcall QueryInterface(const GUID&, void**);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
private:
_di_IOTAModule module;
AnsiString name; // Stocke l’ancien nom du module.
int index; // Indice du notificateur.
};
L’un des moyens d’écrire un notificateur consiste à le faire se recenser lui-même
dans son constructeur. Le destructeur annule le recensement du notificateur.
Dans le cas d’un notificateur de module, l’EDI appelle la méthode Destroyed
quand l’utilisateur ferme le fichier. Dans ce cas, le notificateur doit lui-même
annuler son recensement et libérer sa référence à l’interface de module. L’EDI
libère sa référence au notificateur, ce qui ramène à zéro son compteur de
références et libère l’objet. Il n’est donc pas nécessaire d’écrire le destructeur
défensivement : le notificateur n’est peut être déjà plus recensé.
__fastcall ModuleNotifier::ModuleNotifier(const _di_IOTAModule module)
: index(-1), module(module)
{
// Recense ce notificateur.
index = module->AddNotifier(this);
// Stocke l’ancien nom du module.
name = ChangeFileExt(ExtractFileName(module->FileName), "");
}
__fastcall ModuleNotifier::~ModuleNotifier()
{
// Annule le recensement du notificateur si ce n’est pas déjà fait.
if (index >= 0)
module->RemoveNotifier(index);
}
void __fastcall ModuleNotifier::Destroyed()
{
// L’interface du module estdétruite, nettoyage du notificateur.
if (index >= 0)
{
// Annule le recensement du notificateur.
module->RemoveNotifier(index);
index = -1;
}
module = 0;
}
Implémentations spécifiques
Annexe A
A
de la norme ANSI
Certains aspects du standard ANSI du langage C ne sont pas définis
explicitement. Chaque éditeur ayant créé un compilateur C est laissé libre de
définir ces points comme bon lui semble. Ce chapitre vous montre les choix faits
par Borland. Les numéros de section se réfèrent au document nommé C ANSI/
ISO Standard daté de Février 1990.
Souvenez-vous qu’il existe des différences entre le C et le C++. Ce chapitre ne
concerne que le langage C. Pour plus d’informations sur la compatibilité C++,
reportez-vous au site Web Borland Community à l’adresse
community.borland.com/cpp.
Toute autre option non mentionnée ici peut être choisie dans le sens qui vous
intéresse.
3.1.2.5 The representations and sets of values of the various types of integers
Les représentations et les domaines de valeurs des différents types de valeurs numériques
entières.
Tableau A.2 Identification de diagnostics en C++Builder
Valeur minimum Valeur maximum Valeur minimum Valeur maximum
Type 16 bits 16 bits 32 bits 32 bits
signed char –128 127 –128 127
unsigned char 0 255 0 255
signed short –32 768 32 767 –32 768 32 767
unsigned short 0 65 535 0 65 535
signed int –32 768 32 767 –2 147 483 648 –2 147 483 647
unsigned int 0 65 535 0 4 294 967 295
signed long –2 147 483 648 2 147 483 647 –2 147 483 648 2 147 483 647
unsigned long 0 4 294 967 295 0 4 294 967 295
Si vous avez demandé l’alignement (-a), tous les entiers différents de char sont
alignés sur des adresses paires en mémoire. -a4 provoque un alignement sur
4 octets. Les types caractère ne sont jamais alignés.
3.1.2.5 The representations and sets of values of the various types of floating-point numbers.
Les représentations et ensembles de valeurs des différents types numériques en virgule
flottante.
Les formats en virgule flottante IEEE utilisés par le coprocesseur Intel 8086 sont
utilisés pour tous les types en virgule flottante de C++Builder. Le type float
utilise le format réel IEEE sur 32 bits. Le type double utilise le format réel IEEE
sur 64 bits. Le type long double utilise le format réel étendu IEEE sur 80 bits.
3.1.3.4 The value of an integer character constant that contains a character or escape
sequence not represented in the basic execution character set or the extended character set
for a wide character constant.
La valeur d’une constante caractère entière contenant un caractère ou une séquence
d’échappement qui n’est pas représentée dans le jeu de caractères d’exécution ou le jeu de
caractères étendu qui permet de représenter une constante caractère large.
Les caractères larges sont supportés.
3.1.3.4 The current locale used to convert multibyte characters into corresponding wide
characters for a wide character constant.
La convention “locale” appliquée pour convertir les caractères multi-octets dans des
caractères larges correspondants pour une constante caractère large.
Les constantes caractère large sont reconnues.
3.1.3.4 The value of an integer constant that contains more than one character, or a wide
character constant that contains more than one multibyte character.
La valeur d’une constante entière qui contient plusieurs caractères ou d’une constante
caractère large qui contient plusieurs caractères multi-octets.
Les constantes caractère peuvent comporter un ou deux caractères. Dans le cas
de deux, le premier caractère occupe l’octet de poids faible de la constante et le
second l’octet de poids fort.
3.2.1.2 The result of converting an integer to a shorter signed integer, or the result of
converting an unsigned integer to a signed integer of equal length, if the value cannot be
represented.
Le résultat de la conversion d’un entier en un entier signé plus petit, ou le résultat de la
conversion d’un entier non signé en un entier signé de même taille lorsque la valeur peut être
représentée.
Ces conversions sont réalisées par simple troncature des bits de poids fort. Les
entiers signés sont stockés sous forme de valeurs complémentées à deux, ce qui
fait que la valeur résultante est interprétée de cette manière. Si le bit de poids
fort de l’entier plus petit est différent de zéro, la valeur est interprétée comme
une valeur négative ; dans le cas contraire, c’est une valeur positive.
3.3.2.3 What happens when a member of a union object is accessed using a member of a
different type.
Ce qui se produit lorsqu’un membre d’une union est atteint par le biais d’un membre d’un
autre type.
Cet accès est autorisé et permet simplement d’accéder aux bits qui se trouvent
stockés là. Vous devez avoir une connaissance précise de la configuration de bits
pour les valeurs en virgule flottante pour pouvoir accéder de cette manière à un
membre de ce type. Si le membre est de taille plus petite que celui utilisé pour
accéder à la valeur, les bits supplémentaires gardent la valeur qu’ils avaient
avant le stockage du membre de plus petite taille.
3.3.3.4 The type of integer required to hold the maximum size of an array.
Le type de valeur entière permettant de stocker la taille maximale d’un tableau.
Pour un tableau normal, ce type est unsigned int. Pour un tableau de type
HUGE, le type est signed long.
3.3.6 The type of integer required to hold the difference between two pointers to elements of
the same array, ptrdiff_t.
Le type d’un entier permettant de stocker la différence entre deux pointeurs sur des éléments
d’un tableau, ptrdiff_t.
Le type est signed int.
3.5.1 The extent to which objects can actually be placed in registers by using the register
storage-class specifier.
Les modalités de stockage des objets dans les registres au moyen du spécificateur de
stockage register.
Les objets déclarés de type entier sur deux octets ou pointeur peuvent être placés
dans des registres. Il existe au minimum deux et au maximum six registres pour
ces opérations. Le nombre de registres disponibles réellement pour chaque
opération dépend du nombre de registres nécessaires pour les stockages de
valeurs intermédiaires dans la réalisation de chaque fonction.
3.5.2.1 Whether a plain int bit-field is treated as a signed int or as an unsigned int bit field.
Si un champ de bits de type entier est traité en signed int ou unsigned int.
Les champs de bits homogènes de type int sont traités en tant que champs de
type signed int.
3.5.2.2 The integer type chosen to represent the values of an enumeration type.
Le type entier choisi pour représenter les valeurs d’un type énuméré.
Stocke tous les énumérateurs comme int. Si la valeur ne tient pas dans un int,
stocke les énumérations dans un long ou un unsigned long. C’est le
comportement par défaut spécifié par l’option de compilation –b.
L’option –b– spécifie que toutes les énumérations doivent être stockées dans le
plus petit type entier pouvant représenter les valeurs. Cela inclut tous les types
entiers : signed char, unsigned char, signed short, unsigned short, signed int,
unsigned int, signed long et unsigned long.
Pour se conformer au C++, il faut spécifier –b– car il n’est pas correct en C++ de
stocker toutes les énumérations comme int.
3.5.4 The maximum number of declarators that can modify an arithmetic, structure, or union
type.
Le nombre maximum de déclarateurs qui peuvent être appliqués pour modifier un type
arithmétique, structure ou union.
Il n’y a pas de limites particulières au nombre de déclarateurs. Une limite existe
cependant lorsque ces déclarateurs sont utilisés dans un niveau d’imbrication
important des blocs de codes. Le nombre alloué au niveau des accès fichiers est
de 50.
3.8.2 The support for quoted names for includable source files.
La méthode d’interprétation des noms de fichiers à inclure délimités par des guillemets.
Lorsque les noms de fichiers à inclure sont délimités par des guillemets, ceux-ci
sont cherchés dans l’ordre suivant
1 Dans le même répertoire que le fichier contenant l’instruction #include.
2 Dans les répertoires des fichiers qui incluent (#include) ce fichier.
3 Dans le répertoire en cours.
4 Dans le chemin spécifié par l’option /I du compilateur.
5 Dans les chemins spécifiés par la variable d’environnement INCLUDE.
3.8.8 The definitions for __DATE__ and __TIME__ when they are unavailable.
Les définitions de __DATE__ and __TIME__ lorsque ces éléments ne sont pas disponibles.
Les éléments date et heure sont toujours disponibles et se basent sur l’horloge
du système d’exploitation.
4.1.5 The null pointer constant to which the macro NULL expands.
La constante pointeur null qui est le résultat de l’évaluation de la macro NULL.
NULL est évaluée comme zero int ou zero long. Les deux valeurs sont des
nombres signés codés sur 32 bits.
4.2 The diagnostic printed by and the termination behavior of the assert function.
Le diagnostic affiché et le comportement final de la fonction assert.
Le diagnostic affiché est “Assertion failed: expression file nomfich, line nn”, dans
lequel expression est l’expression qui a échoué, nomfich le nom du fichier source
concerné et nn le numéro de ligne sur laquelle se trouvait cette assertion.
La fonction abort est appelée immédiatement après l’affichage de ce message.
4.3.1 The sets of characters tested for by the isalnum, isalpha, iscntrl, islower, isprint and
isupper functions.
Le domaine de valeurs (jeu de caractères) qui est testé par les fonctions isalnum, isalpha,
iscntrl, islower, isprint et isupper.
Les 128 premiers caractères ASCII pour la fonction locale par défaut du C. Sinon,
l’ensemble des 256 caractères.
4.5.1 Whether the mathematics functions set the integer expression errno to the value of the
macro ERANGE on underflow range errors.
Si les fonctions mathématiques donnent à l’expression entière errno la valeur de la macro
ERANGE lors d’une erreur par débordement inverse.
Non, elles ne le font que pour les autres erreurs : erreur de domaine, de
singularité, de débordement et de perte totale de précision.
4.5.6.4 Whether a domain error occurs or zero is returned when the fmod function has a
second argument of zero.
Si une erreur de domaine survient ou si zéro est renvoyé lorsque la fonction fmod reçoit un
second argument égal à zéro.
Non ; fmod(x,0) renvoie la valeur 0.
4.7.1.1 The semantics for each signal recognized by the signal function.
La sémantique de chaque signal reconnue par la fonction signal.
Reportez-vous à la description de signal.
4.7.1.1 The default handling and the handling at program startup for each signal recognized
by the signal function.
Le comportement standard et le comportement au démarrage du programme pour chaque
signal reconnu par la fonction signal.
Reportez-vous à la description de signal.
4.7.1.1 If the equivalent of signal(sig, SIG_DFL); is not executed prior to the call of a signal
handler, the blocking of the signal that is performed.
Si l’équivalent de l’écriture signal(sig, SIG_DFL); est exécuté ou pas avant l’appel à un
gestionnaire de signal, ainsi que le blocage du signal réalisé.
L’équivalent de l’appel signal(sig, SIG_DFL) est toujours exécuté.
4.7.1.1 Whether the default handling is reset if the SIGILL signal is received by a handler
specified to the signal function.
Si la méthode de gestion implicite est remise à zéro lorsque le signal SIGILL est reçu par le
gestionnaire spécifié à la fonction signal.
Non, elle ne l’est pas.
4.9.2 Whether the last line of a text stream requires a terminating newline character.
Si la dernière ligne d’un flot de texte requiert un caractère de saut de ligne pour indiquer la
terminaison.
Non, aucun caractère spécifique n’est nécessaire.
4.9.2 Whether space characters that are written out to a text stream immediately before a
newline character appear when read in.
Si les caractères espace qui sont écrits dans un flot de texte en sortie immédiatement avant
l’apparition d’un caractère de saut de ligne sont retrouvés en entrée.
Oui, ils le sont.
4.9.2 The number of null characters that may be appended to data written to a binary
stream.
Le nombre de caractères null qui peuvent être ajoutés à des données écrites dans un flot
binaire.
Aucun.
4.9.3 Whether the file position indicator of an append mode stream is initially positioned at
the beginning or end of the file.
Si l’indicateur de position au sein du fichier pour un flux en mode ajout est placé initialement
en début ou en fin de fichier.
L’indicateur de position dans un flux en mode ajout est positionné initialement
en début de fichier. Il est ramené à la fin du fichier avant chaque écriture.
4.9.3 Whether a write on a text stream causes the associated file to be truncated beyond
that point.
Si une écriture dans un flux texte provoque la troncature du fichier associé à cet endroit.
L’écriture de zéro octet peut ou ne pas provoquer la troncature du fichier en
fonction de la manière dont ce fichier est tamponné. Il est plus sûr de considérer
qu’une écriture de zéro octet possède un comportement indéterminé.
4.9.4.2 The effect if a file with the new name exists prior to a call to rename.
Le comportement si un fichier de même nom existe déjà avant l’appel à rename.
Dans ce cas, rename renvoie la valeur -1 et errno reçoit la valeur EEXIST.
4.9.6.2 The interpretation of a –(hyphen) character that is neither the first nor the last
character in the scanlist for a %[ conversion in fscanf.
La manière dont est interprété le tiret (-) lorsque ce n’est ni le premier ni le dernier caractère
dans une liste analysée pour le formateur %[ dans fscanf.
Voir la description de scanf.
4.9.9.1 The value the macro errno is set to by the fgetpos or ftell function on failure.
La valeur que donnent les fonctions fgetpos et ftell à la macro ERRNO en cas d’erreur.
EBADF (Bad file number — Mauvais numéro de fichier).
4.10.3 The behavior of calloc, malloc, or realloc if the size requested is zero.
Le comportement des fonctions calloc, malloc ou realloc lorsque la taille demandée est zéro.
Les fonctions calloc et malloc ignorent la demande et renvoient 0. La fonction
Realloc libère le bloc.
4.10.4.1 The behavior of the abort function with regard to open and temporary files.
Le comportement de la fonction abort par rapport aux fichiers ouverts et aux fichiers
temporaires.
Les tampons fichier ne sont pas vidés et les fichiers ne sont pas fermés.
4.10.4.3 The status returned by exit if the value of the argument is other than zero,
EXIT_SUCCESS, or EXIT_FAILURE.
Le statut renvoyé par exit si la valeur de l’argument est différente de 0, de EXIT_SUCCESS
et de EXIT_FAILURE.
Aucun statut spécial. Le statut renvoyé est le même que celui fourni. Ce statut
est représenté sous forme d’un signed char.
4.10.4.4 The set of environment names and the method for altering the environment list used
by getenv.
L’ensemble des noms d’environnement et les méthodes de modification de l’environnement
employées par getenv.
Les chaînes d’environnement sont celles définies par le système d’exploitation au
moyen de la commande SET. La fonction standard putenv permet de modifier ces
chaînes pour la durée d’exécution du programme. Cependant, la commande SET
doit être utilisée si vous voulez modifier une chaîne d’environnement de manière
permanente.
4.10.4.5 The contents and mode of execution of the string by the system function.
Le contenu et le mode d’utilisation de la chaîne gérée par la fonction system.
Cette chaîne est interprétée en tant que commande du système d’exploitation.
COMPSPEC est utilisée ou CMD.EXE est exécuté et la chaîne est transmise
comme une commande à exécuter. Toute commande interne du système
d’exploitation, ainsi que tout nom de fichier procédure (.BAT) et tout nom de
programme exécutable, peuvent être mentionnés pour exécution.
Référence de scripts
Annexe B
B
côté serveur WebSnap
Cette annexe explique comment les scripts sont utilisés par les adaptateurs
WebSnap pour générer des pages HTML dynamiques dans les applications de
serveur Web WebSnap. Elle est destinée aux développeurs qui utilisent des
générateurs de pages à la place de générateurs de pages d’adaptateur dans leurs
modules de page Web. Les générateurs de pages d’adaptateur gèrent
automatiquement la génération de script, alors qu’il est nécessaire d’ajouter
manuellement des scripts dans les modèles de pages des générateurs de pages.
Les informations contenues dans cette annexe vous aideront à écrire votre propre
script dans vos modèles de pages.
Cette annexe devrait également intéresser les utilisateurs de générateur de page
d’adaptateur qui souhaitent mieux comprendre la sortie du générateur de page
d’adaptateur. La manipulation de script est toutefois un sujet avancé. Vous
n’avez pas besoin de comprendre la manière de générer un script pour écrire des
applications WebSnap de base.
Cette annexe est constituée de trois sections. La première section présente les
différents types d’objet accessibles dans un script. La deuxième section traite des
objets globaux définis dans les applications WebSnap. La troisième section
contient des exemples JScript qui montrent comment un script peut être utilisé
dans des modèles de page HTML pour extraire des informations à partir de
votre application de serveur Web.
Cette annexe correspond à une référence de l’API pour des interfaces de script
d’objets. Les descriptions de propriété d’objet incluent le nom de la propriété,
son type (texte ou booléen) et une indication du fait que la propriété peut être
lue ou écrite. Les descriptions de méthode commencent par le nom de la
méthode et la syntaxe d’appel.
Types d’objets
Le tableau suivant énumère les types d’objets généraux à scripts. Ces types sont
généralement des propriétés d’objets tels que les objets globaux. Tous les types
d’objets à scripts ne sont pas présentés ici ; vous ne trouverez que ceux dont les
instances peuvent avoir différents noms. Par exemple, il existe un type d’objet
application. Comme il n’existe qu’un seul type d’objet application instancié dans
toute application, le type application est décrit comme l’objet Application dans la
section des objets globaux.
Type Adapter
Définit les propriétés et méthodes d’un adaptateur. Vous pouvez accéder aux
adaptateurs par nom comme propriété d’un module (par exemple,
NomModule.Adapter).
Les adaptateurs contiennent des composants champ et des composants action qui
représentent respectivement les éléments de données et les commandes.
Propriétés
Actions : énumérateur
Voir aussi : propriété Fields du type Adapter (ci-dessous), Exemple 8 (page B-24)
Enumère les objets d’action. Utilisez la propriété Actions pour boucler sur les
actions d’un adaptateur.
CanModify : booléen, lecture
Voir aussi : propriété CanView du type Adapter (ci-dessous) et type
AdapterField (page B-7)
Indique si l’utilisateur final a l’autorisation de modifier les champs de cet
adaptateur. Utilisez la propriété CanModify pour générer dynamiquement du
code HTML sensible aux droits de l’utilisateur final. Par exemple, une page
peut inclure un élément <input> si CanModify a la valeur True ou un <p> si
CanModify a la valeur False.
CanView : booléen, lecture
Voir aussi : CanModify du type Adapter (ci-dessus) et le type AdapterField
(page B-7)
Indique si l’utilisateur final a l’autorisation de visualiser les champs de cet
adaptateur. Utilisez la propriété CanModify pour générer dynamiquement du
code HTML sensible aux droits de l’utilisateur final.
ClassName_ : texte, lecture
Voir aussi : Name_ (ci-dessous)
Identifie le nom de classe du composant d’adaptateur.
Errors : AdapterErrors, lecture
Voir aussi : type AdapterErrors (page B-6), Exemple 7 (page B-23)
Enumère les erreurs détectées lors du traitement d’une requête HTTP. Les
adaptateurs interceptent les erreurs qui se produisent lors de la génération
d’une page HTML ou l’exécution d’une action d’adaptateur. Utilisez la
propriété Errors pour énumérer les erreurs et afficher les messages d’erreur
sur une page HTML.
Fields : énumérateur
Voir aussi : Actions
Enumère les objets champs. Utilisez la propriété Fields pour boucler sur les
champs d’un adaptateur.
HiddenFields : AdapterHiddenFields
Voir aussi : HiddenRecordFields, type AdapterHiddenFields (page B-12),
Exemple 10 (page B-25), Exemple 22 (page B-38)
Définit les champs de saisie masqués qui transmettent des informations d’état
de l’adaptateur. Parmi les informations d’état figure le mode de
TDataSetAdapter. Edit et Insert sont deux valeurs possibles de mode. Lorsque
TDataSetAdapter est utilisé pour générer une fiche HTML, la propriété
HiddenFields définit un champ masqué pour le mode. Lorsque la fiche HTML
est soumise, la requête HTTP contient cette valeur de champ masqué. Lors de
l’exécution d’une action, la valeur de mode est extraite de la requête HTTP. Si
le mode est Insert, une nouvelle ligne est insérée dans l’ensemble de données.
Si le mode est Edit, une ligne de l’ensemble de données est mise à jour.
HiddenRecordFields : AdapterHiddenFields
Voir aussi : HiddenFields, type AdapterHiddenFields (page B-12), Exemple 10
(page B-25), Exemple 22 (page B-38)
Définit les champs de saisie cachés qui transmettent les informations d’état
nécessaires à chaque ligne ou enregistrement de la fiche HTML. Par exemple,
lorsque TDataSetAdapter est utilisé pour générer une fiche HTML, la propriété
HiddenRecordFields définira un champ masqué qui identifie une valeur clé pour
chaque ligne d’une table HTML. Lorsque la fiche HTML est soumise, la
requête HTTP contiendra ces valeurs de champs masqués. Lors de l’exécution
d’une action qui met à jour plusieurs lignes dans un ensemble de données,
TDataSetAdapter utilise ces valeurs de clé pour localiser les lignes à mettre à
jour.
Mode : texte, lecture/écriture
Voir aussi : Exemple 10 (page B-25)
Ecrit ou lit le mode de l’adaptateur.
Certains adaptateurs prennent en charge un mode. Par exemple,
TDataSetAdapter gère les modes Edit, Insert, Browse et Query. Le mode affecte
le comportement de l’adaptateur. Lorsque TDataSetAdapter est en mode Edit,
une fiche soumise met à jour une ligne dans une table. Lorsque
TDataSetAdapter est en mode Insert, une fiche soumise insère une ligne dans
une table.
Name_ : texte, lecture
Identifie le nom de variable de l’adaptateur.
Records : énumérateur, lecture
Voir aussi : Exemple 9 (page B-24)
Enumère les enregistrements de l’adaptateur. Utilisez la propriété Records
pour boucler sur les enregistrements de l’adaptateur afin de générer une table
HTML.
Type AdapterAction
Voir aussi : type Adapter (page B-2), type AdapterField (page B-7)
Propriétés
Array : énumérateur
Voir aussi : Exemple 11 (page B-27)
Enumère les commandes d’une action d’adaptateur. Utilisez la propriété Array
pour boucler sur les commandes. Array vaut Null si l’action ne prend pas en
charge plusieurs commandes.
TAdapterGotoPageAction est un exemple d’action à plusieurs commandes. Cette
action possède une commande pour chaque page définie par l’adaptateur
parent. La propriété Array sert à générer une série de liens hypertextes pour
que l’utilisateur final puisse cliquer sur un lien hypertexte afin de sauter à une
page.
AsFieldValue : texte, lecture
Voir aussi : AsHREF, Exemple 10 (page B-25), Exemple 21 (page B-37)
Fournit une valeur texte qui peut être soumise dans un champ masqué.
AsFieldValue identifie le nom de l’action et ses paramètres. Placez cette valeur
dans un champ masqué appelé __act. Lorsque la fiche HTML est soumise, le
répartiteur d’adaptateur extrait la valeur de la requête HTTP et l’utilise pour
localiser et appeler l’action d’adaptateur.
AsHREF : texte, lecture
Voir aussi : AsFieldValue, Exemple 11 (page B-27)
Fournit une valeur texte qui peut être utilisée comme valeur d’attribut href
dans une balise <a>.
AsHREF identifie le nom de l’action et ses paramètres. Insérez cette valeur
dans une balise d’ancrage pour soumettre une requête afin d’exécuter cette
action. Notez qu’une balise d’ancrage sur une fiche HTML ne soumettra pas la
fiche. Si l’action se sert de valeurs d’une fiche soumise, utilisez un champ de
fiche masqué et AsFieldValue pour identifier l’action.
CanExecute : booléen, lecture
Indique si l’utilisateur final possède les autorisations pour exécuter cette
action.
DisplayLabel : texte, lecture
Voir aussi : Exemple 21 (page B-37)
Suggère un libellé d’affichage HTML pour l’action d’adaptateur.
DisplayStyle : chaîne, lecture
Voir aussi : Exemple 21 (page B-37)
Suggère un style d’affichage HTML pour cette action.
Valeur Signification
’’ Style d’affichage non défini
’Button’ Affichage sous la forme <input
type="submit">
’Anchor’ Utilisation de <a>
Méthodes
LinkToPage(PageSuccess, PageFail) : AdapterAction, lecture
Voir aussi : Exemple 10 (page B-25), Exemple 11 (page B-27), Exemple 21
(page B-37), objet Page, type AdapterAction (page B-4)
Utilisez LinkToPage pour spécifier des pages à afficher après l’exécution de
l’action. Le premier paramètre est le nom de la page à afficher si l’action est
exécutée avec succès. Le deuxième paramètre est le nom de la page à afficher
si des erreurs se produisent pendant l’exécution.
Type AdapterErrors
Voir aussi : propriété Errors du type Adapter (page B-2)
Le type AdapterErrors définit les propriétés de la propriété Errors d’un
adaptateur.
Propriétés
Field : AdapterField, lecture
Voir aussi : type AdapterField (page B-7)
Identifie le champ d’adaptateur qui a provoqué une erreur.
Cette propriété a la valeur Null si l’erreur n’est pas associée à un champ
d’adaptateur particulier.
ID : entier, lecture
Type AdapterField
Voir aussi : type Adapter (page B-2), type AdapterAction (page B-4)
Le type AdapterField définit les propriétés et méthodes d’un champ
d’adaptateur.
Propriétés
CanModify : booléen, lecture
Voir aussi : propriété CanView d’un type AdapterField (ci-dessous) et type
Adapter (page B-2)
Indique si l’utilisateur final a le droit de modifier la valeur de ce champ.
CanView : booléen, lecture
Voir aussi : propriété CanModify d’un type AdapterField (ci-dessus) et type
Adapter (page B-2)
Indique si l’utilisateur final a le droit de lire la valeur de ce champ.
DisplayLabel : texte, lecture
Suggère un libellé d’affichage HTML pour ce champ d’adaptateur.
DisplayStyle : texte, lecture
Voir aussi : InputStyle (ci-dessous), ViewMode (ci-dessous), Exemple 17
(page B-34)
DisplayStyle suggère la manière d’afficher une représentation en lecture seule
de la valeur d’un champ.
Le script côté serveur peut utiliser DisplayStyle pour déterminer comment
générer du code HTML. Un champ d’adaptateur peut renvoyer l’un des styles
d’affichage suivants :
Valeur Signification
’’ Style d’entrée non défini.
’TextInput’ Utilisation de <input type="text">.
’PasswordInput’ Utilisation de <input type="password">.
’Select’ Utilisation de <select>. Enumérez la propriété ValuesList pour
générer chaque élément <option>.
’SelectMultiple’ Utilisation de <select multiple>. Enumérez la propriété
ValuesList pour générer chaque élément <option>.
’Radio’ Enumérez la propriété ValuesList pour générer un ou plusieurs
<input type="radio">.
’CheckBox’ Enumérez la propriété ValuesList pour générer un ou plusieurs
<input type="checkbox">.
Valeur Signification
’TextArea’ Utilisation de <textarea>.
’File’ Utilisation de <input type="file">.
Méthodes
IsEqual(valeur) : booléen
Voir aussi : Exemple 16 (page B-33)
Appelez cette fonction pour comparer une variable à la valeur d’un champ
d’adaptateur.
Type AdapterFieldValues
Voir aussi : propriété Values du type AdapterField (page B-7)
Renvoie une liste des valeurs du champ. Cette propriété est prise en charge par
les champs d’adaptateur à valeurs multiples. Un champ à valeurs multiples
serait utilisé, par exemple, pour permettre à l’utilisateur final de sélectionner
plusieurs valeurs dans une liste de sélection.
Propriétés
Records : énumérateur, lecture
Voir aussi : Exemple 15 (page B-32)
Enumère les enregistrements de la liste de valeurs.
Méthodes
HasValue(valeur) : booléen
Voir aussi : Exemple 14 (page B-30)
Indique si une valeur donnée se trouve dans la liste de valeurs de champ.
Cette méthode consiste à déterminer s’il faut sélectionner un élément dans une
liste de sélection HTML ou cocher un élément dans un groupe de cases à
cocher.
Type AdapterFieldValuesList
Voir aussi : type Adapter (page B-2)
Fournit une liste des valeurs possibles pour ce champ d’adaptateur.
Utilisez ValuesList en générant une liste de sélection, un groupe de cases à cocher
ou un groupe de boutons radio HTML. Chaque élément de ValuesList contient
une valeur et peut contenir un nom.
Propriétés
Image : AdapterImage, lecture
Renvoie l’image de l’élément d’énumération en cours ou Null si l’élément ne
possède pas d’image.
Records : énumérateur, lecture
Enumère les enregistrements de la liste de valeurs.
Value : variant, lecture
Renvoie la valeur de l’élément d’énumération en cours.
ValueField : AdapterField, lecture
Voir aussi : type AdapterField (page B-7), Exemple 15 (page B-32)
Renvoie un champ d’adaptateur pour l’élément d’énumération en cours.
Utilisez ValueField, par exemple, pour obtenir le DisplayText de l’élément
d’énumération en cours.
Méthodes
ImageOfValue(valeur) : AdapterImage
Recherche l’image associée à cette valeur. Renvoie Null s’il n’y a pas d’image.
NameOfValue(valeur) : texte
Recherche le nom associé à cette valeur. Renvoie une chaîne vide si la valeur
n’est pas trouvée ou si la valeur ne possède pas de nom.
Type AdapterHiddenFields
Voir aussi : propriétés HiddenFields et HiddenRecordFields du type Adapter
(page B-2)
Permet d’accéder aux noms et valeurs de champs masqués dont un adaptateur a
besoin sur des fiches HTML utilisées pour valider des modifications.
Propriétés
Name : texte, lecture
Renvoie le nom du champ masqué en cours d’énumération.
Value : texte, lecture
Renvoie la valeur chaîne du champ masqué en cours d’énumération.
Méthodes
WriteFields(réponse)
Voir aussi : Exemple 10 (page B-25), Exemple 22 (page B-38)
Ecrit les noms et valeurs des champs masqués en utilisant <input
type=”hidden”>.
Appelez cette méthode pour écrire tous les champs masqués HTML sur une
fiche HTML.
Type AdapterImage
Voir aussi : type AdapterField (page B-12), type AdapterAction (page B-4)
Représente une image associée à une action ou à un champ.
Propriétés
AsHREF : texte, lecture
Type Module
Voir aussi : objet Modules (page B-17)
Les composants d’adaptateur peuvent être référencés par nom comme propriétés
d’un module. Utilisez également un module pour énumérer les objets à scripts
(en général les adaptateurs) d’un module.
Propriétés
Name_ : texte, lecture
Voir aussi : Exemple 20 (page B-36)
Identifie le nom de variable du module. Il s’agit du nom utilisé pour accéder
au module comme propriété de la variable Modules.
ClassName_ : texte, lecture
Voir aussi : Exemple 20 (page B-36)
Identifie le nom de classe du module.
Objects : énumérateur
Voir aussi : Exemple 20 (page B-36)
Utilisez Objects pour énumérer les objets à scripts (en général des adaptateurs)
d’un module.
Type Page
Voir aussi : objet Page (page B-17), Exemple 20 (page B-36)
Définit les propriétés et méthodes de pages.
Propriétés
CanView : booléen, lecture
Indique si l’utilisateur final a le droit de visualiser cette page.
Une page recense des droits d’accès. CanView compare les droits recensés par
la page aux droits accordés à l’utilisateur final.
DefaultAction : type AdapterAction, lecture
Voir aussi : Exemple 6 (page B-23)
Identifie l’action d’adaptateur par défaut associée à cette page.
Une action par défaut est généralement utilisée lorsque des paramètres
doivent être transmis à une page. DefaultAction peut valoir Null.
Objets globaux
Les objets globaux peuvent être référencés avec un script côté serveur ; vous
pouvez créer dans un script des références d’objets globaux similaires aux
références d’objets dans votre code source. Par exemple,
<%= Application.Title %>
affiche le titre de l’application dans une page Web.
Objet Application
Voir aussi : type Adapter (page B-2)
L’objet Application permet d’accéder à des informations sur l’application.
Utilisez l’objet Application pour accéder à des champs et des actions de
l’adaptateur d’application, comme le champ Title. L’objet Application étant un
adaptateur, il peut être personnalisé avec des champs et des actions
supplémentaires. Les champs et les actions qui ont été ajoutés à l’adaptateur
d’application sont accessibles par leur nom, comme propriétés de l’objet
Application.
Propriétés
Designing : booléen, lecture
Voir aussi : Exemple 1 (page B-21)
Indique si l’application Web est en cours de conception dans l’EDI.
Utilisez la propriété Designing pour générer de manière conditionnelle un code
HTML qui doit être différent en mode conception et lorsque l’application Web
s’exécute.
ModulePath : texte, lecture
Voir aussi : méthode QualifyFileName
Méthodes
QualifyFileName(FileName) : texte
Voir aussi : Exemple 1 (page B-21)
Convertit un nom de fichier relatif ou une référence de répertoire relative en
référence absolue.
QualifyFileName utilise l’emplacement de répertoire de l’exécutable de
l’application Web pour qualifier un nom de fichier qui n’est pas complet. La
méthode renvoie le nom de fichier complet. Si le paramètre FileName est
complet, le nom de fichier est renvoyé sans modification. En mode conception,
le paramètre FileName est qualifié avec l’emplacement du répertoire du fichier
projet.
Objet EndUser
Voir aussi : type Adapter (page B-2)
Permet d’accéder à des informations sur l’utilisateur final en cours.
Utilisez EndUser pour accéder à des champs et des actions de l’adaptateur
d’utilisateur final, tels que DisplayName pour l’utilisateur final. Vous pouvez
accéder aux champs et aux actions qui ont été ajoutés à l’adaptateur de
l’utilisateur final par leur nom, en tant que propriétés de l’objet EndUser.
Propriétés
DisplayName : texte, lecture
Voir aussi : Exemple 19 (page B-36)
Fournit le nom de l’utilisateur final.
LoggedIn : booléen, lecture
Objet Modules
Voir aussi : Exemple 2 (page B-21), Exemple 20 (page B-36)
L’objet Modules permet d’accéder à tous les modules qui ont été instanciés ou
activés pour traiter la requête HTTP en cours.
Pour référencer un module particulier, utilisez le nom du module comme
propriété de la variable Modules. Pour énumérer tous les modules dans
l’application, créez un énumérateur en utilisant l’objet Modules.
Objet page
Voir aussi : Exemple 5 (page B-22), type Page (page B-13)
L’objet Page permet d’accéder aux propriétés de la page en cours de génération.
Voir le type Page pour une description des propriétés et méthodes de l’objet
Page.
Objet pages
Voir aussi : Exemple 5 (page B-22)
L’objet Pages permet d’accéder à toutes les pages recensées par l’application.
Pour référencer une page particulière, utilisez le nom de la page comme
propriété de la variable Pages. Pour énumérer toutes les pages de l’application,
créez un énumérateur utilisant l’objet Pages.
Objet Producer
Voir aussi : objet Response (page B-19)
Utilisez l’objet Producer pour écrire un texte contenant des balises transparentes.
Les balises seront traduites par le générateur de page puis écrites dans la
Propriétés
Content : texte, lecture/écriture
Permet d’accéder à la partie contenu de la réponse HTTP.
Utilisez Content pour lire ou écrire toute la partie contenu de la réponse
HTTP. L’initialisation de Content traduit les balises transparentes. Si vous
n’employez pas de balises transparentes, initialisez Response.Content pour de
meilleures performances.
Méthodes
Write(valeur)
Ajoute un élément à la partie contenu de la requête HTTP avec une prise en
charge des balises transparentes.
Utilisez la méthode Write pour ajouter un élément à la partie contenu de la
requête HTTP. Write traduit des balises transparentes comme
Write(’Traduire ce: <#MyTag>‘))
Si vous n’employez pas de balises transparentes, utilisez Response.Write pour
de meilleures performances.
Objet Request
Permet d’accéder à la requête HTTP.
Utilisez les propriétés de l’objet Response pour accéder aux informations de la
requête HTTP.
Propriétés
Host : texte, lecture
Fournit la valeur de l’en-tête Host de la requête HTTP.
Host est identique à la propriété Host de TWebRequest.
PathInfo : texte, lecture
Contient la partie informations de chemin de l’URL.
PathInfo est identique à la propriété InternalPathInfo de TWebRequest.
ScriptName : texte, lecture
Contient la partie nom de script de l’URL, qui spécifie le nom d’une
application serveur Web.
ScriptName est identique à la propriété InternalScriptName de TWebRequest.
Objet Response
Voir aussi : objet Producer (page B-17)
Permet d’accéder à la réponse HTTP. Utilisez l’objet Response pour écrire dans
la partie contenu de la réponse HTTP. Si vous utilisez des balises transparentes,
utilisez l’objet Producer au lieu de l’objet Response.
Propriétés
Content : texte, lecture/écriture
Permet d’accéder à la partie contenu de la réponse HTTP.
Utilisez Content pour lire ou écrire toute la partie contenu de la réponse
HTTP.
Méthodes
Write(valeur)
Voir aussi : Exemple 5 (page B-22)
Ajoute Value à la partie contenu de la requête HTTP.
Utilisez la méthode Write pour ajouter Value au contenu de la requête HTTP.
Write ne traduit pas les balises transparentes.
Utilisez la méthode Write de l’objet Producer pour écrire une chaîne contenant
une ou plusieurs balises transparentes.
Objet Session
L’objet Session permet d’accéder à l’identificateur et aux valeurs de la session.
Une session permet de conserver des informations sur l’utilisateur final pendant
une courte période de temps.
Propriétés
SessionID.Value : texte, lecture/écriture
Permet d’accéder à l’identificateur de la session de l’utilisateur final en cours.
Values(nom) : variant, lecture
Permet d’accéder aux valeurs stockées dans la session de l’utilisateur final
en cours.
Exemples JScript
Les exemples JScript suivants montrent comment de nombreuses propriétés et
méthodes de script côté serveur s’utilisent.
Exemple 1
Voir aussi : propriétés Designing et QualifyFileName de l’objet Application
(page B-15), propriété PathInfo de l’objet Request (page B-18)
Cet exemple génère une référence de chemin relative vers une image. Si le script
est en mode conception, il référence un répertoire réel ; sinon, il référence un
répertoire virtuel.
<%
function PathInfoToRelativePath(S)
{
var R = ’’;
var L = S.length
I = 0
while (I < L)
{
if (S.charAt(I) == ’/’)
R = R + ’../’
I++
}
return R
}
function QualifyImage(S)
{
if (Application.Designing)
return Application.QualifyFileName("..\\images\\" + S); // répertoire relatif
else
return PathInfoToRelativePath(Request.PathInfo) + ‘../images/’ + S; // répertoire
// virtuel
}
%>
Exemple 2
Voir aussi : objet Modules (page B-17)
Cet exemple déclare une variable qui référence WebModule1 :
<% var M = Modules.WebModule1 %>
Exemple 3
Voir aussi : objet Modules (page B-17)
L’exemple 3 énumère le module instancié et affiche son nom de variable et son
nom de classe dans une table :
<table border=1>
<tr><th>Name</th><th>ClassName</th></tr>
<%
var e = new Enumerator(Modules)
for (; !e.atEnd(); e.moveNext())
{
%>
<tr><td><%=e.item().Name_%></td><td><%=e.item()ClassName._%></td></tr>
<%
}
%>
</table>
Exemple 4
Voir aussi : objet Pages (page B-17), propriété Title de l’objet Page (page B-17)
Cet exemple déclare une variable qui référence une page nommée Home. Il
affiche également le titre de cette page.
<% var P = Pages.Home %>
<p><%= P.Title %></p>
Exemple 5
Voir aussi : objet Pages (page B-17), propriétés Published et HREF de l’objet Page
(page B-17), méthode Write de l’objet Response (page B-19)
Cet exemple énumère les pages recensées et crée un menu affichant des liens
hypertextes vers toutes les pages publiées.
<table>
<td>
<% e = new Enumerator(Pages)
s = ’’
c = 0
for (; !e.atEnd(); e.moveNext())
{
if (e.item().Published)
{
if (c>0) s += ’ | ’
if (Page.Name != e.item().Name)
s += ’<a href="’ + e.item().HREF + ’">’ + e.item().Title + ’</a>’
else
s += e.item().Title
c++
}
}
if (c>1) Response.Write(s)
%>
</td>
</table>
Exemple 6
Voir aussi : propriété DefaultAction du type Page (page B-13)
Cet exemple énumère les pages recensées et crée un menu affichant des liens
hypertextes vers les actions par défaut.
<table>
<td>
<% e = new Enumerator(Pages)
s = ’’
c = 0
for (; !e.atEnd(); e.moveNext())
{
if (e.item().Published)
{
if (c>0) s += ’ | ’
if (Page.Name != e.item().Name)
if (e.item().DefaultAction != null)
s += ’<a href="’+e.item().DefaultAction.AsHREF+’"> +e.item().Title+’</a>’
else
s += ’<a href="’ + e.item().HREF + ’">’ + e.item().Title + ’</a>’
else
s += e.item().Title
c++
}
}
if (c>1) Response.Write(s)
%>
</td>
</table>
Exemple 7
Voir aussi : propriété Errors du type Adapter (page B-2), type AdapterErrors
(page B-6), objet Modules (page B-17), méthode Write de l’objet Response
(page B-19)
Cet exemple écrit une liste d’erreurs détectées par un adaptateur.
<% {
var e = new Enumerator(Modules.CountryTable.Adapter.Errors)
for (; !e.atEnd(); e.moveNext())
{
Response.Write("<li>" + e.item().Message)
}
e.moveFirst()
} %>
Exemple 8
Voir aussi : propriété Actions du type Adapter (page B-2), type AdapterAction
(page B-4)
Cet exemple énumère toutes les actions d’un adaptateur et les valeurs des
propriétés d’action d’affichage dans une table.
<% // Affichage de certaines propriétés d’une action dans une table.
function DumpAction(A)
{
%>
<table border="1">
<tr><th COLSPAN=2><%=A.Name%></th>
<tr><th>AsFieldValue:</th><td><%= A.AsFieldValue %></td>
<tr><th>AsHREF:</th><td><%= A.AsHREF %></span>
<tr><th>DisplayLabel:</th><td><%= A.DisplayLabel %></td>
<tr><th>Enabled:</th><td><%= A.Enabled %></td>
<tr><th>CanExecute:</th><td><span class="value"><%= A.CanExecute %></td>
</table>
<%
}
%>
<%
// Affichage des propriétés des actions de l’adaptateur Adapter1.
DumpActions(Adapter1.Actions) %>
Exemple 9
Voir aussi : propriété Records du type Adapter (page B-2), propriété DisplayText
du type AdapterField (page B-7)
Cet exemple génère une table HTML en énumérant les enregistrements d’un
adaptateur.
<%
// Définition des variables pour l’adaptateur et les champs
vAdapter=Modules.CountryTable.Adapter
vAdapter_Name=vAdapter.Name
vAdapter_Capital=vAdapter.Capital
vAdapter_Continent=vAdapter.Continent
%>
<%
// Fonction permettant d’écrire un texte de colonne pour que toutes les cellules
// aient des cadres.
function WriteColText(t)
{
Response.Write((t!="")?t:" ")
}
%>
<table border="1">
<tr>
<th>Name</th>
<th>Capital</th>
<th>Continent</th>
<%
// Enumération de tous les enregistrements de l’adaptateur et écriture des valeurs
// des champs.
Exemple 10
Voir aussi : propriétés LinkToPage et AsFieldValue du type AdapterAction
(page B-4), propriétés InputName et DisplayText du type AdapterField (page B-7),
propriétés HiddenFields et HiddenRecordFields du type Adapter (page B-2)
Cet exemple génère une fiche HTML pour modifier les champs d’adaptateur et
soumettre les actions d’adaptateur.
<%
// Définition de variables pour l’adaptateur, les champs et les actions.
vAdapter=Modules.CountryTable.Adapter
vAdapter_Name=vAdapter.Name
vAdapter_Capital=vAdapter.Capital
vAdapter_Continent=vAdapter.Continent
vAdapter_Apply=vAdapter.Apply
vAdapter_RefreshRow=vAdapter.RefreshRow
if (vAdapter.Mode=="")
vAdapter.Mode="Edit"
%>
<form name="AdapterForm1" method="post">
<!-- Ce champ masqué définit l’action qui est exécutée lorsque la fiche est soumise. -->
<%
// Ecriture des champs masqués définis par l’adaptateur.
if (vAdapter.HiddenFields != null)
{
vAdapter.HiddenFields.WriteFields(Response)
} %>
<% if (vAdapter.HiddenRecordFields != null)
{
vAdapter.HiddenRecordFields.WriteFields(Response)
} %>
<table>
<tr>
<td>
<table>
<tr>
<!-- Ecriture des champs de saisie pour modifier les champs de l’adaptateur -->
<td>Name</td>
<td ><input type="text" size="24" name="<%=vAdapter_Name.InputName%>" value="
<%= vAdapter_Name.EditText %>" ></td>
</tr>
<tr>
<td>Capital</td>
<td ><input type="text" size="24" name="<%=vAdapter_Capital.InputName%>"
value="<%= vAdapter_Capital.EditText %>" ></td>
</tr>
<tr>
<td>Continent</td>
<td ><input type="text" size="24" name="<%=vAdapter_Continent.InputName%>"
value="<%= vAdapter_Continent.EditText %>" ></td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table>
<!-- Ecriture des boutons de validation pour l’exécution des actions.
Utilisez LinkToPage pour que cette page soit regénérée après l’exécution
d’une action. -->
<tr>
<td><input type="submit" value="Apply"
onclick = "AdapterForm1.__act.value=’
<%=vAdapter_Apply.LinkToPage(Page.Name).AsFieldValue%>’"></td>
<td><input type="submit" value="Refresh"
onclick = "AdapterForm1.__act.value=’
<%=vAdapter_RefreshRow.LinkToPage(Page.Name).AsFieldValue%>’"> </td>
</tr>
</table>
</td>
</tr>
</table>
</form>
Exemple 11
Voir aussi : propriétés Array et AsHREF du type AdapterAction (page B-4)
Cet exemple affiche des actions d’adaptateur pour la prise en charge de la
pagination. Les actions PrevPage, GotoPage et NextPage sont affichées sous
forme de liens hypertextes. L’action GotoPage possède un tableau de
commandes. Les commandes sont énumérées pour générer un lien hypertexte
permettant d’afficher directement chaque page.
<%
// Définition des variables pour l’adaptateur et les actions.
vAdapter = Modules.WebDataModule1.QueryAdapter
vPrevPage = vAdapter.PrevPage
vGotoPage = vAdapter.GotoPage
vNextPage = vAdapter.NextPage
%>
<!-- Génération d’une table qui affiche des liens hypertexte entre les pages. -->
<table cellpadding="5">
<tr>
<td>
<%
// Prevpage affiche "<<". Utilisation d’une balise d’ancrage uniquement si la commande
// est permise.
if (vPrevPage.Enabled)
{ %>
<a href="<%=vPrevPage.LinkToPage(Page.Name).AsHREF%>"><<</a>
<%
}
else
{%>
<a><<</a>
<%} %>
<%
// GotoPage possède une liste de commandes. Boucle sur la liste.
// Utilisation d’une balise d’ancrage uniquement si la commande est permise.
if (vGotoPage.Array != null)
{
var e = new Enumerator(vGotoPage.Array)
for (; !e.atEnd(); e.moveNext())
{
%>
<td>
<% if (vGotoPage.Enabled)
{ %>
<a href="<%=vGotoPage.LinkToPage(Page.Name).AsHREF%>">
<%=vGotoPage.DisplayLabel%></a>
<% }
else
{ %>
<a><%=vGotoPage.DisplayLabel%></a>
<% }
%>
</td>
<%
}
}
%>
<td>
<%
// NextPage affiche ">>". Utilisation d’une balise d’ancrage uniquement si la commande
// est permise.
if (vNextPage.Enabled)
{ %>
<a href="<%=vNextPage.LinkToPage(Page.Name).AsHREF%>">>></a>
<%
}
else
{%>
<a>>></a>
<%} %>
</td>
</table>
Exemple 12
Voir aussi : propriété Image du type AdapterField (page B-7)
L’exemple 12 affiche l’image d’un champ d’adaptateur.
<%
vAdapter=Modules.WebDataModule3.DataSetAdapter1
vGraphic=vAdapter.Graphic
%>
Exemple 13
Voir aussi : propriétés Values et ValuesList du type AdapterField (page B-7)
Cet exemple écrit un champ d’adaptateur avec les éléments HTML <select> et
<option>.
<%
// Renvoi d’un objet qui définit les options de sélection HTML pour un champ d’adaptateur.
// L’objet renvoyé possède les éléments suivants :
//
// text - chaîne contenant les éléments <option>.
// count - nombre d’éléments <option>.
// multiple - chaîne contenant ’multiple’ ou ".
// Utilisation de cette valeur comme attribut de l’élément <select>.
//
// A utiliser comme suit :
// obj=SelOptions(f)
// Response.Write(’<select size="’ + obj.count + ’" name="’ + f.InputName + ’" ’ +
// obj.multiple + ’>’ + obj.text + ’</select>’)
function SelOptions(f)
{
var s=’’
var v=’’
var n=’’
var c=0
if (f.ValuesList != null)
{
var e = new Enumerator(f.ValuesList.Records)
for (; !e.atEnd(); e.moveNext())
{
s+= ’<option’
v = f.ValuesList.Value;
var selected
if (f.Values == null)
selected = f.IsEqual(v)
else
selected = f.Values.HasValue(v)
if (selected)
s += ’ selected’
n = f.ValuesList.ValueName;
if (n==’’)
{
n = v
v = ’’
}
if (v!=’’) s += ’ value="’ + v + ’"’
s += ’>’ + n + ’</option>\r\n’
c++
}
e.moveFirst()
}
r = new Object;
r.text = s
r.count = c
r.multiple = (f.Values == null) ? ’’ : ’multiple’
return r;
}
%>
<%
// Génération des options de sélection HTML pour un champ d’adaptateur
function WriteSelectOptions(f)
{
obj=SelOptions(f)
%>
<select size="<%=obj.count%>" name="<%=f.InputName%>" <%=obj.multiple%> >
<%=obj.text%>
</select>
<%
}
%>
Exemple 14
Voir aussi : propriétés Values et ValuesList du type AdapterField (page B-7)
Cet exemple écrit un champ d’adaptateur comme groupe d’éléments <input
type="checkbox">.
<%
// Renvoi d’un objet définissant des cases à cocher HTML pour un champ d’adaptateur.
// L’objet renvoyé possède les éléments suivants :
//
// text - chaîne contenant les éléments <input type=checkbox>.
// count - nombre d’éléments <option>.
//
// A utiliser comme suit pour définir un groupe de cases à cocher avec trois colonnes et
// aucun attribut supplémentaire :
// obj=CheckBoxGroup(f, 3, ’’)
// Response.Write(obj.text)
//
function CheckBoxGroup(f,cols,attr)
{
var s=’’
var v=’’
var n=’’
var c=0;
var nm=f.InputName
if (f.ValuesList == null)
{
s+= ’<input type="checkbox"’
if (f.IsEqual(true)) s+= ’ checked’
s += ’ value="true"’ + ’ name="’ + nm + ’"’
if (attr!=’’) s+= ’ ’ + attr
s += ’></input>\r\n’
c = 1
}
else
{
s += ’<table><tr>’
var e = new Enumerator(f.ValuesList.Records)
for (; !e.atEnd(); e.moveNext())
{
if (c % cols == 0 && c != 0) s += ’</tr><tr>’
s+= ’<td><input type="checkbox"’
v = f.ValuesList.Value;
var checked
if (f.Values == null)
checked = (f.IsEqual(v))
else
checked = f.Values.HasValue(v)
if (checked)
s+= ’ checked’
n = f.ValuesList.ValueName;
if (n==’’)
n = v
s += ’ value="’ + v + ’"’ + ’ name="’ + nm + ’"’
if (attr!=’’) s+= ’ ’ + attr
s += ’>’ + n + ’</input></td>\r\n’
c++
}
e.moveFirst()
s += ’</tr></table>’
}
r = new Object;
r.text = s
r.count = c
return r;
}
%>
<%
// Ecriture d’un champ d’adaptateur comme groupe de cases à cocher
function WriteCheckBoxGroup(f, cols, attr)
{
obj=CheckBoxGroup(f, cols, attr)
Response.Write(obj.text);
}
%>
Exemple 15
Voir aussi : propriétés Values et ValuesList du type AdapterField (page B-7), type
AdapterFieldValues (page B-10)
Cet exemple écrit un champ d’adaptateur sous forme de liste de valeurs en
lecture seule au moyen d’éléments <ul> et <li>.
<%
// Renvoi d’un objet définissant des valeurs de liste HTML pour un champ d’adaptateur.
// L’objet renvoyé possède les éléments suivants :
//
// text - chaîne contenant les éléments <li>.
// count - nombre d’éléments.
//
// text sera vide et count sera égal à zéro si le champ d’adaptateur ne
// prend pas en charge les valeurs multiples.
//
// A utiliser comme suit pour définir l’affichage d’une liste en lecture seule
// des valeurs de champ de cet adaptateur.
// obj=ListValues(f)
// Response.Write(’<ul>’ + obj.text + ’</ul’>’)
//
function ListValues(f)
{
var s=’’
var v=’’
var n=’’
var c=0;
r = new Object;
if (f.Values != null)
{
var e = new Enumerator(f.Values.Records)
for (; !e.atEnd(); e.moveNext())
{
s+= ’<li>’
s += f.Values.ValueField.DisplayText;
s += ’</li>’
c++
}
e.moveFirst()
}
r.text = s
r.count = c
return r;
}
%>
<%
// Ecriture d’un champ d’adaptateur comme liste de valeurs en lecture seule.
function WriteListValues(f)
{
obj=ListValues(f)
%>
<ul><%=obj.text%></ul>
<%
}
%>
Exemple 16
Voir aussi : type AdapterFieldValuesList (page B-11), propriétés Values et
ValuesList du type AdapterField (page B-7)
Cet exemple écrit un champ d’adaptateur comme groupe d’éléments <input
type="radio">.
<%
// Renvoi d’un objet qui définit des boutons radio HTML pour un champ d’adaptateur.
// L’objet renvoyé possède les éléments suivants :
//
// text - chaîne contenant les éléments <input type=radio>.
// count - nombre d’éléments.
//
// A utiliser comme suit pour définir un groupe de boutons radio avec trois colonnes
// et aucun attribut supplémentaire :
// obj=RadioGroup(f, 3, ’’)
// Response.Write(obj.text)
//
function RadioGroup(f,cols,attr)
{
var s=’’
var v=’’
var n=’’
var c=0;
var nm=f.InputName
if (f.ValuesList == null)
{
s+= ’<input type="radio"’
if (f.IsEqual(true)) s+= ’ checked’
s += ’ value="true"’ + ’ name="’ + nm + ’"’
if (attr!=’’) s+= ’ ’ + attr
s += ’></input>\r\n’
c = 1
}
else
{
s += ’<table><tr>’
var e = new Enumerator(f.ValuesList.Records)
for (; !e.atEnd(); e.moveNext())
{
if (c % cols == 0 && c != 0) s += ’</tr><tr>’
s+= ’<td><input type="radio"’
v = f.ValuesList.Value;
var checked
if (f.Values == null)
checked = (f.IsEqual(v))
else
checked = f.Values.HasValue(v)
if (checked)
s+= ’ checked’
n = f.ValuesList.ValueName;
if (n==’’)
{
n = v
}
s += ’ value="’ + v + ’"’ + ’ name="’ + nm + ’"’
if (attr!=’’) s+= ’ ’ + attr
s += ’>’ + n + ’</input></td>\r\n’
c++
}
e.moveFirst()
s += ’</tr></table>’
}
r = new Object;
r.text = s
r.count = c
return r;
}
%>
<%
// Ecriture d’un champ d’adaptateur comme groupe de boutons radio
function WriteRadioGroup(f, cols, attr)
{
obj=RadioGroup(f, cols, attr)
Response.Write(obj.text);
}
%>
Exemple 17
Voir aussi : propriétés DisplayStyle, ViewMode et InputStyle du type AdapterField
(page B-7)
Cet exemple génère le code HTML pour un champ d’adaptateur en fonction des
valeurs des propriétés InputStyle, DisplayStyle et ViewMode du champ.
<%
function WriteField(f)
{
Mode = f.ViewMode
if (Mode == ’Input’)
{
Style = f.InputStyle
if (Style == ’SelectMultiple’ || Style == ’Select’)
WriteSelectOptions(f)
else if (Style == ’CheckBox’)
WriteCheckBoxGroup(f, 2, ’’)
Exemple 18
Voir aussi : objet Page (page B-17), propriété Title de l’objet Application
(page B-15)
Cet exemple utilise des propriétés de l’objet Application et de l’objet Page pour
générer un en-tête de page.
<html>
<head>
<title>
<%= Page.Title %>
</title>
</head>
<body>
<h1><%= Application.Title %></h1>
Exemple 19
Voir aussi : objet EndUser (page B-16)
Cet exemple utilise les propriétés de l’objet EndUser pour afficher le nom d’un
utilisateur final, sa commande de connexion et sa commande de déconnexion.
<% if (EndUser.Logout != null)
{
if (EndUser.DisplayName != ’’)
{
%>
<h1>Bienvenue <%=EndUser.DisplayName %></h1>
<% }
if (EndUser.Logout.Enabled) {
%>
<a href="<%=EndUser.Logout.AsHREF%>">Logout</a>
<% }
if (EndUser.LoginForm.Enabled) {
%>
<a href="<%=EndUser.LoginForm.AsHREF%>">Login</a>
<% }
}
%>
Exemple 20
Voir aussi : type Module (page B-13)
Cet exemple énumère les objets de script d’un module.
<%
// Ecriture d’une table HTML avec le nom et le nom de classe de tous les objets de
script
// d’un module.
function ListModuleObjects(m)
{
%>
<p></p>
<table border="1">
<tr>
<th colspan="2"><%=m.Name_ + ’: ’ + m.ClassName_%></th>
</tr>
<%
Exemple 21
Voir aussi : propriétés DisplayStyle et Enabled du type AdapterAction (page B-4)
Cet exemple génère du code HTML pour une action d’adaptateur en fonction de
la propriété DisplayStyle de l’action.
<%
// Ecriture du code HTML pour une action d’adaptateur au moyen de la propriété
// DisplayStyle.
//
// a - action
// cap - libellé. S’il est vide, le libellé d’affichage de l’action est utilisé.
// fm - nom de la fiche HTML
// p - nom de la page à afficher après l’exécution de l’action. Si vide, la page en
// cours est utilisée.
//
// Remarquez que cette fonction n’utilise pas la propriété Array de l’action. On suppose
// que l’action possède une seule commande.
//
function WriteAction(a, cap, fm, p)
{
if (cap == ’’)
cap = a.DisplayLabel
if (p == ’’)
p = Page.Name
Style = a.DisplayStyle
if (Style == ’Anchor’)
{
if (a.Enabled)
{
// Ne pas utiliser la propriété href. Au lieu de cela, soumettre la fiche pour
// que les champs de la fiche HTML fassent partie de la requête HTTP.
%>
<a href=""onclick="<%=fm%>.__act.value=’
<%=a.LinkToPage(p).AsFieldValue%>’;<%=fm%>.submit();return false;">
<%=cap%></a>
<%
}
else
{
%>
<a><%=cap%></a>
<%
}
}
else
{
%>
<input type="submit" value="<%= cap%>"
onclick="<%=fm%>.__act.value=’<%=a.LinkToPage(p).AsFieldValue%>’">
<%
}
}
%>
Exemple 22
Voir aussi : propriétés HiddenFields, HiddenRecordFields et Mode du type Adapter
(page B-2)
Cet exemple génère une table HTML pour mettre à jour plusieurs
enregistrements détail.
<%
vItemsAdapter=Modules.DM.ItemsAdapter
vOrdersAdapter=Modules.DM.OrdersAdapter
vOrderNo=vOrdersAdapter.OrderNo
vCustNo=vOrdersAdapter.CustNo
vPrevRow=vOrdersAdapter.PrevRow
vNextRow=vOrdersAdapter.NextRow
vRefreshRow=vOrdersAdapter.RefreshRow
vApply=vOrdersAdapter.Apply
vItemNo=vItemsAdapter.ItemNo
vPartNo=vItemsAdapter.PartNo
vDiscount=vItemsAdapter.Discount
vQty=vItemsAdapter.Qty
%>
<!-- Utilisation de deux adaptateurs pour mettre à jour plusieurs enregistrements détail.
L’adaptateur des commandes est associé à l’ensemble de données maître.
L’adaptateur des éléments est associé à l’ensemble de données détail.
Chaque ligne d’une grille affiche des valeurs issues de l’adaptateur des éléments. Une
colonne affiche un élément <input> pour la modification de Qty. Le bouton de
validation
met à jour la valeur Qty dans chaque enregistrement détail.-->
<%
// Positionnement de l’adaptateur des éléments en mode edit, car cette fiche met à jour
// le champ Qty.
vItemsAdapter.Mode = ’Edit’
%>
<!-- Définition d’un champ masqué pour le nom d’action et les paramètres -->
<input type="hidden" name="__act">
<%
// Ecriture des champs masqués contenant des informations d’état sur
// l’adaptateur des commandes et l’adaptateur des éléments.
if (vOrdersAdapter.HiddenFields != null)
vOrdersAdapter.HiddenFields.WriteFields(Response)
if (vItemsAdapter.HiddenFields != null)
vItemsAdapter.HiddenFields.WriteFields(Response)
<table border="1">
<tr>
<th>ItemNo</th>
<th>PartNo</th>
<th>Discount</th>
<th>Qty</th>
</tr>
<%
var e = new Enumerator(vItemsAdapter.Records)
for (; !e.atEnd(); e.moveNext())
{ %>
<tr>
<td><%=vItemNo.DisplayText%></td>
<td><%=vPartNo.DisplayText%></td>
<td><%=vDiscount.DisplayText%></td>
<td><input type="text" name="<%=vQty.InputName%>" value="<%= vQty.EditText %>" ></td>
</tr>
<%
// Ecriture des champs masqués contenant des informations d’état sur chaque
// enregistrement de l’adaptateur des éléments. Cela est nécessaire pour l’adaptateur
// des éléments lors de la mise à jour du champ Qty.
if (vItemsAdapter.HiddenRecordFields != null)
vItemsAdapter.HiddenRecordFields.WriteFields(Response)
}
%>
</table>
<p></p>
<table>
<td><input type="submit" value="Prev Order"
onclick="AdapterForm1.__act.value=’<%=vPrevRow.LinkToPage(Page.Name).AsFieldValue%>’"></td>
<td><input type="submit" value="Next Order"
onclick="AdapterForm1.__act.value=’<%=vNextRow.LinkToPage(Page.Name).AsFieldValue%>’"></td>
<td><input type="submit" value="Refresh"
onclick="AdapterForm1.__act.value=’<%=vRefreshRow.LinkToPage(Page.Name).AsFieldValue%>’"></
td>
<td><input type="submit" value="Apply"
onclick="AdapterForm1.__act.value=’<%=vApply.LinkToPage(Page.Name).AsFieldValue%>’"></td>
</table>
</form>
Index I-1
AfterCancel, événement 22-24 contrôles texte 6-7 Insert et 22-22
AfterClose, événement 22-5 volets 8-48 AppendRecord, méthode 22-25
AfterConnect, événement 21-3, alignement A-4 application à niveau triple
29-30 champs de bits et A-7 Voir applications multiniveaux
AfterConstruction 13-15 membres de structures A-7 application de répartition de
AfterDelete, événement 22-23 mot A-7 sockets 29-11, 29-15, 29-27
AfterDisconnect, Alignment, propriété 9-7 Application, variable 8-2
événement 21-4, 29-30 barres d’état 9-17 applications
AfterDispatch, événement 33-6, champs 23-13 agent Web 33-1–33-22
33-9 contrôles mémo et texte Apache 32-7, 33-2, 34-9
AfterEdit, événement 22-20 formaté 9-3 applications client
AfterGetRecords, contrôles mémo orientés Web 29-33–29-45
événement 28-9 données 19-10 base de données 18-1
AfterInsert, événement 22-21 en-têtes de colonne 19-24 CGI autonome 34-9
AfterOpen, événement 22-5 grilles de décision 20-13 client/serveur 29-1
AfterPost, événement 22-24 grilles de données 19-23 protocoles de réseau 24-17
AfterScroll, événement 22-6 AllowAllUp, propriété 9-9 COM 7-20, 41-1
AggFields, propriété 27-16 boutons outil 8-52 COM+ 44-7
Aggregates, propriété 27-14, turboboutons 8-50 CORBA 31-1–31-20
27-16 AllowDelete, propriété 19-32 création 8-1
agrégation 38-9–38-10 AllowGrayed, propriété 9-9 déploiement 17-1
ensembles de données AllowInsert, propriété 19-32 distribuées 44-1
client 27-13–27-16 alTop, constante 8-48 fichiers 17-3
agrégats maintenus 18-18, ancrage 6-4 graphiques 45-8, 50-1
27-13–27-16 années bissextiles 55-9 informations d’état 9-17
champs agrégat 23-12 ANSI C ISAPI 32-7, 33-1, 34-9
opérateurs de synthèse 27-14 caractères multi-octets A-2 MDI 7-2
sous-totaux 27-15 diagnostics A-1, A-9 MTS 7-21
spécification 27-14–27-15 fonction main A-2 multiniveaux 29-1–29-45
valeurs 27-16 formats de la date et de présentation 29-4
Aide l’heure A-14 multiplates-formes 14-1–
aide contextuelle 9-17 standards, 14-31
bulles d’aide 9-17 implémentation A-1 multithreads 11-1
conseils d’aide 9-17 tirets, interprétation A-12 NSAPI 32-7, 33-1, 34-9
aide ANSI, jeu de caractères 16-3 portage vers Linux 14-2–
informations de types 39-9 AnsiString 52-9 14-22
aide en ligne 52-5 Apache, applications 32-7 réalisation de palettes 50-5,
aide par mot clé 7-34 création 34-9 50-6
Ajout de champs, boîte de débogage 32-11 SDI 7-2
dialogue 23-5 Apache, DLL 17-11 serveur Web 7-18, 34-8
Ajouter au référentiel, apartment, modèle de service 7-4
commande 7-27 thread 41-8 WinCGI autonome 34-9
alias API Open Tools Voir API Tools applications à base de
BDE 24-3, 24-15, 24-28– API outils natifs 58-2 fichiers 18-10–18-12
24-29 API Tools 58-1–58-25 ensembles de données
création 24-28 créateurs 58-3, 58-15–58-19 client 27-39–27-42
locaux 24-28 création de fichiers 58-15– applications à niveau
spécification 24-15, 58-19 double 18-3, 18-10, 18-14
24-16–24-17 débogage 58-12 applications à niveau
suppression 24-29 éditeurs 58-3, 58-13–58-15 unique 18-3, 18-10, 18-14
éditeur de bibliothèques de experts 58-3, 58-3–58-8 à base de fichiers 18-11
types 39-11, 39-18–39-19 modules 58-3, 58-13–58-15 applications Apache
AliasName, propriété 24-15 notificateurs 58-3 création 33-2
Align, propriété 8-4 services 58-2, 58-8–58-15 applications bidirectionnelles
barres d’état 9-17 Append, méthode 22-21, 22-23 méthodes 16-7
Index I-3
Arc, méthode 10-4
architecture
Assign, méthode
listes de chaînes 4-21
B
applications BDE 24-1–24-2 AssignedValues, balises HTML transparentes
applications CORBA 31-2– propriété 19-25 conversion 33-16
31-4 AssignValue, méthode 23-19 paramètres 33-15
applications de bases de Associate, propriété 9-6 prédéfinies 33-15
données 18-6–18-17, 24-1– ATL 38-23–38-25 syntaxe 33-14
24-2 fichiers en-tête 38-24 balises transparentes pour
client 29-5 options 41-9 HTML
serveur 29-6 suivi des appels 41-9, 41-18 prédéfinition 29-44–29-45
applications serveur agent atomicité bandes d’actions 8-21
Web 33-3 transactions 18-5, 44-11 définition 8-19
multiniveau 29-5, 29-6 Attributes, propriété Bands, propriété 8-53, 9-10
architecture multiniveau 29-6 paramètres 22-53, 22-61 barre de défilement
argument dynamique 13-30 TADOConnection 25-7 fenêtres du texte 6-8
arguments attributs barres d’état 9-17
fonction fmod et A-10 éditeurs de propriétés 52-11 internationalisation 16-9
ARRAYSIZE, macro 13-18 attributs d’activation 44-7 barres d’outils 8-47, 9-10
arrêt des threads 11-13 attributs de champs 23-15– ajout 8-50–8-52
Arrière-plan 8-23 23-17 ajout de volets comme 8-48–
arrière-plan 16-10 affectation 23-16 8-50
transparent 16-10 dans les paquets de conception 8-47–8-54
arrondir données 28-7 création 8-21
règles A-5 suppression 23-16 définition 8-19
AS_ApplyUpdates, attributs de transaction définition des marges 8-49
méthode 28-4 modules de données désactivation des
AS_ATTRIBUTE 36-8 MTS 29-17 boutons 8-51
AS_DataRequest, méthode 28-4 attributs transactionnels insertion de boutons 8-48–
AS_Execute, méthode 28-4 définir 44-13 8-50, 8-51
AS_GetParams, méthode 28-4 Audit de code listes d’actions 8-20
AS_GetProviderNames, modèles 7-3 masquées 8-54
méthode 28-4 auto_ptr 12-6 menus contextuels 8-53
AS_GetRecords, méthode 28-4 AutoCalcFields, propriété 22-26 outil de dessin par
AS_RowRequest, méthode 28-4 AutoComplete, propriété 29-8 défaut 8-49
ASCII, tables 24-6 AutoDisplay, propriété 19-10, transparentes 8-51, 8-53
ASP 38-14, 42-1–42-9 19-11 turboboutons 9-9
comparé à ActiveX 42-8 AutoEdit, propriété 19-5 barres de défilement 9-5
comparé au courtier AutoHotKeys, propriété 8-37 barres de progression 9-17
Web 42-1 Automation barres graduées 9-5
conception d’interfaces compatibilité de type 39-13 barres graduées horizontales 9-6
utilisateur 42-1 descriptions de types 38-13 barres graduées verticales 9-6
documents HTML 42-1 IDispatch, interface 41-14 barres multiples 8-47, 9-10
éléments intrinsèques 42-2– liaison tardive 41-15 ajout 8-52–8-53
42-3, 42-3–42-7 objets Active Server 42-2 conception 8-47–8-54
génération de pages 42-3 optimisation 38-19 configuration 8-53
langage de script 42-3 automation masquées 8-54
objet Application 42-4 liaison immédiate 38-19 bascules 8-50, 8-52
objet Request 42-4–42-5 AutoPopup, propriété 8-54 BaseCLX
objet Response 42-5–42-6 AutoSelect, propriété 9-4 classes d’exception 12-18
objet Server 42-7 AutoSessionName, définition 4-1, 14-6
objet Session 42-6–42-7 propriété 24-20, 24-33, 33-19 bases de données 7-16, 18-1–
performances 42-1 AutoSize, propriété 8-5, 9-3, 18-6, 56-1
script 38-14 17-15, 19-9 à base de fichiers 18-3
assembleur GNU .AVI, fichiers 10-35 accès aux 22-1
Linux 14-18 clips .avi 9-21 accès non autorisé 21-4
Index I-5
emplacement 29-36, 29-38 boîte d’état des threads 11-13 glissement des éléments 6-2,
Bind, méthode boîtes à options 9-12, 14-8, 19-2, 6-3
TAutoDriver 40-14 19-13 orientées données 19-11–
biseaux 9-20 de référence 19-24 19-15
bitmap, objets 10-3 dessinées par le propriétés de stockage
bitmaps 9-20, 10-19–10-20, 50-4 propriétaire 6-12 exemple 8-9
ajout aux composants 45-16, measure-item, remplissage 19-12
52-4 événements de type 6-16 boîtes liste de cases à
ajout du défilement 10-18 styles de variant 6-13 cocher 9-11
apparition dans orientées données 19-11– boîtes liste de référence 19-2,
l’application 10-2 19-15 19-13–19-15
association à des boîtes à options de champs de référence 19-14
chaînes 4-21, 6-14 référence 19-3, 19-13–19-15 sources de données
barres d’outils 8-51 champs de référence 19-14 secondaires 19-14
chargement 50-5 dans les grilles de Bookmark, propriété 22-11
comparés aux contrôles données 19-24 BookmarkValid, méthode 22-11
graphiques 54-4 remplissage 19-24 booléennes
dans les cadres 8-16 sources de données valeurs 56-4
défilement 10-18 secondaires 19-14 BorderWidth, propriété 9-15
définition de la taille boîtes à peindre 5-7, 9-21 bordures
initiale 10-19 boîtes de dialogue 57-1–57-7 volets 9-15
dessin sur 10-19 communes 8-17 BorlandIDEServices
destruction 10-23 création 57-1 variable 58-9
événements dessinés par le définition de l’état initial 57-2 BorlandIDEServices,
propriétaire 6-17 éditeurs de propriété variable 58-25
hors écran 50-6–50-7 comme 52-10 boucle des messages
internationalisation 16-11 exemple DLL de 7-14 threads 11-5
pinceaux 10-10 internationalisation 16-9, BoundsChanged,
propriétés des pinceaux 10-8, 16-11 méthode 51-15
10-10 multipages 9-16 boutons 9-7–9-9
remplacement 10-22 standard Windows 57-2 affectation de glyphes
surfaces de dessin 50-4 création 57-2 aux 8-49
temporaires 10-18, 10-19 exécution 57-5 ajout aux barres
vides 10-19 boîtes de dialogue d’outils 8-48–8-50, 8-51
BLOB 19-10 communes 57-1 désactivation sur les barres
mise en cache 24-4 boîtes de dialogue d’outils 8-51
BLOB, champs 19-2, 19-3 multipages 9-16 et barres d’outils 8-47
affichage des boîtes de dialogue navigateur 19-33
graphiques 19-11 standard 8-17, 57-2 boutons bitmap 9-8
affichage des valeurs de création 57-2 boutons outil 8-51
champs 19-10 exécution 57-5 ajout d’images 8-51
extraction à la demande 28-6 boîtes graphiques 19-2 dans plusieurs lignes 8-51
bloc de terminaison 12-14 boîtes groupe 9-14 désactivation 8-51
bloc try 12-2 boîtes liste 9-11, 19-2, 19-13, état initial, définition 8-51
BlockMode, propriété 37-10, 55-1 forcer le passage à la
37-11 déplacement des ligne 8-51
bmBlocking 37-11 éléments 6-3 groupe/interrompre le
BMPDlg, unité 10-22 dessinées par le groupe 8-52
bmThreadBlocking 37-11 propriétaire 6-12 obtenir de l’aide avec 8-53
BOA 31-2, 31-5, 31-6 draw-item, utilisation comme
BOA_init 31-8 événements 6-17 bascules 8-52
conflits de threads 31-12 measure-item, boutons radio 9-9, 19-2
initialisation 31-14 événements de type 6-16 orientés données 19-16
méthode obj_is_ready 31-8 styles de variant 6-13 regroupement 9-14
Bof, propriété 22-7, 22-10 sélection 19-16
Index I-7
taille 6-9 champs BLOB ChangedTableName,
traduction 16-2, 16-9, 16-11 obtenir les valeurs 24-4 propriété 24-60
tri 16-10 champs booléens 19-2, 19-15 CHANGEINDEX 27-9
tronquer 16-3 champs cachés 28-5 Char, type de données 16-3
zéro terminal 4-26–4-27 champs calculés 22-26–22-27, chargement
chaînes, changement 23-7 graphiques 50-4
permanent A-14 affectation de valeurs 23-9 Chart FX 17-5
champ, objets 23-1–23-32 champs de référence et 23-11 CHECK, contrainte 28-15
accès aux valeurs 23-22– définition 23-8–23-10 Checked, propriété 9-9
23-24 ensembles de données CheckSynchronize, routine 11-5
définition 23-6 client 27-13 chemins (URL) 32-4
dynamiques 23-2–23-3 champs de bits A-6 ChildName, propriété 29-32
ou persistants 23-2 alignement A-7 Chord, méthode 10-4
événements 23-18 débordement de frontières classe d’exception 12-18
persistants 23-3–23-19 de mots A-7 classe lien de données sur un
ou dynamiques 23-2 ordre d’affectation A-6 champ 56-12
propriétés 23-2, 23-13–23-18 champs de données 23-7 classes 45-2, 46-1, 47-3
exécution 23-15 définition 23-7–23-8 abstraites 45-3
partage 23-15 champs de référence 19-14, accès 46-4–46-8, 54-7
propriétés d’affichage et 23-7, 23-31–23-32 ancêtre 46-4
d’édition 23-13 dans les grilles de par défaut 46-4
suppression 23-12–23-13 données 19-24 création 46-1
champs 23-1–23-32 définition 23-10–23-11 définition 45-13, 46-2
activation 23-19 fourniture de valeurs par dérivation de nouvelles 46-2
affectation de valeurs 22-25 programme 23-11 descendantes 46-4
affichage des listes 21-15 mise en mémoire cache des éditeurs de propriétés
affichage des valeurs 19-12, valeurs 23-11 comme 52-8
23-20 performances 23-11 hiérarchie 46-4
ajout aux fiches 10-28–10-29 spécification 19-24 instanciation 46-2, 48-2
bases de données 56-6, 56-8 champs mémo 19-2, 19-10 par défaut 46-4
cachés 28-5 texte formaté 19-10–19-11 partie private 46-5
colonnes persistantes champs numériques partie protégée 46-7
et 19-20 formatage 23-17 partie publiée 46-8
création 23-6 champs persistants 19-18, 23-3– partie publique 46-7
définition des limites de 23-19 pointeurs 46-11
données 23-24–23-26 ADT, champs 23-27–23-28 propriétés comme 47-3
enregistrements de affichage des listes 23-5, 23-6 restriction d’accès 46-5
message 51-7 attribution de nom 23-6 support Pascal Objet 13-16
extraction de données 23-20 création 23-4 transmission comme
formats par défaut 23-17 création de tables 22-45 paramètres 46-11
lecture seule 19-6 définition 23-6 classes créateur
mise à jour des valeurs 19-6 ensembles de données, CoClasses 40-6, 40-14
modification des valeurs 19-6 champs 22-43 classes de base
options mutuellement modification de l’ordre 23-6 constructeurs 13-11
exclusives 19-2 paquets de données 28-5 classes de style VCL 13-1
propriétés 23-2 propriétés 23-13–23-18 héritage 13-2
saisie de données 22-22, retour à des champs classes distantes 36-5, 36-8–
23-17 dynamiques 23-4 36-10
types de données suppression 23-12–23-13 exceptions 36-16–36-17
abstraites 23-26–23-32 tableau, champs 23-29 exemple 36-9–36-10
valeurs null 22-25 types de données 23-7 gestion de la durée de
valeurs par défaut 23-24 types spéciaux 23-6, 23-7 vie 36-9
champs agrégat 23-7, 27-16 Change, méthode 56-12 prédéfinies 36-8
affichage 23-12 ChangeCount, propriété 14-29, recensement 36-5
définition 23-12 24-37, 27-7 classes holder 36-6
Index I-9
extensions 38-2 exécution 25-20 déplacement 45-21
interfaces 38-3, 41-10 itération sur les 21-14 double-clic 52-17, 52-18–
identificateurs de paramètres 25-21–25-22 52-19
répartition 41-14 récupération de initialisation 47-14, 54-8,
présentation 38-1–38-25 données 25-21 56-7
proxy 38-8 spécification 25-19–25-20 installation 5-10, 15-6–15-7,
spécification 38-2 commandes, listes 45-20, 52-20
types de serveurs 38-5 d’actions 8-20 interfaces 46-4, 46-7, 57-2
COM+ 7-21, 29-7, 38-11, 38-15, Commands, propriété 21-14, conception 46-8
44-1, 44-21–44-22 25-8 exécution 46-7
Voir aussi objets CommandText, propriété 22-51, menus contextuels 52-17,
transactionnels 25-17, 25-18, 25-19, 25-21, 52-18
applications 44-29 26-7, 26-8, 27-38 modification 53-1–53-5
comparé à 44-2 CommandTimeout, modification des
événements 40-16–40-17, propriété 25-6, 25-21 données 56-9–56-13
44-22–44-26 CommandType, non visuels 45-5, 45-13, 57-3
gestionnaire de propriété 25-17, 25-18, 25-19, orientés données 56-1
composants 44-30 26-6, 26-7, 26-8, 27-38 palette des bitmaps 52-4
objets événement 44-24– commentaires paquets 15-10, 52-20
44-25 conformité ANSI A-2 personnalisation 45-3, 47-1
objets souscripteur Commit, méthode 21-9 personnalisés 5-10, 8-13
d’événement 44-25 CommitTrans, méthode 21-9 présentation 45-1
pointeurs d’interface 38-5 CommitUpdates, recensement 45-14, 52-2
serveurs en processus 38-7 méthode 14-30, 24-37, 24-41 redimensionnement 9-7
synchronisation communes, boîtes de regroupement 9-14–9-16
d’appel 44-21–44-22 dialogue 57-1 répondre aux
transactions 29-20 communication entre événements 56-8
COM, bibliothèque 38-2 niveaux 29-10 scruter les données 56-2–
COM, interfaces 38-3–38-5, 41-3 communications 37-1 56-8
ajout à des bibliothèques de normes 32-3 standard 5-7–5-10
types 39-15 OMG 31-1 test 45-17, 45-19, 57-7
Automation 41-13–41-15 protocoles 24-17, 32-3, 37-2 composants auto-répartis 36-13,
définition 38-3 UDP et TCP 31-3 36-17
identificateurs de communications composants base de
répartition 41-14 inter-entreprises 35-1 données 7-16, 24-3–24-4,
implémentation 38-6, 38-25 commutateurs du lieur 24-14–24-18
informations de type 38-17 paquets 15-13 application des mises à jour
interfaces doubles 41-13– CompareBookmarks, en cache 24-40
41-14 méthode 22-11 identification des bases de
IUnknown 38-4 compilation du code 2-5 données 24-15–24-17
marshaling 38-8–38-9 composant de bases de données partagés 24-18
modification 39-15–39-17, temporaires 24-23 sessions et 24-14–24-15,
41-10 composant enveloppe 57-2 24-23
optimisation 38-19 composants 46-1, 47-3 temporaires
pointeur d’interface 38-5 abstraits 45-3 interruption 24-23
propriétés 39-10 aide à la décision 20-1 composants calendrier 9-14
COMCTL32.DLL 8-47 aide en ligne 52-5 composants connexion
CommandCount, ajout à l’unité existante 45-13 base de données
propriété 21-14, 25-8 ajout à la palette de dans les modules de
commande, objets composants 52-1 données distants 29-6
itération sur les 21-14 ajout aux unités 45-13 implicite 24-3
commandes ADO 25-8, 25-19– bitmaps 45-16 DataSnap 29-5, 29-25
25-22 classes dérivées 45-13, 54-3 fermeture des
annulation 25-20–25-21 création 45-2, 45-9 connexions 29-30
asynchrone 25-20 dépendances 45-6
Index I-11
constructeur de requêtes 22-50 contrôles création 43-2, 43-7
constructeur SQL 22-50 affichage des données 19-4, création à partir d’un
constructeurs 12-6, 12-16, 23-20–23-21 contrôle VCL 43-4–43-7
45-18, 47-13, 49-3, 55-4, 56-7 changement 45-3 débogage 43-17
applications dessin 54-8, 54-10, 55-5 déclenchement
multiplates-formes 14-13 dessinés par le d’événements 43-12
C++ comparé à Pascal propriétaire 6-12, 6-15 déploiement Web 43-18–
Objet 13-22 dessin 6-15, 6-16 43-20
classe de base 13-9, 13-13 dimensionnement 6-15 éléments 43-3–43-4
copie 13-7 événements 6-15 expert 43-7
déclaration 45-14 styles 6-13 expert contrôle
multiples 8-9 éditeur 6-7 ActiveX 43-4–43-6
objets ayant un propriétaire éditeur de texte formaté 6-7 génération 43-2
et 54-6, 54-8 fenêtrés 45-4 gestion des
surcharge 53-3 forme 54-8 événements 43-12
constructeurs de copie 13-7 graphiques 45-4, 50-4 implémentation 43-3
construction de paquets 15-11– comparés aux importation 40-4–40-5
15-14 bitmaps 54-4 informations de version 43-5
contacter Borland 1-3 création 45-4, 54-3 interfaces 43-9–43-14
Contains, liste (paquets) 15-7, dessin 54-3–54-5 licence 43-5, 43-8
15-8, 15-9, 15-11 enregistrement des modèle de thread 43-5
Content, méthode ressources système 45-4 orientés données 40-9, 43-9,
générateurs de page 33-16 événements 50-7 43-12–43-14
Content, propriété mémo 6-7 pages de propriétés 40-8,
réponse Web, objets 33-13 orientés données 19-1–19-36 43-4, 43-14–43-17
ContentFromStream, méthode palettes et 50-5–50-6 propriétés persistantes 43-14
générateurs de page 33-16 personnalisés 45-5 recensement 43-17
ContentFromString, méthode bibliothèques 45-5 types compatibles
générateurs de page 33-16 pour modifier les Automation 43-4, 43-9
ContentStream, propriété données 56-9–56-13 contrôles animation 9-21,
réponse Web, objets 33-13 pour scruter les 10-31–10-33
contexte des données données 56-2–56-8 exemple 10-32
applications de service préexistants 45-5 contrôles d’édition 19-9
Web 36-9 réception de la sélection de texte 6-9
contextes de périphériques 10-2, focalisation 45-4 contrôles de
45-8, 50-1 redessin 55-5 redimensionnement 9-7
contextes objet redimensionnement 50-7, contrôles de saisie 9-1–9-4, 9-5
ASP 42-3 55-5 contrôles de texte formaté 9-3,
ContextHelp 7-38 regroupement 9-14–9-16 19-10–19-11
contraintes contrôles ActiveX 17-5, 38-11, contrôles de texte
contrôles 8-4–8-5 38-14, 40-11, 43-1–43-20 multiligne 19-10
données 23-24–23-26 ajout d’événements 43-10– contrôles dessinés par le
création 23-24–23-25 43-11 propriétaire 4-21
désactivation 27-36 ajout de méthodes 43-10– boîtes liste 9-11, 9-12
ensembles de données 43-11 contrôles en-têtes 9-16
client 27-8–27-9, 27-35– ajout de propriétés 43-10– contrôles graphiques 54-1–
27-36 43-11 54-11
importation 23-25–23-26, applications Web 38-14 dessin 54-9
27-36, 28-15, 28-16 bibliothèques de types 38-18, contrôles haut-bas 9-6
contrat de licence 17-18 43-3 contrôles incrémenteur 9-6
contravariance 13-26 boîte à propos 43-5 contrôles liste 9-11–9-14
contrôle de version 2-5 .cab, fichiers 43-19 contrôles mémo 9-3
ContrôleBD, page de la palette composants enveloppe 40-7, contrôles onglets 9-16
de composants 5-8, 18-17, 40-8, 40-9–40-11
19-1, 19-2 conception 43-4
Index I-13
CreateSuspended, CurValue, propriété 28-13 dates A-14
paramètre 11-12 Custom, propriété 29-43 composants calendrier 9-14
CreateTable, méthode 22-46 CustomConstraint, internationalisation 16-10
CreateTransactionContextEx propriété 23-13, 23-24, 27-9 locales A-14
exemple 44-15 CutToClipboard, méthode 6-10 paramétrage A-9
créateurs 58-3, 58-15–58-19 contrôles mémo orientés saisie 9-14
création d’un module de page données 19-10 DateTimePicker,
Web 34-20 graphiques 19-11 composant 9-14
Créer un ensemble de données, Day, propriété 55-7
commande 22-46 D DB/2, pilote
Créer un sous-menu, commande déploiement 17-10
-D, option du lieur 15-13
(menu Concepteur) 8-38, 8-41 dBASE, tables 24-6
Data, propriété 27-6, 27-16,
Créer une table, ajout
27-18, 27-41
commande 22-46 d’enregistrements 22-22,
Database, paramètre 26-4
crtl.dcu 17-7 22-23
DatabaseCount, propriété 24-24
cryptage DBChart, composant 18-18
DatabaseName, propriété 21-2,
TSocketConnection 29-27 DBCheckBox, composant 19-2,
24-3, 24-16
cubes de décision 20-7, 20-10 19-15–19-16
requêtes hétérogènes 24-10
affichage des données 20-10, DBComboBox, composant 19-2,
Databases, propriété 24-24
20-12 19-12–19-13
DataChange, méthode 56-12
DimensionMap 20-8 DBConnection, propriété 27-20
DataCLX
dimensions paginées 20-23 DBCtrlGrid, composant 19-3,
définition 14-6
dimensions, ouverture/ 19-31–19-33
DataField, propriété 19-12, 56-6
fermeture 20-10 propriétés 19-32
boîtes listes de référence et
état perforé 20-10 DBEdit, composant 19-2, 19-9
boîtes à options de
événements 20-8 DBEdit, contrôles 19-2
référence 19-14
forage 20-5 multiligne 19-10
DataRequest, méthode 27-38,
gestion de la mémoire 20-9 texte formaté 19-10
28-4
obtention de données 20-5 dbExpress 17-8, 18-2, 26-1–26-2
DataSet, propriété
options de conception 20-9 applications
fournisseurs 28-2
paramètres de multiplates-formes 14-22–
grilles de données 19-19
dimensions 20-22 14-29
DataSetCount, propriété 21-14
pivotement 20-5 composants 26-1–26-21
DataSetField, propriété 22-43
rafraîchissement 20-8 débogage 26-19–26-21
DataSets, propriété 21-14
sous-totaux 20-5 déploiement 26-1
DataSnap, page de la palette de
Currency, propriété métadonnées 26-13–26-19
composants 5-8, 29-3, 29-5,
champs 23-13 pilotes 26-4
29-7
curseurs 22-6 dbExpress, applications 17-11
DataSource, propriété
bidirectionnel 22-57 dbExpress, page de la palette de
boîtes listes de référence et
clonage 27-17 composants 5-8, 18-2, 26-2
boîtes à options de
déplacement 22-7, 22-8, dbGo 25-1
référence 19-14
22-33, 22-34 DBGrid, composant 19-2,
contrôles orientés
avec des conditions 22-12 19-17–19-31
données 56-6
sur la dernière ligne 22-7, événements 19-30
grilles de données 19-19
22-9 propriétés 19-23
navigateurs de
sur la première ligne 22-7, DBGridColumns,
données 19-35
22-10 composant 19-18
requêtes 22-54
liaison 22-41, 26-13 DBImage, composant 19-2,
DataSource, propriétés
synchronisation 22-48 19-11
contrôles ActiveX 40-9
unidirectionnels 22-57 DblClick, méthode 51-14
DataType, propriété
curseurs bidirectionnels 22-57 DBListBox, composant 19-2,
paramètres 22-53, 22-60,
curseurs de glissement 6-2 19-12–19-13
22-61
curseurs unidirectionnels 22-57 DBLogDlg, unité 21-5
date, champs
CursorChanged, méthode 51-15 DBLookupComboBox,
formatage 23-17
CursorType, propriété 25-14 composant 19-3, 19-13–19-15
Index I-15
détail, fiches 19-17 DirtyRead 21-10 ActiveForms 43-6
détails imbriqués 22-43, 23-30– DisableCommit, méthode 44-14 applications
23-31, 29-21 DisableConstraints, InternetExpress 29-35
extraction à la demande 28-6 méthode 27-36 ASP 42-1
DeviceType DisableControls, méthode 19-7 bases de données et 33-18
propriété 10-34 DisabledImages, propriété 8-51 contrôles ActiveX
.DFM, fichiers 16-11 DisconnectEvents, 43-1
génération 16-13 méthode 40-16 ensembles de données 33-21
.dfm, fichiers 47-11 Dispatch, méthode 51-4, 51-5 feuilles de style 29-43
fichiers .dfm 14-2 dispID 38-18, 40-15, 41-14 générateurs de page 33-14–
diagnostic (ANSI C) A-1 liaison 41-15 33-18
Dialogues, page de la palette de dispIDs 41-14 générateurs de table 33-20–
composants 5-9 dispinterfaces 41-13, 41-14– 33-22
dictionnaire de données 23-15– 41-15 incorporation de tables 33-21
23-17, 24-60–24-61 bibliothèques de types 39-10 modèles 29-41, 29-44–29-45,
contraintes 28-16 liaison dynamique 39-10 33-14–33-16
dictionnaire des données 29-3 DisplayFormat, propriété 19-30, documents XML 30-1, 35-1–
didacticiel 23-13, 23-18 35-10
WebSnap 34-12–34-25 DisplayLabel, propriété 19-20, attributs 35-5
différence entre majuscules et 23-13 composants 35-3–35-4, 35-9
minuscules DisplayWidth, propriété 19-19, conversion en paquets de
identificateurs externes 23-13 données 30-1–30-9
et A-3 Dissocier attributs, fichiers de
suppression A-3 commande 23-17 transformation 30-1
différence majuscules/ division, signe du reste A-6 génération des
minuscules DLL 7-13, 31-15, 31-16 interfaces 35-6
index 27-10 création 7-10, 7-12 mappage des nœuds et des
Linux 14-15 déploiement 17-11 champs 30-2
DII HTTP, serveurs 32-6, 32-7 nœud racine 35-4, 35-7, 35-9
référentiel d’interface 31-14 incorporation dans le nœuds
DimensionMap, propriété 20-8 document HTML 33-15 attributs 30-6
Dimensions, propriété 20-13 installation 17-6 nœuds 35-2, 35-4–35-6
Direction, propriété internationalisation 16-12, nœuds enfant 35-5–35-6
paramètres 22-53, 22-61 16-13 propriétés des nœuds 35-7
directives liaison 7-16 publication d’informations
#ifdef 14-19 Linux Voir fichiers .so de base de données 30-10
#ifndef 14-20 MTS 44-2 DoExit, méthode 56-14
#pragma paquets 15-1, 15-2, 15-13 DOM 35-2, 35-2–35-3
messagecompiler 14-20 serveurs COM 38-7 implémentations 35-2
$LIBPREFIX, modèles de thread 41-7 utilisation 35-4
compilateur 7-11 DLL serveur Apache 32-7 DoMouseWheel, méthode 51-14
$LIBSUFFIX, création 33-2, 34-9 données
compilateur 7-11 DLL serveur Microsoft 32-7 accès 56-1
$LIBVERSION, création 34-9 affichage 23-20, 23-20–23-21
compilateur 7-11 dllexport 7-12, 7-13 dans les grilles 19-18,
compilation DllGetClassObject 44-3 19-31
conditionnelle 14-19 dllimport 7-12 désactivation de
Linux 14-20 DllRegisterServer 44-3 l’affichage 19-7
override 51-4 DML 21-11, 22-49, 22-56, 24-9 valeurs actuelles 19-9
protected 48-5 fichiers .dmt 8-42, 8-44 affichage seulement 19-9
published 47-3, 57-4 document actif 40-18 analyse 18-18, 20-2
directives de compilation DocumentElement, établissement de
applications Linux 14-19 propriété 35-4 rapports 18-18
bibliothèques 7-11 documents Active 38-11, 38-15 formats,
paquets 15-12 documents HTML internationalisation 16-10
Index I-17
éditeur de pages Web 29-42– lignes de séparation 8-37 itération dans les 22-9
29-43 modification 8-40 lecture 26-9, 27-31–27-32
éditeur de propriétés de bases nommer 8-34, 8-44 asynchrone 25-13
de données 24-16 regroupement 8-37 marquage 22-11–22-12
affichage des paramètres de sélection 6-10 mise à jour 22-25–22-26,
connexion 24-17 suppression 8-36, 8-41 24-9, 24-57, 28-9
éditeur de requête de éléments Web à partir de documents
décision 20-6 propriétés 29-43–29-44 XML 30-11–30-12
éditeur SQL de mise à Ellipse, méthode 10-5, 10-12, ensembles de données
jour 24-47–24-48 50-3 client 27-24–27-29
page Options 24-47 ellipses filtrage des mises à
page SQL 24-47 dessin 10-12, 54-10 jour 28-13
éditeurs Embed , balise HTML identification des
API Tools 58-3, 58-13–58-15 (<EMBED>) 33-15 tables 28-14
éditeurs de composants 52-17– empaquetage faible 15-12 multiples 28-7
52-20 EmptyDataSet, méthode 22-47, paquets delta 28-9, 28-10
par défaut 52-17 27-32 requêtes et 24-12
recensement 52-20 EmptyTable, méthode 22-47 opérations 24-9
éditeurs de propriétés 5-3, 47-3, EnableCommit, méthode 44-14 opérations groupées 24-9,
52-8 EnableConstraints, 24-57, 24-58
attributs 52-11 méthode 27-36 rafraîchissement 19-7,
boîtes de dialogue EnableControls, méthode 19-7 27-36–27-37
comme 52-10 Enabled, propriété recherche 22-12–22-14,
comme classes dérivées 52-8 contrôles orientés 22-32–22-35
recensement 52-12–52-13 données 19-8 régularisation des mises à
EditFormat, propriété 19-30, éléments d’action 33-7 jour 27-27
23-13, 23-18 menus 6-10, 8-45 réitération de
EditKey, méthode 22-32, 22-35 sources de données 19-4, recherches 22-35
EditMask, propriété 23-17 19-6 suppression 22-23, 22-47,
champs 23-13 turboboutons 8-49 24-9, 24-58
EditRangeEnd, méthode 22-39 EnabledChanged, synchronisation de
EditRangeStart, méthode 22-39 méthode 51-15 l’enregistrement en
éléments d’action 33-3, 33-4, END_MESSAGE_MAP, cours 22-48
33-6–33-9 macro 51-4, 51-8 tri 22-30–22-32
activation et EndRead, méthode 11-9 validation 19-7, 22-24
désactivation 33-7 EndWrite, méthode 11-9 à la fermeture des
ajout 33-5 enregistrement ensembles de
chaînage 33-9 graphiques 50-4 données 22-24
générateurs de page et 33-16 Enregistrement de modèle, boîte grilles de données 19-29
gestionnaires de dialogue 8-44 Enregistrer attributs,
d’événements 33-4 enregistrements commande 23-15
par défaut 33-6, 33-7 affichage 19-31 Enregistrer comme modèle,
précaution de ajout 22-21–22-23, 22-25, commande (menu
changement 33-3 24-57 Concepteur) 8-41, 8-44
répartition 34-43 opérations groupées 24-57 ensemble de données
sélection 33-6, 33-7 ajout à la fin 22-23 BDE 24-2–24-3
éléments de menu 8-35–8-37 ajouts 24-9 ensemble de données BDE
ajout 8-35, 8-45 copie 24-9, 24-57 support de base de données
définition 8-33 critères de recherche 22-12, locale 24-6–24-8
définition des 22-13 types 24-2
propriétés 8-40–8-41 déplacement dans les 19-33, ensembles 47-2
déplacement 8-38 22-6–22-10, 22-19 ensembles d’onglets 9-16
emplacements 8-41 éditeur de bibliothèques de ensembles de données 18-8,
imbrication 8-38 types 39-11, 39-19 22-1–22-63
lettres soulignées 8-37 filtrage 22-15–22-19 ADO 25-9–25-19
Index I-19
types 26-2–26-3 fonctions mathématiques utilisateur 3-3
ensembles de données, et A-9 wrappeurs de composants
champs 23-26, 23-30–23-31 espaces de nommage 45-14 VCL 40-3
affichage 19-27 interfaces invocables 36-3 événements clavier
persistants 22-43 événement, objets 11-11 internationalisation 16-9
en-têtes événements 5-4–5-7, 45-7, événements de connexion 21-5
de réponse 33-13 48-1–48-10 événements Qt
de requête 33-9 accès 48-5 messages 51-16
requêtes HTTP 32-4 aide sur 52-5 événements souris 10-25–10-28,
en-têtes de colonne 9-16, 19-20, association à des 54-3
19-24 gestionnaires 5-5 définis 10-25
en-têtes de messages attente d’ 11-11 informations d’état 10-26
(HTTP) 32-3, 32-4 champ, objets 23-18 paramètres 10-26
entiers clic 48-1, 48-2 test 10-28
décalage à droite A-6 COM 41-11, 41-12 événements standard 48-4
division A-6 COM+ 40-16–40-17, 44-22– événements système
énumérations et A-7 44-26 personnalisation 51-16
pointeurs et A-6 connexion 21-5 EventFilter, méthode
signés connexions ADO 25-8–25-9 événements système 51-15
opérateurs au niveau contrôles graphiques 50-7 évolutivité 18-13
bit A-5 contrôles orientés données EWriteError 4-3
tableaux et A-5 activation 19-8 __except, mot clé 12-8, 12-9
transtypage en pointeurs A-6 contrôleurs Exception
entrée, paramètres 22-59 Automation 40-12, 40-16– définition 3-5
entrée/sortie, paramètres 22-59 40-17 __except, mot clé 12-11
énumérations A-7 courtiers XML 29-40 exceptions 49-2, 51-3
enveloppes 45-5, 57-2 déclenchement 43-12 constructeurs 13-14
initialisation 57-4 définition de déclenchement 4-2
enveloppes de composant 45-5 nouveaux 48-7–48-10 définition 12-1
enveloppes de composants délai 11-12 format bit 12-13
initialisation 57-4 gestion des messages 51-4, Linux 14-16
environnement de traduction 51-6 redéclenchement 4-2
intégré 16-14 gestionnaires par threads 11-7
environnement du système défaut 48-10 exceptions non gérées 12-6
d’exploitation grilles de décision 20-14 Exclusive, propriété 24-6
chaînes, changement grilles de données 19-30– ExecProc, méthode 22-62, 26-11
permanent A-14 19-31 ExecSQL, méthode 22-56, 26-11
environnements A-14 hérités 48-5 objets mise à jour 24-53
envoi des messages 51-8–51-11 implémentation 48-2 Execute, méthode 57-5
EOF, marqueur 4-5 interfaces 41-12 boîtes de dialogue 8-17
Eof, propriété 22-7, 22-8, 22-9 niveau application 8-2 commandes ADO 25-20,
équilibrage de charge 31-3 nommer 48-9 25-22
EReadError 4-3 objets Automation 41-5 composants de
ERemotableException 36-16, objets COM 41-4, 41-11– connexion 21-11–21-12
36-17 41-13 ensembles de données
erreurs par défaut 5-4 client 27-33, 28-4
débordement inverse A-10 partagés 5-6 fournisseurs 28-4
fonctions mathématiques répondre aux 56-8 TBatchMove 24-59
et A-10 signalement 11-11 threads 11-4
domaine A-9 sources de données 19-4– ExecuteOptions, propriété 25-13
erreurs de mise à jour 19-5 ExecuteTarget, méthode 8-31
messages de réponse 29-41 souris exemple "techniques de
résolution 27-25, 27-27– glisser-déplacer 6-1–6-4 dessin" 10-25–10-31
27-29, 28-10, 28-13–28-14 système 3-4 Exemples, page de la palette de
erreurs du domaine types 3-3 composants 5-9, 5-10
Index I-21
renommer 4-10, A-12 et bibliothèques de options des champs
ressource 8-46–8-47 types 38-19 texte 22-18
routines fichiers source portées ou 22-35
API Windows 4-5 changement 2-2 requêtes et 22-15
bibliothèque paquets 15-2 utilisation de signets 25-12
d’exécution 4-8 partage (Linux) 14-14 filtres de données 22-15–22-19
routines date-heure 4-10 fichiers XML 25-16 activation/
routines date-heure 4-10 FieldAddress, méthode 13-24 désactivation 22-15
source A-8 FieldByName, méthode 22-37, champs vierges 22-17
suppression 4-8 23-23 définition 22-16–22-18
taille 4-4 FieldCount, propriété définition à l’exécution 22-18
tamponnage A-11 champs persistants 19-20 ensembles de données
temporaires FieldDefs, propriété 22-45 client 27-3–27-6
fonction abort et A-13 FieldKind, propriété 23-13 opérateurs 22-17
troncature pendant l’écriture FieldName, propriété 23-6, requêtes et 22-15
dans A-11 23-13, 29-43 utilisation de signets 25-12
fichiers .so 14-10, 14-16 champs persistants 19-20 __finally, mot clé 12-8, 12-14
fichiers .TLB 39-21 grilles de décision 20-14 FindClose, procédure 4-8
fichiers ADTG 25-16 grilles de données 19-23, FindDatabase, méthode 24-23
fichiers CAB 43-19 19-24 FindFirst, fonction 4-8
fichiers de collection de Fields, propriété 23-23 FindFirst, méthode 22-19
paquets 15-15 FieldValues, propriété 23-22 FindKey, méthode 22-32, 22-34
fichiers de configuration FileAge, fonction 4-10 EditKey ou 22-35
Linux 14-15 FileExists, fonction 4-8 FindLast, méthode 22-19
fichiers de contrôle de FileGetDate, fonction 4-10 FindNearest, méthode 22-32,
réseau 24-27 FileName, propriété 22-34
fichiers de traitement par lots ensembles de données FindNext, fonction 4-8
Linux 14-15 client 18-11, 27-40, 27-42 FindNext, méthode 22-19
fichiers de transformation 30-1– FileSetDate, fonction 4-10 FindPrior, méthode 22-19
30-7 FillRect, méthode 10-5, 50-3 FindResourceHInstance,
nœuds définis par Filter, propriété 22-16, 22-16– fonction 16-13
l’utilisateur 30-6, 30-8–30-9 22-17 FindSession, méthode 24-33
TXMLTransform 30-7 Filtered, propriété 22-15 FireOnChanged 43-14
TXMLTransformClient 30-10 FilterGroup, propriété 25-14, FireOnRequestEdit 43-13
TXMLTransformProvider 25-15 First Impression 17-5
30-9 FilterOnBookmarks, First, méthode 22-7
fichiers du projet méthode 25-12 FixedColor, propriété 9-18
changement 2-2 FilterOptions, propriété 22-18 FixedCols, propriété 9-18
distribution 2-5 filtres 22-15–22-19 FixedOrder, propriété 8-53, 9-10
fichiers exécutables activation/ FixedRows, propriété 9-18
internationalisation 16-12, désactivation 22-15 FixedSize, propriété 9-10
16-13 champs vierges 22-17 FlipChildren, méthode 16-7
serveurs COM 38-7 comparaison de FloodFill, méthode 10-5, 50-3
modèles de thread 41-9 chaînes 22-18 flots binaires
sous Linux 14-16 définition 22-16–22-18 caractères null et A-11
fichiers fiche 3-8, 14-2, 16-13 définition à l’exécution 22-18 flots de texte
fichiers IDL distinction majuscules/ écriture, troncature et A-11
création 39-21 minuscules 22-18 flux 4-2
fichiers objet partagés ensembles de données copie des données 4-3
Voir fichiers .so client 27-3–27-6 déplacements 4-4
fichiers palette des bitmaps 52-4 utilisation de lecture et écriture de
fichiers paquet 17-3 paramètres 27-34–27-35 données 4-2
fichiers ressource gestion des exceptions 12-9 position 4-4
chargement 8-46 opérateurs 22-17 support de stockage 4-4
fichiers ressources taille 4-4
Index I-23
catch, instruction 12-3 surcharge 48-10 GetPalette, méthode 50-6
constructeurs et transmission de paramètres GetParams, méthode 28-4
destructeurs 12-6 par référence 48-10 GetPassword, méthode 24-25
expressions structurées 12-7 type de renvoi 48-3 GetProcAddress 7-12
exemple 12-12 types 48-3–48-4 GetProcedureNames,
syntaxe 12-7 gestionnaires de messages 51-1, méthode 21-15
filtres 12-9 51-3, 51-4–51-6 GetProcedureParams,
fonctions utilitaires 12-7 création 51-6–51-16 méthode 21-16
options du compilateur 12-15 déclarations 51-5, 51-6, 51-8 GetProperties, méthode 52-11
pointeurs sécurisés 12-6 méthodes, surcharge 51-8 GetRecords, méthode 28-4, 28-8
spécification des par défaut 51-4 GetSessionNames,
exceptions 12-4 surcharge 51-4 méthode 24-33
syntaxe C++ 12-2 GetAliasDriverName, GetStoredProcNames,
throw, instruction 12-2, 12-3 méthode 24-30 méthode 24-30
VCL 12-16 GetAliasNames, méthode 24-30 GetStrValue, méthode 52-10
gestion des exceptions GetAliasParams, méthode 24-30 GetTableNames,
Win32 12-7 GetAttributes, méthode 52-11 méthode 21-15, 24-30
gestion mémoire GetBookmark, méthode 22-11 GetValue, méthode 52-10
fiches 8-5 GetConfigParams, GetVersionEx, fonction 17-17
gestionnaire d’actions 8-20, méthode 24-30 GetViewerName 7-32
8-21, 8-24 GetData, méthode -Gi, option du lieur 15-13
définition 8-19 champs 23-19 -Gl, option du lieur 15-13
gestionnaire d’aide 7-30, 7-30– GetDataAsXml, méthode 30-11 glisser-ancrer 6-4–6-7
7-40 GetDatabaseNames, glisser-déplacer 6-1–6-4
gestionnaire de projet 8-3 méthode 24-30 DLL 6-4
gestionnaire de propriétés GetDriverNames, événements 54-3
partagées 44-7 méthode 24-30 obtention d’informations
exemple 44-8–44-9 GetDriverParams, d’état 6-4
gestionnaires méthode 24-30 personnalisation 6-4
d’événements 5-4–5-7, 45-7, getenv, fonction pointeur de la souris 6-4
48-2, 48-9, 56-8 noms d’environnement et Global Offset Table (GOT) 14-21
affichage de l’éditeur de méthodes A-14 Glyph, propriété 8-49, 9-8
code 52-19 GetExceptionCode, GotoBookmark, méthode 22-11
association à des fonction 12-7 GotoCurrent, méthode 22-48
événements 5-5 GetExceptionInformation, GotoKey, méthode 22-33
contrôles dessinés par le fonction 12-7, 12-9 GotoNearest, méthode 22-33,
propriétaire 6-15 GetFieldByName, méthode 33-9 22-34
déclarations 48-5, 55-13 GetFieldNames, méthode 21-15, -Gpd, option du lieur 15-13
définition 5-4 24-30 -Gpr, option du lieur 15-13
dessin de lignes 10-27 GetFloatValue, méthode 52-10 Graph Custom Control 17-5
écriture 5-4 GetGroupState, méthode 27-12 graphes de décision 20-14–
menus 5-6–5-7, 6-12 GetHandle 7-32 20-20
méthodes 48-5 GetHelpFile 7-32 changement du type de
surcharge 48-6 GetHelpStrings 7-33 graphe 20-18
modèles de menus 8-44 GetIDsOfNames, comportements à
paramètres 48-8, 48-10 méthode 40-15, 41-14 l’exécution 20-21
notification GetIndexNames, création 20-14
d’événements 48-8 méthode 21-16, 22-31 définition des séries de
partage 10-16 GetMethodValue, données 20-19–20-20
partagés 5-5–5-7 méthode 52-10 états de pivotement 20-10
recherche 5-5 GetNextPacket, méthode 14-30, états en cours des
réponse aux clics de 24-37, 27-31, 27-32, 28-4 pivots 20-10
bouton 10-14 GetOptionalParam, modèles 20-18
Sender, paramètre 5-6 méthode 27-18, 28-7 options d’affichage 20-16
suppression 5-7 GetOrdValue, méthode 52-10 personnalisation 20-17–20-19
Index I-25
restrictions 13-2 en-têtes de requête 33-9, 42-4 incorrects 8-35
héritage de classe 3-4 en-têtes de requêtes 32-4 longueur A-3
héritées présentation 32-5–32-7 méthodes 49-2
propriétés 54-3, 55-3 SOAP 36-1 paramètres de propriété 47-7
Hériter (référentiel HTTP, messages de réponse ressources 52-4
d’objets) 7-28 Voir messages de réponse types 10-13
heure A-14 HTTP, messages de requête types d’enregistrement de
internationalisation 16-10 Voir messages de requête message 51-7
locale A-14 httpsrvr.dll 29-11, 29-15, 29-28 idéogrammes 16-3
heure, champs HyperHelp, visualiseur 7-30 abréviations et 16-9
formatage 23-17 caractères 16-3
heures I IDispatch, interface 38-9, 38-21,
saisie 9-14 41-13, 41-14–41-15
IApplicationObject,
hidesbase, argument 13-30 Automation 40-15
interface 42-4
hiérarchie (classes) 46-4 automation 38-13
IAppServer, interface 27-37,
Hint, propriété 9-18 identificateurs 41-15
27-39, 28-3–28-4, 29-5, 29-6
Hints, propriété 19-35 IDL (Interface Definition
appel 29-31
HookEvents, méthode 51-12 Language) 31-5, 38-18, 38-20,
extension 29-18
HorzScrollBar 9-5 39-1
fournisseurs distants 28-3
Host, propriété éditeur de bibliothèques de
fournisseurs locaux 28-3
TSocketConnection 29-27 types 39-8
informations d’état 29-22
hôtes 29-27, 37-4 IDL, compilateur 38-20
transactions 29-20
adresses 37-4 IDL, fichiers 31-5, 31-6
XML, courtiers 29-36
URL 32-4 clients CORBA 31-14
IAppServerSOAP,
HotImages, propriété 8-51 compilation 31-6–31-7
interface 29-6, 29-28
HotKey, propriété 9-7 expert serveur CORBA 31-6
icon
HTML IDOMImplementation 35-3
objets graphiques 10-4
modèles par défaut 29-41, IEEE
icônes 9-20, 50-4
29-44 arrondir A-5
ajout aux composants 45-16
HTML, commandes 33-14 format virgule flottante A-4
ajout aux menus 8-23
génération 33-16 IETF, protocoles et normes 32-3
barres d’outils 8-51
informations de base de IExtendedHelpViewer 7-31,
vues arborescentes 9-13
données 33-19 7-35
IConnectionPoint,
HTML, documents 32-5 directive #ifdef 14-19
interface 40-16, 41-13
générateurs de page directive #ifndef 14-20
IConnectionPointContainer,
ensemble de données 33-19 IHelpManager 7-31, 7-39
interface 40-16, 41-12, 41-13
HTTP, messages de IHelpSelector 7-31, 7-35
IConnectionPointContainerImpl,
réponse 32-6 IHelpSystem 7-31, 7-39
implémentation 41-12
HTML, tables 33-15, 33-21 IID 38-4, 40-6
ICustomHelpViewer 7-30, 7-31,
création 33-20–33-22 IInterface
7-33
définition des gestion de la durée de
implémentation 7-31
propriétés 33-20 vie 13-5
ID de contexte 7-34
légendes 33-21 implémentation 13-3
IDataIntercept, interface 29-27
HTMLDoc, propriété 29-41, IInvokable 36-2
identificateurs
33-15 IIS 42-1
Voir aussi GUID
HTMLFile, propriété 33-15 version 42-3
caractères significatifs dans
HTTP 32-3 Image, balise HTML
les A-3
applications (<IMG>) 33-15
constantes 10-13
multiniveaux 29-11–29-12 ImageIndex, propriété 8-51,
définition des propriétés 47-7
code de statut 33-12 8-53
données membre 48-2
connexion au serveur ImageList 8-22
événements 48-9
d’applications 29-28 ImageMap , balise HTML
externes
en-têtes de messages 32-3 (<MAP>) 33-15
différence entre
en-têtes de réponse 33-13, images 9-20, 10-18, 19-2, 50-3,
majuscules et
42-6 50-3–50-6
minuscules et A-3
Index I-27
inspecteur d’objets 5-2, 47-2, InterBase Express éléments de programme non
52-8 déploiement 17-7 visuels 45-5
aide sur 52-5 InterBase, page de la palette de en sortie 41-12
modification des propriétés composants 5-8, 18-2 exécution 46-7
de tableau 47-3 InterBase, pilote extension du modèle
sélection des menus 8-42 déploiement 17-10 d’héritage simple 3-4
installation InterBaseExpress 14-24 héritage multiple 13-2
support 1-3 intercepteurs 38-5 implémentation 38-6
installation de __interface 13-2, 36-3 implémenter 41-3
composants 45-20 interface d’appel dynamique internationalisation 16-9,
Installation de composants, Voir DII 16-11, 16-13
boîte de dialogue 45-21 interface de document invocables 36-2–36-10
Installer les objets COM+, multiple 7-2–7-3 liaison différée 31-4
commande de menu 44-29 interface de document liaison dynamique 39-10,
Installer les objets MTS, unique 7-2–7-3 41-13
commande de menu 44-29 Interface Definition Language nœuds XML 35-5
Installer, commande (IDL) 38-20, 39-1 objets événement
(composants) 45-21 interface événement proxy 40-6 COM+ 44-25
InstallShield Express 2-5, 17-1 INTERFACE_UUID, personnalisées 41-15
déploiement macro 13-3, 36-3 propriétés, déclaration 57-4
applications 17-2 interfaces 7-13, 46-4, 46-7, 57-2, recensement 31-13
BDE 17-9 57-3 serveurs
paquets 17-3 ajout de méthodes 41-11 d’applications 29-18–29-19,
SQL Links 17-10 ajout de propriétés 41-10– 29-31
instances 48-2 41-11 services Web 36-1
Instanciation 13-6 API Tools 58-1, 58-4–58-7 squelettes et 31-3
instanciation numéros de stubs et 31-2, 31-3
serveurs COM 41-9 version 58-12–58-13 système d’aide 7-30
instructions d’affectation 47-2 applications distribuées 3-4 interfaces de répartition
instructions de commutation Automation 41-13–41-15 appels de méthodes 40-15–
valeurs de cas A-8 bibliothèques de types 40-6, 40-16
instructions SQL 41-10 bibliothèques de types 39-10
ensembles de données d’aide bibliothèques de types interfaces de types 38-19
à la décision 20-5 et 38-13 interfaces doubles
ensembles de données de COM 7-21, 38-1, 38-3, 38-3– appels de méthodes 40-14–
décision et 20-6 38-5, 39-9–39-10, 40-1, 41-3 40-15
fournies par le client 27-38, déclarations 40-6 MTS 44-19
28-7 enveloppes 40-6 objets Active Server 42-3
fournies par le événements 41-12 interfaces du composant
fournisseur 28-14 conception 46-8 création 57-3
génération CORBA 31-2, 31-5–31-13 propriétés, déclaration 57-4
fournisseurs 28-4, 28-11– de répartition 41-13, 41-14– interfaces invocables 36-2–36-10
28-13 41-15 appel 36-18–36-19
TSQLDataSet 26-9 compatibilité de espaces de nommage 36-3
objets mise à jour 24-46– type 41-16 implémentation 36-13–36-15
24-50 déclaration 13-2 recensement 36-3
paramètres 21-12 DOM 35-2 interfaces utilisateur 8-1, 18-17–
SQL transparent 24-35 doubles 41-13–41-14 18-18
INTAComponent 58-15 compatibilité de disposition 8-4–8-5
INTAServices 58-8, 58-9, 58-19 type 41-16 fiches 8-1–8-4
IntegralHeight, propriété 9-11, paramètres 41-17 organisation des
19-12 éditeur de bibliothèques de données 19-8–19-9, 19-17
intégrité des données 18-6, types 39-9–39-10, 39-15, InternalCalc, champs 23-7,
28-15 41-10 27-13
intégrité référentielle 18-6 index et 27-11
Index I-29
KeyExclusive, propriété 22-34, liaison statique 31-15 liste Requires (paquets) 52-21
22-39 COM 38-18 listes
KeyField, propriété 19-14 liaison tardive accès 4-15
KeyFieldCount, propriété 22-34 Automation 41-13, 41-15 ajout 4-15
KeyPress, méthode 51-14 .lib, fichiers 15-2, 15-14 chaîne 4-17–4-22
KeyString, méthode 51-14 paquets 15-15 chaînes 4-16
KeyUp, méthode 51-14 libellé 45-4 collections 4-17
KeyViolTableName, libellés 9-4, 16-10, 19-2 persistantes 4-16
propriété 24-60 colonnes 19-20 réorganisation 4-16
KeywordHelp 7-38 $LIBPREFIX, directive 7-11 suppression 4-15
Kind, propriété LibraryName, propriété 26-4 utilisation dans les
boutons bitmap 9-8 libre, modèle de thread 41-7 threads 11-5
$LIBSUFFIX, directive 7-11 listes d’actions 5-5, 8-19, 8-21,
L $LIBVERSION, directive 7-11 8-26–8-54
.lic, fichier 43-8 listes de chaînes 4-17–4-22
langage de définition de
licence à court terme 4-18
données 21-11, 22-49, 26-12
contrôles ActiveX à long terme 4-18
langage de manipulation de
Internet Explorer 43-8 ajout d’une chaîne 4-20
données 21-11, 22-49
Internet Explorer 43-8 contrôles dessinés par le
Last, méthode 22-7
licence d’utilisation 17-18 propriétaire 6-14–6-15
Layout, propriété 9-8
liens de données 56-5–56-8 copie 4-21
lecteurs de cassettes
initialisation 56-7 création 4-18–4-19
audio-numériques 10-35
liens hypertextes déplacement d’une
lecteurs multimédia 10-33–
ajout au document chaîne 4-21
10-36
HTML 33-15 dessinées par le
exemple 10-35
lignes 9-18 propriétaire 6-13
lecture des paramètres de
dessin 10-6, 10-10, 10-10– écriture dans un fichier 4-17
propriété 52-10
10-11, 10-29–10-31 lecture depuis un fichier 4-17
lecture incrémentale 27-31,
changement de la largeur objets associés 4-21–4-22
29-22
du crayon 10-6 parcourir 4-20
lecture seule
dessin de gestionnaires persistantes 4-16
champs 19-6
d’événements 10-27 positionnement 4-20
mise à jour des ensembles de
effacement 10-30 recherche de chaînes 4-20
données 18-12
grilles de décision 20-12 sous-chaînes 4-20
propriétés 46-7, 46-8, 47-7
lignes de séparation suppression d’une
tables 22-44
(menus) 8-37 chaîne 4-21
lecture seule, propriétés 56-3
limites des rectangles 10-12 tri 4-21
Left, propriété 8-4
Lines, propriété 9-3, 47-9 listes de fichiers
LeftCol, propriété 9-18
LineSize, propriété 9-6 déplacement des
liaison 7-12
LineTo, méthode 10-5, 10-8, éléments 6-3
liaison avancée 31-15
10-11, 50-3 glissement des éléments 6-2,
liaison de données 43-12
Link, balise HTML (<A>) 33-15 6-3
liaison de fiche 8-3
Linux listes de recherche (système
liaison de vtable
applications d’aide) 52-6
liaison immédiate
multiplates-formes 14-1– listes déroulantes 19-24
COM 38-18
14-31 ListField, propriété 19-14
liaison différée 31-15
fichiers de traitement par ListSource, propriété 19-14
CORBA 31-4
lots 14-15 Loaded, méthode 47-14
DII 31-4
notifications système 51-11– LoadFromFile, méthode
liaison dynamique 7-12, 7-13,
51-16 chaînes 4-17
31-15
registre 14-15 ensembles de données
CORBA 31-16
répertoires 14-17 ADO 25-16
liaison immédiate
Windows et 14-15–14-17 ensembles de données
automation 38-19
List, propriété 24-33 client 18-11, 27-40
liaison précoce
liste Contains (paquets) 52-21 graphiques 10-21, 50-5
Automation 41-13
Index I-31
contenu 33-13, 33-14–33-22 initialisation 47-14 ensembles de données clients
création 33-11–33-13, 33-14– nommer 49-2 application
33-22 propriétés et 47-5–47-7, 49-1, tables multiples 24-46,
envoi 33-9, 33-13 49-2, 54-4 24-50
informations protégées 49-3 objets mise à jour 27-22
d’en-tête 33-12–33-13 publiques 49-3 présentation 27-19–27-21
informations de base de suppression 5-7 relations maître/détail 27-22
données 33-18–33-22 surcharge 51-4, 51-8, 55-13 mises à jour en cascade 28-7
informations de statut 33-12 virtuelles 46-10, 49-4 mises à jour groupées 25-13–
réponse aux 33-13 héritage 13-2 25-16
messages de requête 33-3, 42-4 MethodType, propriété 33-7, annulation 25-16
contenu 33-11 33-11 application 25-16
courtier XML 29-40 Microsoft Server, DLL mises à jour placées en mémoire
éléments d’action 33-6 messages de requête 33-3 cache
HTTP, présentation 32-5– Microsoft SQL Server ADO 25-13–25-16
32-7 pilote de déploiement 17-10 annulation 25-16
informations d’en-tête 33-9– Microsoft Transaction application 25-16
33-11 Server 7-21, 44-1 ensembles de données
répartition 33-5 Microsoft Transaction Server client 18-12–18-16
réponse aux 33-8–33-9 Voir MTS erreurs de mise à
traitement 33-5 midas.dll 27-1, 29-3 jour 28-13–28-14
types 33-10 midaslib.dcu 17-7, 29-3 transactions 21-7
messages générés par A-12 MIDI, fichiers 10-35 fournisseurs 28-9
messages liés au clavier 56-10 MIDL MM, film 10-35
messages WM_PAINT 10-2 génération de fichiers modales, fiches 8-5
messages.hpp, fichier 51-2 en-tête 38-20 mode d’édition 22-20
mesures génération du code proxy/ annulation 22-21
conversion 4-28–4-35 stub 38-20 Mode, propriété 24-56
unités 4-30 Voir aussi IDL crayons 10-6
métadonnées 21-14–21-16 MIME, messages 32-6 modèle "briefcase" 18-16
dbExpress 26-13–26-19 Min, propriété modèle "déconnecté" 18-16
modification 26-12–26-13 barres de progression 9-17 modèle de délégation
obtention auprès des barres graduées 9-5 CORBA 31-9
fournisseurs 27-32 MinSize, propriété 9-7 modèles 7-27, 7-29
métafichiers 9-20, 10-1, 10-20, MinValue, propriété 23-14 applications serveur agent
50-4 mise à jour des données 29-40– Web 33-3
quand les utiliser 10-4 29-41 composant 8-13
Method, propriété 33-10 mise à jour des générateurs de page 34-5
MethodAddress, méthode 13-24 enregistrements 29-40–29-41 graphes de décision 20-18
méthodes 3-3, 10-16, 45-7, 49-1, Mises à jour du projet, boîte de menus 8-34, 8-41, 8-42, 8-43
55-12 dialogue 31-10 programmation 7-3
ajout aux interfaces 41-11 mises à jour en cache 27-18– suppression 8-43
appel 48-6, 49-3, 54-5 27-29 modèles de composants 8-13,
déclaration 10-16, 46-10, BDE 24-36–24-55 46-2
49-4 application 24-38–24-43 et cadres 8-15, 8-16
publiques 49-3 tables multiples 24-46, modèles de projet 7-29
dessin 54-9, 54-10 24-50 modèles de thread 41-5–41-9,
gestion des messages 51-1, gestion d’erreur 24-43– 44-20–44-21
51-5 24-45 apartment 41-8
gestionnaires ensembles de données contrôles ActiveX 43-5
d’événements 48-5 client 27-19, 27-24–27-29 libre 41-7
surcharge 48-6 application des mises à objets COM 41-3, 41-5
graphiques 50-3, 50-5, 50-7 jour 27-24–27-25 registres 41-7
palettes 50-6 erreurs de mise à modèles HTML 29-44–29-45,
héritées 48-6 jour 27-27–27-29 34-5
Index I-33
multiniveaux, NextRecordSet, méthode 22-63 Nouveaux éléments, boîte de
applications 29-1–29-45 niveau d’isolation des dialogue 7-27, 7-28, 7-29
Multi-niveaux, page (Nouveaux transactions 21-10–21-11 Nouvel objet thread, boîte de
éléments, boîte de spécification 21-11 dialogue 11-2
dialogue) 29-3 transactions locales 24-35 NSAPI, applications 32-7
multi-octets niveaux 29-1 création 34-9
jeux de caractères 16-3 niveaux de regroupement 27-12 débogage 32-11
multi-octets, caractères agrégats maintenus 27-15 messages de requête 33-3
(MBCS) A-2, A-4 nodefault, mot clé 47-8 NumericScale, propriété 22-53,
MultiSelect, propriété 9-11 nom de démarrage du 22-60, 22-61
multithread, applications 11-1 service 7-9 numéros de contexte (aide) 9-17
multitraitement nombres 47-2 NumGlyphs, propriété 9-8
threads 11-1 internationalisation 16-10
mutex valeurs de propriété 47-13 O
CORBA 31-12 nommer un thread 11-14–11-15
OAD 31-4, 31-14
MyBase 27-39 noms d’hôte 37-4
.obj, fichiers 15-3, 15-14
MyEvent_ID, type 51-16 adresses IP 37-5
paquets 15-15
noms de chemins
N Object , balise HTML
Linux 14-16
(<OBJECT>) 33-15
noms de connexion 26-5–26-6
Name, propriété Object Activation Daemon
changement 26-6
champs 23-14 Voir OAD
définition 26-6
éléments de menu 5-6, 5-7 Object Management Group
suppression 26-6
paramètres 22-60, 22-61 Voir OMG
noms de fichiers
navigateur 19-2, 19-33–19-36, ObjectBroker, propriété 29-27,
changer A-12
22-6, 22-7 29-28, 29-29
recherche de A-8
activation/désactivation des ObjectContext, propriété
noms de pilotes 24-15
boutons 19-34 exemple 44-16–44-17
non modales, fiches 8-5, 8-7
boutons 19-33 objets Active Server 42-3
NOT NULL UNIQUE,
édition 22-21 Objects, propriété 9-18
contrainte 28-15
panneaux listes de chaîne 6-16
NOT NULL, contrainte 28-15
d’informations 19-35 listes de chaînes 4-21
notes de dernière minute 17-18
partage entre ensembles de ObjectView, propriété 19-26,
notificateurs 58-3
données 19-35 22-43, 23-27
API Tools
suppression de objet de mise à jour
notificateurs 58-19–58-23
données 22-23 fournisseurs et 24-12
écriture 58-22
navigateur de base de objet, champs 23-26–23-32
notification d’événements 48-8
données 19-2, 19-33–19-36, types 23-26
notifications système 51-11–
22-6, 22-7 objets
51-16
activation/désactivation des arguments de fonctions 13-8
NotifyID 7-32
boutons 19-34 construction 13-8–13-13,
Nouveau champ, boîte de
boutons 19-33 14-13
dialogue 23-6
édition 22-21 copie 13-7
définition de champs 23-8,
panneaux distribués 31-1
23-10, 23-12
d’informations 19-35 glisser-déplacer 6-1
Définition de la
suppression de héritage 3-4
référence 23-7
données 22-23 image 50-4
Champ résultat 23-11
.Net initialisation 10-14
Champs clé 23-10
services Web 36-1 scripts 34-37
Clés de référence 23-10
NetCLX 7-18 temporaires 50-7
Ensemble de
définition 14-6 TObject 3-6
données 23-10
NetFileDir, propriété 24-27 Voir aussi objets COM
Propriétés du champ 23-6
NewValue, propriété 24-43, volatile, accès A-7
Type 23-7
28-13 objets abonnés 40-16–40-17
Type de champ 23-7
Next, méthode 22-7 objets Active Server 42-1–42-9
Nouveau, commande 45-13
NextRecordSet method 26-10 création 42-2–42-8
Index I-35
OnFilterRecord, OnReceive, événement 37-11 bases de données
événement 22-16, 22-18 OnReconcileError, différentes 24-57
OnGetData, événement 28-9 événement 14-30, 24-37, copie d’ensembles de
OnGetDataSetProperties, 27-25, 27-28 données 24-57
événement 28-7 OnRefresh, événement 20-8 exécution 24-59
OnGetTableName, OnRequestRecords, gestion d’erreur 24-59–24-60
événement 24-12, 27-26, 28-14 événement 29-39 mappage des types de
OnGetText, événement 23-18 OnResize, événement 10-3 données 24-58–24-59
OnGetThread, événement 37-10 OnRollbackTransComplete, mise à jour de données 24-57
Onglet Prévisualiser 34-2 événement 21-10, 25-9 mise en place 24-55–24-56
onglets OnScroll, événement 9-5 modes 24-9, 24-56
draw-item, événements 6-17 OnSend, événement 37-11 suppression
styles dessinés par le OnSetText, événement 23-18 d’enregistrements 24-58
propriétaire 6-13 OnStartDrag, événement 19-31 optimisation des ressources
OnHandleActive, OnStartPage, méthode 42-3 système 45-4
événement 37-9 OnStartup, événement 24-20 optimisation du code 10-16
OnHTMLTag, événement 29-45, OnStateChange, options
33-16, 33-17, 33-18 événement 19-5, 20-10, 22-4 mutuellement
OnIdle, gestionnaire OnSummaryChange, exclusives 8-49
d’événement 11-6 événement 20-10 Options de déploiement Web,
OnInfoMessage, OnTerminate, événement 11-7 boîte de dialogue 43-19
événement 25-9 OnTitleClick, événement 19-31 Options de projet, boîte de
OnKeyDown, événement 19-31, OnTranslate, événement 30-8 dialogue 7-3
48-5, 51-13, 56-11 OnUpdateData, options du compilateur 7-3
OnKeyPress, événement 19-31, événement 19-5, 28-9, 28-10 alignement A-7
48-5, 51-13 OnUpdateError, options du projet 7-3
OnKeyString, événement 51-13 événement 14-30, 24-37, par défaut 7-3
OnKeyUp, événement 19-31, 24-43–24-45, 27-27, 28-13 Options, propriété 9-18
48-5, 51-13 OnUpdateRecord, fournisseurs 28-6–28-7
OnLayoutChange, événement 24-37, 24-41– grilles de décision 20-14
événement 20-10 24-43, 24-46, 24-53 grilles de données 19-28
OnListening, événement 37-9 OnValidate, événement 23-18 TSQLClientDataSet 27-20
OnLogin, événement 21-5 OnWillConnect, Oracle, pilotes
OnMeasureItem, événement 21-6, 25-8 déploiement 17-10
événement 6-16 Open, méthode Oracle8
OnMouseDown, composants de limites de création des
événement 10-25, 10-26, 48-5, connexion 21-3 tables 22-46
51-13, 56-10 ensembles de données 22-5 ORB 31-1, 31-6
paramètres transmis à 10-25 requêtes 22-56 initialisation 31-4
OnMouseMove, serveur, sockets 37-8 ORB_init 31-8
événement 10-25, 10-27, 48-5, sessions 24-20 ORDER BY, clause 22-30
51-13 OPENARRAY, macro 13-20 ordre A-2
paramètres transmis à 10-25 OpenDatabase, méthode 24-20, ordre de tri 16-10
OnMouseUp, événement 10-15, 24-22 décroissant 27-10
10-25, 10-27, 48-5, 51-13 OpenSession, méthode 24-32, définition 22-32
paramètres transmis à 10-25 24-33 ensembles de données
OnNewDimensions, opérateur as 13-24 client 27-9
événement 20-10 opérateurs TSQLTable 26-8
OnNewRecord, au niveau bit Orientation, propriété
événement 22-21 entiers signés A-5 barres graduées 9-6
OnPaint, événement 9-21, 10-2 opérateurs d’affectation 13-7 grilles de données 19-32
OnPassword, événement 24-15, opérations avec effet 50-7 Origin, propriété 10-29, 23-14
24-25 opérations groupées 24-8–24-9, osagent 31-2, 31-3
OnPopup, événement 6-12 24-55–24-60 outils de dessin 50-2, 50-8, 54-6
OnPostError, événement 22-24 ajout de données 24-57 affectation par défaut 8-49
Index I-37
modification 28-9, 28-10– entrée/sortie 22-59 Pen, propriété 10-4, 10-6, 50-3
28-11 événements souris 10-25, PenPos, propriété 10-4, 10-8
XML 29-38, 29-40–29-41 10-26 penwin.dll 15-13
paquets MTS 44-7, 44-29 gestionnaires Perform, méthode 51-9
par défaut d’événements 48-8 périphériques média 10-33
classe ancêtre 46-4 HTML, balises 33-15 périphériques, interactifs A-2
gestionnaires interfaces doubles 41-17 permanence
message 51-4 messages 51-5, 51-7, 51-10 fournisseurs de
options du projet 7-3 modes de liaison 24-13 ressources 44-6
paramètres 13-22 résultat 22-59 permissions de fichiers
valeurs 19-11 sortie 22-59, 27-33 Linux 14-16
valeurs de propriété 47-8 transmission par perror, fonction A-12
modification 53-3, 53-4 référence 48-3 persistantes, colonnes 19-18,
spécification 47-12 TXMLTransformClient 30-10 19-20
spécification des valeurs paramètres de création 19-21–19-25
propriété par connexion 24-16–24-17 insertion 19-22
défaut 47-13 ADO 25-4 modification de l’ordre 19-22
par référence seulement dbExpress 26-4–26-5, 26-6 suppression 19-19, 19-22
propriétés d’interface informations de personnalisation de
COM 39-9 connexion 21-5, 25-4 composants 47-1
Paradox, tables 24-6 paramètres de localisation 4-24 PickList, propriété 19-23, 19-24
ajout paramètres optionnels 27-18, picture, objets 10-3
d’enregistrements 22-22, 28-8 Picture, propriété 9-20, 10-19
22-23 ParamName, propriété 29-43 dans les cadres 8-16
récupération des index 22-31 Params, propriété Pie, méthode 10-5
renommer 24-8 ensembles de données pilotes de base de données
ParamBindMode, client 27-32, 27-33 BDE 24-3
propriété 24-13 procédures stockées 22-59 pilotes de bases de données
ParamByName, méthode requêtes 22-52, 22-54 BDE 24-1, 24-15
procédures stockées 22-62 TDatabase 24-16 pilotes ODBC
requêtes 22-53 TSQLConnection 26-4 utilisation avec le BDE 24-1,
ParamCheck, propriété 22-52, XML, courtiers 29-39 24-17
26-13 ParamType, propriété 22-53, pinceaux 10-8–10-10, 54-6
Parameters, propriété 25-22 22-60 bitmap, propriété 10-10
TADOCommand 25-22 ParamValues, propriété 22-54 changement 54-8
TADOQuery 22-52 Parent, propriété 45-18 couleurs 10-9
TADOStoredProc 22-59 ParentColumn, propriété 19-27 styles 10-9
paramétrage des requêtes 22-50, ParentConnection, pivots de décision 20-10–20-11
22-51–22-54 propriété 29-32 boutons de dimension 20-11
création ParentShowHint, propriété 9-18 comportement à
à l’exécution 22-53 partage des fiches et des boîtes l’exécution 20-20
à la conception 22-52 de dialogue 7-27–7-30 orientation 20-11
paramètres partie publiée des classes 46-8 propriétés 20-11
classes comme 46-11 Pascal Objet Pixel, propriété 10-4, 50-3
de courtiers XML 29-39 modèles objet 13-2 pixels
de propriété 47-7 pascalimplementation, lecture et définition 10-10
de lecture 47-7, 47-9 argument 13-31 Pixels, propriété 10-5, 10-10
de tableau 47-9 PasteFromClipboard, pmCopy, constante 10-31
écriture 47-9 méthode 6-10 pmNotXor, constante 10-31
ensembles de données contrôles mémo orientés pointeur de la souris
client 27-32–27-35 données 19-10 glisser-déplacer 6-4
filtrage graphiques 19-11 pointeurs
d’enregistrements 27-34 PathInfo, propriété 33-6 classes 46-11
–27-35 .pce, fichiers 15-15 déréférencés 13-7
entrée 22-59 pdoxusrs.net 24-27 gestion des exceptions 12-6
Index I-39
stockage de données
interne 47-4, 47-7
Q recensement
applications serveur 29-13
stockage et chargement des QApplication_postEvent, composants 45-14, 45-15
propriétés non méthode 51-16 éditeurs de
publiées 47-14–47-16 QCustomEvent_create, composants 52-20
tableau 47-3, 47-9 fonction 51-16 éditeurs de propriétés 52-12–
types 47-2, 47-9, 52-10, 54-4 QEvent 51-13 52-13
valeurs par défaut 47-8, QKeyEvent 51-13 familles de conversion 4-29
47-12–47-13 QMouseEvent 51-13 interfaces CORBA 31-13
redéfinition 53-3, 53-4 QReport, page de la palette de objets Active Server 42-8–
visualisation 52-10 composants 5-9 42-9
propriétés de tableaux 13-24 Query, propriété objets COM 41-17–41-18
propriétés, contrôles de saisie objets mise à jour 24-54 recensement des objets de
mémo et texte formaté 9-3 QueryInterface, méthode 38-9 l’aide 7-36
protected IUnknown 38-4 récepteurs d’événements 41-13
directive 48-5 recherche de fichiers A-8
événements 48-5 R recherche incrémentale 19-12
mot clé 47-3, 48-5 recherches indexées 22-13,
raccourcis clavier 9-7
protégée 22-14, 22-32–22-35
ajout aux menus 8-37
partie des classes 46-7 RecNo, propriété
RaiseException, fonction 12-13
protocole (Digital) 37-1 ensembles de données
rappels
protocoles client 27-3
applications
choix 29-10 Reconcile, méthode 14-30, 24-37
multiniveaux 29-19
composants RecordCount, propriété
limitation 29-12
connexion 29-10–29-12 TBatchMove 24-59
rapports 18-18
connexion, composants 29-25 Recordset, propriété 25-11,
RC, fichiers 8-46
connexions de réseau 24-17 25-21
RDSConnection, propriété 25-19
Internet 32-3, 37-1 RecordsetState, propriété 25-11
Read, méthode
sélection 29-10–29-12 RecordStatus, propriété 25-14,
TFileStream 4-2
Provider, propriété 25-4 25-15
read, méthode 47-7
ProviderFlags, propriété 28-5, Rectangle, méthode 10-5, 10-12,
read, mot réservé 47-9, 54-5
28-12 50-3
ReadBuffer, méthode
ProviderName, propriété 18-14, rectangles
TFileStream 4-3
27-30, 28-4, 29-25, 29-39, 30-10 à coins arrondis 10-12
ReadCommitted 21-10
proxy 38-8 dessin 10-12, 54-10
README 17-18
objets transactionnels 44-3 Récupérer les paramètres,
ReadOnly, propriété 9-3, 56-3,
public commande 27-33
56-9, 56-10
mot clé 48-5 redéclaration des
champs 23-14
propriétés 47-12 propriétés 48-5
contrôles mémo orientés
publication redéfinition
données 19-10
propriétés méthodes virtuelles 13-12
contrôles orientés
exemple 54-3, 55-3 redessin des contrôles 55-5
données 19-6
publieur WSDL 36-13 redimensionnement de
contrôles orientés données de
publique contrôles
texte formaté 19-10
partie de classes 46-7 graphiques 50-7
grilles de données 19-23,
published 47-3 redimensionnement des
19-29
directive 47-3, 57-4 contrôles 17-14, 55-5
tables 22-44
mot clé 48-5 référence d’objet 13-6
Real48, type 13-24
propriétés 47-12, 47-13 référence, champs 23-26
réalisation de palettes 50-5, 50-6
__published, mot clé 13-29 affichage 19-27
realloc, fonction
putenv, fonction références
allocation mémoire de taille
noms d’environnement et C++ comparé à Pascal
zéro et A-13
méthodes A-14 Objet 13-6
ReasonString, propriété 33-12
PVCS Version Manager 2-5 fiches 8-3
ReceiveBuf, méthode 37-8
Receiveln, méthode 37-8
Index I-41
définition à la couche de RPC 38-9
conception 22-52 communication 31-2 RTTI 46-8
liaison 22-52 réseaux locaux 31-3 C++ comparé à Pascal
nommés 22-51 ResetEvent, méthode 11-11 Objet 13-23
non nommés 22-51 résolution 28-1, 29-4 interfaces invocables 36-2
propriétés 22-52–22-53 ResolveToDataSet,
relations maître/ propriété 28-5 S
détail 22-54–22-55 resourcestring, macro 13-22
SafeArray 39-14
préparation 22-55–22-56 Ressource DLL
SafeRef, méthode 44-27
relations maître/ basculement
SaveConfigFile, méthode 24-29
détail 22-54–22-55 dynamique 16-13
SavePoint, propriété 27-7
répartition 34-38 expert 16-11
SaveToFile, méthode 10-21
spécification 22-49–22-51, ressource, fichiers 8-46–8-47
chaînes 4-17
26-7 ressources 45-8, 50-1
ensembles de données
spécification de la base de chaînes 16-11
ADO 25-16
données 22-48 isolement 16-11
ensembles de données
Web, applications 33-22 localisation 16-11, 16-12,
client 18-11, 27-41, 27-42
requêtes d’action 34-40 16-13
graphiques 50-5
requêtes d’image 34-42 nomenclature 52-4
SaveToStream, méthode
requêtes de décision, système, conservation 45-4
ensembles de données
définition 20-6 système, optimisation 45-4
client 27-42
requêtes du répartiteur ressources en mémoire
ScanLine, propriété
d’adaptateur 34-40 cache 50-2
bitmap, exemple 10-19
requêtes hétérogènes 24-10– RestoreDefaults, méthode 19-25
ScktSrvr.exe 29-11, 29-15, 29-27
24-11 restrictions A-1
SCM 7-5
Local SQL 24-10 Result, paramètre 51-7
Screen, variable 8-2, 16-9
requêtes HTTP Résultat HTML, onglet 34-2
script
images 34-42 résultat, paramètres 22-59
côté serveur 34-35–34-38
requêtes SQL 22-49–22-51 Resume, méthode 11-12, 11-13
Script HTML, onglet 34-2
chargement depuis un retour à la ligne 6-8
scripts 34-8
fichier 22-51 retour automatique 6-8
actifs 34-35
copie 22-51 ReturnValue, propriété 11-10
génération dans
ensembles de résultats 22-56 RevertRecord, méthode 14-30,
WebSnap 34-36
exécution des 24-37, 27-7
modification et
instructions 22-56–22-57 RFC, documents 32-3
visualisation 34-37
modification 22-50 rôles
URL 32-4
objets mise à jour 24-53 sécurité en fonction des
scripts actifs 34-35
optimisation 22-57 rôles 44-17
scripts côté serveur 34-8, 34-35–
paramètres 22-51–22-54, Rollback, méthode 21-10
34-38, B-1–B-40
24-48–24-49 RollbackTrans, méthode 21-10
exemples JScript B-20–B-40
définition à RoundRect, méthode 10-5,
objets globaux B-14–B-19
l’exécution 22-53 10-12
types d’objets B-2–B-14
définition à la routines
scripts de connexion 21-4–21-6
conception 22-52 zéro terminal 4-26–4-27
scripts shell
liaison 22-52 routines à zéro terminal 4-26–
Linux 14-15
relations maître/ 4-27
scripts Web 34-8
détail 22-54–22-55 routines globales 4-1
ScrollBars, propriété 6-8, 9-18
préparation 22-55–22-56 RowAttributes, propriété 33-21
contrôles mémo orientés
Requires, liste (paquets) 15-7, RowCount, propriété 19-15,
données 19-10
15-8, 15-9, 15-10 19-32
SDI, applications 7-2–7-3
.res, fichiers 45-17 RowHeights, propriété 6-16,
sections critiques 11-8
réseaux 9-18
précaution d’utilisation 11-9,
connexion aux bases de RowRequest, méthode 28-4
11-10
données 24-17 Rows, propriété 9-18
Sections, propriété 9-16
RowsAffected, propriété 22-56
sécurité
Index I-43
espaces de nommage 36-3 SetComplete 44-10 Simple Object Access Protocol
exceptions 36-16–36-17 SetComplete, méthode 29-19, Voir SOAP
expert 36-12–36-16 44-5, 44-14 site d’ancrage 6-6
importation 36-15–36-16 SetData, méthode 23-20 Size, propriété
recensement des classes SetEvent, méthode 11-11 champs 23-14
d’implémentation 36-14 SetFields, méthode 22-25 paramètres 22-53, 22-60,
serveurs 36-11–36-18 SetFloatValue, méthode 52-10 22-61
types complexes 36-4–36-10 SetKey, méthode 22-33 sizeof, opérateur 13-18, A-9
types énumérés 36-6 EditKey ou 22-35 Smart Agents 31-2, 31-3
types scalaires 36-4 SetMethodValue, localisation 31-3
Session, variable 24-4, 24-18 méthode 52-10 SOAP 36-1
SessionName, propriété 24-4, SetOptionalParam, applications
24-14, 24-31–24-32, 33-19 méthode 27-18 multiniveaux 29-12
sessions 24-18–24-33 SetOrdValue, méthode 52-10 connexion à des serveurs
activation 24-20–24-21 SetPenStyle, méthode 10-7 d’applications 29-28
applications SetProvider, méthode 27-30 connexions 29-12, 29-28
multithreads 24-14, 24-32– SetRange, méthode 22-37, 22-38 expert d’application 36-12
24-33 SetRangeEnd, méthode 22-37 modules de données 29-6
bases de données SetRange ou 22-37 paquets d’erreur 36-16
associées 24-23 SetRangeStart, méthode 22-36 socket, composants 37-5
bases de données et 24-14– SetRange ou 22-37 socket, connexions
24-15 SetSchemaInfo, méthode 26-14 ouverture 37-7
connexions aux bases de SetStrValue, méthode 52-10 sockets 37-1–37-11
données implicites 24-15 SetUnhandledExceptionFilter, acceptation des requêtes
création 24-30–24-31, 24-32 fonction 12-7 client 37-3
défaut 24-14, 24-18–24-19 SetValue, méthode 52-10 affectation d’hôtes 37-4
dénomination 33-19 SGBD 29-1 connexions 29-11, 29-27
ensemble de données 24-4 SGBDR 18-3, 29-1 description 37-3
état en cours 24-20 Shape, propriété 9-20 écriture dans 37-11
fermeture 24-20 shift, état des touches 10-26 fourniture
fermeture des ShortCut, propriété 8-37 d’informations 37-4
connexions 24-22 Show, méthode 8-6, 8-8 gestion d’événements 37-8–
gestion des alias 24-28 ShowAccelChar, propriété 9-4 37-10
gestion des ShowButtons, propriété 9-13 gestion des erreurs 37-9
connexions 24-22–24-24 ShowFocus, propriété 19-32 gestionnaire
méthodes 24-15 ShowHint, propriété 9-18, 19-35 d’événement 37-11
mots de passe 24-24 ShowHintChanged, implémentation des
multiples 24-14, 24-30, méthode 51-15 services 37-1–37-2, 37-7
24-32–24-33 ShowLines, propriété 9-13 lecture depuis 37-11
nom 24-31–24-32 ShowModal, méthode 8-6 lecture/écriture 37-10–37-11
ouverture de ShowRoot, propriété 9-13 réseau, adresses 37-3, 37-4
connexions 24-22 ShutDown 7-32, 7-33 sockets client
par défaut 24-4 signalement objets socket 37-6
propriétés de la connexion d’événements 11-11 sockets serveur
par défaut 24-21 signaux objets socket 37-7
réactivation 24-21 Linux 14-16 SoftShutDown 7-32
récupération des réponse aux signaux Sorted, propriété 9-11, 19-13
informations 24-29 (CLX) 51-11–51-13 SortFieldNames, propriété 26-8
Web, applications 33-19 signets 22-11–22-12 sortie, paramètres 22-59, 27-33
Sessions variable 24-32 filtrage sources de décision 20-10
Sessions, propriété 24-33 d’enregistrements 25-12 événements 20-10
Sessions, variable 24-19 prise en charge par type propriétés 20-10
SetAbort 44-10 d’ensembles de sources de données 18-7, 19-3–
SetAbort, méthode 44-5, 44-14 données 22-11 19-5
SetBrushStyle, méthode 10-9 activation 19-4
Index I-45
en tant qu’arguments de portées 22-35–22-40 TADOCommand 25-2, 25-8,
fonctions 13-24 recherche 22-32–22-35 25-10, 25-19–25-22
en tant que propriétés 13-24 relations maître/ TADOConnection 18-9, 21-1,
en tant que types de détail 22-40–22-43 25-2, 25-3–25-9, 25-11
renvoi 13-24 spécification de la base de se connecter aux stockages
ouverts 13-18 données 22-29 de données 25-3–25-5
protégés 39-14 suppression 22-47 TADODataSet 25-2, 25-10,
types entier A-5 synchronisation 22-48 25-17–25-19
pointeurs vers A-6 tri 22-30, 26-8 TADOQuery 25-2, 25-10
tableaux ouverts 13-18 vidage 22-47 commande SQL 25-19
temporaires 13-19 tables Access TADOStoredProc 25-2, 25-10
TableName, propriété 22-30, transactions locales 24-35 TADOTable 25-2, 25-10
22-45, 26-8 tables dBASE Tag, propriété 23-14
TableOfContents 7-35 accès aux données 24-10 TApplication 7-31, 7-38
tables 22-27, 22-29–22-48 DatabaseName 24-4 styles 14-7
affichage dans les index 24-7 événements système 51-13
grilles 19-19 protection par mot de TApplicationEvents 8-2
affichage des listes 21-15 passe 24-24–24-27 TASPObject 42-2
basées sur BDE renommer 24-8 TAutoDriver 40-6, 40-14, 40-15
recherches indexées 22-32 transactions locales 24-35 TBatchMove 24-55–24-60
BDE 24-2, 24-5–24-9 tables de problèmes 24-59 gestion d’erreur 24-59–24-60
ajout tables FoxPro TBCDField
d’enregistrements 24-9 transactions locales 24-35 formatage par défaut 23-18
copie tables imbriquées 22-43, 23-30– TBDEClientDataSet 24-3
d’enregistrements 24-9 23-31, 29-21 TBDEDataSet 22-2
droits d’accès 24-6–24-7 tables InterBase 24-10 TBevel 9-20
fermeture 24-5 tables Oracle 24-13 TBitmap 50-4
liaisons 24-5 tables Paradox 24-4 TBrush 9-20
mise à jour accès aux données 24-10 tbsCheck, constante 8-52
d’enregistrements 24-9 actions groupées 24-60 TByteDynArray 36-5
opérations DatabaseName 24-4 TCalendar 55-1
groupées 24-8–24-9 fichiers de contrôle de TCanvas
suppression réseau 24-27 utilisation 4-22
d’enregistrements 24-9 protection par mot de TCharProperty, type 52-9
verrouillage exclusif 24-7 passe 24-24–24-27 TClassProperty, type 52-9
composants d’aide à la répertoires 24-27–24-28 TClientDataSet 7-26, 27-21
décision et 20-3 transactions locales 24-35 TClientSocket 37-6
création 22-44–22-47 TableType, propriété 22-45, TColorProperty, type 52-9
champs persistants 22-45 24-6 TComInterface 40-6, 40-14
index 22-45 Tabs, propriété 9-16 TComponent 3-4, 3-7, 45-5
dbExpress 26-7–26-8 TabStopChanged, définition 3-5
définition 22-44–22-46 méthode 51-15 interfaces 13-5
définitions de champs et TAction 8-23 TComponentClass 45-15
d’index 22-45 TActionClientItem 8-25 TComponentProperty, type 52-9
définitions de champs et TActionList 8-20, 8-21 TControl 3-9, 45-4, 48-5
d’index TActionMainMenuBar 8-18, définition 3-5
préchargement 22-46 8-20, 8-21, 8-22, 8-24 TConvType, valeurs 4-29
grilles non orientées TActionManager 8-18, 8-21, TConvTypeInfo 4-33
données 9-18 8-22 TCoolBand 9-10
imbriquées 22-43 TActionToolBar 8-18, 8-20, TCoolBar 8-47
index 22-30–22-43 8-21, 8-22, 8-24 TCP/IP 24-17, 37-1
insertion TActiveForm 43-3, 43-7 applications
d’enregistrements 22-21– TAdapterDispatcher 34-38 multiniveaux 29-11
22-23, 22-25 TAdapterPageProducer 34-36 clients 37-6
lecture seule 22-44
Index I-47
CORBA 31-12–31-13 TLIBIMP 38-20 TQuery 24-2, 24-9–24-12
création 11-12 TLIBIMP, outil en ligne de ensembles de données de
espace de processus 11-4 commande 40-2, 40-6, 41-15 décision et 20-6
éviter les accès TListBox 45-3 TQueryTableProducer 33-22
simultanés 11-8 TLocalConnection 27-30, 29-5 traduction 16-9
exceptions 11-7 TMainMenu 8-21 outils 16-1
exécution 11-12 TMaskEdit 9-1 traduction des chaînes de
graphiques, objets 11-5 TMemIniFile 4-11, 14-8 caractères 16-2, 16-9, 16-11
identificateurs 11-13 TMemo 9-1 conversions sur 2 octets 16-3
initialisation 11-3 TMemoryStream 4-2 traitement distribué des
ISAPI/NSAPI, TMessage 51-5, 51-7 données 29-2
programmes 33-3, 33-19 TMetafile 50-4 transaction, paramètres
libération 11-3, 11-4 TMethod, type 51-12 niveau d’isolation 21-11
limites du nombre de 11-12 TMethodProperty, type 52-9 transactions 18-5–18-6, 21-6–
nommer 11-14–11-15 TMTSASPObject 42-2 21-11
priorités 11-1, 11-3 TMtsDll 44-4, 44-27 achèvement 21-9–21-10
redéfinition 11-12 TMultiReadExclusiveWriteSync ADO 25-7, 25-9
renvoi de valeurs 11-10 hronizer 11-9 conservation des
sections critiques 11-8 TNestedDataSet 22-43 annulations 25-7
utilisation de listes 11-5 TNotifyEvent 48-8 conservation des
VCL, thread 11-4 TObject 3-4, 13-9, 13-24, 13-29, validations 25-7
verrouillage des objets 11-8 46-4 annulation 21-9–21-10
threads de service 7-7 définition 3-5 application des mises à
threads en suspens 11-13 ToCommon 4-33 jour 21-7, 29-19
threads multiples TOleContainer 40-18 applications
attente de 11-11 documents Active 38-15 multiniveaux 29-19, 29-19–
throw, instruction 12-2, 12-3, TOleControl 40-7, 40-8 29-20
12-18 TOleServer 40-7 arrêt 44-14
THTMLTableAttributes 33-20 ToolsAPI, unité 58-2 atomicité 18-5
THTMLTableColumn 33-21 Top, propriété 8-4, 8-49 attributs 44-12–44-13
THTTPRio 36-18 TopRow, propriété 9-18 automatiques 44-15
THTTPSoapCppInvoker 36-11, TOrdinalProperty, type 52-8 BDE 24-34–24-36
36-12 touches d’accès rapide 9-7 contrôle 24-34–24-35
THTTPSoapDispatcher 36-11, TPageControl 9-16 implicites 24-34
36-13 TPageDispatcher 34-39 cohérence 18-5
TIBCustomDataSet 22-2 TPageProducer 33-14 composées de plusieurs
TIBDatabase 18-10, 21-1 TPaintBox 9-21 objets 44-11
TickMarks, propriété 9-6 TPanel 8-47, 9-15 contrôlées par le client 44-15
TickStyle, propriété 9-6 TPersistent 13-8 contrôlées par le
TIcon 50-4 définition 3-5 serveur 44-16–44-17
TImage tpHigher, constante 11-3 délai maximum 44-17, 44-28
dans les cadres 8-16 tpHighest, constante 11-3 démarrage 21-7–21-8
TImageList 8-51 TPicture, type 50-4 durabilité 18-5
timers 5-7 tpIdle, constante 11-3 IAppServer 29-20
TIniFile 4-11 tpLower, constante 11-3 imbriquées 21-7
TIntegerProperty, type 52-8 tpLowest, constante 11-3 validation 21-9
TInterfacedObject 13-5 tpNormal, constante 11-3 isolation 18-5
TInvokableClass 36-13 TPopupMenu 8-53 niveaux 21-10–21-11
Title, propriété -Tpp, option du lieur 15-13 locales 24-35–24-36
grilles de données 19-23, TPrinter 4-27 mises à jour en cache 24-38
19-24 utilisation 3-4 modules de données
TKeyPressEvent 48-3 TPropertyAttributes 52-11 MTS 29-17
TLabel 9-4, 45-4 TPropertyEditor, classe 52-8 modules de données
.TLB, fichiers 38-19, 39-2 TPropertyPage 43-15 transactionnels 29-8, 29-19,
TLCDNumber 9-2 tpTimeCritical, constante 11-3 29-19–29-20
Index I-49
champs persistants 23-7 UpdateObject, propriété 24-12, valeurs des axes 20-16
types de serveurs 34-9 24-37, 24-46, 24-51 valeurs logiques 19-2, 19-15
types de tableaux UpdatePropertyPage, valeurs null
dynamiques 36-5 méthode 43-16 portées 22-37
types énumérés UpdateRecordTypes, valeurs récapitulatives 20-21
éditeur de bibliothèques de propriété 14-29, 24-37, 27-23 agrégats maintenus 27-16
types 39-10–39-11, 39-18 UpdateRegistry, méthode 29-9 graphes de décision 20-16
services Web 36-6 UpdatesPending, références croisées 20-3
types sans correspondants 13-24 propriété 14-29, 24-37 validation des saisies de
UpdateStatus, propriété 14-29, données 23-19
U 24-37, 25-14, 27-23, 28-10 validation en deux phases 29-20
UpdateTarget, méthode 8-31 Value, propriété
UDP, protocole 37-1
URI et URL 32-4 agrégats 27-16
un-à-plusieurs, relations 22-41,
URL 32-4 champs 23-20
26-13
bibliothèques paramètres 22-53, 22-60,
UndoLastChange, méthode 27-7
javascript 29-36, 29-38 22-61
unexpected, fonction 12-5
connexions SOAP 29-29 ValueChecked, propriété 19-15
UnhandledExceptionFilter,
connexions Web 29-28 Values, propriété
fonction 12-7
IP, adresses 37-4 groupes radio 19-16
Unicode, caractères 16-3, 16-4
noms d’hôte 37-4 ValueUnchecked,
chaînes 4-22
ou URI 32-4 propriété 19-15
UniDirectional, propriété 22-57
Web, navigateurs 32-5 var, paramètres 13-17
unions
URL, propriété 29-28, 29-29, variables de thread
accès A-5
33-10, 36-19 CORBA 31-12
éditeur de bibliothèques de
uses, clause variables locales aux
types 39-11, 39-19
ajout de modules de threads 11-6
membres
données 7-25 OnTerminate,
avec des types
utilisateur, interfaces événement 11-7
différents A-5
enregistrement unique 19-8 VCL 7-13, 45-1–45-2
unité de base 4-30, 4-31
isolation 18-7 branche TComponent 3-7
unité stub-et-squelette 31-15
plusieurs branche TControl 3-9
unités
enregistrements 19-17 branche TObject 3-6
ajout de composants 45-13
utilitaire d’administration branche TPersistent 3-7
C++Builder 45-13
BDE 24-16, 24-62 branche TWinControl 3-10
CLX 14-10–14-13
utilitaire make GNU classes d’exception 12-18
existantes
Linux 14-16 CLX et 14-5–14-9
ajout de composants 45-13
uuid, argument 13-3 construction d’objets 13-9
VCL 14-10–14-13
gestion des exceptions 12-16
unités de conversion 4-30 V présentation 3-1–3-2
unités de température 4-31
support du langage C++
Unlock, méthode 11-8 valeurs 47-2
pour 13-1–13-31
UnlockList, méthode 11-8 booléennes 47-2, 47-13
thread principal 11-4
UnRegisterTypeLib, fonction default, propriété 47-12
unités 14-10–14-13
désinstallation des données par défaut 19-11
vcl60.bpl 15-1, 15-11, 17-6
bibliothèques de en virgule flottante A-5
penwin.dll 15-13
désinstallation 38-20 caractère virgule
VCLCONTROL_IMPL,
UPDATE, instruction 24-46, décimale A-9
macro 43-3, 43-6
24-50 entières A-7
VendorLib, propriété 26-4
UPDATE, instructions 28-11 propriété par défaut 47-8
verrouillage des objets
UpdateBatch, méthode 14-30, redéfinition 53-3, 53-4
imbrication des appels 11-8
25-14, 25-16 séquentielles 10-13
threads 11-8
UpdateCalendar, méthode 56-4 séquentielles, affectation aux
verrouillage exclusif
UpdateMode, propriété 28-12 constantes 10-13
tables 24-7
ensembles de données test 47-7
version finale 7-33
client 27-26 valeurs booléennes 56-4
VertScrollBar 9-5
UpdateObject, méthode 43-16 valeurs de référence 19-20
Index I-51
fichiers 36-17 déclaration de type de XSLPageProducer 34-5
importation 36-3, 36-15– document 35-2
36-16, 36-18 instructions de Y
publication 36-17–36-18 traitement 35-2
Year, propriété 55-7
WSDLIMP 36-16 mappages 30-2–30-4
définition 30-4
X SOAP et 36-1
XML, courtiers 29-36
XDR, fichier 35-2
messages HTTP 29-40
Xerox Network System
XML, schémas 35-2
(XNS) 37-1
XMLBroker, propriété 29-43
fichiers .xfm 14-2
XMLDataFile, propriété 28-3,
XML 29-38–29-41, 30-1, 35-1
30-9
analyseurs 35-2
XMLDataSetField,
applications de bases de
propriété 29-43
données 30-1–30-12
XMLMapper 30-2, 30-4–30-7
XSD, fichier 35-2