• Aucun résultat trouvé

Les Classes (suite)

N/A
N/A
Protected

Academic year: 2022

Partager "Les Classes (suite)"

Copied!
8
0
0

Texte intégral

(1)

IFT 1175 / E05 Page 1 Module 3

Les Classes (suite)

Les classes «normales»

Rappel : définir une classe, c'est essentiellement définir ses membres, c'est-à-dire ses propriétés, ses méthodes et ses événements. Voici quelques particularités que l'on peut attribuer à ces différents membres.

La clause Overloads (surcharge d'une méthode)

La clause Overloads appliquée à une procédure (sous-routine ou fonction) permet de définir plusieurs versions d'une même méthodes d'une classe. L'ambiguïté sera levée simplement en attribuant à chaque version une signature distincte. La signature de la méthode est déterminée par la liste des paramètres, à savoir le nombre et le type de chacun., mais pas leurs noms, bien sûr. Ainsi : Rep = InputBox("Entrez le nom ou le numéro de l'article")

If Val(Rep) > 0 Then 'Réponse numérique PrixUnit = CherchePrix(Val(Rep))

Else 'Réponse non numérique

PrixUnit = CherchePrix(Rep) End If

...

Public Overloads Function PrixUnit(ByVal Valeur As Integer) As Single ' Code qui trouve le prix à partie du numéro de l'article

Public Overloads Function PrixUnit(ByVal Valeur As String) As Single ' Code qui trouve le prix à partie du nom de l'article

Lors de l'appel de la fonction, le type du paramètre (Rep est de type String et Val(Rep) de type Integer) détermine laquelle des méthode sera utilisée. Souvent la surcharge viendra simplement de la présence ou de l'absence d'un paramètre. Par exemple, une fonction «Age()» sans paramètre donnera l'age actuel d'un patient alors que «Age(2000)» renverra l'âge du patient en l'an 2000.

Public Overloads Function Age() As Integer ' Calcule l'âge dans l'année courante

Public Overloads Function Age(ByVal Valeur As Integer) As Integer ' Calcule l'âge à l'année spécifiée

Notez qu'il peut y avoir autant de versions que nécessaire. Notez enfin que la procédure New() dite le constructeur peut être définie en plusieurs exemplaires mais que, par exception, la clause Overloads NE DOIT PAS être utilisée. Voir l'exemple de la section précédente.

La clause Shared (propriété/variable partagée ou «statique»)

La clause Shared indique que la variable désignée est commune à toutes les instances (tous les objets) créées à partir de la classe. Parfois appelée «propriété statique», une propriété utilisant une telle variable n'occupe qu'un emplacement de mémoire appartenant à la classe elle-même. Tous les objets partageront cette valeur, qu'elle soit en lecture-écriture, en lecture seule ou en écriture seule.

(2)

IFT 1175 / E05 Page 2 Module 3

On peut utiliser, par exemple une telle propriété pour indiquer le nom de l'entreprise dans le cas d'une classe d'employés. Une autre application consiste à indiquer, en lecture seule, le nombre d'instances en cours.

Private Shared mNbObj As Integer = 0 ' Variable commune Public ReadOnly Property NbObj() As Integer

Get

Return mNbObj ' Indique le nombre d'objets «vivants»

Eng Get

End Property Public Sub New()

mNbObj += 1 ' On augmente le compteur lors de la création End Sub

Public Overrides Sub Finalize() ' Voir plus loin la clause Overrides mNbObj -= 1 ' On diminue le compteur lors de la destruction End Sub

La clause Shared (méthode)

Dans le cas d'une méthode, la clause Shared a une toute autre signification. Elle indique tout simplement que cette méthode peut être utilisée directement à partir de la classe, sans passer par un objet, c'est-à-dire par une instanciation de cette classe. Soit par exemple les méthodes suivantes :

Class clEmp

Private Shared mNomComp As String = "ABC Ltée" ' Variable commune Public Function NomComp() As String

Get

Return mNomComp End Get

End Function

Public Shared Function NomEntreprise() As String Return "ABC Ltée"

End Function End Class

Dim X As New clEmp()

MsgBox(X.NomComp) ' Renvoie "ABC Ltée"

MsgBox(X.NomEntreprise) ' Renvoie "ABC Ltée"

MsgBox(clEmp.NomEntreprise) ' Renvoie "ABC Ltée"

MsgBox(clEmp.NomComp) ' Erreur de compilation

Une utilisation majeure des méthodes «partagées» est celle qu'en fait VB.Net pour la diffusion des fonctions spécialisées (mathématiques, aléatoires, gestion des dates/heures, etc. Par exemple, les deux classes MATH et RANDOM sont définies dans l'espace de nom «System» et donc accessibles directement dans la page de code. MATH contient la plupart des «anciennes» fonctions de base (Abs, Sin, Acos, etc) en mode Shared. On peut donc utiliser directement

V3 = Math.Abs(V2-V1) ' Retourne la différence «positive»

Long = Math.Sin(UnAngle) ' Retourne le sinus de l'angle ce qui donne accès aux fonctions correspondantes.

(3)

IFT 1175 / E05 Page 3 Module 3

Par ailleurs, la classe RANDOM permet d'obtenir une suite de nombre aléatoire au moyen d'une fonction «Next()» qui n'est pas en mode Shared. Donc pour obtenir une séquence, on doit instancier un objet Random :

Dim UnAlea As New Random() ' Création d'une instance

V3 = UnAlea.Next(V1, V2) ' Retourne une valeur entre V1 et V2 V3 = Random.Next(V1, V2) ' Cause une erreur de compilation

La clause Friend (classe, méthode et propriété)

Comme pour les variables standard, les classes et leurs membres peuvent être déclarés comme Public ou Private. Dans le premier cas, l'élément désigné sera visible de l'intérieur comme de l'extérieur, et donc de tout utilisateur de la classe à partir d'un autre projet. Dans le dernier cas, la visibilité sera restreinte aux seuls éléments à l'intérieur de la classe elle-même. Entre les deux extrêmes, se trouve une clause intermédiaire Friend restreignant la visibilité au seul code situé à l'intérieur du projet.

Les Classes «dérivées» (héritage)

La «puissance» des classes tient en grande partie à la possibilité qu'elles ont de «se reproduire» au moyen de l'héritage. Ainsi, si un développeur «A» se crée une classe d'objets «CX» et qu'il partage cette classe en en diffusant le code compilé (sous la forme d'un fichier «X.dll»), un développeur «B»

pourra utiliser cette classe mais ne pourra pas la modifier. S'il désire utiliser cette classe mais en la modifiant pour lui ajouter quelques membres ou bien en modifier certains, il pourra le faire en créant une nouvelle classe «CY» BASÉE SUR LA CLASSE «CX», qu'il possède ou non le code source le la classe. Ainsi,

Friend Class CY InHerits CX

crée la classe Y et lui confère chacun des membres de la classe «X». Dès lors les objets OX et OY Dim OX As New CX

Dim OY As New CY

auront exactement le même comportement à tous les égards. Sauf que la classe Y peut être enrichie de nouvelles propriétés ou de nouvelles méthodes qui permettront à «B» d'atteindre ses objectifs.

Après avoir lui-même rendu disponible sa classe (code source ou fichier compilé), un développeur - pourra à son tour développer une classe «CZ» basée sur «CY», et ainsi de suite. De fait, toutes les classes sont dérivées de la «classe-mère Object». Notez qu'une classe ne peut hériter que d'une seule classe de base - laquelle peut elle-même hériter d'une classe antérieure. Par exemple, si la classe

«CY» définit une propriété «Supp», seul l'objet OY en sera pourvu.

Un exemple classique de cette possibilité est le développement d'une classe «Personne» comportant les propriétés et les méthodes associées naturellement à une telle classe «d'objets». Une fois la classe définie, on peut l'utiliser comme base pour développer d'une part la classe «Employé» où s'ajouteront les caractéristiques pertinentes, et d'autre part la classe «Retraité» avec ses propres membres. Dans les deux cas, tout le travail fait pour la classe de base sera récupéré dans la classe dérivée grâce à une seule ligne de code.

(4)

IFT 1175 / E05 Page 4 Module 3

La clause Overrides (propriété, méthode) La clause Overridable (propriété, méthode) La clause Shadows (propriété, méthode) L'objet MyBase

Si l'ajout de méthodes/propriétés/événements se fait tout naturellement de la même manière que leur création, il en va différemment des modifications qu'on veut leur apporter. La clause Overrides sert justement à cette fin. En effet, supposons que la classe de base «CX» contient une propriété «PX».

Friend Class CX

Public Overridable ReadOnly Property Affiche() As String Get

Return "Texte 1"

End Get

End Property Friend Class CY InHerits CX

Public Overrides ReadOnly Property Affiche() As String Get

Return "Texte 2"

End Get

End Property End Class

...

Dim OX As New CX Dim OY As New CY

MsgBox(OX.Affiche) ' Affichera "Texte1"

MsgBox(OY.Affiche) ' Affichera "Texte2"

Mais si on ré-écrit la propriété Affiche :

Return MyBase.Affiche & "Texte 2"

alors «OY.Affiche) retournera "Texte1Texte2" où la partie «Texte1» provient de l'appel à la propriété «Affiche» de la classe de base «MyBase = CX» . En résumé, il existe deux méthodes

«Affiche», celle de la classe de base «CX» et celle de la classe dérivée «CY». Par défaut, c'est la méthode de substitution («CY») qui est exécutée. Mais celle-ci peut à son tour appeler la méthode originelle de «CX» au moyen du mot-clé «MyBase» qui désigne la classe de base.

La substitution d'une méthode peut cependant avoir des effets secondaires imprévus si, par exemple, la méthode de base interagit avec les autres membres de sa classe. Par exemple, la propriété Sorted d'un ComboBox ne fait pas que modifier une valeur cachée de la propriété : l'appel

«MonCombo.Sorted = True» change la valeur de la propriété, bien sûr, mais surtout TRIE LES ÉLÉMENTS DE LA LISTE «ITEMS». Si on substitue la propriété Sorted et qu'on ne fait que changer la valeur d'une variable cachée, alors la liste demeurera dans l'ordre d'arrivée plutôt que dans l'ordre alphabétique. D'où la nécessité de faire appel à la propriété de base :

Public Overrides Property Sorted() As Boolean Get

Return MyBase.Sorted End Get

Set(ByVal Value As Boolean)

' énoncés particuliers à la nouvelle propriété

MyBase.Sorted = Value ' Pour que le tri s'effectue au besoin End Set

End Property

(5)

IFT 1175 / E05 Page 5 Module 3

Pour éviter qu'un membre d'une classe ne soit substituée de façon «dangereuse» la clause

«Overrides» n'est légitime que si la propriété/méthode de la classe de base contient la clause de

«mise en garde» «Overridable». Ainsi, le développeur d'une classe qui risque d'être sous-classée (dérivée) peut indiquer quelles propriétés/méthodes sont susceptibles de se voir substituées.

Par ailleurs il peut arriver que le développeur «B», tout en sachant que la méthode/propriété «PA»

n'est pas sensée être substituée, décide quand même de la «réécrire». Dans ce cas, il peut «avec grande prudence» décider d'aller de l'avant au moyen de la clause «Shadows» qui remplace alors la propriété de base. De fait, la clause est optionnelle puisque par défaut tous les membres remplacent leur homonyme de la classe de base. Si vous l'insérez, vous ne faites que prévenir le compilateur que vous êtes conscient de la chose et vous évitez de recevoir un avertissement de la similarité de noms lors de la compilation.

En résumé, il est recommandé d'utiliser Overrides de préférence à Shadows. Si la substitution est acceptée, cela indique que le développeur de la classe de base avait prévu le remplacement sans problème de la méthode. Si la clause Overrides n'est pas acceptée, on peut alors utiliser la clause Shadows, mais avec précaution et en faisant exécuter la méthode de la base à l'intérieur de la méthode de substitution.

Les Contrôles dérivés

On sait que tous les contrôles, graphiques ou non, que l'on utilise dans la feuille d'une application (sans oublier la feuille elle-même) sont créés à partir d'une définition d'une classe apparaissant dans l'une des nombreuses ramifications des ensembles de classes issues de l'espace de nom «System».

Pour la plupart, il s'agit en fait de la classe Or, une des applications les plus marquante de l'héritage est sans doute la possibilité de développer de nouveaux contrôles à partir de contrôles existants.

L'idée étant, bien sûr, de modeler un contrôle connu pour lui ajouter des comportements particuliers.

Par exemple, un TextBox spécial qui possède une propriété «Langue» qui indique la langue du texte (Anglais/Français/Italien), une méthode (Sub) «Traduire(ByVal UneLangue As String)» qui traduit le texte dans la langue désirée et enfin un événement «ChangeLangue» déclenché lorsque la langue du texte a été modifiée. En fait le nombre de variations potentielles est virtuellement illimité.

Une fois un tel contrôle obtenu, on pourra le compiler et obtenir un fichier «binaire» de type «.dll»

qui pourra ensuite être utilisé comme tous les autres contrôles. Il faudra cependant, avant de pouvoir le placer sur une feuille, l'ajouter à la Boîte d'outils de l'éditeur VB. Pour obtenir un tel contrôle, on procède comme suit : (voir le TP pour la description détaillée de chcune des étapes)

1. On crée un nouveau projet VB mais on choisit le modèle «Bibliothèque de contrôles Windows» (plutôt que le modèle standard «Application Windows». On donne un nom approprié au projet.

2. Dans la page de code, on modifie la ligne par défaut

«Inherits System.Windows.Forms.UserControl»

pour remplacer le «modèle» UserControl par le type de contrôle que l'on veut utiliser comme base : TextBox, ComboBox, Button, etc. Puis on renomme la classe pour lui donner un nom représentatif.

3. On ajoute les nouveaux membres de la nouvelle classe simplement en insérant les énoncés nécessaires et on modifie s'il y a lieu les membres existants de la classe de base en utilisant les clauses Overrides ou Shadows.

(6)

IFT 1175 / E05 Page 6 Module 3

4. On génère la solution, ce qui produit le fichier «dll» dans le dossier «Bin» de la solution.

5. On ajoute le contrôle compilé à la boîte d'outils.

Une fois ces étapes effectuées, la boîte d'outils contiendra le nouveau contrôle qui pourra être placé en autant d'exemplaires que nécessaires dans toutes les applications qui seront développées sur cet ordinateur.

NOTES :

• Comme le contrôle dérivé utilise entièrement les propriétés graphiques du contrôle de base, l'éditeur VB ne vous permet pas, en mode design, de visualiser et donc de modifier graphiquement votre contrôle. Le nouveau contrôle se présentera donc entièrement comme l'ancien quand il sera manipulé sur une feuille, dans un projet.

• En théorie, le développement d'un contrôle devrait se faire comme suit : on modifie le contrôle et on le compile. Puis on ouvre une nouvelle solution de type application Windows, on ajoute le contrôle à la boîte d'outils et on le teste à fond. Si on détecte une erreur, ou revient dans le premier projet, on re-modifie et on recompile, puis on re-teste, et ainsi de suite. Pour éviter ce va-et-vient, l'éditeur permet par la commande du menu Fichier Ajouter_Un_Projet d'ouvrir DEUX projets dans la même application. Ainsi, après avoir défini le projet No 2 comme projet de démarrage, VB compile les deux projets simultanément, produit les deux fichiers exécutables et permet de vérifier le contrôle directement. (Voir le TP3)

• Le fichier «dll», étant un fichier exécutable complémentaire (.dll) requis par une fichier exécutable (.exe), il suffit de les placer dans le même dossier pour que le lien (référence) se fasse entre les deux. N.B. Microsoft offre une petite application «ILMerge» qui permet de fusionner le «.exe» et les «.dll» nécessaires dans un même «.exe» autonome à l'adresse «http://research.microsoft.com/%7Embarnett/ilmerge.aspx».

• Par défaut, le nom attribué par VB au fichier «.dll» compilé sera celui de l'application, mais il peut être modifié dans la fenêtre des propriétés du projet (menu Projet Propriétés Nom_de_l'assembly). Éventuellement, un fichier «.dll» peut contenir la définition de plusieurs classes, comme l'indique le nom du type de projet «Bibliothèque de contrôles Windows».

Les Contrôles utilisateurs

Les contrôles utilisateurs sont des contrôles créés sur mesure pour des besoins particuliers. Lorsque l'on crée un projet de type «Bibliothèque de contrôles Windows» (étape 1 des contrôles dérivés, ci- haut), VB fournit une surface de travail, un conteneur basé sur la classe UserControl. Sur cette surface, on peut placer tous les contrôles nécessaires à nos besoins, tout comme sur une feuille. Ces contrôles définiront l'interface visuelle du contrôle. En fait la classe de base (UserControl) a de très nombreux points communs avec la feuille standard Windows. De fait, la principale différence consiste en l'absence totale de bordure et de barre de titre. Si on désire appliquer une bordure visible au contrôle, on peut y placer un cadre (Panel) et «l'amarrer» (propriété Dock) aux quatre bords de la surface. La bordure du cadre coïncidera donc avec les bords du contrôle malgré les changements de taille.

(7)

IFT 1175 / E05 Page 7 Module 3

Propriétés / méthodes / événements

Lors de la création du nouveau contrôle, celui-ci hérite des membres de la classe de base, UserControl. Ce sont pour la plupart les éléments qui définissent l'apparence du contrôle. On trouve entre autres les propriétés, les méthodes et les événements suivants.

Nom du membre Type de

membre Description Nom du membre Type de

membre Description BackColor Prop Couleur de fond BackgroundImage Prop Image de fond CausesValidation Prop Autorise la validation CompanyName P(Lect) Nom du concepteur Controls Prop Collection contrôles Dock Prop Type d'amarrage Enabled Prop Si accessible ForeColor Prop Couleur d'affichage HasChildren Prop Si contient contrôles Location Prop Position du contrô;e Size Prop Taille du contrôle Visible Prop Si visible

CreateGraphics Func Permet de dessiner Refresh Sub Réaffiche ses contrôles Click Évé Clic sur le contrôle DoubleClick Évé Double clic

Enter Évé Va obtenir le focus GotFocus Évé Vient d'obtenir le focus KeyPress Évé Touche enfoncée KeyDown/KeyUP Évé T. enfoncée/relâchée Leave Évé Va perdre le focus Load Évé Premier affichage LostFocus Évé A perdu le focus MouseDown/Up Évé Clic de souris Paint Évé A été réaffiché Validating Évé Phase de valisdation

Notez bien que, peu importe quels contrôles on ajoute sur la surface du contrôle utilisateur, les membres déjà prédéfinis (dont ceux listés ci haut) seront les seuls membres dont celui-ci disposera à moins que l'on en ajoute explicitement. Ainsi, l'ajout d'un contrôle sur la surface de travail n'a aucun impact direct sur les membres du contrôle conteneur.

Il est possible à ce moment d'ajouter explicitement propriétés, méthodes et événements à ceux hérités de la classe de base UserControl. Ces nouveaux membres seront alors visible de la feuille qui accueillera le contrôle dans les applications à venir.

Visibilité des membres

Considérons la situation où une feuille «F» d'une application contient une instance «U» de notre classe de contrôle utilisateur dans laquelle nous avons placé deux contrôles «C1» et «C2» (contrôles de VB ou bien autres contrôles utilisateurs). Chacun des objets F, U, C1 et C2 aura donc ses propres membres qui réagiront les uns avec les autres. On dénotera trois niveaux d'interactions : F-U, U-C et F-C.

Interaction F-U : tous les membres prédéfinis du contrôle (liste ci haut) pourront être accessibles à partir du code de la feuille, en plus des membres ajoutés explicitement dans le code de l'objet U.

Ainsi, une propriété «U.Valeur» pourra être codé dans les énoncés du code «F». De même, une procédure événementielle «Sub U_Terminé()» pourra être créée dans le code de la feuille «F» si le code de «U» contient l'énoncé «Public Event Terminé()».

(8)

IFT 1175 / E05 Page 8 Module 3

Interaction U-C : tous les membres des contrôles «C1» et «C2» pourront être traités dans le code du contrôle utilisateur. Par exemple si C1 est une barre de défilement, le code de «U» pourra contenir une procédure événementielle «C1_ValueChanged()» qui pourra modifier la valeur de la zone de texte «C2», tout comme on le retrouve sur une feuille. Par ailleurs, une propriété du contrôle «U» peut être une «propriété déléguée» : ici, par exemple, la propriété «Valeur» du contrôle

«U» peut très bien être associée à une propriété d'un contrôle composant «C».

Propriété «régulière» (dans le code «U») utilise une variable cachée Private mValeurOK As Boolean

Public Property ValeurOK() As Boolean Get

Return mValeurOK End Get

Set(ByVal Value As Boolean) mValeur = Value

End Set

End Property

Propriété «déléguée» (dans le code «U») utilise une propriété de l'un des composants Public Property Valeur() As Integer

Get

Return C2.Text

End Get

Set(ByVal Value As Integer) C2.Text = Value

End Set

End Property

Événement «délégué» (dans le code «U») utilise un événement de l'un des composants Public Event Changement

Public Sub C1_ChangedValue(Byval sender As ... ' événement standard ' code du traitement de l'événement

RaiseEvent Changement

End Sub ' Tout changement de valeur du contrôle «C2» provoquera le déclenchement de l'événement de Changement «U».

Interaction F-C : Il n'y a aucune possibilité pour «F» de voir directement les membre de «C» et donc d'en programmer les événements. Toute interaction doit passer par l'intermédiaire des membres délégués de «U» comme illustré ci haut. Si on veut que la feuille qui recevra notre contrôle puisse accéder à un membre de ses composants, il faudra définir ces membres au niveau de «U» et harmoniser la relation «U-C».

Références

Documents relatifs

En ce qui concerne les chaines y (gamma), les donnees ac- tuelles sur leurs sequences completes dans les immu- noglobulines humaines montrent que la region VH et la r6gion VL

class Button { private string Nom=””; public string Name() { get { return Nom;} set { if ( value != null ) Nom = value; } } Utilisation : Button X = new Button(); X.Name

[r]

Tu peux à présent créer des systèmes de deux équations à deux inconnues et tu peux t’entraîner à

S’agit-il d’une valeur exacte ou d’une valeur approchée?.

avec le sq uels

Dans la mesure où les deux classes sont intéressées, nous permettons qu'ils se poursuivent aussi longtemps qu'il faut.. J'arrive avec mes gamins dans la classe

Service offert par la Ville à la suite d’un dépôt pour analyse – PIIA – Construction d’un nouveau bâtiment principal d’usage résidentiel. Unifamilial (H1) :