La programmation visuelle avec Delphi consiste à placer des composants sur des fiches et à y ajouter du code afin de les coller ensemble. C'est simple et facile mais Delphi permet de faire plus: il permet aux utilisateur de construire leurs propres composants à partir du même environnement de programmation. Cette page vous permettra d'acquérir les connaissances nécessaires pour y arriver.
Très peu de gens utiliseraient l'environnement de programmation de Delphi pour développer des applications Windows si ce n'était pour ses capacités de programmation visuelle qui consiste à placer des composants de la bibliothèque de composants visuels (VCL) sur des fiches et à y ajouter du code afin de les coller ensemble. C'est simple et facile mais Delphi permet de faire plus: il permet aux utilisateur de construire leurs propres composants à l'intérieur du même environnement de programmation. En fait, construire un composant, c'est générer une extension de la bibliothèque de composants visuels de Delphi, la VCL. De plus, c'est une façon très efficace de réutiliser du code.
C'est pour cette raison que j'écris cette page qui traite de la conception et du développement des composants car chaque programmeur Delphi devrait savoir comment faire s'il s'avère nécessaire de le faire.
Dans ce qui suit, je fais une révision rapide des conceptes menant à la conception et au développement de composants en décrivant sommairement l'environnement de programmation de Delphi, l'orientation objet du langage ainsi que la hiérarchie des ses classes et objets. Pour plus de détails, je recommande la lecture des ouvrages suivants: "Delphi Developer's Handbook" et "Mastering Delphi 5" de Marco Cantu ainsi que "Delphi 6" de Steve Texera et Xavier Pacheco.
Delphi
Delphi produit un environnement de programmation visuel basé sur la démarche de la programmation objet. En effet, Delphi est un environnement de programmation basé sur le langage de programmation Pascal-Objet, une version orientée-objet du langage Pascal. Si on aborde ce sujet ici, c'est principalement parce que c'est cette caractéristique qui permet la conception et le développement de nouveaux composants.
Programmation orientée-objet
La programmation orientée objet (POO ou OOP en anglais) est un concept qui se fonde sur des entités logiques qui ont chacune une certains autonomie puisque chaque objet réunit en son sein des données (appelées souvent variables ou propriétés) et des instructions (appelés souvent méthodes).
Si une technologie modélise les choses sous forme de groupes de données et méthodes, on va dire qu'elle est orientée-objet si elle supporte aussi trois autres caractéristiques: l'encapsulation, l'héritage et le polymorphisme.
- Encapsulation - implique que les données et les instructions recoivent une protection contre l'accès direct;
- Héritage - implique qu'un objet peut hériter automatiquement des caractéristiques d'un objet existant (ancètre); et
- Polymorphisme - implique qu'un client peut traiter des objets différents comme s'ils étaient identiques, chaque objet se comportant de la façon qui lui est propre.
En programmation orientée-objet, on doit distinguer les mots classe, objet et instance:
- Une classe est une définition d'une entité. Il s'agit d'une abstraction qui ne consomme pas d'espace de mémoire et n'existe que dans le code source (c'est l'équivalent d'un devis);
- Un objet est le résultat de la création d'une instance réelle à partir de la définition d'une classe. On dit souvent qu'un objet est une instance d'une classe. Notons qu'un objet consomme de la mémoire.
Membres d'une classe
Puisqu'une classe et les objets qui en résultent est constituée de données et d'instructions, on va définir la forme que prennent ces données et instructions.
- Variables - Il s'agit des données définies dans une classe ou appartenant à un objet
- Méthode - il s'agit simplement d'un nouveau nom pour une routine (procédure ou fonction) qui appartient à une classe. En C++, on parle de fonction membre.
- Propriété - Il s'agit d'un moyen logique pour accéder à une donnée ou à du code appartenant à une classe. Les propriétés isolent l'extérieur de la classe des détails de l'implémentation d'une classe.
À cause de l'encapsulation, ces caractéristiques peuvent avoir différentes visibilités:
- privée - le membre n'est accessible que dans sa propre classe;
- protégée - le membre n'est accessiblee que dans sa classe et dans ses classes descendantes;
- publique - le membre est accessible de partout à l'exécution; et
- publiée - le membre est accessible de partout tant à l'exécution qu'à la conception.
Delphi expose cependant une exception importante à ces règles: toutes les classes qui sont déclarées dans une même unité peuvent accéder aux informations privées des autres classes de la même unité. C'est une façon indirecte de simuler la caractéristique friend du C++.
Classes et objets de Delphi
Les classes de Delphi forment une hiérarchie qui prend sa source dans la classe TOBject, l'ancêtre de toutes les autres classes. Évidemment, ces classes répondent aux critères de l'orientation-objet: l'encapsulation, l'héritage et le polymorphisme, un énoncé qu'on va admettre dans ce qui suit.
La figure qui suit présente une partie de la hiérarchie des classes de Delphi. La mère de toutes les classes est la classe abstraite TObject. Cette classe est à la base de toutes les autres et définit toute une série de fonctions permettant de récupérer toutes sortes d'information au sujet des objets. Il faut toutefois noter les méthodes héritées de TObject nommées Create (constructeur) et Destroy (destructeur) qui servent à réserver et libérer l'espace de mémoire requises par les instances de classes (objets).
Notons aussi la classe TPersistent qui dérive directement de TObject. Elle se caractérise par le fait que les objets qui en sont issues peuvent lire leurs propriétés et les écrire par rapport à un flux dès qu'ils sont créés.
Il existe de nombreuses classes qui héritent de TObject et de TPersistent qui ne sont pas des composants. Ils n'apparaissent pas dans la figure. La classe TComponent qui hérite de TObject et TPersistent est la mère de tous les composants: c'est l'ancêtre de la VCL.
Bibliothèque des composants visuels
Les composants Delphi sont des classes et la bibliothèque des composants visuels de Delphi est la collection de toutes les classes définissant les composants Delphi. Par définition, tous les descendants de TComponent sont des composants.
Types de composants
En Delphi, il existe deux grandes catégories de composants (descendants de TComponent):
- Composants visuels - Ce sont ces composants qui apparaissent sur
une fiche avec une position et une dimension - ce sont des descendants de
TControl; cette catégorie se divise aussi en deux sous-catégories, soit:
- Composants fenestrés - Ce sont des composants basés sur une fenêtre et possédant un "handle" de fenêtre - ce sont des descendants de TWinControl;
- Composants non-fenestrés - ce sont des composants qui ne sont pas basés sur une fenêtre: ils se dessinent sur ls fenêtre qui les affiche - ce sont des descendants de TGraphicControl;
- Composants non-visuels - Ce sont des composants qui affichent un icône lorsqu'on les place sur une fiche; cette icône disparaît lors de l'exécution - ce sont des descendants de TComponent.
Le fait d'être un descendant de TComponent n'est pas une conditions suffisante pour être un composant affiché dans la bibliothèque des composants de Delphi. Il faut enregistrer le composant en ajoutant la procédure Register au code et l'insérer dans un paquetage.
Paquetages de composants
Le recensement d'un composant permet à Delphi de savoir quels sont les composants à ajouter à la palette des composants. Pour ce faire, il suffit d'ajouter un appel à la procédure Register dans la section interface de l'unité. Cette procédure appelle la procédure RegisterComponent qui requiert deux arguments: le nom du volet de la palette de composant dans laquelle les nouveaux composants et un tableau de type de composants.
En Delphi 1 et Delphi 2, tout le code des composants était placé à l'intérieur d'une unique bibliothèque de composants. Depuis Delphi 3, Borland a introduit l'architecture des paquetages (packages en anglais) qui permet aux utilisateurs de placer leurs composants dans des modules séparés qui, techniquement parlant, sont des bibliothèques à liaisons dynamiques portant l'extension .bpl (Borland Package Library).
Sauf mention contraire, les nouveaux composants sont insérés dans un paquetage par défaut qui se nomme DclUser6 mais chaque développeur de composant peut utiliser ses propres empaquetages.
Les paquets de composants Delphi sont définis soit comme paquetages de conception utilisés dans l'environnement de développement de Delphi, soit comme paquets d'exécution utilisés directement par les applications. Comme ces deux catégories ne sont pas mutuellement exclusives, on retrouve donc quatre sortes de paquetages:
- Paquetages d'exécution - ce genre de paquetage est constitué d'une poi plusieurs unités dont le contenu est nécessaire pendant l'exécution d'une application;
- Paquetages de conception - ce genre de paquetage réunit des éléments utilisables pendant la phase de conception d'une application: composants, propriétés, éditeurs de composants, assistants.
- Paquetages complets - ce genre de paquetage est utilisable pendant la conception et pendant l'exécution. Le développement des applications et leur distribution en est simplifiée mais l'efficacité en souffre car le paquetagecontient des informations qui ne sont utiles que pendant la conception, même dans la version diffusée;
- Paquetages secondaires - ce dernier genre de paquetage est rarement utilisé et il ne peut l'être que par un autre paquetage et il interdit toute référence directe depuis une application ou toute utilisation lors de la conception.
Développement de composants
La capacité de concevoir aisément de nouveaux composants est l'un des points forts de Delphi. La possibilité d'incorporer des composants personnels aux applications Delphi garantit de pouvoir contrôler précisément l'interface utilisateur de ces applications. Depuis Delphi 6, il est possible de développer des composants soit pour la VCL soit pour la nouvelle architecture multi-plates-formes CLX. Ici, nous ne parlerons que de la VCL.
La première question à se poser avant de commencer la conception et le développement d'une composant est la suivante: le jeu en vaut-il la chandelle. Serait-il plus simple d'utiliser une solution vite-faite à pertir de composant existants. La réponse à cette question dépend du type de programmation à effectuer et de la disponibilité de solutions au problème.
Démarche de conception
Concevoir et développer un composant demeure relativement simple mais le concepteur ne peut en aucun cas se servir des possibilité de programmation visuelle de Delphi. C'est une limitation certaine qui rend difficile, sinon impossible, la conception de composants incorporant d'autres composants.
On doit en tout premier lieu déterminer clairement ce que contiendra et saura faire le nouveau composant. Il faudra ensuite mettre sur papier l'algorithme général correspondans au composant. Voici les six étapes principales de l'écriture d'un composant Delphi:
- Choix de la classe ancestrale - Lorsqu'on construit un nouveau composant, on part généralement d'un composant existant ou d'une classe de base de la VCL comme TComponent, TGraphicControl, TWinControl, TCustomControl ou d'une des classes TCustomNomClasse;
- Création de l'unité composant - La création d'une unité pour le nouveau composant permet de déclarer la classe du nouveau composant ainsi que sa classe ancestrale. Le nouveau composant héritera automatiquement des variables, propriétés et méthodes protégées, publiques et opubliées de la classe ancestrale;
- Ajoût des propriétés, des méthodes et des événements - Lors de cette étape, on ajoute les variables, méthodes et propriétés propres au nouveau composant. On peut aussi rendre visible des méthodes et des propriétés qui étaient protégées;
- Test du composant - Pour tester le nouveau composant, il suffit de créer un projet qui crée puis utilise une instance du composant. On peut aussi recenser le composant et le déposer sur une fiche mais cela n'est pas recommandé car ça peut entraîner le blocage de tout l'environnement de programmation Delphi si une erreur sérieuse est rencontrée;
- Recensement du composant dans l'environnement Delphi - Nous avons parlé de cette étape dans la section intitulée Paquetages de composants;
- Création d'un fichier d'aide pour le composant - il s'agit ici d'une étape que nous ne décrirons pas ici car elle échappe au cadre de cette page.
Conclusion
Cette page a fourni une base de compréhension de l'utilité des composants dans Delphi.