• Aucun résultat trouvé

[PDF] ressource de formation a propos de C++ Builder | Cours informatique

N/A
N/A
Protected

Academic year: 2021

Partager "[PDF] ressource de formation a propos de C++ Builder | Cours informatique"

Copied!
41
0
0

Texte intégral

(1)

C++ Builder met en œuvre, conjointement, plusieurs concepts récemment généralisés dans le domaine de la programmation. En particulier il utilise des objets ( sous leur forme originale ou sous forme de composants ) et permet de créer des applications fonctionnant selon un mode événementiel.

Outre l'apprentissage du langage C++ - qui sert de base aux développements - et celui permettant de maîtriser les utilitaires permettant de créer et mettre au point des programmes écrits dans ce langage, il faut aussi apprendre à maîtriser l'environnement en lui-même et bien percevoir les impacts qu'il a sur le mode de développement.

Dans un premier temps, on se contentera d'utiliser les objets prédéfinis, proposés par les différentes bibliothèques de C++ Builder, pour créer des applications. Mais l'on pourra ultérieurement créer ses propres objets ou modifier les objets existants.

9.1 : Entités manipulées par

C++ Builder

L'environnement C++ Builder est fourni avec un ensemble de bibliothèques comportant : - Des ensembles de fonctions : Ces ensembles peuvent être standardisés ( fonctions du

langage C++ regroupant celles propres à ce langage et quelques unes subsistantes du langage C ) ou propres à Borland.

- Des classes prédéfinies. Ces classes peuvent être les classes standardisées du langage C++, ou des classes créées spécialement par Inprise-Borland.

- Des composants spécifiques à l'environnement C++ Builder ( et à Delphi puisqu'ils proviennent de cet environnement ). Ces composants sont regroupés au sein d'une bibliothèque appelée VCL ( Visual Component Library ).

9.

Principes de base de la programmation

(2)

ligne associée ) pour pouvoir développer directement des applications Windows ou pour utiliser ces fonctions lorsque le besoin s'en fait sentir.

9.11 : Classes prédéfinies

C++ Builder est fourni avec deux catégories de classes prédéfinies :

-La bibliothèque STL ( Standard Template Library ), développée au départ par Hewlett-Packard et qui est devenue le noyau de la bibliothèque standardisée du langage C++. -Des bibliothèques spécifiques à C++ Builder, fortement liées aux composants de la

VCL.

Ces deux bibliothèques sont très "copieuses" et leur étude ne peut être réalisée que dans la durée. Le chapitre suivant du cours présentera brièvement les classes les plus utiles ( classes AnsiString, Currency et TDateTime en particulier.

9.12 : Les composants

8.121

/ Généralité

Au niveau conceptuel, les composants manipulés par C++ Builder sont des objets et en présentent donc les caractéristiques principales. Ils ont cependant des caractéristiques particulières qui les rendent aptes à être manipulés directement dans l'environnement de développement.

En première analyse, les composants sont des entités :

-Regroupant, comme tous objets, des données qui les caractérisent et des méthodes qui modélisent leurs comportements.

-Susceptibles de réagir à des événements.

Comme tout objet, les composants sont instanciés à partir de classes prédéfinies, regroupées au sein de la bibliothèque VCL. Mais ils ont la possibilité :

-D'être créés dynamiquement dans l'environnement de développement pour construire "à la souris", une application ;

-D'être créés dans l'environnement d'exécution ( on parle de run-time ), selon les besoins de l'application.

Le premier mode de création est celui qui nous intéresse dans un premier temps car il permet le RAD. Il sera utile, dans un deuxième temps, de savoir comment créer à l'exécution les composants dont on peut avoir besoin.

Pour que le premier mode de création soit possible, il faut que l'environnement de développement mette en œuvre un "environnement d'exécution virtuel" dans lequel ils peuvent être créés. C'est cette caractéristique majeure ( et difficile à mettre au point, ce qui explique le petit nombre d'environnement susceptible de la mettre en œuvre ) qui fait que l'on peut accéder aux données de chaque composant, et que certaines de leurs méthodes sont activées, de manière à pouvoir simuler leur comportement à l'exécution.

9.122 / Constituants d'un composant :

Comme tout objet créé à partir d'une classe développée en langage C++, un composant est constitué de données et de méthodes, qui peuvent être publics ou privés. Mais en

(3)

plus les composants sont susceptibles de réagir à certains événements et sont donc "pré-câblés" en conséquence.

 Données et propriétés :

Les données caractérisant un composant peuvent être manipulées à parti de l'environnement de développement ( il s'agit en quelque sorte de les initialiser ) ou en cours d'exécution du programme.

En fait une donnée n'est généralement pas accessible directement ( sauf à disposer du source de la classe d'origine du composant ) et n'est manipulable qu'au travers d'une interface particulière – spécifique à l'environnement C++ Builder - appelée propriété.

Une propriété n'est que la partie apparente de méthodes particulières dont l'unique rôle est de permettre d'accéder à une donnée de la classe sous-jacente. A une propriété correspond en général deux méthodes : une permettant de connaître la valeur de la donnée ( get ) et une permettant de modifier celle-ci ( set ).

Il est du ressort du développeur de composant de définir les couples de méthodes permettant d'accéder aux données. Il n'est donc pas utile d'aller plus loin dans la description des mécanismes mis en jeu pour réaliser cette interface.

Tout au plus est-il utile de savoir que le programmeur, créateur de composant, peut spécifier que sa propriété sera :

- Publique ( statut published ) et dans ce cas elle apparaît en tant que telle dans l'inspecteur d'objet ( décrit plus loin ) ;

- Protégée ( statut public du standard C++ ) et dans ce cas elle n'apparaît pas dans l'inspecteur d'objet mais reste accessible par programmation ( on appelle ces propriétés des propriétés run-time ).

Les propriétés accessibles pendant la phase de conception du programme, permettent de personnaliser l'aspect du composant ( couleur, position, dimension, etc. ).

Les propriétés sont surtout caractérisées par les types de données qu'elles sont capables de manipuler. On dit, par abus de langage, que les propriétés sont "typées". Leur comportement dans l'inspecteur d'objet dépend de ce type.

Une propriété peut être :

- Une valeur numérique ( entière ou réelle ) ; - Une chaîne de caractères ;

- Un booléen ;

- Un tableau de chaînes de caractères ;

- Un objet ( mis en œuvre du concept de l'agrégation ).

Dans un premier temps, lorsqu'il s'agit de créer une application avec les composants fournis avec C++ Builder, on peut assimiler tout simplement une propriété à la donnée à laquelle elle donne accès. N'importe comment l'aide en ligne présente, elle-aussi, une propriété comme une donnée ( alors que celles-ci sont cachées et n'ont, souvent, pas exactement le même nom ).

Certains composants peuvent contenir plusieurs dizaines de propriétés.  Méthodes :

(4)

méthodes. Celles-ci ne sont accessibles qu'en programmation. Ces méthodes permettent d'agir sur le comportement du composant.  Événements :

Comme un composant est destiné à fonctionner dans un environnement "événementiel", il est conçu pour être capable de réagir à un nombre variable d'événements.

Ces événements peuvent être des "clicks" souris, des actions sur le clavier ou d'autres types.

Les événements auxquels un composant réagit sont conformes à son type et aux règles de programmation Windows.

C'est le concepteur du composant qui le programme pour réagir à certains événement. Nativement un composant ne peut donc pas réagir à un autre événement que ceux pour lesquels il a été conçu.

Si l'on dispose du source du composant on peut toujours le modifier ( ce qui revient à dire que l'on réalise une classe fille par rapport à la classe du composant ) pour le faire réagir à d'autres événements.

Le composant est donc susceptible de réagir à des événements. Cela ne veut pas dire que ce sera toujours le cas : il faut en effet que l'utilisateur du composant ait créé un sous-programme "gestionnaire" de l'événement pour que le composant réagisse réellement à ce dernier. S'il n'existe pas de gestionnaire approprié, le composant ne réagit pas quand un événement intervient.

9.13 : La bibliothèque VCL :

Toute construction d'application nécessite l'utilisation de composants et/ou de classes contenues dans les différentes bibliothèques fournies avec C++ Builder. Mais si l'utilisation de classes n'est pas impérative, celle de composant l'est car il n'est pas possible de réaliser une application, aussi simple qu'elle soit, sans utiliser quelques composants.

Il serait cependant fastidieux de décrire d'emblée toutes les classes constituant la bibliothèque VCL ( Visual Composant Library ) de C++ Builder. Il est plus profitable d'apprendre à utiliser l'aide en ligne afin de savoir quelles classes sont adaptées aux besoins de l'application, quelles seront les propriétés qui devront être initialisées ou modifiées à l'exécution, quelles seront les méthodes utilisées et les événements gérés.

Avant même d'apprendre à utiliser les composants de base, il est intéressant de savoir que – conformément aux concepts objets sous-jacents – les classes de la bibliothèque constituent une arborescence unique : toutes les classes dérivent plus ou moins directement de la classe "virtuelle" TObject.

On n'utilise pas directement cette classe d'objets ( car, du fait qu'il s'agit d'une classe virtuelle, ses méthodes associées sont redéfinies dans les classes dérivées ). Mais dans certains cas il est intéressant de se rappeler que n'importe quel composant est avant tout un Object dérivé de la classe TObject.

(5)

A partir de TObject, la connaissance globale des principales "branches" de l'arborescence permet de mieux comprendre les caractéristiques fondamentales des composants qui sont créés.

L'extrait de l'arborescence décrit ci-dessous permet de distinguer les différentes familles de composants que nous utiliserons dans le reste du cours :

A partir de la classe TObject de nombreuses classes sont dérivées :

- Une première famille est composée des classes qui permettent de constituer des objets évolués ( objets "liste", "chaîne de caractères", etc. ) qui pourront être utilisés, en tant que données membres dans les classes de composants ( par agrégation ).

- L'autre famille est, à partir de la classe TPersistent, constituée principalement par les classes d'objets graphiques, qui servent eux aussi à la constitution d'objets évolués, tels les objets "fonte", "pinceau", "bitmap", etc. , et la classe TComponent.

La classe TComponent est la classe de base de tous les composants visuels ( ceux qui apparaissent à l'écran lors de l'exécution ) ou non.

Elle contient toutes les données et les méthodes qui permettent de manipuler les objets, qui instanciés à partir des classes dérivées, comme des composants.

TObject

TPersistent

TComponent

TControl

TWinControl

TGraphicControl

Classes générales de gestion interne et objets

de base à partir desquels les composants sont réalisés. ex : TPrinter TException TStream etc. Classes générales permettant la construction d'objets graphiques ex : TGraphicPrinter, TPen, TCanvas, TMetafile, TFont, TBrush, etc.

Classes permettant la gestion internes des

bases de données

Classes des différents "contrôles" constituant l'interface graphique ( boutons, listes, combo,

zone de saisie, etc. )

Classes des différents "contrôles" graphiques ( barre d'icônes, images, etc. )

(6)

- La branche dérivée de la classe TControl ;

- La branche composée des composants servant à la manipulation interne des bases de données ( les composants non visuels assurant le lien entre l'application et le moteur de base de données BDE ).

La classe TControl, enfin, est la classe de base de tous les composants servant à créer des interfaces graphiques. Elle est dérivée principalement en TWinControl et TGraphicControl et leurs classes dérivées respectives.

Il y a lieu de distinguer les composants dérivés de la classe TWinControl de ceux dérivés de TGraphicControl.

¤ Les contrôles dérivés de TWinControl ( ex : les boutons, les listes, les cases à cocher, etc. ) peuvent détenir le focus ( c'est à dire qu'ils peuvent devenir le composant actif de la fenêtre )et sont gérés par Windows à l'aide de handles. Ils peuvent être parent d'autres composants.

¤ Les contrôles dérivés de TGraphicControl ne peuvent pas détenir le focus, ne sont pas gérés par handle et ne peuvent pas contenir d'autres composants.

Un handle est un entier qui permet à Windows d'identifier chaque objet pouvant recevoir des messages.

En fait Windows considère les contrôles dérivés de TWinControl comme des "fenêtres" et les gère comme telles.

Dans certains cas il y a peu de différence de comportement entre un composant dérivé de TWinControl et un autre dérivé de TGraphicControl. On peut alors se poser la question de savoir quel est le composant à utiliser. Sous réserve d'autres contraintes, il est intéressant de noter que la mise en place de handles est synonyme de consommation de ressources.

Par exemple il y a peu de différence entre un BitButton, qui est un TWinControl et un SpeedButton qui est un TGraphicControl. Cependant l'utilisation massive de SpeedButtons dans une barre d'icônes est préférable, car plus "économe" de ressources système, quand on sait que certaines barres peuvent contenir jusqu'à 50 boutons.

9.2 : L'inspecteur d'objet

9.21 : Présentation de l'inspecteur d'objet

L'inspecteur d'objet est l'utilitaire qui est le plus utilisé lorsque l'on crée des applications avec C++ Builder.

Lorsque l'on dépose un composant sur la fenêtre en cours de conception, l'inspecteur d'objet affiche automatiquement, grâce à deux onglets :

- Une grande partie de ses propriétés ( celles qui ont le statut published et sont accessibles lors de la phase de conception ) ;

(7)

 La zone de texte située en haut indique le nom de l'objet sélectionné et sa classe d'appartenance. On peut ainsi accéder à tous les objets de la feuille en cours de conception en faisant dérouler la zone ( en appuyant sur la flèche située à droite ).

Onglet "Propriétés" Onglet "Événements"

 L'inspecteur d'objet risque d'être caché par le nombre de fenêtres ouvertes par C++ Builder, dès que le projet devient conséquent. On peut le placer au-dessus des fenêtres en appuyant sur la touche F11 mais aussi le configurer de manière à ce qu'il soit "toujours au-dessus" en validant l'option correspondante dans le "pop-up menu" apparaissant suite à un click droit de la souris sur l'inspecteur.

(8)

gauche liste les identifiants des différentes propriétés publiques ( = accessibles lors de la phase de conception ) du composant.

La colonne de droite affiche la valeur courante des différentes propriétés.

Le fait de modifier la valeur d'une propriété a un effet immédiat sur l'objet concerné à l'écran ( taille, positionnement, couleur, etc. ). De même le fait de modifier à la souris certaines caractéristiques du composant modifie immédiatement les valeurs des propriétés concernées.

¤ Si une entrée de l'onglet "propriétés" comporte un signe ' + ' c'est qu'on peut accéder à des sous-propriétés en cliquant sur l'entrée concernée. Quand la liste se déploie, le ' + ' est changé en ' - ' .

Lorsque la colonne de droite d'une entrée comportant un signe ' + ' possède, sur sa droite, un petit bouton légendé '...' c'est qu'il est possible de modifier les sous-propriétés via une boite de dialogue.

Le fait d'avoir cliqué sur la propriété "font" affiche ces sous-propriétés. Celles-ci peuvent être modifiées plus intuitivement via la boite de dialogue.

¤ D'autre part, le fait de cliquer sur certaines valeurs de données fait apparaître une flèche descendante ( sur la droite ) indiquant qu'une liste de valeurs est disponible. En déroulant la liste on peut sélectionner la valeur souhaitée.

Certaines propriétés ne peuvent prendre que deux valeurs ( en général True et False ). Le seul fait de double-cliquer sur la valeur en cours la modifie en son inverse.

(9)

Lorsque l'on a cliqué dans une valeur de propriété et que l'on change ensuite de composant, c'est la propriété identique du nouveau composant qui est activée, sans que l'on ait besoin de la rechercher.

9.23 : Accès aux événements par l'inspecteur d'objet

L'onglet 'événements' de l'inspecteur d'objet référence tous les événements auquel le composant est susceptible de réagir ( il a été programmé pour cela ).

Lorsque l'on affiche l'onglet 'événements' de l'inspecteur d'objet, les entrées de droite sont toutes vierges.

L'utilisateur du composant ( le programmeur de l'application ) choisit un événement auquel le composant doit réagir en double-cliquant sur l'entrée concernée de l'inspecteur d'objet ).

La fenêtre de code apparaît proposant un nom par défaut à la fonction chargée de gérer l'événement ainsi qu'un squelette de procédure.

Le programmeur n'a plus qu'à remplir, par les instructions appropriées, le squelette pour créer le gestionnaire d'événement associé à un événement.

... au travail.

En interne, il faut savoir que les composants accèdent aux gestionnaires d'événements par des pointeurs sur des fonctions ( les gestionnaires ). Si le pointeur est NULL c'est qu'il n'y a pas d'événement associé, sinon, lorsque l'événement survient, le code de son gestionnaire est exécuté.

(10)

Sauf en de rares occasions qu'il faut justifier, il n'est pas utile de modifier les noms des gestionnaires d'événement proposés par défaut. Ils sont assez explicites comme cela.

9.3 : L'aide en ligne

L'aide en ligne ( en français - mais pour une part seulement ) propose une description de chaque composant dans le bandeau située en haut de la fenêtre. Elle permet d'accéder à trois ou quatre rubriques distinctes :

- La rubrique "Propriétés" décrit le rôle de chaque propriété du composant ( celles qui sont accessibles via l'inspecteur d'objet et les autres ).

- La rubrique "Méthode" décrit toutes les méthodes publiques du composant ( c'est le seul endroit où l'on peut obtenir ces informations ).

- La rubrique "Événements" récapitule les événements pouvant être associés au composant.

- La rubrique, facultative, "Tâches" donne des conseils d'utilisation sur le composant. Accès aux méthodes :

Contrairement aux propriétés et aux événements, il n'est pas possible d'accéder aux méthodes via des utilitaires facilitant leur manipulation.

La manipulation des méthodes propres à un composant ( ou à un objet ) se fait donc uniquement par programmation.

Pour savoir quelles sont les méthodes publiques associées à un composant ou à une classe, il faut se reporter à l'aide en ligne de C++ Builder ( en appuyant sur la touche F1 après avoir sélectionné le composant concerné ).

(11)

Il est possible d'accéder directement à une propriété en l'ayant au préalable sélectionnée dans l'inspecteur d'objet avant d'appuyer sur F1.

Il faut considérer les aides en ligne de C++ Builder comme des utilitaires à part entière - et incontournables - de l'environnement de développement. Il n'est pas question de chercher à réaliser quoi que ce soit sans cette aide et aucun ouvrage ne pourra référencer la somme d'informations contenues dans ces fichiers.

En fait le problème est simple. Les aides de C++ Builder proposent :

- La description exhaustive de la syntaxe et de la grammaire du langage C++ ; - La totalité de la bibliothèque de fonctions du C++ et des extensions propres à C++

Builder ( plusieurs centaines de fonctions ) ;

- La description complète du SDK Windows, ce qui représente encore plusieurs centaines de fonctions.

- La description des spécificités de C++ Builder, et en particulier de ses dizaines de composants.

Au niveau des composants il faut bien comprendre que chacun peut renfermer quelques dizaines de propriétés ( dont certaines sont des objets.... ) et méthodes et peut réagir à un nombre très variable d'événements.

On comprend qu'il ne soit pas possible de décrire la totalité des fonctions, composants et autres "objets" entrant dans la réalisation d'une application C++ Builder. Il faut donc apprendre à utiliser l'aide en ligne en la considérant comme un outil à part entière.

Les questions que l'on doit se poser, pour tout développement, sont alors : - Quel composant utiliser ?

- Quelles propriétés du composant modifier ? - Quelles méthodes activer ?

- Quels événements utiliser ?

Une bonne maîtrise de l'utilisation de l'aide en ligne est absolument nécessaire : il faut savoir comment trouver l'information et, éventuellement, savoir "naviguer" de rubrique en rubrique pour trouver le renseignement souhaité.

9.4 : Programmation événementielle

Les méthodes et les propriétés ( qui sont, rappelons le cette fois encore, des méthodes particulières ) des différents objets composent leur interface vis à vis du monde extérieur. Ce qui revient à dire qu'elles ne seront que rarement invoquées par les composants eux-mêmes mais plutôt par d'autres composants.

Il faut considérer que l'activation d'une méthode à partir d'un autre composant correspond à l'envoi et à la réception d'un "message" ( au sens P.O.O. du terme ) : un objet source envoie, sous la forme de l'activation d'une méthode adéquate, un message à un objet destination pour que ce dernier modifie ses caractéristiques ou son comportement.

(12)

On peut comprendre ce fonctionnement sur le cas suivant :

Un composant bouton ( Button1 ) réagit à l'événement "click" souris. Lorsque cet événement survient, le gestionnaire exécute deux actions :

- Il modifie la propriété Text du composant Edit1 ( qui est une zone de saisie et d'affichage ) en lui donnant la valeur "bonjour " ;

- Il invoque la méthode Add ( ) du composant ListBox1 ( qui est une liste de chaînes de caractères pouvant - le cas échéant – mettre en œuvre un ascenseur ) afin d'ajouter un élément à la liste.

La fenêtre, en mode conception, se présente sous cette forme :

Composant source

Evénement

Composant

destination

void __fastcall TForm1::ComposantSourceClick(TObject *Sender)

{

ComposantDest->Methode ( ... ) ; }

Le gestionnaire d'événement est exécuté lorsque l'événement survient. Son code contient des instructions pouvant activer des méthodes d'autres composants afin de modifier leurs caractéristiques et/ou comportement.

Composant Edit1

(13)

Le code du gestionnaire d'événement associé est alors le suivant :

void __fastcall TForm1::Button1Click(TObject *Sender) {

Edit1->Text = "Bonjour" ;

ListBox1->Items->Add( "Nouvel élément" ); }

A l'exécution, une fois le bouton activé par un click souris, la fonction événement associée modifie les deux composants :

Notation événementielle "pointée" :

C++ Builder utilise la notation "pointée" pour accéder aux différents constituants de ces composants. Toutefois, comme en langage C/C++ "tout est pointeur", les noms attribués aux différents composants manipulés sont en fait des pointeurs. C'est ce qui explique que l'on utilise l'opérateur '->' pour accéder aux différents membres de l'objet. .

Cette notation permet de définir, pour un objet considéré, la propriété à modifier ou la méthode à invoquer.

La notation pointée se lit de droite à gauche :

ListBox1->Items->Add ( Edit1 ->Text ) ;

Se lit :

Add ( ... ) : Ajouter

Ici il s'agit d'ajouter le contenu de la zone de saisie Edit1. Items : Elément de la liste .

ListBox1 : Boite de liste

Soit : " Ajouter un nouvel élément, dont la valeur est celle contenue dans la zone de saisie Edit1, dans la liste ListBox1".

(14)

9.5 : Génération de code

Au fur et à mesure que des composants sont posés sur la feuille de conception de l'interface, les lignes de codes correspondantes sont automatiquement générées par C++ Builder. On peut distinguer les lignes correspondant :

C++ Builder se charge de tout :

- Si le nom d'un composant est ensuite modifié ( via l'inspecteur d'objet ), cette modification est répercutée dans le code ;

- Si un composant est effacé de la feuille de conception, ses références sont effacées ; - Si un gestionnaire d'événement reste vide ( il n'y a que le squelette ), il est effacé

lors de la première opération de sauvegarde. Procédures et fonctions internes :

Si la plus grande partie du code généré consiste en la réalisation de gestionnaires d'événements associés à des événements précis, il est possible de créer des fonctions à usage interne.

Si certaines d'entre elles doivent être "visibles" à partir d'autres fichiers source il faut qu'elles soient déclarées extern.

Exemple :

void __fastcall TForm1 :: MaFonction ( int a , int ) ; {

{ Code de la procédure } };

- Il faut toujours indiquer dans la déclaration de la procédure ( ou de la fonction ) de quelle feuille elle dépend.

- Le prototype de cette fonction doit être placé dans le fichier en-tête correspondant.

- L'appel de la fonction se fera sous la forme : MaFonction ( x , y ) { en interne }

Form1->MaFonction ( x , y ) { à partir d'une autre unité }

Si ces fonctions sont destinées à être utilisées dans plusieurs unités, il y a lieu de créer une unité spéciale - sans fiche associée - qui pourra être associée aux unités qui en feront la demande.

(15)

 Cependant, C++ Builder ne modifie ou ne supprime que les références qu'il a lui-même créées automatiquement. Si un composant, ou une fonction, est référencé "manuellement" ( c'est à dire par le programmeur ) dans le source, cette référence n'est pas modifiée ou supprimée le cas échéant. C'est au programmeur de s'en charger.

 De même, il ne faut pas tenter de modifier "à la main" ce qui a été créé automatiquement par C++ Builder :

- Pour modifier un nom de composant il faut passer par l'inspecteur d'objet ; - Pour supprimer un composant il faut l'effacer de la feuille de conception ; - Pour supprimer un gestionnaire d'événement il faut simplement effacer le

code tout en conservant son squelette ( celui-ci sera ensuite effacé automatiquement ).

Le non-respect de ces règles peut provoquer des incohérences lors des compilations ultérieures dont il est souvent malaisé de s'en sortir.

9.6 : Notion de projet

9.61 : Contenu d'un projet

La création d'une application est réalisée, au sein de l'environnement C++ Builder, via un gestionnaire de projet qui gère l'ensemble des éléments constitutifs de l'application.

Au niveau de l'environnement de développement, un projet est constitué de tout ou partie des éléments suivants :

¤ De fiches :

Une fiche correspond à une fenêtre affichée à l'écran.

Il y a donc autant de fiches dans le projet de développement que l'application affichera de fenêtres lors de son exécution.

Au niveau de C++ Builder une fiche sert à concevoir les interfaces utilisateurs de l'application. Elle peut donc contenir des menus, des boutons, des boîtes de saisie, des boîtes de dialogue et tous les autres objets nécessaires au fonctionnement de l'application.

Lorsque la conception d'une fiche est terminée, il est possible de l'ajouter au référentiel d'objets afin que d'autres programmeurs puissent la réutiliser "telle qu'elle" dans leurs projets.

Qu'est-ce qu'une application ?

Une application est constituée d'un nombre variable de fenêtres qui s'affichent selon un enchaînement qui lui est propre.

En règle générale une application est composée d'une fenêtre principale, qui sert d'interface utilisateur primaire, et qui est affichée au lancement de l'application. Elle contient un menu et/ou une barre d'icônes.

L'application est constituée d'autres fenêtres, constituant les différentes interfaces avec l'utilisateur destinées à lancer et à contrôler les différents traitements réalisés.

(16)

d'extension '.dfm' ( qui signifie Delphi ForM , du fait de l'origine "Delphi" de C++ Builder ).

Un fichier '.dfm' contient la description complète de l'interface graphique d'une feuille ( c'est à dire la description – élément par élément - des différents composants utilisés pour constituer l'interface ). Ce fichier a un format particulier qui le rend illisible tel quel.

Exemple de description d'interface contenue dans un fichier '.dfm'. :

object Button1: TButton

Left = 184 Top = 44 Width = 161 Height = 55 Caption = 'Button1' TabOrder = 0 end

L'éditeur de C++ Builder peut afficher et imprimer un tel fichier sous une forme lisible. Pour cela il suffit d'activer la fenêtre constituant le fichier '.dfm' et, en cliquant sur le bouton droit de la souris, afficher un menu contextuel. En cliquant sur l'item "Voir comme texte" le contenu du fichier '.dfm' apparaît.

Pour afficher de nouveau la fenêtre de conception il faut, de nouveau ouvrir, via un clic-droit, un menu contextuel est activer l'item "Voir comme fiche".

Il faut noter que si l'on copie un composant dans le presse-papiers puis qu'on colle le contenu de ce dernier dans un éditeur de texte, comme le bloc-notes, c'est la description au format texte du composant qui apparaît.

La description "lisible" de chaque fenêtre de l'application doit faire partie du dossier de documentation de l'application ( ainsi d'ailleurs qu'une copie d'écran de l'interface en question ).

En effet, contrairement à ce qui se passe dans des environnements de programmation classique, les indications concernant les dimensions et le positionnement des composants n'apparaissent pas dans les sources. Le fichier '.dfm' est donc le seul à disposer de ces indications, indispensables si l'on souhaite maintenir l'application ou la porter dans d'autres environnements.

A chaque fiche sont associés deux fichiers composant l'unité de la fiche. Ces fichiers contiennent les algorithmes ( fichier '.cpp' ) et les en-têtes ( fichier '.h' ) des traitements mis en œuvre quand la fiche est active à l'écran.

Les fichiers '.cpp' et '.h' associés sont générés automatiquement à la création d'une nouvelle fiche. Chacun contient un squelette de déclaration créé automatiquement par C++ Builder.

Le fichier '.cpp' est affiché dans l'éditeur de texte à l'arrière de la fenêtre de construction de l'interface. Pour faire apparaître le fichier '.h' il faut, activer la fenêtre d'édition contenant le fichier '.cpp' et, en ouvrant un menu contextuel par un clic-droit sur la souris, activer l'item "Afficher le fichier source/en tête".

¤ Des unités autonomes :

Il se peut que l'application ait à réaliser certains traitements internes sans qu'une interface graphique lui soit associée.

(17)

Le projet peut donc contenir des ensembles de fichiers '. et ' ' autonomes. Ces unités contiennent en général des sous-programmes génériques utilisés dans de nombreuses fiches.

¤ Des fichiers ressources

Ces fichiers, d'extension '.rc', contiennent les ressources graphiques utilisées par l'application ( images bitmap, icônes, etc. ).

¤ Des fichiers "projet"

Le projet en lui-même manipule un certain nombre d'informations ( pour référencer en particulier les différents fichiers constitutifs ) et permettre leur compilation. Ces informations sont stockées dans un fichier d'extension '.bpr', qui peut être facilement édité en tant que fichier-texte mais que l'on ne doit, sous aucun prétexte, modifier. Le fichier '.bpr' est en quelque sorte un fichier makefile ( cher aux anciens programmeurs en langage C. Il contient des indications sur tous les fichiers sources, modules objets dérivés, modules de bibliothèques, etc. nécessaires à la création de l'exécutable.

Un fichier '.cpp' lui est associé. Il décrit la fonction Winmain ( ) qui, dans l'environnement Windows, remplace la fonction main ( ) traditionnelle.

Les sources de ces différents fichiers ont l'allure suivante : Fichier '.bpr' : # ---!if !$d(BCB) BCB = $(MAKEDIR)\.. !endif # ---# Section EDI # ---# La section suivante du Makefile du projet est gérée par l'EDI de BCB.

# Il est recommandé d'utiliser l'EDI pour modifier les valeurs de cette # section. # ---VERSION = BCB.04.04 # ---PROJECT = Project1.exe

OBJFILES = Project1.obj Unit1.obj RESFILES = Project1.res

RESDEPEN = $(RESFILES) Unit1.dfm LIBFILES =

LIBRARIES = SPARELIBS =

PACKAGES = VCL40.bpi VCLX40.bpi VCLJPG40.bpi bcbsmp40.bpi QRPT40.bpi VCLDB40.bpi \

ibsmp40.bpi VCLDBX40.bpi TEEUI40.bpi TEEDB40.bpi TEE40.bpi nmfast40.bpi \

dclocx40.bpi DEFFILE =

# ---PATHCPP = .;

(18)

PATHRC = .; DEBUGLIBPATH = $(BCB)\lib\debug RELEASELIBPATH = $(BCB)\lib\release USERDEFINES = SYSDEFINES = _RTLDLL;NO_STRICT;USEPACKAGES # ---CFLAG1 = -I$(BCB)\include;$(BCB)\include\vcl -Od -Hc -H=$ (BCB)\lib\vcl40.csm -w -Ve -r- \

-a8 -k -y -v -vi- -c -b- -w-par -w-inl -Vx -tW -tWM \ -D$(SYSDEFINES);$(USERDEFINES)

PFLAGS = -U$(BCB)\lib\obj;$(BCB)\lib;$(RELEASELIBPATH) \ -I$(BCB)\include;$(BCB)\include\vcl -$YD -$W -$O- -v -JPHNE -M

RFLAGS = -i$(BCB)\include;$(BCB)\include\vcl

AFLAGS = /i$(BCB)\include /i$(BCB)\include\vcl /mx /w2 /zd LFLAGS = -L$(BCB)\lib\obj;$(BCB)\lib;$(RELEASELIBPATH) -aa -Tpe -x -Gn -v

#

---ALLOBJ = c0w32.obj Memmgr.Lib $(PACKAGES) sysinit.obj $ (OBJFILES)

ALLRES = $(RESFILES)

ALLLIB = $(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib #

---!ifdef IDEOPTIONS

...suit un nombre impressionnant d'informations variées sur la configuration.

Le fichier Project1.cpp contient, quant à lui les lignes suivantes :

//---#include <vcl.h> #pragma hdrstop USERES("Project1.res"); USEFORM("Unit1.cpp", FMaPremiereFeuille);

//---WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { try { Application->Initialize(); Application->CreateForm (__classid(TFMaPremiereFeuille), &FMaPremiereFeuille); Application->Run(); }

catch (Exception &exception) { Application->ShowException(&exception); } return 0; }

//---Au final, un projet est constitué par un nombre, qui peut être rapidement impressionnant, de fichiers :

(19)

Type de fichier Extension Nombre Utilité

Projet .bpr 1 Description du projet

Projet .cpp 1 Source du projet

Unité .cpp X + Y Source des traitements

En tête .h X + Y Déclarations diverses

Interface .dfm X Description des interfaces

Ressources .rc 1 Contient les ressources

X : Nombre de fiches de l'application ; y : nombre d'unités autonomes.

A ce nombre il faut rajouter :

- Tous les fichiers de sauvegarde, générés automatiquement par C++ Builder, en fonction des options validées par le développeur. Ces fichiers sont reconnaissables par le fait que le premier caractère de l'extension est remplacé par un caractère '~' ( ex: un fichier 'fichier1.cpp' est sauvegardé en 'fichier1.~pp' ).

- Les modules objets générés à la compilation. Ils ont l'extension '.obj' pour les modules créés à partir des sources, et '.res' pour celui réalisé à partir du fichier de ressources.

- Différents fichiers de travail générés par et pour l'usage de C++ Builder (extensions '.ilc', '.ild', '.tds', etc. ).

- Le fichier exécutable généré au final.

Les fichiers de travail ne sont pas impératifs, C++ Builder les crée pour ses besoins internes. S'ils sont absents ils sont régénérés lors d'un processus de compilation / génération d'un exécutable. Mais cela se traduit par un allongement du processus.

Seuls les fichiers '.bpr', '.cpp', '.dfm', sont donc indispensables.

Il est fortement souhaitable de créer un répertoire spécifique par projet.

Page IX.19

Nommage des éléments constitutifs :

Par défaut, les différents fichiers s'appellent Form1.dfm / Unit1.cpp / Project1 pour la première feuille puis Form2.dfm / Unit2.cpp, .... FormX.dfm / UnitX.cpp,

au fur et à mesure de l'avancement du projet.

Il est évident qu'il est souhaitable de donner des noms plus explicites aux différents composants de l'application. Pour cela :

- Dès la création du projet, le sauvegarder à l'aide du menu "Fichier / Enregistrer le projet sous".

Une fenêtre de dialogue apparaît demandant de fournir un nom pour le fichier d'extension '.cpp'. Indiquer le nom souhaité ainsi que l'emplacement où ce fichier sera stocké.

Une deuxième fenêtre apparaît demandant de fournir un nom au fichier '.bpr'. Indiquer le nom souhaité en sachant que ce sera le nom du projet.

- A chaque création de fiche, la sauvegarder en lui fournissant un nom approprié.

Les fichiers '.dfm' et '.h' sont automatiquement sauvegardés avec le nom fourni au fichier '.cpp'.

Le nom fourni au fichier de projet sera le nom de l'exécutable. Faire attention à son choix.

Distinguer les fichiers correspondants à une fiche, en leur donnant par exemple le prefixe 'F', de ceux correspondants à des unités autonomes, préfixées par exemple 'U'.

(20)

A l'issue de la création de l'application seul le fichier exécutable doit être diffusé. Il faudra éventuellement y ajouter un certain nombre de modules externes :

- Modules constituant BDE, et ses DLL associés, s'il s'agit d'une application utilisant ce SGBD ;

- DLL diverses, en fonction de l'application créée.

Comme le programmeur n'a pas toujours connaissance des DLL associées aux composants qu'il manipule pour construire l'application, il est préférable de réaliser l'installation du produit final à l'aide de l'utilitaire Install Shield qui associera automatiquement les bonnes DLL au module exécutable et qui saura où les installer sur la machine cible.

9.62 : Gestion d'un projet

Les opérations permettant de gérer un projet sont accessibles via des items répartis dans plusieurs menus.

Ouverture d'un projet :

L'ouverture d'un projet existant se fait grâce au menu Fichier / Ouvrir un projet ( ou Ctrl + F11 ).

L'option "Réouvrir" permet d'accéder rapidement à une liste référençant les derniers projets ouverts sans avoir à parcourir l'arborescence du disque.

Fermeture d'un projet :

Avant de quitter C++ Builder il est conseillé de sauvegarder les différents fichiers utilisés. Le moyen le plus sûr et d'utiliser le menu Fichier / Tout enregistrer.

Ajout d'un composant au projet :

On peut ajouter une fiche ou une unité à un projet existant. Ces entités peuvent être fournies au projet sous la forme d'un fichier .cpp, d'un module objet ( .obj ) ou d'une librairie ( .lib ).

Il faut activer pour cela le menu Projet / Ajouter au projet.

Le fait d'ajouter au projet un fichier .cpp fait que les fichiers associés .dfm et .h sont considérés comme faisant partie du projet.

(21)

Il est préférable de copier les fichiers concernés dans le répertoire courant du projet avant de réaliser l'ajout au sein du projet. Sinon le projet sera constitué de fichiers stockés dans plusieurs répertoires.

C++ Builder prévient le développeur si la fiche intégrée dans le projet a un nom déjà utilisé par une des fiches du projet.

Suppression d'un composant au projet :

On peut supprimer un composant du projet en activant le menu Projet / Retirer du projet.

Le fait de supprimer un composant du fichier n'efface pas les fichiers correspondant du répertoire du projet.

Options du projet :

Il est possible de définir de nombreuses options pour chaque projet. Celles-ci sont accessibles via l'item Projet / Options.

Sauf dans les cas qui seront vus dans la suite du cours, il est préférable de ne pas modifier intempestivement les options par défaut proposées par C++ Builder.

Visualisation des composants d'un projet :

On peut visualiser la constitution d'un projet en activant le menu Voir / Gestionnaire de projet.

Cette activation fait apparaître une fenêtre spécifique :

Fenêtre de gestion de projet / elle permet de visualiser la composition du projet et d'accéder rapidement à un de ses constituant ( par double-click sur le constituant souhaité ).

(22)

ouverts. Il permet en outre de supprimer des éléments constitutifs du projet ( au lieu de passer par le menu Projet / Retirer du projet ).

Le fait d'activer un composant, avec le bouton adéquat, après l'avoir sélectionner dans la liste, le fait s'afficher en avant-plan ( on peut aussi double-cliquer sur le nom de l'élément ).

Autres possibilités :

La gestion d'un projet peut devenir complexe dès lors que plusieurs fichiers et/ou unités sont ouvertes.

Il est possible d'accéder rapidement à la fenêtre désirée en utilisant les touches ou combinaisons de touches suivantes :

F 12 : Permet d'afficher en avant plan le "complément" de l'entité active. ( Par exemple un appui sur F2 affichera le fichier .cpp associé à la feuille de création d'interface si celle-ci est active. Ou l'inverse si c'était le fichier .cpp qui était actif ).

Maj + F 12 : Affiche la liste des fiches ( .dfm ) ouvertes. Il suffit alors d'activer la fiche désirée pour qu'elle apparaisse au premier plan.

Ctrl + F 12 : Affiche la liste des unités ( .cpp ) ouvertes. Il suffit alors d'activer le source désiré pour qu'il apparaisse au premier plan.

Il est possible de disposer de certaines informations sur le projet en activant l'item Projet / Information sur ....

Les informations disponibles sont : - Nombre total de lignes compilées ;

- Taille de code ( taille totale du fichier exécutable ou de la DLL sans les informations de debuggage ) ;

- Taille des données ( mémoire nécessaire au stockage des variables globales ) ; - Taille de pile initiale ( mémoire nécessaire au stockage des variables locales ) ; - Taille du fichier ( taille du fichier résultant final ).

9.7 : Construction d'une application

La construction d'une application se fait, feuille par feuille, sous le contrôle permanent de C++ Builder.

Si une application est réalisée dans le cadre d'un projet, son constituant de base est la fiche (ou feuille, ou forme, ou form ) qui – généralement- correspond à une fenêtre ou une boite de dialogue qui s'affiche à l'écran.

C++ Builder génère automatiquement une partie du code source en fonction des actions du développeur réalisées dans l'environnement de développement.

(23)

9.71 : Constitution d'une feuille

Dès qu'une feuille est créée ( au lancement de C++ Builder pour la première feuille et via les menus Fichier / Nouveau ou Fichier / Nouvelle fiche pour les autres ), une classe particulière nommée TForm1 est créée par dérivation directe de la classe TForm ( classe "forme" ou classe "fenêtre" ).

Il est souhaitable de donner rapidement un nom significatif à cette feuille de manière que, automatiquement, la classe créée prenne ce nom.

Le code généré par C++ Builder est scindé en deux parties :

¤ Une partie dans le fichier '.cpp' associé à la feuille en construction. Au départ le code généré est le suivant :

//---#include <vcl.h> #pragma hdrstop #include "Unit1.h" //---#pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1;

//---__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner) {

}

//---

Notez que Form1 est un pointeur sur une classe de type TForm1. C'est dans cette partie qu'apparaîtront, au fur et à mesure de la construction de la feuille les codes des différents gestionnaires d'événements ainsi que, le cas échéant, les codes des fonctions "internes".

¤ Une partie ( description de la classe ), dans le fichier en-tête associé au fichier source.

Au départ le code généré est le suivant :

//---#ifndef Unit1H #define Unit1H //---#include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp>

//---class TForm1 : public TForm

(24)

public: // Déclarations de l'utilisateur __fastcall TForm1(TComponent* Owner);

};

//---extern PACKAGE TForm1 *Form1;

//---#endif

On voit bien qu'il s'agit là de la définition d'une classe fille ( TForm1 ) dérivée de la classe de base TForm.

Après avoir renommé la feuille, via la propriété Name de l'inspecteur d'objet en FMaPremiereFeuille, toutes les références à Form1, et TForm1, dans les différents fichiers, sont remplacées automatiquement par des références à FMaPremiereFeuille et TFMaPremiereFeuille.

Le nom de la feuille, qui est celui par lequel elle pourra être invoquée dans les différents sources, peut être différent de celui donné au fichier '.cpp' ( et donc au fichier '.h' ) lors de la sauvegarde. Mais il est souhaitable que les différents noms attribués aient, au moins, une certaine similitude.

Parallèlement, le fichier projet ( d'extension '.bpr' ) est lui même aménagé. Par la suite, cette classe dérivée, évolue pas à pas en fonction des constituants qui lui sont rajoutés :

- Les différents composants qui constituent l'interface ( composants visibles ) ou l'architecture de la feuille ( composants non visibles ). Chaque composant est une "donnée" de la classe en application du principe d'agrégation.

- Les différents gestionnaires d'événements créés.

- Les fonctions internes à la feuille ( fonctions réalisant un traitement particulier, non liées à un événement, et appelées par d'autres fonctions ou par les gestionnaires d'événement ). Ces fonctions peuvent être privées ou publiques.

Par exemple, à la suite de la "dépose" de trois composants ( un bouton, une zone de saisie et un mémo ) sur la feuille, la description de la classe correspondante, dans le fichier '.h' associé, devient :

class TFMaPremiereFeuille : public TForm {

__published: // Composants gérés par l'EDI

TButton *Button1; TMemo *Memo1; TEdit *Edit1;

private: // Déclarations de l'utilisateur

public: // Déclarations de l'utilisateur

__fastcall TFMaPremiereFeuille(TComponent* Owner); };

Comme il s'agit d'une classe dérivée, seules les "caractéristiques" particulières à la classe sont indiquées dans le source.

(25)

Ne pas oublier que, parallèlement, le fichier '.dfm' de description de l'interface est lui aussi mis à jour.

Dans l'exemple précédent, sont contenu est devenu :

object FMaPremiereFeuille: TFMaPremiereFeuille Left = 275 Top = 243 Width = 696 Height = 480 Caption = 'FMaPremiereFeuille' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11

Font.Name = 'MS Sans Serif' Font.Style = []

OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object Button1: TButton Left = 86 Top = 58 Width = 113 Height = 59 Caption = 'Button1' TabOrder = 0 end

object Memo1: TMemo Left = 222 Top = 42 Width = 143 Height = 139 Lines.Strings = ( 'Memo1') TabOrder = 1 end

object Edit1: TEdit Left = 74 Top = 132 Width = 133 Height = 21 TabOrder = 2 Text = 'Edit1' end end

Remarquez que les indentations indiquent bien que les descriptions des objets Button1, Memo1 et Edit1 sont "contenues" dans celle de l'objet FMaPremiereFeuille

9.72 : Déclaration d'objet

Il faut distinguer la manière dont un objet est déclaré selon qu'il s'agit d'un composant ou d'un objet créé à partir d'une classe "interne" – fournie avec la bibliothèque - ( voire d'une classe créée par le programmeur ).

(26)

correspondant est généré automatiquement dans le fichier source et son en-tête concernés.

Si l'on rajoute un bouton à une fiche, le code suivant est rajouté automatiquement dans le fichier en-tête :

class TFMaPremiereFeuille : public TForm {

__published: // Composants gérés par l'EDI

TButton *Button1;

Remarquez qu'il s'agit en fait d'un pointeur sur un composant de type TButton.

Cet objet est créé implicitement lorsque la feuille qui le contient est créée.

9.722 / Cas d'un objet instancié par programmation :

"Objet" est ici pris dans le sens le plus général : il peut s'agir d'instance d'une classe interne comme d'un composant créé par programmation.

Dans ce cas, il faut :

- Déclarer l'objet, en fonction de la classe souhaitée ( comme pour une variable quelconque ) ;

- Créer l'objet explicitement, afin que la zone mémoire correspondante soit attribuée. Exemple :

Cas d'un bouton ( MonBouton ) créé "dynamiquement" lorsque l'on clique sur le bouton Button1. La création est réalisée comme suit :

-Déclarer un pointeur MonBouton sur un composant TButton, dans la partie publique de la classe TForm1, comme suit :

class TForm1 : public TForm

{

__published: // Composants gérés par l'EDI

TButton *Button1;

void __fastcall Button1Click(TObject *Sender);

private: // Déclarations de l'utilisateur

public: // Déclarations de l'utilisateur

__fastcall TForm1(TComponent* Owner); TButton *MonBouton ;

};

-Créer le gestionnaire d'événement correspondant :

void __fastcall TForm1::Button1Click(TObject *Sender) {

MonBouton = new TButton( this ); MonBouton->Top = 200 ;

(27)

MonBouton->Caption = "Premier" ; MonBouton->Parent = this ; }

La création dynamique de l'objet composant se fait classiquement en utilisant l'opérateur new et le constructeur de la classe. Le paramètre du constructeur, indique l'objet auquel le bouton appartient. En l'occurrence, ici this référence l'objet appelant la méthode c'est à dire Form1.

Les autres indications permettent d'initialiser le bouton ( la liste est non limitative : l'on peut agir sur d'autres propriétés ).

La dernière instruction est primordiale : il faut définir le parent du bouton ( la notion de parent est distincte de celle de propriétaire ). Si cette instruction n'est pas rédigée, le composant n'apparaît pas à l'exécution après un clic sur Button1.

Il faudrait, pour que cette création ait un sens, associer les gestionnaires d'événements de ce bouton. Cela se ferait avec des instructions particulières utilisant des pointeurs sur ces gestionnaires.

La destruction d'un objet ou d'un composant créé à l'aide de l'opérateur new se fait à l'aide de l'opérateur delete qui appelle le destructeur.

9.73 : Passage de paramètre ( s )

Même si les différentes feuilles ont des comportements relativement indépendants, il peut être utile de créer une interface entre deux feuilles ( une feuille mère par exemple et la feuille qu'elle crée ).

Le passage de paramètre se fait comme suit :

On reprend l'exemple précédent de deux feuilles distinctes : le feuille mère FMere appelle la feuille fille via un bouton BOuvrir. La feuille FFille se ferme lorsqu'on clique sur le bouton BFermer.

On ajoute à chaque feuille une zone d'édition EMere ( feuille mère ) et EFille (feuille fille ).

La donnée saisie dans EMere doit être récupérer dans EFille à l'ouverture de cette feuille. De même si la donnée est modifiée dans EFille, cela doit se répercuter dans EMere lorsque la feuille fille est close.

1. Déclarer une donnée publique dans la classe constituant la fenêtre fille :

class TFFille : public TForm

{

__published: // Composants gérés par l'EDI TButton *BFermer;

TEdit *EFille;

void __fastcall BFermerClick(TObject *Sender); void __fastcall FormActivate(TObject *Sender);

private: // Déclarations de l'utilisateur

public: // Déclarations de l'utilisateur

AnsiString Chaine ;

__fastcall TFFille(TComponent* Owner); };

Déclaration de la variable pointeur

(28)

Cette déclaration se fait au sein du fichier en-tête. Ce dernier doit, bien sûr être inclus dans le fichier '.cpp' de la fenêtre mère.

2. Initialiser ce paramètre avant d'afficher la fenêtre fille.

void __fastcall TFMere::BOuvrirClick(TObject *Sender) {

FFille = new TFFille ( this ); FFille->Chaine = EMere -> Text ; FFille->ShowModal ( ) ;

EMere -> Text = FFille->Chaine ; delete FFille ;

}

Cette initialisation ne peut se faire qu'après que la feuille fille a été créée ( sinon le paramètre interface n'existe pas ).

Notez que, comme Chaine est défini dans la feuille FFille il faut spécifier cette appartenance ( FFille -> Chaine ).

3. Récupérer la valeur du paramètre dans la fenêtre fille dans une des méthodes invoquées lors de sa création :

void __fastcall TFFille::FormActivate(TObject *Sender) {

EFille->Text = Chaine ; }

Pour faire passer la valeur dans l'autre sens il faut réaliser l'opération inverse.

En continuant l'exemple précédent, on a, en imaginant que le bouton BFermer, ferme la fenêtre :

void __fastcall TFFille::BFermerClick(TObject *Sender) {

Chaine = EFille -> Text ; Close ( ) ;

}

Cette valeur peut être récupérée dans le composant EMère au retour dans la feuille mère, après l'exécution de la méthode ShowModal ( ) :

void __fastcall TFMere::BOuvrirClick(TObject *Sender) {

FFille = new TFFille ( this ); FFille->Chaine = EMere -> Text ; FFille->ShowModal ( ) ;

EMere -> Text = FFille->Chaine ; delete FFille ;

}

/* La récupération doit se faire avant que la fenêtre fille soit détruite, car après Chaine n'existe plus */

(29)

9.8 : Généralités sur les composants

Chaque composant possède ses propres propriétés, ses propres méthodes et réagit à divers événements. Néanmoins certaines caractéristiques se retrouvent fréquemment d'un composant à l'autre et sont par ailleurs les plus utilisées.

Il est donc intéressant de les connaître pour être capable, à la lecture des informations contenues dans l'inspecteur d'objet ou dans l'aide en ligne, de manipuler rapidement le composant.

Par ailleurs certaines propriétés des composants sont en fait des classes internes. Il faut alors connaître le comportement de ces classes pour être en mesure de manipuler correctement le composant qui l'utilise en tant que propriété.

9.81 : Principales propriétés et méthodes des composants

9.811 : Principales propriétés :

Nom et étiquette :

Toutes les classes de composant possèdent la propriété Name qui permet de donner un nom logique à l'objet créé.

Grâce à ce nom logique on peut manipuler l'objet par programmation ( en modifiant ses propriétés, en invoquant ses méthodes, etc. ).

On ne peut modifier le nom d'un objet que pendant la phase de conception. Cette modification est reportée automatiquement dans toutes les lignes de codes gérées automatiquement par C++ Builder. Par contre elle n'est pas répercutée dans les lignes de code créées par le programmeur.

En conséquence, si l'on doit modifier le nom d'un composant il faut le faire dans l'inspecteur d'objet afin que cette modification soit répercutée automatiquement dans tous les codes générés par C++ Builder.

La valeur donnée à la propriété Name doit respecter les règles de dénomination des identifiants du langage C++ ( commencer par une majuscule, pas d'espaces, etc. ).

Si le nom prévu est déjà utilisé par un autre composant du même type, une erreur est signalée par C++ Builder.

Plusieurs objets possèdent aussi une propriété Caption qui est une "étiquette" apparaissant à l'écran ( c'est la "légende" affichée sur le composant ).

Ce peut être le titre d'une fenêtre, le texte apparaissant sur le haut d'un bouton, etc. Cette propriété n'est donc qu'une propriété "apparente". Toutefois, par défaut, la valeur de la propriété Caption est le nom de l'objet : si l'on modifie ce dernier la valeur de Caption est modifiée tant qu'une valeur spécifique n'est pas fournie.

(30)

dimensionner et de les positionner.

Les propriétés Left etTop permettent de positionner l'objet sur la fiche ( par rapport au coin haut/gauche de la feuille ). Les propriétés Height et Width permettent de modifier ses dimensions.

Si l'on modifie les dimensions et la position à la souris, cela a un effet immédiat sur les valeurs affichées dans l'inspecteur d'objet ( et réciproquement ).

Certains objets, dont les feuilles, possèdent des propriétés indiquant leurs dimensions internes ( la dimension de l'objet moins la dimension cumulée des bordures, cadres, etc. ) : il s'agit des propriétés ClientHeight et ClientWidth.

Propriété Text :

Cette propriété est présente dans tous les objets qui permettent la saisie et la modification d'une chaîne de caractères. Elle correspond à la valeur du texte qui apparaît et qui peut être modifié.

Propriétés Font et Color :

La propriété Font permet de modifier l'aspect des polices de caractères utilisées avec le composant ( titre, étiquette, zone de texte, etc. ).

La propriété Color permet de modifier la couleur de certains composants.

Ces deux propriétés sont en fait des objets comportant plusieurs propriétés et méthodes.

Si l'on initialise à une fonte particulière ( type de police, couleur, taille, etc. ) la propriété 'font' du composant feuille, de type TForm, cette modification est reprise automatiquement dans tous les composants utilisés dans cette fiche ( sauf si une initialisation contraire intervient alors ).

Propriétés Visible, Enabled et ReadOnly :

Ces propriétés permettent de sécuriser une application en forçant l'utilisateur à n'exécuter certaines actions qu'à certains moments bien précis.

La propriété Visible est un booléen permettant d'afficher ou de rendre invisible un objet.

La propriété Enabled est un booléen qui rend actif ou inactif un composant. Lorsqu'un composant est inactif, il est rendu "grisé" et les événements associés ne sont pas pris en compte.

Lorsqu'un composant est inactif les textes qui lui sont associés, comme par exemple le texte sur le haut d'un bouton, apparaissent estompés.

La propriété ReadOnly, lorsqu'elle est activée, permet de rendre les données associées au composant seulement accessibles en lecture seule.

(31)

Propriété Cursor :

La propriété Cursor de chaque composant permet de modifier l'aspect du curseur lorsque celui-ci "passe" au-dessus du composant concerné ( croix, sablier, etc. ).

Propriété Hint :

La propriété Hint permet d'afficher une bulle d'aide concernant le composant lorsque le curseur de la souris passe dessus.

Pour que le mécanisme fonctionne il suffit d'initialiser la propriété Hint avec une chaîne de caractères correspondant au message à afficher et positionner la propriété ShowHint = True.

9.812 : Principales méthodes utilisées :

Les méthodes personnalisent les composants. De fait elles sont beaucoup plus spécifiques à chaque classe. Néanmoins certaines sont relativement génériques et se retrouvent dans la plupart des composants utilisés.

Au premier rang des méthodes génériques figurent les constructeurs et destructeur.

Méthodes Repaint et Refresh :

La méthode Repaint oblige le contrôle à repeindre son image à l'écran mais sans effacer ce qui est déjà affiché. Pour effacer avant de repeindre, il faut appeler la méthode Refresh.

Méthode SetFocus :

Cette méthode attribue la focalisation au contrôle ( c'est lui qui devient actif ).

On ne peut attribuer le focus à un composant qui n'est pas créé. En

particulier on ne peut l'attribuer à un composant tant que la fenêtre qui le contient n'est pas créée.

Méthodes Show et Hide :

Ces méthodes rendent visible ou non une fiche, ou un contrôle, en modifiant la propriété Visible.

Show met la propriété Visible à True, Hide la positionne à False.

(32)

composants sont construits. Les principales classes sont :

Classe Description

TBitmap Image de type bitmap

TBrush Pinceau

TCanvas Zone de dessin TClipboard Presse-papiers TFont Polices de caractères TList Liste générique d'objets

TPen Crayon

TPicture Graphique TPrinter Imprimante

TStringList Liste de chaînes de caractères TStrings Manipulation de chaîne de caractère

Il existe par ailleurs des classes standardisées du langage C++ comme la classe AnsiString vue plus loin.

Tous ces objets ne sont pas étudiés, en particulier celles orientées "graphisme". Néanmoins il faut connaître les caractéristiques de certains d'entre eux qui utilisent tous, plus ou moins, les propriétés et méthodes suivantes :

9.821 / Propriétés et méthodes générales :

Propriété Items :

La propriété Items est un tableau d'éléments quelconque.

On peut accéder à chaque élément d'un tableau de type Items par son indice, de type entier ( Items[ int Indice ] ).

L'indice 0 permet d'accéder au premier élément du tableau.

Si un composant possède une propriété du type Items, il possède aussi la propriété ItemIndex qui lui permet de savoir quel est l'élément de la liste qui est actif.

Si le premier élément est sélectionné, ItemIndex vaut 0. Tant qu'aucun élément n'est sélectionné, ItemIndex vaut -1.

Propriété Count :

La propriété Count ( type int ) permet de savoir combien il y a d'éléments dans un tableau de type Items.

Il y a un décalage de 1 entre la valeur de la propriété Count et l'indice correspondant.

Exemple : Lorsque il n'y a qu'une entrée dans le tableau, Count vaut 1 mais l'indice correspondant à l'entrée est 0.

(33)

La propriété Strings permet d'accéder à une chaîne spécifique d'un objet chaîne ou liste de chaînes.

Il faut spécifier la position de la chaîne dans la liste de chaînes avec le paramètre Index ( exemple : Strings [ Index ] ).

L'indice 0 référence la première chaîne.

Pour connaître l'indice d'une chaîne particulière, il faut invoquer la méthode IndexOf ( ).

Strings est la propriété par défaut des objets chaîne. On peut donc l'omettre et traiter l'objet chaîne lui-même comme un tableau indicé de chaînes.

Dans l'exemple suivant, Lines est une propriété objet chaîne d'un composant Memo ( TMemo ). Ces deux lignes de codes sont valides et équivalentes :

Memo1->Lines->Strings[0]= "C'est la première ligne" ;

Memo1->Lines[0] = "C'est la première ligne" ;

Propriété Sorted :

Si Sorted ( qui est une variable de type bool ) est à True, les chaînes sont triées en ordre croissant. Si Sorted est à False, elles ne sont pas triées.

Propriété Duplicates :

Duplicates détermine si les chaînes dupliquées sont autorisées dans la liste des chaînes triées d'un objet liste de chaînes.

Les valeurs possibles sont :

dupIgnore Les tentatives d'ajout d'une chaîne dupliquée dans la liste des chaînes triées sont ignorées.

dupAccept Les chaînes dupliquées peuvent être ajoutées dans la liste des chaînes triées.

dupError L'ajout d'une chaîne dupliquée provoque une exception EListError.

Si la liste n'est pas triée, la valeur de Duplicates est sans effet.

Méthode IndexOf ( ) :

La méthode IndexOf ( ) renvoie l'indice de l'élément d'un tableau de type Items passé en paramètre.

if ( MyList->IndexOf ( TheObject )== -1 ) MyList->Add( TheObject );

Renvoie -1 si l'élément n'a pas été trouvé.

(34)

La méthode Add ( ) permet de rajouter un élément passé en paramètre dans un tableau de type Items.

La méthode Delete ( ) permet de supprimer d'un tableau de type Items l'élément correspondant à l'indice passé en paramètre.

Méthode Assign( ) :

La méthode Assign ( ) affecte un objet dans un autre. La forme générale d'un appel à Assign( ) est la suivante :

Destination->Assign( Source );

où Destination indique l'objet de l'affectation et Source l'objet initial.

Par exemple, si on utilise une fiche contenant un mémo et une boîte liste. Quand le bouton est cliqué, le contenu du mémo est rempli avec le contenu de la boîte liste.

void __fastcall TForm1::Button1Click(TObject *Sender) {

Memo1->Lines->Assign( ListBox1->Items ); }

Bien que le compilateur autorise tout objet TPersistent dans un appel à Assign(), ce dernier ne peut aboutir lors de l'exécution que si les objets concernés sont en mesure d'effectuer l'affectation.

Par exemple, si Destination est un bouton ( TButton ) et Source une boîte d'édition ( TEdit ), un appel à Assign( ) provoque une exception EConvertError à l'exécution.

Méthode Clear ( void ) :

La méthode Clear ( ) efface toutes les chaînes d'une liste de chaînes.

Méthode Find ( ) :

La méthode Find ( ) recherche la chaîne spécifiée dans la liste de chaînes stockée et triée dans un objet liste de chaînes.

Son prototype est :

virtual bool __fastcall Find ( const System::AnsiString S, int &Index) ; Si la chaîne spécifiée comme valeur du paramètre S ( de type AnsiString ) est trouvée, Find ( ) renvoie True ( False si elle n'est pas trouvée ) et la position de la chaîne dans la liste de chaîne est affectée à la valeur du paramètre Index (de base 0).

Méthode LoadFromFile ( ) : Son prototype est :

Figure

Tableau  récapitulatif  des  propriétés   et  méthodes   implémentées  par   les  classes  TList, TStrings et TStringList.

Références

Documents relatifs

L’archive ouverte pluridisciplinaire HAL, est destinée au dépôt et à la diffusion de documents scientifiques de niveau recherche, publiés ou non, émanant des

La carte 1 (voir annexes, carte 1) illustre la répartition des sites ayant livré des inscriptions en préci- sant, selon les cas, l’emploi du syllabaire levantin, du

C’est pour tenter de répondre à cette question que, dans ce chapitre, nous quantifions la réduction des émissions de CO 2 du transport de fret obtenue grâce

Les résultats à plus haute concentration de catalyseur, comme ceux de la Figure 5.26, peuvent être expliqués par une faible concentration de 5-8 qui demeure plus ou moins

ثحبلا صخلم :ناونع تحت ةركذم هذهف نم يسوللا ماملاا دنع ريخأتلاو ميدقتلل ةيغلابلا ضارغلا&#34; &#34;يناعملا حور هباتِ ل لاخ ةرهاظ ماملاا اهيف ركذ

Cette étude exploratoire examine par quel processus, dans le cadre d’un projet d’exploitation d’une mine de nickel, une entreprise française fait

groupe &lt;&lt; Politique en Grande-Bretagne &gt;&gt; de l'Association franqaise de science politique, sur le theme &lt;&lt;Choix rationnel et d6mocra- tie &gt;&gt;, en cours

Sont également donnés, et nous aurions tout aussi bien pu commencer par là, tous les ingrédients de l’érogène freudien : une zone de corps ou un corps entier (la défunte