IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Cours VB.NET

Par Philippe Lasserre
 


            

I. Démarrer le cours
I-A. Introduction , page de présentation , principe du site.
II. Introduction: débutez ici
II-A. Qu'allons nous étudier?
II-B. Quel plan de cours suivrons nous?
II-C. Quels logiciels utiliser?
II-D. Quelle configuration est nécessaire?
III. Principe et structure des programmes.
III-A. Les 'Objets
III-A-1. A - Dans la vie courante:
III-A-1-a. Propriétés (Attributs):
III-A-1-b. Méthodes :
III-A-1-c. Evènement:
III-A-1-d. Interface et implémentation:
III-A-1-e. Relation entre Objet:
III-A-2. B- Et dans Visual Basic.net:
III-A-2-a. Tout objet a des propriétés.
III-A-2-b. Les objets ont des méthodes parfois.
III-A-2-c. Interface et implémentation:
III-A-2-d. Relation :
III-A-3. En résumé :
III-A-4. Lexique anglais=>Français:
III-B. Programmation évènementielle: le premier programme.
III-B-1. Principes de la programmation VB
III-B-2. Exemple :le premier programme:
III-B-3. En pratique, que fait le programmeur:
III-B-3-a. A- Il dessine l'interface utilisateur
III-B-3-b. B- Il va écrire le code correspondant aux événements :
III-B-4. En résumé :
III-B-5. Lexique anglais=>Français:
III-C. Les instructions, les procédures . Les 'Sub' , les 'Function'
III-C-1. Les instructions:
III-C-2. Les procédures:
III-C-3. Procédures liées aux événements.
III-C-4. Procédures non liées:
III-C-5. Procédures Sub :
III-C-6. Procédures 'Function' :
III-C-7. Module standard :
III-C-8. Private Public :
III-C-9. Remarques :
III-C-10. Lexique anglais=>Français:
III-D. Les modules
III-D-1. Qu'est ce qu'un module?
III-D-2. Comment créer un module standard:
III-D-3. Lexique anglais=>Français:
III-E. Notion de programmation 'fonctionnelle' et de programmation 'objet'
IV. Environnement de développement: les IDE.
IV-A. IDE Visual Studio 2003 ( Microsoft )
IV-A-1. Fenêtre Projet.
IV-A-2. Dans un nouveau projet, créer une fenêtre :
IV-A-3. Voir les procédures:
IV-A-4. Ajouter des contrôles à la feuille
IV-A-5. Modifier les propriétés d'un contrôle ou du formulaire.
IV-A-6. Voir tous les composants d'un projet:
IV-A-7. Tester son logiciel:
IV-A-8. Projet et solutions.
IV-A-9. Fichiers, Chemins des sources.
IV-A-10. VB propose des AIDES.
IV-A-11. Il existe une abondante documentation:
IV-A-12. Erreur.
IV-A-13. Mode déboguage (mode BREAK):
IV-B. IDE Visual Studio 2005 ( Microsoft )
IV-B-1. Fenêtre Projet.
IV-B-2. Dans un nouveau projet, créer ou ajouter une fenêtre :
IV-B-3. Voir les procédures:
IV-B-4. Ajouter des contrôles à la feuille
IV-B-5. Modifier les propriétés d'un contrôle ou du formulaire.
IV-B-6. Voir tous les composants d'un projet:
IV-B-7. Tester son logiciel:
IV-B-8. Projet et solutions.
IV-B-9. Fichiers, Chemins des sources.
IV-B-10. VB propose des AIDES.
IV-B-11. Il existe une abondante documentation:
IV-B-12. Erreur.
IV-B-13. Mode débogage (mode BREAK):
IV-B-14. Projet Designer:
IV-B-15. Conclusion:
IV-C. VB.NET 2005 Nouveautés 2005
IV-C-1. Le matériel:
IV-C-2. L'IDE
IV-C-2-a. On peut créer des fenêtres toutes faites, avec les contrôles..:
IV-C-2-b. Edit and Continue:
IV-C-2-c. Il y a des exemples de code.
IV-C-2-d. Il est proposé des solutions pour corriger les erreurs de code:
IV-C-2-e. Le Projet Designer:
IV-C-2-e-i. a- Exemple de ressource.
IV-C-2-e-ii. b- Exemple de paramètre.
IV-C-2-f. Pour l'utiliser dans le programme, on fera:
IV-C-2-g. Le déplacement des contrôles ou l'accès aux principales tâches est amélioré:
IV-C-2-h. Renommer un nom: modification automatique.
IV-C-2-i. Commentaire en Xml
IV-C-3. Les nouveaux Objets
IV-C-4. Les instances de Forms:
IV-C-5. Les nouveaux Contrôles
IV-C-5-a. DataGridView
IV-C-5-b. MaskedTextBox
IV-C-5-c. SoundPlayer
IV-C-5-d. SplitContainer:
IV-C-5-e. ListView
IV-C-5-f. WebBrowser:
IV-C-5-g. LayoutPanel:
IV-C-5-h. MenuStrip :
IV-C-5-i. ToolStrip:
IV-C-5-j. StatuStrip:
IV-C-5-k. ProgesBarr:
IV-C-6. Les nouvelles 'Variables'.
IV-C-7. Les nouvelles 'Collections'.
IV-C-8. Dans le Code: les nouvelles instructions
IV-C-9. Les nouveautés dans les Classes:
IV-D. IDE SharpDevelop (alternative gratuite) MAJ version 2.1)
IV-D-1. Où le trouver? Comment l'installer?.
IV-D-1-a. Quelques liens
IV-D-2. Fenêtre Projet.
IV-D-3. Dans un nouveau projet, créer une fenêtre :
IV-D-4. Ajouter des contrôles au formulaire.
IV-D-5. Modifier les propriétés d'un contrôle ou du formulaire.
IV-D-6. Voir les procédures:
IV-D-7. Voir tous les composants d'un projet:
IV-D-8. Remarque relative aux fenêtres de l'IDE:
IV-D-9. Tester son logiciel:
IV-D-10. Fichiers, Chemins des sources.
IV-D-11. Propriétés du projet.
IV-D-12. #Develop propose des AIDES.
IV-D-13. Erreur de compilation :
IV-D-14. Erreur d'exécution: Exceptions
IV-D-15. Débogage :
IV-D-16. Conclusion:
IV-D-17. J'ai besoin d'aide:
V. Langage Visual Basic
V-A. Introduction
V-A-1. Les Classes du FrameWork
V-A-2. Les instructions de Microsoft.VisualBasic
V-A-2-a. Saisir, Afficher.
V-B. Les 'Algorithmes'.
V-B-1. A- Pour écrire un programme.
V-B-2. B- Définition de l'algorithme.
V-B-3. C- Principe généraux
V-B-3-a. Séquences
V-B-3-b. Les variables, leur 'Type':
V-B-3-c. Affectation ( ou Assignation):
V-B-3-d. Booléens
V-B-3-e. Les choix: Si..Alors
V-B-3-f. Les choix: Décider entre :
V-B-3-g. Les répétitions: Pour...Répéter
V-B-3-h. Les répétitions: Tant que :
V-B-3-i. Structuration: 'Sous-programme' ou 'procédure':
V-B-3-j. Tableaux
V-B-3-k. Notion de 'Collection':
V-B-3-l. Erreur d'exécution: Notion de 'Sécurisation' du code:
V-B-3-m. Flag et variables d'état.
V-B-4. D -Quelques algorithmes.
V-B-4-a. Recherche dans un tableau
V-B-4-b. Tri de tableau
V-B-5. Lexique anglais=>Français:
V-C. L'affectation.
V-C-1. Permutation de variables:
V-D. Les variables.
V-D-1. Les variables.
V-D-1-a. Nom des variables :
V-D-1-b. Déclaration, initialisation:
V-D-1-c. En pratique: Exemple.
V-D-1-d. Les différents types de variable:
V-D-1-e. Détaillons :
V-D-1-f. Variable entière:
V-D-1-g. Variable avec virgule:
V-D-1-h. String, Char:
V-D-1-i. Annexe 1:Place occupée en mémoire:
V-D-1-j. Annexe 2: Type primitif
V-D-1-k. Annexe 3: Choix des noms de variable
V-D-2. Variables 'String' et 'Char'
V-D-2-a. A- STRING
V-D-2-a-i. 1- System.String est une Classe du Framework:
V-D-2-a-ii. 2- On peut aussi utiliser les instructions 'Visual Basic':
V-D-2-a-iii. 3- Un exemple:
V-D-2-a-iv. 4- Comparaison de caractères et 'Option Compare'
V-D-2-a-v. 5- Unicode:
V-D-2-b. B- CHAR.
V-D-2-b-i. Et les Chaînes de longueur fixe:
V-D-3. Variables Numériques
V-D-3-a. La Classe MATH du Framework est disponible:
V-D-3-b. Il existe aussi les instructions du langage VisualBasic comme:
V-D-3-c. Dépassement de capacité, 'Non Nombre'.
V-D-4. Conversion, séparateur décimal
V-D-4-a. Conversion numérique=>String
V-D-4-b. Conversion String=>numérique
V-D-4-c. CType pour toutes les conversions
V-D-4-d. Fonctions spécifiques
V-D-4-e. Val et Str (de MicroSoft.VisualBasic) existe aussi:
V-D-4-f. La Classe System.Convert:
V-D-4-g. Pour résumer et faire très simple, retenir ++++:
V-D-4-h. Conversion Explicite et Implicite.
V-D-4-i. Conversion restrictive.
V-D-4-j. Séparateur décimal: le point ou la virgule?
V-D-4-k. IsNumeric
V-D-4-l. Lexique anglais=>Français:
V-D-5. Les 'Tableaux'
V-D-5-a. Un tableau est un objet !!
V-D-5-b. La Classe Array.
V-D-5-c. Exemple:
V-D-6. Les 'Collections'
V-D-6-a. Exemple simpliste permettant de comprendre la notion de collection:
V-D-6-b. L'objet 'Collection' c'est du VisualBasic:
V-D-6-c. Liste d'objets: ArrayList : c'est une Classe .Net.
V-D-6-d. StringCollection: c'est une Classe .Net
V-D-6-e. HashTable c'est une Classe .Net
V-D-6-f. SortedList: c'est une Classe .Net
V-D-6-g. Queue: c'est une Classe .Net
V-D-6-h. Stack: c'est une Classe .Net
V-D-6-i. BitArray: c'est une Classe .Net
V-D-6-j. En VB 2005 :il y a les Collections 'generic' ou 'Specialized'
V-D-6-k. Généralisation de la notion de collection.
V-D-6-l. Pourquoi le premier élément est 0 ou 1?
V-D-6-m. Exemples sur les collections:
V-D-6-n. Lexique anglais=>Français:
V-D-7. Les 'Structures'
V-D-7-a. Attention quand dans une structure il y a un tableau, il faut l'initialiser:
V-D-7-b. Allons plus loin:
V-D-7-b-i. Les structures sont des types 'valeur'.
V-D-7-b-ii. Les structures peuvent contenir plein de choses:
V-D-7-b-iii. Portée:
V-D-8. Attention type valeur ou référence
V-D-8-a. La variable 'par Valeur':
V-D-8-b. La variable 'par Référence':
V-D-8-c. Influence sur l''Affectation':
V-D-8-d. On se méfiera donc du type 'référence ' ou 'Valeur' des données que l'on utilise: exemple des Tableaux
V-D-8-e. Le cas particulier des 'String' qui sont 'Par référence':
V-D-8-f. Déclaration avec New ?
V-D-8-g. Valeur après déclaration:
V-D-8-h. Comparaison:
V-D-8-i. Il existe une instruction permettant de voir si une variable est de type 'Par référence'
V-D-9. Variable 'Object' et autre
V-D-9-a. Le Type 'Object':
V-D-9-a-i. Comparaison d'objet.
V-D-9-a-ii. Nothing.
V-D-9-b. Les variables d'autres types:
V-D-9-c. Utilisez donc des variables le plus typées possible.
V-D-9-d. Attention quand on met un objet dans un autre objet:
V-D-10. Variable Booléenne
V-D-10-a. Introduction:
V-D-10-b. Les booléens:
V-D-10-c. Les conditions:
V-D-10-d. Les opérateurs logiques:
V-E. Soyons strict et explicite.
V-E-1. Notion de conversion Explicite et Implicite:
V-E-2. Option Strict
V-E-2-a. 1-Avec Option Strict=On VB refuse les conversions implicites qui pourraient entraîner des pertes de données.
V-E-2-b. 2-Avec Option Strict=On VB refuse les conversions String<->numériques implicites.
V-E-2-c. 3-Avec Option Strict=On VB refuse les 'Liaisons tardives':
V-E-2-d. 4-Avec Option Strict=On VB est plus rapide
V-E-3. Option explicit
V-E-4. Option strict et Explicit dans un module:
V-F. Les constantes, les énumérations.
V-F-1. Constantes:
V-F-1-a. Intérêt des constantes ?
V-F-1-b. Constantes prédéfinies dans le langage:
V-F-1-c. True False:
V-F-2. Enumération:
V-F-3. Généralisation de la notion d'énumération:
V-F-3-a. ControlChars:
V-F-3-b. Couleurs:
V-F-3-c. Math:
V-F-3-d. Touche du clavier dans le Framework:
V-F-3-e. Autre Enumération, un exemple:
V-G. Les opérateurs.
V-G-1. Addition :+
V-G-2. Soustraction : -
V-G-3. Multiplication :*
V-G-4. Division : /
V-G-5. Division entière:\
V-G-6. Puissance : ^
V-G-7. Modulo :
V-G-8. Concaténation : &
V-G-9. Priorités :
V-G-10. Comparaison :
V-G-11. Logique : Not And Or ElseOr Xor
V-G-12. Déplacement de bits: << et >>
V-G-13. Remarque 1: Allons plus loin avec / \ :
V-G-14. Remarque 2: Division par zéro:
V-H. Les structures de contrôle: Choix et boucles
V-H-1. If Then
V-H-2. Select Case
V-H-3. For Next
V-H-4. Do Loop
V-H-5. While End While
V-H-6. For Each
V-H-7. Switch
V-H-8. IIF
V-I. Les procédures et leurs paramètres.
V-I-1. Les parenthèses.
V-I-2. Par Valeur, Par Référence.
V-I-3. Par Défaut que se passe t-il?.
V-I-4. Optional
V-I-5. Tableau de paramètres.
V-I-6. ParamArray
V-J. Portée des variables.
V-J-1. Dans les procédures.
V-J-2. Dans un bloc d'instruction.
V-J-3. Dans la section déclaration d'un Module.
V-J-4. Dans la section déclaration d'une fenêtre, d'un formulaire.
V-J-5. En pratique:
V-K. Les nombres aléatoires
V-K-1. A- Avec les instructions Rnd() et Randomize() de Visual Basic.Net
V-K-1-a. Simuler un jeu de lancé de dé.
V-K-2. B- Avec la classe Random du Framework
V-K-3. C- En cryptographie avec le Framework
V-K-4. D - Un peu de théorie (creusons).
V-L. La 'Récursivité'
V-L-1. Exemple 1: calcul de 'Factorielle'.
V-L-2. Exemple 2: calcul d'une expression avec parenthèses multiples:
V-L-3. Exemple 3: PGCD
V-L-4. Exemple 4: Tri récursif:
V-L-5. Exemple 5: Parcours de répertoires et sous répertoires:
V-L-6. Exemple 6: Evaluation d'un nombre écrit en chiffre romain:
V-L-7. Exemple 7: Suite de Fibonacci
V-L-8. Autres exemples:
V-L-9. On en déduit les règles fondamentales d'une fonction récursive:
V-M. Faut-il oublier le GoTo
V-M-1. Goto.
V-M-2. Pourquoi éviter le 'GoTo'.
V-M-3. Quant utiliser le 'GoTo'.
V-N. Annexes:
V-N-1. Le codage de caractère ASCII ANSI UNICODE et UTF
V-N-1-1. Codage sur 7 bits: Ascii:
V-N-1-2. Codage sur 8 bits:
V-N-1-3. Codage sur 16 bits: Unicode:
V-N-1-4. Représentation graphique des caractères: Glyphe, Font, Police:
V-N-1-5. Sur le Web:
V-N-1-6. En VB:
V-N-2. Nom des objets visuels (recommandation microsoft)
V-N-3. Couleur disponible dans VB
V-N-4. Format de fichier texte: le Rtf
VI. Classes
VI-A. Espace de noms, Classes, Objet
VI-A-1. Classes.
VI-A-1-a. Essayons de comprendre:
VI-A-1-b. A - Détails en VB 2003:
VI-A-1-b-i. - Les Références:
VI-A-1-b-ii. - Importation d'espace de noms:
VI-A-1-c. B - Détails en VB 2005:
VI-A-1-c-i. - Les Références:
VI-A-1-c-ii. - Importation d'espace de noms:
VI-A-1-d. Portée de l'espace de noms:
VI-A-1-e. Propriété ambiguë:
VI-A-1-f. Alias:
VI-A-1-g. Héritage:
VI-A-1-h. Membres d'instance et membres partagés.
VI-A-1-i. Classes statiques ou non
VI-A-2. Les différentes Classes, le Framework. MAJ
VI-A-2-a. Les différentes 'Classes'.
VI-A-2-a-i. 1- Les Classes spécifiques.
VI-A-2-a-ii. 2- Les classes prédéfinies du Framework fournies par Microsoft.
VI-A-2-a-iii. 2-Les classes fournies par des tiers.
VI-A-2-b. Dans Visual Basic.Net.
VI-A-2-c. Lors de la création d'un nouveau projet:
VI-A-2-d. Framework 1, 2, 3.
VI-A-2-e. ANNEXE 1: Les principales Classes du Framework 1.
VI-A-2-f. ANNEXE 2: Visual Basic .NET.
VI-A-2-g. ANNEXE 3: Fonctions VB6 de VisualBasic.Compatibility
VI-A-3. Procédures évènement, surcharge de méthode.
VI-A-3-a. Évènement et procédure évènement:
VI-A-3-b. Surcharge de Méthode:
VI-A-4. L'écriture 'Compact'
VI-A-4-a. Comment 'compacter'?
VI-A-5. Notion de flux ou 'Stream'
VI-A-5-a. Utiliser les "Stream".
VI-A-6. Exemple de petites routines de code.
VI-A-6-a. Petites routines sur les chaînes de caractères
VI-A-6-a-i. Une string 'Nom' contient un nom , mettre si nécessaire la première lettre en majuscule.
VI-A-6-a-ii. Comment voir si un caractère est une voyelle:
VI-A-6-a-iii. Comment éliminer une combinaison bien précise de caractères en début de chaîne:
VI-A-6-a-iv. Vous avez une chaîne de caractères, comment afficher, le premier caractère puis les 2 premiers, puis 3..?
VI-A-6-a-v. Vous avez deux chaînes de caractères, comment savoir si la second est un anagramme de la première?
VI-A-6-a-vi. Compter combien de fois un mot apparaît dans un texte?
VI-A-6-b. Petits programmes mathématiques
VI-A-6-b-i. Calcul de l'hypoténuse d'un triangle rectangle.
VI-A-6-b-ii. Somme de N entiers.
VI-A-6-b-iii. Afficher les tables de multiplication.
VI-A-6-b-iv. Trouver la valeur la plus élevée d'un tableau d'entier:
VI-A-6-b-v. Factorielle.
VI-A-6-b-vi. Factorielle avec 'Récursivité':
VI-A-6-b-vii. Un nombre est-il premier?
VI-A-6-b-viii. Decomposition en nombre premier?
VI-A-6-b-ix. Diviseurs d'un nombre?
VI-A-6-c. Travail sur les tableaux et collections - (Tri, recherche, insertion effacement d'éléments)
VI-A-6-c-i. Utiliser les TABLEAUX
VI-A-6-c-i-a-. A- Trier un tableau.
VI-A-6-c-i-b-. B- Rechercher un élément dans un tableau.
VI-A-6-c-i-c-. C- Effacer, insérer un élément dans un tableau.
VI-A-6-c-ii. Utiliser les COLLECTIONS
VI-A-6-c-ii--. A- Trier une collection.
VI-A-6-c-ii-b-. B- Rechercher un élément dans une collection.
VI-A-6-c-ii-c-. C- Effacer, insérer un élément dans une collection.
VI-A-6-c-iii. Différences tableau collection.
VI-A-6-c-iv. Utilisation particulière des tableaux.
VI-A-6-d. Calculs financiers simples
VI-A-6-d-i. Conversion Francs=>Euros.
VI-A-6-d-ii. Coût d'augmentation de la vie.
VI-A-6-d-iii. Remboursement d'un prêt.
VII. Interface utilisateur.
VII-A. La console
VII-A-1. A- Faire une application purement 'Console':
VII-A-2. B- Faire une application 'WinForm': Créer des fenêtres
VII-A-3. Entrée au clavier:
VII-A-4. Affichage sur la console:
VII-A-5. Exemple en 'Sortie console':
VII-A-6. En résumé:
VII-B. Interface utilisateur et 'control'.
VII-B-1. En pratique comment créer l'interface utilisateur ?
VII-B-2. La Classe 'Control':
VII-B-3. Évènements liés aux objets avec représentation visuelle
VII-B-4. En résumé:
VII-C. Les fenêtres ou 'Formulaires'.
VII-C-1. Créer une fenêtre en mode conception:
VII-C-2. Propriétés:
VII-C-3. Ouvrir un formulaire
VII-C-4. Fermer un formulaire
VII-C-5. Propriétés:
VII-C-6. Evènements:
VII-C-7. Méthodes:
VII-C-8. System.Windows.Forms.Form
VII-C-9. Formulaire d'avant plan:
VII-D. Les 'Boutons'.
VII-D-1. Créer un bouton :
VII-D-2. Modifier ses propriétés:
VII-D-3. Utiliser les évènements:
VII-D-4. Créer un bouton Ok ou Cancel:
VII-D-5. Couleur transparent dans les images des boutons:
VII-D-6. Utilisation avancée: Créer de magnifique bouton en VB2005:
VII-D-7. Utilisation avancée: Création d'un bouton par code:
VII-E. Les 'TextBox'
VII-E-1. Les contrôles TextBox.
VII-E-2. Le contrôle RichTextBox :
VII-E-3. Le contrôle MaskedTextBox (VB Framework 2):
VII-F. Les 'Labels'
VII-F-1. Les labels.
VII-F-2. Les LinkLabel
VII-G. Les cases à cocher.
VII-H. Les 'Listes'.
VII-H-1. Les 'ListBox'
VII-H-1-a. Pour ajouter ou supprimer des éléments dans un contrôle ListBox:
VII-H-1-b. Vider la ListBox:
VII-H-1-c. Ajouter l'élément "poisson"
VII-H-1-d. Charger dans une ListBox1 les nombres de 1 à 100 :
VII-H-1-e. Comment enlever des éléments?
VII-H-1-f. Comment lire l'élément 3?
VII-H-1-g. Comment rechercher l'élément qui contient une chaîne de caractères?
VII-H-1-h. Comment sélectionner un élément par code?
VII-H-1-i. L'utilisateur double-clique sur un des éléments, comment récupérer son numéro ?
VII-H-1-j. Et la multi sélection, quels éléments ont été sélectionnés?
VII-H-1-k. On peut 'charger' une ListBox automatiquement avec un tableau en utilisant Datasource:
VII-H-1-l. Comment 'charger' une ListBox automatiquement à partir d'un fichier texte.
VII-H-1-m. Comment connaître l'index de l'élément que l'on vient d'ajouter? (et le sélectionner)
VII-H-1-n. Comment affecter à chaque élément de la liste un numéro, une clé?
VII-H-1-o. Comment à partir des coordonnées de la souris connaître l'élément de la liste qui est survolé?
VII-H-2. Les CheckedListBox
VII-H-3. Les ComboBox
VII-H-4. Le Contrôle ListView :
VII-H-4-a. A- Liste avec sous éléments.
VII-H-4-b. B- Liste d'icônes.
VII-H-5. Le Contrôle DomainUpDown :
VII-H-6. Le Contrôle TreeView :
VII-H-7. Annexe: Afficher des images dans un ListView
VII-I. Boites toutes faites (MessageBox..).
VII-I-1. MessageBox du Framework 2 (VB 2005):
VII-I-2. MsgBox du Visual Basic
VII-I-3. InputBox
VII-I-4. OpenFileDialog
VII-I-5. SaveFileDialog
VII-J. Regroupement de contrôles 'Groupe de contrôles'.
VII-J-1. GroupBox et Panel
VII-J-2. PictureBox
VII-J-3. TabControl
VII-J-4. SplitContainer:
VII-J-5. LayoutPanel
VII-J-6. Comment se passer des groupes de contrôles de VB6 qui n'existent plus en VB.Net?
VII-J-7. 1 - Evènement commun.(Comment pallier à la disparition des groupes de contrôles?)
VII-J-8. 2 - Comment travaillez sur plusieurs contrôles.(Comment pallier à la disparition des groupes de contrôles?)
VII-K. Dimensions, position des contrôles.
VII-K-1. Unité de mesure :
VII-K-2. Position initiale dans l'écran d'un formulaire:
VII-K-3. Taille et position d'un formulaire ou d'un contrôle:
VII-K-4. Pour le re-dimensionnement de fenêtre par l'utilisateur:
VII-K-5. Déplacement.
VII-K-6. Coordonnées souris:
VII-K-7. Anchor :
VII-K-8. Dock
VII-K-9. Spliter
VII-L. Main Menu, ContextMenu
VII-L-1. MainMenu en Vb 2003
VII-L-2. Menu Contextuel Vb 2003
VII-L-3. MenuStrip de Vb 2005:
VII-L-4. ContextMenuStrip de Vb 2005:
VII-M. Avoir le Focus
VII-M-1. Comment donner le focus à une fenêtre ?
VII-M-2. Comment donner le focus à un contrôle ?
VII-M-3. Cascade d'évènement quand on prend ou on perd le focus:
VII-M-4. Usage du clavier pour passer d'un contrôle à l'autre. la touche 'TAB'
VII-M-5. Raccourcis clavier.
VII-N. Barre de bouton , barre de status. MAJ 2005
VII-N-1. La barre de bouton: ToolBar en VB 2003
VII-N-2. Contrôle StatusBar en VB 2003.
VII-N-3. ToolStrip en VB 2005:
VII-N-4. StatuStrip en VB 2005:
VII-O. Les images
VII-O-1. Le contrôle 'PictureBox':
VII-O-2. La propriété 'Image' des contrôles:
VII-O-3. Le contrôle ImageList:
VII-P. Couleurs et Font
VII-P-1. Les couleurs:
VII-P-1-a. A- Généralités:
VII-P-1-b. B- Constantes:
VII-P-1-c. C- Rouge,vert, bleu
VII-P-1-d. D-Couleurs 'system'
VII-P-1-e. E- Couleur dans les objets:
VII-P-1-f. F- Choix d'une couleur par l'utilisateur.
VII-P-2. Police de caractères (ou Font)
VII-Q. Grille ou Grid
VII-Q-1. A - Contrôle 'MsFlexGrid' de VB6
VII-Q-2. B - Contrôles Freeware à télécharger, c'est du '.Net':
VII-Q-2-a. 'lameGrid'en français +++++
VII-Q-2-b. Autre:
VII-Q-3. C - Contrôle 'DataGrid ' de VB 2003
VII-Q-3-a. Aspect du contrôle 'DataGrid'
VII-Q-3-b. Comment améliorer la rapidité de l'affichage:
VII-Q-4. D - Contrôle 'DataGridView ' de VB 2005
VII-Q-5. Annexe: code permettant de simuler la saisie dans un MsFlexGrid:
VII-R. ProgressBar
VII-R-1. ProgressBar de VB 2003
VII-R-2. ProgressBar de VB 2005
VIII. Programmation fonctionnelle (procédurale).
VIII-A. La programmation fonctionnelle.
VIII-A-1. Comment créer un module standard? une Sub?
VIII-A-2. Exemple d'utilisation de procédures et de modules:
VIII-B. Programmation fonctionnelle: l'IMC.
VIII-B-1. Qu'est ce que l'IMC?
VIII-B-2. Quel est le cahier des charges du programme?
VIII-B-3. Création de l'interface
VIII-B-4. Structuration:
VIII-C. Ordre des instructions dans un module: résumé.
VIII-C-1. Contenu des modules.
VIII-C-2. Composant visuel et Classe.
VIIII-E. Exemple de petits programmes.
VIII-F-1. Conversion F/€ (Une fenêtre)
VIII-F-2. Calcul mensualités d'un prêt.(les fonctions financières de VB)
IX. Faire un vrai programme: il faut savoir:
IX-A. Démarrer, arrêter un programme. - Sub Main(), fenêtre Splash.
IX-A-1. Démarrer par un formulaire.
IX-A-2. Démarrer par Sub Main()
IX-A-3. Autre méthode de récupération de la ligne de commande en VB 2005:
IX-A-4. Fenêtre Splash
IX-A-5. Comment arrêter le programme?
IX-A-6. Fin de programme :Attention!
IX-B. Ouvrir plusieurs formulaires
IX-B-1. Créer un formulaire en VB 2003:
IX-B-2. Créer un formulaire en VB 2005:
IX-B-3. Formulaire modale ou non modale:
IX-B-4. Dénomination des formulaires après leur création:
IX-B-5. Autres remarques sur les formulaires:
IX-B-5-a. Un formulaire est un objet:On peut ajouter à un formulaire des méthodes et des membres:
IX-B-5-b. Exemple plus complet: Afficher un formulaire.
IX-B-5-c. Récupération d'information par DialogResult.
IX-B-5-d. Bouton par défaut.
IX-C. bis Faire communiquer les formulaires.
IX-C-1. A- Comment à partir du premier formulaire consulter un objet du second formulaire?
IX-C-1-a. 1-En VB 2003 (en VB 2005) si on instancie le formulaire
IX-C-1-b. 1-Première solution:
IX-C-1-c. 2 - Seconde solution.
IX-C-1-d. 3 -Troisième solution:
IX-C-1-e. 4 -Quatrième solution:
IX-C-1-e-i. 2-En VB 2005, sans instanciation de formulaire:
IX-C-2. B- Comment à partir du formulaire 'secondaire' connaître le formulaire 'propriétaire'?
IX-C-3. C- Les formulaires ouverts en VB 2005
IX-D. Traiter les erreurs.
IX-D-1. Les erreurs de syntaxe:
IX-D-2. Les erreurs d'exécution:
IX-D-3. Les erreurs de logique:
IX-D-4. Les Tests:
IX-E. Créer une fenêtre 'multi document'.
IX-E-1. Comprendre les programmes MDI :
IX-E-2. A - En VB 2003
IX-E-2-a. Création de la fenêtre conteneur parent :
IX-E-2-b. Création des fenêtres filles :
IX-E-2-c. Comment connaître la fenêtre fille active?
IX-E-2-d. Comment avoir accès aux objets de la fenêtre fille à partir du conteneur?
IX-E-2-e. Comment parcourir toutes les fenêtres filles?
IX-E-2-f. Comment fermer toutes le fenêtres filles?
IX-E-2-g. Comment avoir accès aux objets du conteneur à partir de la fenêtre fille?
IX-E-2-h. Comment une routine du module conteneur appelle une routine dans la fenêtre fille active?
IX-E-2-i. Agencement des fenêtres filles :
IX-E-3. A - En VB 2005
IX-F. Travailler sur les dates, les heures, sur le temps.
IX-F-1. Définir une date, une heure
IX-F-2. Afficher une date, une heure.
IX-F-3. Variable "temps"
IX-F-4. Add, Substrat
IX-F-5. AddDay, AddMouths, AddHours, AddSeconds, AddMiliseconds
IX-F-6. Year, Mouth, Day, Hour, Minute, Seconde, Millisecond
IX-F-7. DayOfWeek
IX-F-8. Now, ToDay, TimeOfDay
IX-F-9. Ticks
IX-F-10. Année bissextile?
IX-F-11. Comparaison de DateTime
IX-F-12. Calcul de la différence entre 2 dates
IX-F-13. Comment saisir rapidement une date dans un programme?
IX-F-14. Les Timers.
IX-F-15. Perdre du temps:
IX-F-16. Chronométrer:
IX-G. Lire et écrire dans les fichiers (séquentiels ou aléatoires)
IX-G-1. Généralités et rappels:
IX-G-2. A- Classe FileInfo et File, Stream.
IX-G-3. Classe My.Computer.FileSystem en VS 2005.
IX-G-3-a. Utiliser les "Stream".
IX-G-4. B- Utiliser "FileOpen".
IX-G-4-a. Fichier à accès aléatoire:
IX-G-4-b. Fichier binaire:
IX-G-5. C-Utilisation du Contrôle RichTextBox.
IX-G-6. Lire ou écrire des octets ou du XML:
IX-H. Travailler sur les répertoires
IX-H-1. Classe DirectoryInfo et la Classe Directory du Framework:
IX-H-2. Classe Path
IX-H-3. Classe DriveInfo
IX-H-4. Classe Environment
IX-H-5. Classe My.Computer.FileSystem en VS 2005.
IX-H-6. On peut aussi utiliser les anciennes méthodes de l'espace Visual Basic:
IX-H-7. Comment créer une boite de dialogue 'Choix de répertoire' en VB2005?
IX-I. Afficher correctement du texte
IX-I-1. A - Remarque sur la mise à jour de l'affichage:
IX-I-2. B - Afficher du text:
IX-I-2-a. ToString
IX-I-2-b. Str() de Microsoft.VisualBasic est toujours accepté
IX-I-2-c. String.Format du Framework
IX-I-3. C - CultureInfo
IX-J. Modifier le curseur, gérer la souris
IX-J-1. Apparence du curseur
IX-J-2. Curseur sur un contrôle:
IX-J-3. La souris:
IX-J-4. Exemples:
IX-K. Lancer une autre application, afficher une page Web
IX-K-1. L'ancienne méthode VisualBasic toujours valable: Shell
IX-K-2. On peut utiliser la Classe 'Process' du Framework.
IX-L. Imprimer
IX-L-1. A- Avec PrintDocument
IX-L-1-a. 1 Imprimer 'Hello' avec le composant 'PrintDocument'
IX-L-1-a-i. Imprimer un dessin:
IX-L-1-a-ii. Afficher un Message Box indiquant 'Fin d'impression'
IX-L-1-b. 2-Même programme: Imprimer 'Hello' mais avec la Classe PrintDocument
IX-L-1-b-i. Comment choisir l'imprimante?
IX-L-1-b-ii. Comment modifier la page à imprimer?
IX-L-1-c. Prévisualisation de la page à imprimer?
IX-L-1-d. Construction d'une application d'impression complexe:
IX-L-1-e. Propriétés du 'PrintDocumet':
IX-L-1-f. Imprime le formulaire en cours.
IX-L-1-g. Imprime un contrôle DataGrid.
IX-L-2. B- Imprimer comme en VB6 avec un objet 'Printer'
IX-M. Dessiner
IX-M-1. A- Sur quoi dessiner?
IX-M-2. B-Comment dessiner?
IX-M-3. C- Travailler sur un Objet Image
IX-M-4. D- Comment voir un Graphics?
IX-M-4-a. Paint déclenché par Resize.
IX-M-5. E- Un exemple: Afficher un texte en 3D
IX-M-6. Espace de nom
IX-N. Faire une aide pour l'utilisateur
IX-N-1. Généralisées sur les 4 sortes d'aide.
IX-N-2. Les fichiers d'aide:
IX-N-3. Utilisation des fichiers d'aide:
IX-N-3-a. Appel direct:
IX-N-3-b. Appel par F1:
IX-N-3-c. Utilisation du bouton d'aide
IX-N-3-d. Utilisation des info bulles.
IX-N-3-e. Utilisation de ErrorProvider.
IX-O. Appeler un API
IX-O-1. Appel d'une fonction dans une Api
IX-O-2. Les Api Windows
IX-O-3. Autre exemple classique.
IX-P. Faire du glisser déplacer (Drag&Drop)
IX-P-1. Exemple No 1 (simple)
IX-P-2. Exemple No 2 plus complexe:
IX-Q. Utiliser le 'Registre'
IX-R. Utiliser le 'Presse papier'
IX-R-1. En VB 2003 (Framework 1)
IX-R-1-a. Mettre dans le presse papier:
IX-R-1-b. Récupérer du presse papier:
IX-R-1-c. Exemple:
IX-R-1-d. Alternative:
IX-R-2. My.Computer.Clipboard en VB
IX-S. Paramètres de configuration(App.ini, registre, App.config)
IX-S-1. Les Fichiers:
IX-S-2. Fichiers .INI.
IX-S-3. Registre.
IX-S-4. Fichier de configuration. App.Config File de VB2003 (Framework 1)
IX-S-5. Configuration par paramètres Settings de VB2005 (Framework 2)
IX-S-6. Liaison propriétés <=> Settings de VB2005 (PropertyBinding)
IX-T. Utiliser les 'Ressources'
IX-T-1. Intérêt des ressources?
IX-T-2. Les types de ressource?
IX-T-3. Voir les ressources:
IX-T-4. Ajouter des ressources:
IX-T-5. Ou se trouvent les ressources:
IX-T-6. Modifier une ressource
IX-T-7. Utiliser une ressource dans le programme:
IX-T-8. Ressources localisées:
IX-T-9. Ressources liées ou incorporées
IX-T-10. Comment cela marche?
IX-U. Ou mettre les programmes et les données
IX-U-1. Il faut séparer les données des programmes !!!
IX-U-2. Sécurité:
IX-U-3. Quels répertoires utiliser ?
IX-U-4. Obtenir le répertoire de l'exécutable et des données:
IX-U-5. Droits d'accès des utilisateurs dans Vista : l'UAC.
IX-V. Choisir une icône, utiliser la barre de taches - Créer un raccourci, lancer au démarrage
IX-V-1. Icône de l'application
IX-V-2. Bouton dans la barre de tache:
IX-V-3. Icone dans la barre de processus: NotifyIcon
IX-V-4. Créer un raccourci sur le bureau:
IX-V-5. Lancer le programme au démarrage de Windows:
IX-W. Petits problèmes pratiques:
X. Déboguage:
X-A. Débogage ( ou comment rechercher les 'Bugs')
X-A-1. A - Suspendre l'exécution.
X-A-2. B - Débogage pas à pas.
X-A-2-a. Comment voir rapidement la valeur des propriétés ou de variables.
X-A-2-b. Modification du code source.
X-A-2-c. C - Sortie des informations de débogage.
X-A-2-c-i. Objet Console.
X-A-2-c-ii. Objet Debug
X-A-2-c-iii. Trace:
X-A-2-c-iv. Mode 'Trace', 'Release', Mode 'Debug'
X-B. Comprendre les 'Messages d'erreur'
X-B-1. Instance d'objet
X-B-2. Membre absent
X-B-3. Type Attendu.
XI. Comprendre le fonctionnement de VB:
XI-A. Comprendre le FrameWork, la compilation, le garbage collector, le code managé, le code IL et binaire.
XI-A-1. Le Framework.NET
XI-A-2. Inconvénients?
XI-A-3. Intérêts?
XI-A-4. Revoyons en détails le contenu du Framework:
XI-A-5. Framework 1, 2, 3.
XI-A-6. Code managé:
XI-A-7. Garbage Collector:
XI-A-8. Compilation:
XI-A-9. Comment voir le code source ,le code IL, le code exécutable?
XI-A-10. Installation du Framework:
XI-A-10-a. Nouvelle version 2:
XII. Diffuser le programme:
XII-A. Assembly
XII-A-1. Assembly: définition, composition.
XII-A-2. Les propriétés de l'assembly:
XII-A-3. Le manifeste:
XII-B. Distribuer l' application
XII-B-1. Introduction:
XII-B-2. A - Avant de 'Publier':
XII-B-3. B - Comment installer simplement un programme chez l'utilisateur?
XII-B-4. C - Créer un programme d'installation classique en VB 2003 ( de type Windows Installer):
XII-B-5. D - Créer un programme d'installation 'ClickOnce' en en VB 2005:
XII-C. Exemples de programme:
XII-C-1. Horloge numérique
XII-C-2. 'Scribble' l'exemple de Microsoft
XII-C-3. Programme simple de dessin
XII-C-4. Exemples de petits applications par Microsoft:
XIII. Programmation Objet: création de Classes et composant,
XIII-A. Programmation orientée objet, Propriétés des objets (Rappel)
XIII-A-1. Interface et Implémentation:
XIII-A-2. Encapsulation:
XIII-A-3. Héritage:
XIII-A-4. Polymorphisme:
XIII-A-5. Constructeur, destructeur:
XIII-A-6. Accesseur, mutateur:
XIII-A-7. Déclaration, instanciation:
XIII-A-8. Propriétés, Méthodes:
XIII-A-9. Les Objets: ils sont 'By Ref':
XIII-A-9-a. Création de variable objet
XIII-A-9-b. Affectation:
XIII-A-9-c. Comparaison:
XIII-B. Créer une Classe
XIII-B-1. Création de Classe.
XIII-B-1-a. Revenons une nouvelle fois sur la notion de Classe et d'Objet.
XIII-B-1-b. Créer une Classe
XIII-B-1-c. Ajouter des variables dans une classe
XIII-B-1-d. Ajouter des propriétés grâce à 'Property'
XIII-B-1-e. Méthode
XIII-B-1-f. Récapitulatif Property, méthodes.
XIII-B-1-g. Constructeur
XIII-B-1-h. Destructeur
XIII-B-1-i. Surcharge
XIII-B-1-j. Evènement
XIII-B-1-k. Exception
XIII-B-1-l. Les Classes partielles
XIII-B-2. Classe suite et astuces
XIII-B-2-a. Me , My, MyClass, MyBase.
XIII-B-2-b. Propriété par défaut
XIII-B-2-c. Méthode de Classe avec Shared:
XIII-B-2-d. Création d'un compteur d'instance.
XIII-B-2-e. Création d'un identifiant unique d'instance.
XIII-B-2-f. Singleton
XIII-C. Créer un composant (Bibliothèque de Classe et de Contrôles)
XIII-C-1. Créer une Bibliothèque de Classe
XIII-C-1-a. NameSpace:
XIII-C-1-b. Utilisation du composant:
XIII-C-2. Créer un 'contrôle utilisateur' à partir d'un contrôle existant en le modifiant:
XIII-C-3. Créer un 'contrôle utilisateur' contenant un ou plusieurs contrôles pilotés:
XIII-D. Les interfaces
XIII-D-1. Définition: Interface et implémentation:
XIII-D-2. Les interfaces présentes dans les classes du Framework.
XIII-D-3. Les interfaces crées par le programmeur:
XIII-E. L'héritage
XIII-E-1. Définition de l'héritage:
XIII-E-2. Membres de la classe dérivée:
XIII-E-2-a. Redéfinition de membres (Overrides)
XIII-E-2-b. Surcharge de membres (Overloads)
XIII-E-2-c. Cacher un membre de la classe de base(Shadows)
XIII-E-3. MyBase:
XIII-E-4. Constructeur dans une classe fille:
XIII-E-5. Héritage successif:exemple:
XIII-E-6. Création de Classe à partir de Classe du Framework:
XIII-E-7. Création de composant et héritage:
XIII-F. Les espaces de nom , portées des classes et membres (friend protected public private)
XIII-F-1. Intérêts des espaces de noms (NameSpace):
XIII-F-2. Pour créer une classe dans un espace de noms:
XIII-F-3. Portée des Classes, procédures, membres.
XIII-G. Composition et groupe d'objets :Tableau, collection d'objets, Classe contenant un groupe d'objets
XIII-G-1. Un Objet dans un autre: Composition d'objets:
XIII-G-2. Groupe d'objets:
XIII-G-2-a. Comment utiliser un tableau ou une collection d'objets 'Salarié':
XIII-G-2-b. Utiliser Une Classe contenant des Salariés:
XIII-G-2-b-i. Créer une Classe contenant une ArrayList
XIII-G-2-b-ii. Créer une Classe héritant de la Classe ArrayList
XIII-G-2-b-iii. Créer une Classe héritant de la Classe CollectionBase
XIII-G-2-b-iv. Créer une Classe contenant une Classe générique
XIII-G-2-b-v. Conclusion:
XIII-H. Conservation (sauvegarde) d'objet, sérialisation
XIII-H-1. La Sérialisation
XIII-H-2. Exemple 1: Sérialisation binaire.
XIII-H-3. Sérialisation:
XIII-H-4. Déserialisation:
XIII-H-5. Exemple 2: Sérialisation Xml.
XIII-H-6. Exemple 3: Sérialisation d'une collection
XIII-H-7. Exemple 4: Sérialisation d'un tableau
XIII-H-8. Exemple 5: Sérialisation d'une collection généric
XIII-I. Surcharge
XIII-I-1. Surcharge en VB 2003
XIII-I-2. Surcharge en VB 2005: nouveautés
XIII-J. Structure de programme: programmation à 3 couches
XIII-J-1. Introduction:
XIII-J-2. Architecture n-tiers
XIII-J-3. Architecture 3 tiers
XIII-J-4. Exemple 1:Ma bibliothèque (En écrivant du code)
XIII-J-4-a. Couche métier
XIII-J-4-b. Couche d'accès aux données:
XIII-J-4-c. Couche de présentation: interface graphique ]
XIII-J-5. Exemple 2: Ma bibliothèque (Avec un BindingSource et génération automatique de l'IU)(VB 2005)
XIII-J-5-a. Couche métier:
XIII-J-5-b. Création de la source de données:
XIII-J-5-c. Génération automatique de l'interface utilisateur:
XIII-J-5-d. Création du Binding:
XIII-K. Utilisation de Patron (Design Pattern)
XIII-K-1. Singleton
XIII-K-2. Itérateur
XIV. Un peu de théorie pour en déduire de bonnes règles :
XIV-A. Diverses sortes de programmation .
XIV-A-1. Programmation impérative
XIV-A-2. Programmation structurée
XIV-A-3. Programmation fonctionnelle
XIV-A-4. Programmation procédurale
XIV-A-5. Programmation défensive
XIV-A-6. Programmation sécurisée:
XIV-A-6-a. Conception
XIV-A-6-b. Réalisation
XIV-A-6-c. Exécution
XIV-A-7. Programmation évènementielle
XIV-A-8. Programmation Objet
XIV-B. Programmation 'fonctionnelle' ou 'objet'?
XIV-B-1. L'approche fonctionnelle
XIV-B-2. Approche Objet
XIV-B-3. Conclusion
XIV-C. Programmation 'fonctionnelle': faire de bonnes procédures.
XIV-C-1. Approche fonctionnelle, analyse 'descendante' ou 'ascendante'
XIV-C-2. Pourquoi utiliser des procédures?
XIV-C-3. La 'cohésion' de la procédure doit être importante
XIV-C-4. Le 'couplage' entre procédures doit être modéré
XIV-C-5. Squelette d'un programme
XIV-C-6. Les paramètres
XIV-C-7. Utiliser une 'Sub' ou une 'Function'?
XIV-C-8. Programmation défensive
XIV-D. Programmation 'objet': faire de bonnes Classes
XIV-D-1. Rappel:
XIV-D-2. Pourquoi utiliser 'Classe' et 'Objet'?
XIV-D-3. Identifier les objets
XIV-D-4. Faire un 'couplage' modéré
XIV-D-5. Conserver une bonne abstraction et une bonne cohérence
XIV-D-6. Créer des méthodes par paires
XIV-D-7. L'encapsulation doit être bonne
XIV-D-8. Initialisez les données dans le constructeur d'une Classe.
XIV-D-9. Problèmes liés à l'héritage.
XIV-E. Faire du bon 'code ' bonnes variables.
XIV-E-1. Usage des variables
XIV-E-1-a. Utilisez OptionStrict=On et Option Explicit= On
XIV-E-1-b. Donner à chaque variable un seul rôle
XIV-E-1-c. Eviter les variables avec des significations non évidentes
XIV-E-1-d. Initialisez les variables dés leur déclaration.
XIV-E-1-e. Utilisez le principe de proximité
XIV-E-1-f. Travaillez sur des variables qui restent actives le moins de temps possible.
XIV-E-1-g. Si vous codez la valeur d'une variable en 'dur' utiliser plutôt des constantes
XIV-E-1-h. Groupez les instructions liées
XIV-E-1-i. Réduisez la portée des variables (problème des variables globales)
XIV-F. Règles de bonne programmation.
XIV-F-1. Séparer l'interface utilisateur et l'applicatif.
XIV-F-2. Utiliser le typage fort.
XIV-F-3. Forcer la déclaration des variables et les conversions explicites
XIV-F-4. Utiliser des constantes ou des énumérations
XIV-F-5. Vérifier la validité des données que reçoit une Sub une Function ou une Classe
XIV-F-6. Se méfier du passage de paramètres 'par valeur' ou par 'référence'
XIV-F-7. Les Booléens sont des Booléens
XIV-F-8. Utiliser les variables Date pour stocker les dates
XIV-F-9. Ne faire aucune confiance à l'utilisateur du logiciel
XIV-G. Rendre le code lisible: commentaires, noms de variable .
XIV-G-1. Ajoutez des commentaires.
XIV-G-2. Choisissez les noms de procédures et de variables avec soins
XIV-G-3. Eclaircir, aérer le code
XV. Les bases de données
XV-A. Notion sur les bases de données
XV-A-1. Généralités:
XV-A-2. Tables
XV-A-2-1. Exemple
XV-A-3. Type de colonne
XV-A-4. Clé primaire
XV-A-5. Index
XV-A-6. Relations entre les tables: différents types de relations.
XV-A-6-a. 1 à N (relation un à plusieurs)
XV-A-6-b. 1 à 1
XV-A-6-c. N à M
XV-A-6-d. Relation N à M avec N fixe et petit
XV-A-7. Contraintes
XV-A-8. Serveur de fichier, Client serveur.
XV-A-9. Opérations sur les enregistrements
XV-B. Généralités sur ADO.NET
XV-B-A. Généralités:
XV-B-B. Les Managed Providers
XV-B-C. Les Objets ADO.NET
XV-B-D. Le DataReader
XV-B-E. Le DataSet
XV-C. Syntaxe SQL
XV-C-A. Généralités:
XV-C-B. Les commandes SQL
XV-C-C. A - SELECT: interrogation.
XV-C-D. TRI des enregistrements:
XV-C-E. Statistiques:
XV-C-F. Extraction de données sur plusieurs tables:
XV-C-G. B - Ajout, suppression, modification d'enregistrement:
XV-C-H. C - Ajout de table:
XV-D. Lire rapidement en lecture seule: le DataReader
XV-D-A. Généralités:
XV-D-B. Exemple de DataReader avec une base access.
XV-D-C. Comment compter?
XV-D-C-1. L'objet Connection:
XV-D-C-2. L'objet Command:
XV-D-C-3. L'objet DataReader
XV-D-C-4. Exceptions:
XV-E. Travailler sur un groupe de données: le DataSet
XV-E-A. Généralités:
XV-E-B. A - Utilisation du DataSet, du DataView :En pratique:
XV-E-C. B - Remplir un DataGrid ou une ListBox avec un DataSet:
XV-E-D. Etudions en détails un DataSet:
XV-F. Liaison DataGrid, ListBox et base de données: le "DataBinding"
XV-F-A. A - Remplir une ListBox avec une colonne d'une table d'une BD:
XV-F-B. B - Remplir un DataGrid avec une base de données via un DataSet
XV-F-B-1. Comment ne pas écrire de code.
XV-F-B-2. Mise à jour:
XV-F-C. C - Remplir un DataGrid avec une base de données sans une ligne de code (VB 2005):
XV-F-C-1. A - Création de la source de données:
XV-F-C-1-B. B - Génération automatique de l'interface utilisateur:
XV-G. Créer une BD, ajouter une table à une base de données.
XV-G-A. Créer une base de données:
XV-G-B. Ajouter une table à une BD existante:
XVI. Migration VB6=>VB.NET 2003=>VB.NET 2005
XVI-A. Les objets
XVI-B. Les Classe du Framework
XVI-C. Les formulaires ou fenêtres:
XVI-D. Les Controles
XVI-E. Les Variables
XVI-F. Les Tableaux
XVI-G. Les Collections
XVI-H. Les Structures
XVI-I. Les Fonctions et Sub
XVI-I-1. Dans le code
XVI-J. Gestion des erreurs
XVI-K. Les graphiques
XVI-L. Les bases de données
XVI-M. Les Classes
XVI-N. GOSUB et ON GOSUB n'existent plus
XVI-O. Les Timers
XVI-P. Conversion VB6 vers VB.NET
XVII. Nouveautés dans VB.NET 2005 (Framework 2)
XVII-A. Le matériel
XVII-B. L'IDE
XVII-B-a.
XVII-B-b. Edit and Continue:
XVII-B-c. Le Projet Designer:
XVII-B-d. L'alignement automatique des contrôles:
XVII-B-e. Le déplacement des contrôles ou l'accès aux principales tâches est amélioré:
XVII-B-f. Renommer un nom: modification automatique.
XVII-B-g. Commentaire en Xml
XVII-C. Les nouveaux Objets
XVII-C-i. My: le SUPER RACCOURCI.
XVII-D. Les instances de Forms:
XVII-E. Les nouveaux Contrôles
XVII-E-i. DataGridView
XVII-E-ii. MaskedTextBox
XVII-E-iii. SoundPlayer
XVII-E-iv. SplitContainer:
XVII-E-v. ListView
XVII-E-v-1. WebBrowser:
XVII-E-vi. LayoutPanel:
XVII-E-vii. MenuStrip :
XVII-E-viii. ToolStrip:
XVII-E-ix. StatuStrip:
XVII-E-x. ProgesBarr:
XVII-F. Les nouvelles 'Variables'
XVII-G. Les nouvelles 'Collections'
XVII-H. Dans le Code: les nouvelles instructions
XVII-I. Les nouveautés dans les Classes:
XVIII. Optimisation en vitesse
XVIII-A. Comparaison VB6 VB.Net
XVIII-A-a. Comment VB.NET 2003 est situé en comparaison avec les autres langages de programmation?
XVIII-A-b. VB.NET(2003 ou 2005) est-il plus rapide que VB6?
XVIII-B. Chronométrer le code.
XVIII-B-a. Pour chronométrer une évènement long.
XVIII-B-b. Créer un compteur pour les temps très court (Framework 1 , VB2003)
XVIII-B-c. Créer un compteur pour les temps très court (Framework 2 , VB2005)
XVIII-C. Optimiser en vitesse.
XVIII-C-a. Comment accélérer une application VB.net?
XVIII-C-a-i. Utilisation des nouvelles fonctionnalités:
XVIII-C-b. Choix des variables:
XVIII-C-c. Tableau:
XVIII-C-d. Collections:
XVIII-C-e. Eviter la déclaration de variables 'Objet' et les liaisons tardives, les variables non typées:
XVIII-C-f. Utiliser les bonnes 'Options':
XVIII-C-g. Pour les fichiers utiliser System.IO:
XVIII-C-h. If..Then ou Select Case?
XVIII-C-h-1. If..Then
XVIII-C-i. Utiliser les bonnes 'Opérations':
XVIII-C-j. Utiliser :With End With
XVIII-C-k. Optimiser les boucles:
XVIII-C-l. Appel de procédure:
XVIII-C-m. Usage de thread:
XVIII-C-n. Comment accélérer quand on utilise des 'String':
XVIII-C-o. Comment accélérer l'affichage?:
XVIII-C-p. Utiliser les tableaux en mémoire plutôt que la lecture de fichier sur disque:
XVIII-C-q. Ce qui n'influence pas la rapidité du code:
XVIII-C-r. Compilation Dll:
XVIII-C-s. En conclusion:
XIX. Allons plus loin
XIX-A. Les bases binaires, hexadécimales, algèbre de Boole.
XIX-A-1. Introduction.
XIX-A-2. Notions théoriques:
XIX-A-3. Pratique en Visual Basic.
XIX-A-4. Viewer Hexadecimal
XIX-A-5. Editeur hexadecimal:
XIX-B. Comprendre le code crée par VB
XIX-B-1. Code généré automatiquement lors de la création d'un formulaire ou d'un contrôle.
XIX-B-2. Substitution de procédures évènement:
XIX-C. Créer des contrôles par code
XIX-C-1. Créer par code des contrôles.
XIX-C-2. Ajouter des évènements.
XIX-C-3. Les délégués:
XIX-C-4. Création de menu contextuel par code:
XIX-D. Les 'régions',la compilation conditionnelle, les 'Attributs'.
XIX-D-1. Les Régions.
XIX-D-2. La Compilation conditionnelle.
XIX-D-3. Les Attributs.
XIX-E. Multithread.
XIX-E-1. Un Thread c'est quoi?
XIX-E-2. Comment ajouter un Thread d'arrière plan?
XIX-E-3. État d'avancement:
XIX-E-4. Arrêter le thread en cours:
XIX-E-5. Résultat retourné par le thread d'arrière plan:
XIX-F. Les délégués, les évènements.
XIX-F-1. Définition.
XIX-F-2. A- Création d'un délégué avec 'Delegate'
XIX-F-3. B-Délégué et appel asynchrone
XIX-F-4. C-Délégué et évènement:
XIX-G. Les génériques VB 2005
XIX-G-1. Définition.
XIX-G-2. Exemple de Fonction utilisant un 'generic'
XIX-G-3. Exemple de Classe utilisant un 'generic'
XIX-G-4. Exemple de Collection utilisant un 'generic'
XIX-G-5. Intérêts des génériques ?
XIX-G-6. En VB 2005: il y a des classes permettant l'usage de génériques:
XIX-G-7. En VB 2005:il y a les Collections 'generic' ou 'Specialized'
XX. Bonnes adresses, bibliographie du site.
XX-A. Sur le Net : trouver des informations.
XX-A-1. Vb 2003:
XX-A-1-a. Chez Microsoft
XX-A-1-b. VB 2005:
XX-A-2. Sites dédiés au Visual Basic
XX-A-3. Convertisseur C# -> VB
XX-A-4. SQL
XX-A-5. Glossaire


I. Démarrer le cours


I-A. Introduction , page de présentation , principe du site.


II. Introduction: débutez ici


II-A. Qu'allons nous étudier?

Ce cours est un cours de Visual Basic.Net

Nous étudierons principalement: LES APPLICATIONS WINDOWS. (les WindowsForms).

Les applications Windows sont des programmes directement exécutables qui utilisent des fenêtres Windows: des programmes de traitement de texte, d'image, de musique, des jeux, de petits utilitaires, des logiciels métiers (médicaux)...

Nous laisserons de côté les applications 'Web' (en ASP qui utilisent les WebForms) et qui permettent de créer des sites Internet, les applications 'console'..

Les versions étudiées sont VB 2003 (Framework 1.1) , et VB 2005 (Framework 2)


II-B. Quel plan de cours suivrons nous?

Nous étudierons donc comment créer une application Windows:

Nous étudierons la notion d'objet, d'évènement.(Section 0.)

Nous étudierons le langage Visual Basic. (Section 1.)

Nous utiliserons les objets 'formulaire' et les 'divers contrôles' pour créer l'interface utilisateur (Section 3.).

Nous découvrirons la manière de créer une application.(Section 4.)

Nous apprendrons à créer une classe (Section 5.)

Nous verrons la différence entre programmation objet et programmation fonctionnelle. (5-10)

Nous verrons comment utiliser les bases de données. (Section 6.)

Quelle différence entre VB6 VB.Net 2003 et 2005, problèmes de vitesse (Section 7.)

Nous terminerons dans des choses plus subtiles (Délégué, génériques..)(Section 8.)

voir le Sommaire du cours. On peut s'aider de l'Index pour rechercher un mot clé.

Conseil de lecture :Lire la succession de pages en cliquant sur le bouton Suivant en bas de page. Ne pas hésiter à relire plusieurs fois les chapitres.


II-C. Quels logiciels utiliser?

Il y a plusieurs manières de faire du VB.NET:
  • de Microsoft.
    Il fonctionnait avec le Framework 1.1

  • de Microsoft et le Framework 2.0.
    Ce produit .Net est maintenant mature, l'environnement de développement est magique, les quelques points noirs de la version 2003 ont été corrigés.

    Dans VS 2005, il y a Visual Basic 2005. Dans Visual Studio il y a aussi Visual C#...

    Il existe aussi Visual Basic Express 2005 version allégée mais très bien et GRATUITE, en français. Nouveau Framework 2, avec nouvelles Class.

    Ce cours utilise Visual Studio.Net 2003 et 2005 Express

    Si vous débutez, utiliser sans hésitation Visual Basic Express 2005

    Différences entre les versions. Que permet la version Express GRATUITE?



  • Autre gratuit:
    Installer un logiciel de développement gratuit:

    SharpEditor
    par exemple,SharpDevelop le configurer pour qu'il marche en VB (il supporte VB et C#).


    Moins pratique et puissant que VB 2005 Express.


II-D. Quelle configuration est nécessaire?

Pour développer avec Visual Studio 2003 ou VB 2005:

il faut Windows XP ou 2000 ou Vista avec au minimum 256 Mo de mémoire vive. Un grand écran (vu le nombre de fenêtres) est conseillé.

Les exécutables fonctionnent sous Windows 98, XP, 2000 Vista.


III. Principe et structure des programmes.


III-A. Les 'Objets

VB utilise la notion d''OBJET'.

Pour bien comprendre ce qu'est un objet, nous allons prendre des exemples dans la vie courante puis nous passerons à des exemples dans Visual Basic.

Voir la vidéo au format 'Flash': ou au format AVI en Visual Basic 2005.

La vidéo (identique à celle du chapitre 1-20)contient:
  1. Objets, Classes.
  2. Références, espaces de noms(a visionner plus tard).

III-A-1. A - Dans la vie courante:

Mon gâteau est un objet, cet objet existe.

Pour créer un gâteau, j'utilise un 'moule à gâteau', ce moule à les caractéristiques du gâteau (forme, hauteur..), mais je ne peux pas manger le moule!! Le moule se nomme la Classe.

Avec le moule, je crée un ou plusieurs gâteaux.

Autre exemple:

Ma voiture est un objet, cet objet existe, on peut l'utiliser.

Ma voiture fait partie de "Les voitures", du type, du genre "Les voitures". "Les voitures" c'est une classe (Class) qui a ses caractéristiques : "Les voitures" ont une couleur, un moteur.., elles roulent en transportant des passagers…

mais je ne peux pas utiliser "Les voitures", la Classe; pour me déplacer, il faut avoir un objet "voiture".

Avec la Classe je vais créer des Objet.

De manière générale, une classe est une représentation abstraite de quelque chose, tandis qu'un objet est un exemple utilisable de ce que représente la classe.

Pour fabriquer ma voiture, je prends les caractéristiques de la class "Les voitures" (c'est comme un moule) et je fabrique une voiture, je la nomme 'MaVoiture'.

Dim MaVoiture As New Lesvoitures
MaVoiture est maintenant un nouvel objet de type 'Les voitures'.

Class --> Objet

Type 'Les voitures'--> Objet 'Mavoiture'

Un Objet est créé selon un 'modèle' qu'on appelle une Classe.

On dit aussi qu'il faut instancier un objet à partir de la Classe.

'Mavoiture' est une instance de la classe 'Les voitures'.

(On dit aussi une 'occurence' de la classe)

Remarque:

Avec la même classe ont peu instancier plusieurs Objets.


III-A-1-a. Propriétés (Attributs):

Prenons MaVoiture.

Elle a des propriétés : une marque, une couleur, une puissance…

Pour indiquer la couleur de ma voiture on utilise la notation :

MaVoiture.couleur
Syntaxe : Objet.Propriété (Il y a un point entre les 2 mots)

Pour modifier la couleur et avoir une voiture verte on écrit :

MaVoiture.couleur= "Vert"
Et la voiture devient verte !!

MaVoiture.Phares.Avant indique les phares avant de la voiture.

MaVoiture.Phares.Avant.Allumé indique l'état des phares (Allumé ou non)

Si je fais :

MaVoiture.Phares.Avant.Allumé=True (Vrai) cela allume les phares.


III-A-1-b. Méthodes :

MaVoiture fait des choses : elle roule par exemple.

Pour faire rouler la voiture j'appelle la méthode 'Roule'

MaVoiture.Roule

Syntaxe : Objet.Méthode (Il y a un point entre les 2 mots)

Si c'est possible pour cette méthode je peux indiquer à quelle vitesse la voiture doit rouler :

MaVoiture.Roule(100) 'j'ai ajouté un paramètre.

Le paramètre est un renseignement envoyé avec la méthode.

Il est possible parfois d'indiquer en plus si la voiture doit rouler en marche avant ou en marche arrière.

MaVoiture.Roule(10, Arriere)

Il y a donc 2 manières d'appeler la méthode Roule : avec 1 ou 2 paramètres, on dit que la méthode est surchargée; chaque manière d'appeler la méthode s'appelle 'signature'.

Première signature: MaVoiture.Roule(100)

Seconde signature: MaVoiture.Roule(10, Arriere)


III-A-1-c. Evènement:

Des évènements peuvent survenir sur un objet.

MaVoiture_démarre est un évènement, quand la voiture se met en route (si par exemple j'ai fait MaVoiture.Roule(10, Arriere)), cet évènement démarre se déclenche automatiquement.


III-A-1-d. Interface et implémentation:

Ce que je vois de l'objet, c'est son interface exemple: la méthode Roule fait partie de l'interface d'une voiture. Par contre ce qui fait rouler physiquement la voiture se nomme implémentation, c'est le moteur, ce n'est ni visible ni accessible.

Si je crée une voiture je vais faire l'implémentation, je vais fabriquer le moteur, mais si je suis simplement utilisateur de l'objet voiture, je vais me contenter d'utiliser l'interface.

Visibilité:

Quand un objet est créé, il est visible et utilisable, uniquement dans la zone où il a été défini.


III-A-1-e. Relation entre Objet:

Héritage:

Une Classe (un moule) peut hériter d'une autre classe (d'un autre moule).

La classe Voiture hérite de la classe Véhicule, cela veut dire qu'une voiture est un véhicule; la classe voiture aurait les propriétés de la classe Véhicule.

Contenant-contenu:

On peut créer une Classe qui contient des Objets, une classe qui se compose d'objets. on parle de composition.

L'objet Voiture contient 4 objets Roue.

On dit que l'objet encapsule le contenu.

Collections:

Les collections sont des groupes d'objets semblables qui peuvent être énumérés.

Un parc automobile contient X Voitures; chaque voiture a un numéro d'item:

ParcVoiture.item(1) pour la première Voiture

ParcVoiture.item(2) pour la seconde Voiture


Tous cela ce sont des images, mais voila, vous avez compris ce qu'est un objet !


III-A-2. B- Et dans Visual Basic.net:

Une application Windows se compose de fenêtres (nommées aussi formulaires) dans lesquelles se trouvent des contrôles (bouton, liste, texte…)

Exemple de fenêtre avec 2 boutons, une zone de texte (un label) et une icône:

Dans une application Windows, il y a aussi des lignes de code utilisant des variables pour faire des calculs.

En Visual Basic.Net tout est objet :

les fenêtres (on dit les formulaires),

les variables,

les contrôles (les boutons, liste, image, case à cocher..)

...

Il faut un moule pour faire un objet. Le moule c'est une classe.

Le moule va servir à créer un objet,on dit une instance.

On peut créer, instancier une multitude d'objets avec le même moule.

Pour créer, démouler un objet, on utilise les mots clé Dim et As New.

Dim objet As New Classe
New est un constructeur.

Exemple : créer une fenêtre (un formulaire) :

Je dessine une fenêtre FormDémarrage (c'est la Classe, le moule)

puis

	Dim F As New FormDémarrage 
Crée une fenêtre qui se nomme 'F' à partir du moule, du modèle (FormDémarrage) que j'ai dessiné.

Autre exemple :

Dim B as New Button
Créer un bouton nommé 'B' avec les attributs habituels des boutons (Class Button)

Troisième exemple:

Comment créer une variable nommée Mavariable pouvant contenir un entier (Integer)

		Dim MaVariable As New Integer
Dim MaVariable As Integer 'est correct aussi

Ici, pour une variable, on remarque que New peut être omis


III-A-2-a. Tout objet a des propriétés.

On utilise la syntaxe : Objet.Propriété (Il y a un point entre les 2 mots)

Si F est une fenêtre, F.BackColor indique la couleur de fond de la fenêtre.

S'il y a un bouton, la couleur de fond du bouton sera :

Bouton.BackColor

Ou

F.Bouton.BackColor

Noter la syntaxe : La couleur du bouton qui est dans la fenêtre F

En fait une propriété c'est une sorte de variable.

Comment modifier cette propriété?

Bouton.BackColor=Color.Red 'modifie la couleur de fond du bouton

Autre exemple:

La propriété Visible: si elle a la valeur True (Vraie) l'objet est visible; si elle est à False l'objet n'est pas visible.

Bouton.Visible=False 'fait disparaître le bouton

<==Ici il y a un bouton invisible!! oui, oui!!


III-A-2-b. Les objets ont des méthodes parfois.

Une méthode agit sur l'objet ou fait agir l'objet.

Prenons un exemple simplifié.

Les Listes ( liste déroulante) ont des lignes (Items) et une méthode Clear qui permet de les vider.

Si je veux vider toutes les lignes d'une liste nommé Liste1, je fais:

Liste1.Items.Clear() '

Les propriétés et méthodes se nomment les membres d'un objet.

Certains objets ont des évènements:

Reprenons notre bouton. Quand l'utilisateur click dessus, l'évènement Bouton_Click survient.

Ce sont les objets contrôles (bouton, case à cocher..)et les formulaires qui ont des évènements.


III-A-2-c. Interface et implémentation:

Ce que je vois de l'objet, c'est son interface (le nom des propriétés, méthodes..) exemple: la méthode Clear fait partie de l'interface d'une ListBox. Par contre le code qui effectue la méthode (celui qui efface physiquement toutes les lignes de la listeBox),ce code se nomme implémentation, lui n'est ni visible ni accessible.

Visibilité:

Quand un objet est créé, il est visible et utilisable, uniquement dans la partie du programme où il a été défini.

Par exemple habituellement, je peux voir et modifier la couleur d'un bouton uniquement dans le code de la fenêtre ou il est situé.

Pour les variables on parle de portée: la variable peut être locale (Private) ou de portée générale ('Public') visible partout.


III-A-2-d. Relation :

Héritage:

Une Classe (un moule) peut hériter d'une autre classe (d'un autre moule).

La classe Button hérite de la classe Control, cela veut dire qu'un bouton est un contrôle.

Si je crée un bouton, il aura les caractéristiques de la classe Button mais aussi de la classe Control.

Contenant-contenu:

Une Classe peut contenir d'autres classes.

Je peux décider d'un Objet Rectangle va contenir 4 Objets Point

Collections:

Les collections sont des groupes d'objets semblables qui peuvent être énumérés.

Une fenêtre Windows (on dit un 'formulaire' contient une collection nommée 'Controls' composées de tous les objets (boutons, List, texte) contenus dans la fenêtre:

maFenetre.Controls.item(1) contient par exemple le premier bouton

maFenetre.Controls.item(2) contient par exemple une list.


III-A-3. En résumé :

En Visual Basic.net tout est objet.

Les Classes sont des types d'objet.

Pour créer (instancier) un objet à partir d'une Classe, il faut utiliser les mots clé Dim ..As New:

Dim Objet As New Class
Un objet a :
  • Des propriétés.
  • Des méthodes.
  • Des évènements.
warning Attention, par abus de langage, on emploie parfois indifféremment les mots 'Classe' et 'Objet', mais il est préférable de ne pas confondre le modèle et l'objet lui même.

III-A-4. Lexique anglais=>Français:

New = Nouveau.


III-B. Programmation évènementielle: le premier programme.

Nous allons comprendre la programmation évènementielle: Comment fonctionne Visual Basic:
  • Ce que voit l'utilisateur.
  • Ce qu'a fait le développeur pour arriver à ce résultat.
Voir la vidéo au format 'Flash': ou au format AVI en Visual Basic 2005


III-B-1. Principes de la programmation VB

Le programmeur va dessiner l'interface utilisateur (fenêtre, bouton, liste..), il va ensuite uniquement écrire les actions à effectuer quand certains événements se produisent sur cette interface.

C'est Visual Basic qui va entièrement s'occuper de la gestion des événements.


III-B-2. Exemple :le premier programme:

Il affiche 'Bonjour' quand on clique sur un bouton.

C'est pas original: le premier programme, dans tous les cours d'informatique, permet d'afficher 'Bonjour' (ou 'Hello Word').

  • Que voit l'utilisateur du programme?
    L'utilisateur final, celui qui utilise le logiciel, voit une fenêtre avec un bouton, Si il appuie sur ce bouton il voit s'afficher « Bonjour ».

  • Que se passe t-il dans le programme?
    Quand l'utilisateur clique sur le bouton cela déclenche automatiquement un événement. (Button1_Click), cet évènement contient du code qui affiche « Bonjour ».

  • Que doit faire le programmeur pour arriver à ce résultat?
    Pour atteindre ce résultat, le programmeur va dessiner la fenêtre, le bouton, la zone d'affichage du texte (un label) puis il va simplement indiquer dans l'évènement Button_Click d' afficher « Bonjour ».

    info Le fait de déterminer la procédure à appeler ou de réaliser l'appel est entièrement pris en charge par VB.

III-B-3. En pratique, que fait le programmeur:

Voir la vidéo au format 'Flash': ou au format AVI en Visual Basic 2005

Le programmeur est en mode 'conception' (ou mode Design):Il écrit le programme :


III-B-3-a. A- Il dessine l'interface utilisateur

(Ce que verra l'utilisateur final, c'est l'interface utilisateur : une fenêtre avec des boutons, des listes, du texte..) :

Il ouvre un projet : une fenêtre 'Form1' apparaît.

Il ajoute un bouton :

Pour cela il utilise la Boite à outils:

Il clique sur 'Boite à Outils' à gauche , bouton Windows Forms, puis bouton 'Button', il clique dans Form1, déplace le curseur sans lâcher le bouton, puis lâche le bouton de la souris : le dessin d'un bouton apparaît.

Pour l'exemple,Il ajoute un label.

Un label est un contrôle qui permet d'afficher un texte.

Comme pour le bouton il clique sur 'Boite à Outils' à gauche, bouton Windows Forms, bouton 'Label' et met un contrôle label sur la fenêtre.


III-B-3-b. B- Il va écrire le code correspondant aux événements :

Il double-clique sur le bouton qu'il a dessiné :

Une fenêtre de conception de code s'ouvre et il apparaît :

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

End Sub
Cela correspond à la procédure évènement en rapport avec l'évènement 'On a cliqué sur le bouton1'.

Quand le programme fonctionne, quand l'utilisateur du logiciel clique sur le bouton1, le code situé entre Private Sub Button1Click et End Sub est effectué.

Une procédure est un ensemble de lignes de code qui commence par Sub et se termine par End Sub (ou Function..End Function).

Comment indiquer dans cette procédure d'afficher "Bonjour"?

Le label possède une propriété nommé '.text' qui contient le texte à afficher.

Il faut taper le code qui modifie cette propriété '.text' , qui y met la chaîne de caractère "Bonjour":

 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Label1.Text = "Bonjour"

End Sub
Cela donne:

Voila votre premier programme est écrit.

Comment exécuter ce programme?

Il est possible de tester immédiatement le programme en mode déboguage, sans quitter l'environnement de développement:

Utiliser le menu 'Déboguer' puis 'Démarrer' qui lance l'exécution du programme.

On peut aussi taper sur F5 pour lancer le programme.

Ou plus simplement cliquer sur la flèche:

C'est plus rapide, lancer l'exécution avec le premier bouton, le second servant à arrêter temporairement l'exécution, le troisième à terminer l'exécution.

En mode exécution :

L'utilisateur voit bien une fenêtre avec un bouton, s'il clique dessus, « Bonjour » s'affiche.

Quand le programme est totalement écrit, terminé, testé, il est possible de le compiler et ainsi de créer un fichier exécutable (possédant une extension '.exe') qui fonctionne de manière autonome en dehors de l'environnement de développement.

C'est ce fichier exécutable qui est fourni à l'utilisateur.

Par opposition le code écrit par le programmeur, composé d'instructions Visual Basic, se nomme le code source.


III-B-4. En résumé :

Le programmeur utilise des outils de dessin pour construire une interface utilisateur : des fenêtres avec des contrôles dessus: menus, boutons, case à cocher..

VB, pour chaque fenêtre ou pour chaque contrôle, génère une liste d'événements, (Evènement lié au chargement d'une fenêtre, évènement lié au fait de cliquer sur un bouton, évènement survenant quand on modifie un texte...)

Il suffit, dans la procédure événement qui nous intéresse, d'écrire le code qui doit être effectué lorsque cet événement survient.

Comme nous l'avons vu le code sert à agir sur l'interface (Afficher un texte, ouvrir une fenêtre, remplir une liste, un tableau), mais il peut aussi effectuer des calculs, évaluer des conditions et prendre des décisions, travailler en boucle de manière répétitive et ainsi effectuer les taches nécessaires .


III-B-5. Lexique anglais=>Français:

Button = Bouton.

End =Fin.

Form= formulaire


III-C. Les instructions, les procédures . Les 'Sub' , les 'Function'

Qu'est ce qu'une instruction , une procédure?

Quelle différence entre les procédures:

liées aux évènement?

les procédures non liées?

Les 'Sub', les 'Functions'.


III-C-1. Les instructions:

Une instruction est le texte permettant d'effectuer une opération, une déclaration, une définition.

Dim A As Integer est une instruction (de déclaration)

A=1 est aussi une instruction qui effectue une opération.

C'est habituellement une 'ligne de code exécutable'.

Une instruction est exécutée lorsque le programme marche.

Plusieurs instructions peuvent se suivre sur une même ligne, séparées par ':'

Dim B As String : B="Bonjour"
Si une ligne est très longue, on peut passer à la ligne grâce à ' _'

(caractère 'Espace' puis caractère"_" puis immédiatement après, passage à la ligne) :

Dim B As String = "Bonjour monsieur ": C= _

"le professeur"
est équivalent à:

Dim B As String = "Bonjour monsieur ": C= "le professeur"
Quand un programme tourne, les instructions sont effectuées ligne après ligne.

1  Dim B As String 

2  B="Bonjour"

3  Dim A As Integer 

4  A= 3

5  A= A + 1
La ligne 1 est exécutée puis la ligne 2 puis la 3, la 4...

Bien que l'on puisse avoir des numéro de ligne, ils ne sont plus utilisé actuellement et non visible:

Dim B As String 

B="Bonjour"

Dim A As Integer 

A= 3

A= A + 1
Pour mettre des commentaires dans un programme, on le fait précéder de "'" .

'Ceci est un commentaire, ce n'est pas une instruction.

Le commentaire ne sera pas exécuté.


III-C-2. Les procédures:

Une procédure est un ensemble d'instructions, de lignes de code, un groupement d'instructions bien définies effectuant une tache précise.

Les procédures sont bien délimitées:

Il y en a de 2 sortes:

Les procédures Sub:

Elles débutent par le mot Sub et se terminent par End Sub.

Les procédures Function:

Elles débutent par Function et se terminent par End Function.

Exemple:

Sub Maprocédure

   A=1

End Sub
Exemple concret d'une procédure: la procédure Button_Click du premier programme.(Celui qui affiche 'Bonjour'; elle ne contient qu'une ligne de code. Le mot Sub est précédé de Private, on verra plus loin ce que cela signifie.

Vous avez vu que l'on peut dessiner l'interface, une fenêtre Form1 par exemple. En mode conception, après avoir dessiné l'interface, on doit avoir accès aux procédures.

info Si on double-clique sur la fenêtre, on a accès aux procédures évènement liées à cette fenêtre, si on double-clique sur un objet (bouton, case à cocher… on voit apparaître les procédures évènement de ce contrôle.
Quand on voit ces procédures, on peut y inclure du code.

Nous allons voir qu'il y a 2 types de procédures: les procédures liées aux évènements et celles qui ne sont pas liées.


III-C-3. Procédures liées aux événements.

Si on double clique sur le fond d'une fenêtre,(Celle du programme 'Bonjour') on voit apparaître les procédures liées à cette fenêtre et aux contrôles contenus dans cette fenêtre :

Public Class Form1

    Inherits System.Windows.Forms.Form

    Dim a As String

#Region " Code généré par le Concepteur Windows Form "  '<===En VB 2003 uniquement

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

            Label1.Text = ""   

End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Label1.Text = "Bonjour"

End Sub

End Class
Détaillons:

On voit 3 parties:
  • Form1
    Ce n'est pas une procédure mais la définition de la fenêtre.

    La fenêtre fait partie des Windows.Forms.Form..

    Ces lignes sont générées automatiquement par VB.

    En VB 2003,si vous déroulez cette partie, en cliquant sur le petit +, vous pouvez lire le code permettant de créer la fenêtre, les contrôles.. C'est généré automatiquement par VB. (le chapitre 8-2 explique en détails le code généré par VB, mais c'est un peu complexe pour les débutants pour le moment!!)

    En VB 2005 cette partie générée par VB n'est pas visible directement.

  • Form1_Load
    Chaque fenêtre a une procédure Form_Load qui est exécutée lorsque la fenêtre est chargée, on y met généralement le code initialisant la feuille.

    Il y a bien d'autres procédures liées à la fenêtre :

    Dérouler la liste box en haut à gauche de la fenêtre de code, cliquer sur (Form1 events), si vous déroulez maintenant la liste à droite vous aurez tous les événements qui génèrent une procédure :

    Load Lors du chargement de la fenêtre

    Unload Lors du déchargement de la fenêtre

    Activated Lorsque la fenêtre devient active

    GotFocus Lorsque la fenêtre prend le focus

    Resize Lorsque la fenêtre est redimensionnée

    _

  • Button1_Click
    C'est la procédure liée au bouton et qui contient le code à effectuer quand l'utilisateur clique sur le bouton.

    C'est là que l'on écrit le code qui doit s'effectuer lorsque l'utilisateur clique sur le bouton.

    De la même manière que pour la fenêtre, vous pouvez voir dans la liste en haut, tous les événements liés aux boutons qui génèrent une procédure :

    Click Lorsque l'utilisateur clique sur le bouton.

    DoubleClick Lorsque l'utilisateur double-clique sur le bouton.

    MouseDown 'se déclenche si appui du bouton de la souris

    MouseUp 'se déclenche si relâchement du bouton de la souris

    _

info On voit donc que le formulaire (la fenêtre) et tous les contrôles d'une application ont chacun des procédures pour chaque évènement qui peut survenir.

III-C-4. Procédures non liées:

Parfois on a besoin de code qui fait une tâche particulière, qui est utilisé à plusieurs endroits et qui n'est pas liée à un événement.

On crée dans ce cas une procédure indépendante des évènements.

Le système des procédures permet aussi de découper un problème complexe en quelques fonctions moins complexes et indépendantes les unes des autres.

Ces procédures sont en fait des sous-programmes : si une ligne appelle une procédure, le programme 'saute' au début de la procédure, il effectue le code de la procédure puis revient juste après la ligne qui avait appelé la procédure et continue les lignes suivantes.

Exemple : plusieurs fois dans le programme j'ai besoin de calculer la surface d'un cercle à partir de son rayon et de l'afficher sur un label.

Plutôt que de retaper dans chaque procédure le code, je peux créer une procédure 'Sub' nommée AfficheSurfaceCercle.

Il suffit ensuite si nécessaire d'appeler la procédure qui effectue le calcul et affiche le résultat puis revient effectuer le code situé après l'appel.

Comment appeler une procédure?

Par Call NomdeProcedure() ou par

NomdeProcedure()

Call est facultatif.

Noter les parenthèses après le nom de la procédure.


III-C-5. Procédures Sub :

Comment créer cette procédure Sub?

Dans la fenêtre de code, tapez :

Sub AfficheSurfaceCercle  puis validez. Vous obtenez :

Sub AfficheSurfaceCercle()

End sub
Le code de la procédure est compris entre le Sub et le End Sub.

Pour que le calcul se fasse, il faut fournir, (transmettre de la procédure qui appelle à la procédure Sub) la valeur du rayon.

Pour indiquer que la Sub doit recevoir un paramètre (un argument en VB) ajouter entre les parenthèses :

 Sub AfficheSurfaceCercle( Rayon as Single)
Cela signifie qu'il existe une procédure qui reçoit comme paramètre une variable de type Single (Réel simple précision) contenant le Rayon.

Ajouter le code :

Label.text =(3.14*Rayon*Rayon).ToString
Que fait cette ligne ?

Elle fait le calcul: '3.14*Rayon*Rayon' ('*' signifie multiplier), on transforme le résultat en chaîne de caractères (grâce à '.ToString') que l'on met dans la propriété .text du label : Cela affiche le résultat. (On verra toute cette syntaxe en détail ultérieurement)

On obtient:

Sub AfficheSurfaceCercle( Rayon as Single)

    Label.text =(3.14*Rayon*Rayon).ToString

End sub
Comment appeler cette Sub?

N'importe quelle procédure pourra appeler la Sub AfficheSurfaceCercle en envoyant la valeur du rayon afin d'afficher la surface du cercle dans un label.

Exemple d'appel pour un rayon de 12 :

AfficheSurfaceCercle(12)
Affiche dans le label: 452.16


III-C-6. Procédures 'Function' :

Parfois on a besoin que la procédure retourne un résultat, qu'elle donne en retour un résultat à la procédure appelante. . Dans ce cas on utilise une Fonction.

Exemple: je veux créer une fonction à qui je fournis un rayon et avoir en retour la surface d'un cercle.

Comment créer cette Function?

Tapez Function SurfaceCercle puis validez, ajouter (Rayon As Single)

Tapez Return 3.14*Rayon*Rayon

Ce que la fonction doit retourner est après Return (ce que la procédure doit renvoyer à la procédure appelante.)

On obtient la fonction complète:

Function SurfaceCercle( Rayon as Single)

    Return 3.14*Rayon*Rayon

End Function
Comment appeler cette Function?

Dans la procédure qui appelle, il faut une variable pour récupérer la valeur retourner par la Fonction:

S= NomdelaFonction()
N'importe quelle procédure pourra appeler la fonction et obtenir le résultat dans la variable S par exemple pour un rayon de 12 :

Dim S As Single

S=SurfaceCercle(12)
On appelle la fonction SurfaceCercle en envoyant le paramètre '12', ce qui fait que à l'entrée de la fonction, Rayon=12, le calcul est effectué et le résultat du calcul (452.16) est retourné grâce à Return. S récupère ce résultat.

Après l'appel de cette fonction, S est égal à 452.16

Il est possible de spécifier le type retourné par la fonction:

Function SurfaceCercle( Rayon as Single) As Single
As Single en fin de ligne après () indique que la fonction retourne un Single. Il faut donc que la variable qui reçoit la valeur retournée (S dans notre exemple) soit aussi un Single.

Il existe une autre manière de retourner le résultat d'une fonction, reprenons l'exemple précédent, on peut écrire:

Function SurfaceCercle( Rayon as Single)

     SurfaceCercle= 3.14*Rayon*Rayon

     Exit Function

End Function
Ici on utilise le nom de la fonction pour retourner le résultat , avec un signe '='.

Utilisez plutôt la méthode Return.

Exit Function permet aussi de sortir de la fonction, cela a le même effet que Return sauf que Return peut être suivi d'un argument de retour (et pas Exit Function).


III-C-7. Module standard :

La sub AfficheSurfaceCercle affiche le résultat dans le formulaire où elle est située.

Par contre la fonction SurfaceCercle est d'intérêt général, n'importe quelle procédure doit pouvoir l'appeler, de plus elle n'intervient pas sur les contrôles des formulaires et n'est donc pas liée aux formulaires.

On la placera donc dans un module standard qui est un module du programme qui ne contient que du code. (Pas d'interface utilisateur)

Pour créer un module standard Menu Projet>Ajouter un module.

Y mettre les procédures.


III-C-8. Private Public :

Avant le mot Sub ou Function on peut ajouter :

Private indiquant que la procédure est accessible uniquement dans le module.

C'est donc une procédure privée.

Les procédures liées aux évènements d'une feuille sont privées par défaut.

Public indiquant que la procédure est accessible à partir de toute l'application.

S'il n'y a rien devant Sub la procédure est publique


III-C-9. Remarques :

  1. Pour sortir d'une procédure Sub avant la fin, utiliser Exit Sub (Exit Function pour une fonction).
  2. Quand vous appelez une procédure, il faut toujours mettre des parenthèses même s'il n'y a pas de paramètres.
    
    FrmSplash.ShowDialog ()
    
    Eventuellement on peut faire précéder l'appel du mot clé Call, mais ce n'est pas obligatoire.
    
    Call FrmSplash.ShowDialog ()
    
  3. Quand vous créez une procédure utilisez "la casse Pascal" pour créer les noms de routine:
    la première lettre de chaque mot est une majuscule (C'est donc une convention).
    
    Sub CalculTotal()
    

III-C-10. Lexique anglais=>Français:

Call = Appel.

Return= Retour.

Private= Privé.

Show= spectacle, exposition.

To show= montrer.


III-D. Les modules


III-D-1. Qu'est ce qu'un module?

On a vu qu'un programme est décomposé en modules, chaque module contenant des procédures.

Chaque module correspond physiquement à un fichier '.vb'.

Il existe
  • les modules de formulaire.
  • les modules standards.
  • les modules de 'Classe'.
Comment se présentent-ils?

Un programme Visual Basic comporte donc :
  • Les 'Modules de Formulaires':
    contenant:

    Le dessin des fenêtres de l'interface utilisateur (ou formulaire)contenant les contrôles (boutons, listes, zones de texte, cases à cocher…)

    Le code qui comprend :

    Les procédures liées aux événements de la feuille (Button_Click..)

    Les procédures indépendantes des événements. Ce sont des Sub() ou des Function().

    
    Class Form1            'Nom du Formulaire
    
       Inherits System.Windows.Forms
    
        Public A as String
    
        ....
    
     Private Button1_Click 'Procédure liée à un évènement
    
     ..
    
     End Sub
    
     
    
     Sub MaRoutine         'Procédure indépendante
    
     ...
    
     End Sub
    
    End Class
    
  • Les modules standards.
    Ils servent de stockage de procédures. Procédures "d'intérêt général".

    Ces procédures sont des Sub() ou des Function() qui peuvent être appelées à partir de n'importe quel endroit (pourvu qu'elles soient 'Public').

    Ils peuvent aussi servir à déclarer les objets ou déclarer les variables 'Public' qui seront utilisées donc accessibles par la totalité du programme.

    Exemple:
    
    Module Module1        'Nom du Module
    
        Public A as String
    
        ....
    
     Sub MaRoutine        'Procédure indépendante
    
     ....
    
     End Sub
    
    End Module
    
  • les modules de Classe
    Ils ont vocation à fabriquer des objets, on verra cela plus loin (chapitre 5).

    Exemple:
    
    Class MaClasse            'Nom de la Classe
    
        Public A as String
    
        ....
    
    End Class
    
warning On remarque que les Class, formulaires, Modules, Sub, Functions sont délimités par:
Une ligne de début comportant le type et le nom du module.
Une ligne de fin contenant End et le Type.
Exemple:

Module Module1        'Nom du Module

...

End Module

 

Sub MaRoutine        'Procédure

 ....

End Sub

III-D-2. Comment créer un module standard:

Faire Menu Projet>Ajouter un module. Donner un nom au module. C'est Module1.vb par défaut.

Module Module1        'Nom du Module

...

End Module
On remarque que le module est bien enregistré dans un fichier .vb

Un module standard ne contient que du code.

Comment ajouter une Sub dans un module Standard?

Taper Sub Calcul puis valider, cela donne:

Sub Calcul()

End Sub
Voir exemple d'utilisation de procédures et de modules:3-29


III-D-3. Lexique anglais=>Français:

Return = Retour.


III-E. Notion de programmation 'fonctionnelle' et de programmation 'objet'

Il y a deux manières de travailler en VB.NET:
  • En programmation 'Fonctionnelle':
    Chaque problème est décomposé en 'Fonctions'(Les Subs et Fonctions).

    la programmation structurée découpe les problèmes en fonctions ( Sub et Function)., ce découpage s'il est systématiquement employé aboutit à la programmation fonctionnelle qui consiste en un emboîtement de fonctions que l'on peut voir comme des « boîtes noires » que l'on peut imbriquer les unes dans les autres. Chaque fonction contient du code VB qui permet d'effectuer le travail dévolu à la fonction.

    Ces fonctions sont stockées dans des modules standards (ou dans les modules de formulaire).

    C'est cette approche qui est privilégiée jusqu'aux chapitres 4-..

    Dans une application en programmation 'fonctionnelle' il y a habituellement:

    Des modules de formulaires.

    Des modules standard contenant des Sub et Function.

  • En programmation 'Objet':
    On le verra dans les chapitres 5-..: on crée ses propres objets dans des modules de Classe, on utilise les membres (propriétés et méthodes) de ces objets pour programmer.

    Dans une application en programmation 'Objet' il y a habituellement:

    Des modules de formulaires.

    Des modules de classe permettent de créer des Objets.

    Grâce aux Classes (qui contiennent le code, on crée des objets.

    Ensuite on utilise les propriétés et méthodes des objets.

info De toutes façon, dans les 2 cas, que se soit dans des Sub ou des Classes, on utilise du code Visual Basic.
La mode est à la programmation Objet!!

Voir le chapitre 5-10 pour approfondir ces notions.

En fait, on peut mélanger les 2.


IV. Environnement de développement: les IDE.


IV-A. IDE Visual Studio 2003 ( Microsoft )

C'est l'IDE (Integrated Development Environment): Environnement de développement intégré de Visual Studio de Microsoft 2003 en français.


IV-A-1. Fenêtre Projet.

Quand on lance VB.net, le logiciel présente une fenêtre Projets qui permet:

d'ouvrir un projet existant

ou

de créer un nouveau projet:

Pour un projet Visual Basic normal, il faudra choisir dans les projets Visual Basic 'Application Windows'.

Puis il faut donner un nom au projet, modifier si nécessaire le chemin de l'emplacement du projet qui est par défaut ' C:\Documents and Settings\Nom Utilisateur\Mes documents\Visual Studio Projects' enfin valider sur 'Ok'.


IV-A-2. Dans un nouveau projet, créer une fenêtre :

Pour ajouter un fenêtre (un formulaire) Menu Projet, Ajouter un formulaire Windows,

cliquer sur Windows Form, une fenêtre 'Form1' apparaît ('Form2' pour la seconde feuille).

La zone de travail se trouve au centre de l'écran: C'est l'onglet Form1.vb[Design] ci-dessous qui donne donc accès au dessin de la feuille (du formulaire); on peut ajouter des contrôles, modifier la taille de ces contrôles..


IV-A-3. Voir les procédures:

L'onglet Form1.vb donne accès aux procédures liées à Form1.

La liste déroulante de gauche donne la liste des objets, celle de droite, les évènements correspondants.

info Il est possible en double-cliquant dans le formulaire ou un contrôle de se retrouver directement dans le code de la procédure correspondant à cet objet.

IV-A-4. Ajouter des contrôles à la feuille

Ajouter un bouton par exemple:

Cliquer sur 'Boite à Outils' à gauche , bouton Windows Forms, puis sur 'Button',cliquer dans la Form, déplacer le curseur sans lâcher le bouton, puis lâcher le bouton :

Un bouton apparaît.


IV-A-5. Modifier les propriétés d'un contrôle ou du formulaire.

Quand un formulaire ou un contrôle est sélectionné dans la fenêtre Design, ses propriétés sont accessibles dans la fenêtre de propriétés à droite en bas:

Ici ce sont les propriétés du contrôle 'Button1' (BackColor, Image, Texte..)

(on peut les modifier directement.)


IV-A-6. Voir tous les composants d'un projet:

Pour cela il faut utiliser L'explorateur de solution en haut à droite, il permet de voir et d'avoir accès au contenu du projet:

Form2.vb qui est un formulaire (une fenêtre).

Module1.vb qui est un module standard.

Références qui contient les espaces de nom.

AssemblyInfo: info nécessaire pour créer un installateur.

Il suffit de cliquer sur la ligne module1.vb dans l'explorateur de solution pour voir apparaître le module et son code dans la fenêtre principale.

Si on clique sur un espace de noms dans la liste Références, cela ouvre la fenêtre Explorateur d'objet qui montre l'arborescence des Classes et une description sommaire en bas de la fenêtre.


IV-A-7. Tester son logiciel:

On peut tester le projet grâce à : lancer l'exécution avec le premier bouton (mode 'Run', le second servant à arrêter temporairement l'exécution (mode 'Debug'), le troisième à terminer l'exécution (Retour au mode 'Design' ou 'Conception').

Quand on est en arrêt temporaire en mode 'Debug', la ligne courante, celle qui va être effectuée, est en jaune:

For i=0 To 100

 Label1.Text=i.ToString

Next i
Si on tape la touche F10 (exécution pas à pas), la ligne 'Label1.Text=i.ToString' est traitée et la position courante passe à la ligne en dessous.

For i=0 To 100

 Label1.Text=i.ToString

Next i
La sauvegarde du projet se fait comme dans tous les logiciels en cliquant sur l'icône du paquet de disquettes.


IV-A-8. Projet et solutions.

Dans la terminologie VB, un projet est une application en cours de développement.

Une solution regroupe un ou plusieurs projets (C'est un groupe de projets).


IV-A-9. Fichiers, Chemins des sources.

Si vous regardez les fichiers correspondant à un projet VB, les extensions sont:

.vbproj est le fichier de projet.

.sln est le fichier solution.

.vb sont tous les fichiers Visual Basic (Feuille module...)

Les sources sont par défaut dans ' C:\Documents and Settings\NomUtilisateur\Mes documents\Visual Studio Projects\nom projet'

Si on compile le projet l'exécutable est dans un sous répertoire \Bin


IV-A-10. VB propose des AIDES.

Quand on tape du code, VB affiche, quand il le peut, des aides:
  • VB permet de choisir dans une liste une des propriétés d'un objet.
    Exemple: Si je crée une variable chaîne de caractères (Dim Chaine As String , on verra cela plus loin), et que je tape le nom de la variable suivi d'un point: 'Chaîne.' la liste des méthodes possibles s'affiche.

    Chaine.

    Quand je pointe dans la liste un des membres (propriété ou méthode) un carré jaune affiche la définition de la fonction avec ses paramètres et une explication.

  • VB aide à retrouver les paramètres d'une fonction:
    Si on tape le nom d'une fonction et ( , VB affiche les paramètres possibles dans un cadre.

    En plus il affiche les différentes manières d'utiliser les paramètres (les différentes signatures), on peut les faire défiler avec les petites flèches du cadre jaune.

  • VB aide à compléter des mots.
    Si je tape App puis sur le bouton 'A->', Vb affiche la liste des mots commençant pas App
    
    AppActivate
    AppDomain
    

IV-A-11. Il existe une abondante documentation:

  • VB donne accès à l'aide sur un mot Clé. Si le curseur passe sur un mot clé, un carré affiche la définition de la fonction. Si je clique sur un mot et que je tape F1 l'aide s'ouvre et un long texte donne toutes les explications.
  • VB donne accès à l'aide sur les contrôles. Si le curseur est sur un contrôle et que je tape F1 l'aide s'ouvre pour donner accès à la description des différents membres de cet objet.
  • L'aide dynamique est constamment mise à jour. Pour la voir, il faut cliquer sur l'onglet 'Aide Dynamique' en bas à droite (même fenêtre que la fenêtre propriété). Elle donne une liste de liens en rapport avec le contexte en cours.
  • Enfin il est toujours possible de rechercher des informations en passant par les 3 onglets de la fenêtre en haut à droite.
    • Sommaire (plan , arbre de l'aide)
    • Index (liste des mots)
    • Recherche (rechercher un mot)
(Ici on vient de décrire l'aide interne; on peut paramétrer le logiciel pour avoir l'aide externe c'est à dire que l'aide s'affiche dans une fenêtre externe à l'ide, cela allége les fenêtres et onglets de l'IDE.)


IV-A-12. Erreur.

S'il existe une erreur dans le code au cours de la conception, celle-ci est soulignée en bleu ondulé. Un carré donne la cause de l'erreur si le curseur passe sur la zone ou se trouve l'erreur.

Ici la propriété 'Text' a été mal orthographiée.

Si je lance le programme en mode 'Run' et qu'il y a des erreurs, Vb me le signale et répertorie les erreurs dans la liste des taches en bas.


IV-A-13. Mode déboguage (mode BREAK):

Une fois lancée l'exécution (F5), puis stoppée (Ctrl +Alt +Pause), on peut:

Voir la valeur d'une propriété d'un objet en la sélectionnant avec la souris:

Il s'affiche un petit cadre donnant la valeur de la propriété d'un objet.

Voir la valeur d'une variable, simplement en positionnant le curseur sur cette variable.

Par défaut on ne peut pas modifier le code en mode Break.

On peut l'autoriser en passant par les menus Outils/Options/Déboguage/Modifier&continuer, activer 'M'autoriser à modifier des fichiers vb durant le déboguage' mais la modification n'est pas prise en compte sauf si on relance le programme!!!

F11 permet l'exécution pas à pas (y compris des procédures appelées)

F10 permet le pas à pas (sans détailler les procédures appelées)

Maj+F11 exécute jusqu'à la fin de la procédure en cours.

En cliquant sur le bouton droit de la souris, on peut afficher ou définir l'instruction suivante, exécuter jusqu'au curseur, voir la définition de ce qui est sous le curseur (La définition, c'est l'instruction ou une variable à été déclarée par exemple).

On peut grâce au menu déboguage puis Fenêtre ouvrir les fenêtres:

Automatique, qui affiche les valeurs des variables de l'instruction en cours et des instructions voisines.

Immédiat où il est possible de taper des instructions ou expressions pour les exécuter ou voir des valeurs.

Espions permettant d'afficher le contenu de variables ou d'expressions.

Espions Express permet d'afficher la valeur de l'expression sélectionnée.

Points d'arrêts permet de modifier les propriétés des points d'arrêts. on peut mettre un point d'arrêt en cliquant dans la marge grise à gauche: l'instruction correspondante s'affiche en marron et l'exécution s'arrêtera sur cette ligne.

Me affiche les données du module en cours.

Variables locales affiche les variables locales.

Modules affiche les dll ou .exe utilisés.

Mémoire, Pile d'appels, Thread, Registres, Code Machine permettent d'étudier le fonctionnement du programme à un niveau plus spécialisé et technique.

Il est possible de mettre des points d'arrêt, des espions pour arrêter l'exécution et suivre la valeur de certaines expressions. (voir traiter les erreurs)

voir déboguage pour plus d'information.


IV-B. IDE Visual Studio 2005 ( Microsoft )

C'est l'Integrated Development Environment (IDE): Environnement de développement intégré de Visual Studio de Microsoft 2005

Il y a Visual Studio 2005 et pour les débutants :'Edition Express' (version légère GRATUITE):

Différences entre les versions. Que permet la version Express GRATUITE?

Télécharger VB Express 2005 GRATUIT à vie. Télécharger le Service Pack 1 (SP1) New



voir aussi Nouveautés de VS 2005

Voir la vidéo sur l'IDE 2005 au format 'Flash': ou au format AVI

(En flash, il y a un arrêt au milieu: patientez. En Avi ne pas tenir compte des avertissements qui déclarent que le fichier n'est pas valide)


IV-B-1. Fenêtre Projet.

Quand on lance VB.net 2005 , le logiciel présente une Page de démarrage "Start Page" qui permet:

d'ouvrir un projet existant Ouvrir (Recent Projects ou Open)

ou

de créer un nouveau projet:Créer (Create)

Pour créer un projet Visual Basic normal (WinForms), il faudra choisir 'Creer'. La fenêtre suivante s'ouvre:

Choisir l'icône 'Application Windows', puis donner un nom au projet, enfin valider sur 'Ok'.

(Le chemin de l'emplacement du projet n'est pas modifiable ici, il est par défaut ' C:\Documents and Settings\Nom Utilisateur\Mes documents\Visual Studio 2005\ Projects\MonProjet')


IV-B-2. Dans un nouveau projet, créer ou ajouter une fenêtre :

Pour ajouter un fenêtre (un formulaire) Menu Project,Ajouter un formulaire Windows ( Add a WindowsForms ):

cliquer sur Windows Form, une fenêtre (un formulaire) ‘Form2' vide apparaît ('Form1' était le nom du premier formulaire).

Il y a des fenêtres toutes faites pour accélérer le travail (les templates) comme les 'Ecran de démarrage' les 'Formulaire Explorateur'...

La zone de travail se trouve au centre de l'écran: C'est l'onglet Form1.vb[Design] ci-dessous qui donne donc accès au dessin de la feuille (du formulaire); on peut ajouter des contrôles, modifier la taille de ces contrôles..

On peut passer en mode 'Multidocument Mdi' (comme en VB6) au lieu du mode 'Onglet':

(Passer par le menu 'Outils' puis 'Options..' puis bouton 'Multidocument (Mdi)')

Exemple en mode Mdi montrant les 3 types de module.

A noter que si on utilise le menu 'Projet' puis 'Ajouter..' la box de droite ci-dessus permet d'ajouter un formulaire, un module standard, un module de Classe.


IV-B-3. Voir les procédures:

L'onglet Form1.vb donne accès aux procédures liées à Form1.

La liste déroulante de gauche donne la liste des objets, celle de droite, les évènements correspondants.

info Il est possible en double-cliquant dans le formulaire ou un contrôle de se retrouver directement dans le code de la procédure correspondant à cet objet.
Ici on voit la procédure Button1_Click liée au Button1 de la fenêtre de Design.


IV-B-4. Ajouter des contrôles à la feuille

Ajouter un bouton par exemple:

Cliquer sur ‘Toolbox'(Boite à outils) à gauche , les contrôles apparaissent tous ou classés par catégories grâce au bouton 'All Windows Forms'(Tous les Windows Forms),

Cliquer sur ‘Button',cliquer dans la Form, déplacer le curseur sans lâcher le bouton, puis lâcher le bouton :

Un bouton apparaît.


IV-B-5. Modifier les propriétés d'un contrôle ou du formulaire.

Quand un formulaire ou un contrôle est sélectionné dans la fenêtre Design, ses propriétés sont accessibles dans la fenêtre de 'Propriétés' (Properties) à droite en bas:

Ici ce sont les propriétés du contrôle 'Button1' (Text, Location..)

(on peut modifier directement les valeurs.)

Dessous, il y a une explication succincte de la propriété sélectionnée (Si elle n'apparaît pas , faire sur la propriété: click droit puis dans le menu 'Description').

Le déplacement des contrôles ou l'accès aux principales tâches est facile:

La croix à gauche permet de déplacer le contrôle, la petite flèche à droite permet d'ouvrir un menu qui donne accès aux tâches les plus fréquentes.

L'alignement automatique des contrôles:

Si on modifie la taille ou l'emplacement d'un contrôle, VB signale par un trait bleu que le contrôle modifié et le contrôle voisin sont alignés:

Renommer un nom: modification automatique.

On nomme cela 'Refactoring': Cliquer sur une variable, puis bouton droit, dans le menu cliquer sur 'Renommer'. Modifier le nom de la variable, valider. Dans toute la Classe la variable est renommée.


IV-B-6. Voir tous les composants d'un projet:

Pour cela il faut utiliser la fenêtre Explorateur de solutions en haut à droite, elle permet de voir et d'avoir accès au contenu du projet (Pour voir tous les fichiers, il faut cliquer sur le deuxième bouton en haut) :

gridview est le nom du programme.

MyProjet: double-cliquer dessus, vous ouvrirez la fenêtre 'propriétés du projet'.

Références qui contient les dll chargées. Pour atteindre les références, on peut aussi passer par le menu 'Projet' puis 'Propriétés' ou double cliquer sur 'MyProjet' puis choisir l'onglet 'Références.

Form1.vb est un formulaire (une fenêtre).Les formulaires, modules de classe ou standard sont tous des '.vb' Il suffit de double-cliquer dessus pour les ouvrir.

Si on ouvre la sous-liste de Form1.vb (en cliquant su le '+'), on voit:

Form1.Designer.vb (qui montre le code qui crée le formulaire, on n'a pas à y toucher)

Form1.resx (le fichier de ressources)

Il suffit de cliquer sur la ligne Form1 dans l'explorateur de solution pour voir apparaître la Form1 dans la fenêtre principale.

Si on clique sur un espace de noms dans la liste Références, cela montre l'arborescence des Classes .


IV-B-7. Tester son logiciel:

On peut tester le projet grâce à : lancer l'exécution avec le premier bouton (mode 'Run', le second servant à arrêter temporairement l'exécution (mode 'Debug'), le troisième à terminer l'exécution (Retour au mode 'Design' ou 'Conception').

Quand on est en arrêt temporaire en mode 'Debug', la ligne courante, celle qui va être effectuée, est en jaune:

For i=0 To 100

 Label1.Text=i.ToString

Next i
Si on tape la touche F10 (exécution pas à pas), la ligne 'Label1.Text=i.ToString' est traitée et la position courante passe à la ligne en dessous.

For i=0 To 100

 Label1.Text=i.ToString

Next i
Il y a maintenant le 'Edit and continue': en mode Debug, on peut modifier une ligne et poursuivre le programme qui tiendra compte de la modification (Sauf pour les déclarations).

La sauvegarde du projet se fait comme dans tous les logiciels en cliquant sur l'icône du paquet de disquettes.

On peut compiler le programme pour créer un exécutable par le menu Générer ('Build')


IV-B-8. Projet et solutions.

Dans la terminologie VB, un projet est une application en cours de développement.

Un Team Project regroupe un ou plusieurs projets (C'est un groupe de projets). Il n'y en a pas dans la version express.


IV-B-9. Fichiers, Chemins des sources.

Si vous regardez dans ' C:\Documents and Settings\Nom Utilisateur\Mes documents\Visual Studio 2005\ Projects\MonProjet')les fichiers correspondant à un projet VB:

MonProjet.sln est le fichier solution.

MonProjet.psess est le fichier de performance.

MonProjet.suo est le fichier de User solution.

Dessous existe un répertoire nommé aussi MonProjet qui contient:

	MonProjet.vbProj
Form1.vb contient les procédures.

Form1.Designer.vb contient le code qui créer la fenêtre et les contrôles.

Si on compile le projet l'exécutable est dans un sous répertoire \Bin, il y a aussi un répertoire Obj


IV-B-10. VB propose des AIDES.

Quand on tape du code, VB affiche, des aides:
  • VB permet de choisir dans une liste une des propriétés d'un objet.
Exemple: Je tape le nom d'un label nommé label1 puis je tape un point, cela me donne la liste des propriétés du label.

Quand je pointe dans la liste un des membres (propriété ou méthode) un carré jaune affiche la définition de la fonction avec ses paramètres et une explication.

  • VB aide à retrouver les paramètres d'une fonction:
Si on tape le nom d'une fonction et ( , VB affiche les paramètres possibles dans un cadre.

En plus il affiche les différentes manières d'utiliser les paramètres (les différentes signatures), on peut les faire défiler avec les petites flèches du cadre jaune.

  • VB aide à compléter des mots.
    Si je tape App puis sur le bouton 'A->', Vb affiche la liste des mots commençant pas App


AppActivate

AppDomain
  • VB fournit des exemples de code.
    Les Snippets (bride, morceau de code) permettent d'insérer du code tout fait.

Exemple comment récupérer le dessin de l'écran? en français puis en anglais l'exemple!!

Dans le code d'une procédure, le click droit de la souris ouvre un menu.

Cliquer sur Insérer un extrait (Insert Snipper).

Cela affiche:

Choisir Windows Operating System :

Puis 'Copy the Active Windows or the Screen to the Clipboard'

On obtient le code suivant:

' Copy the active window.

SendKeys.SendWait("{PRTSC}")

System.Threading.Thread.Sleep(1000)

Dim window As Bitmap

window = CType(Clipboard.GetDataObject().GetData("Bitmap"), Bitmap)

' Copy the entire screen.

SendKeys.SendWait("+{PRTSC}")

System.Threading.Thread.Sleep(1000)

Dim screen As Bitmap

screen = CType(Clipboard.GetDataObject().GetData("Bitmap"), Bitmap)
Génial!!

  • Vb propose des solutions pour corriger les erreurs de code:
Si je veux afficher une valeur numérique (avec option Strict=On),il y a erreur, VB me propose la correction:


IV-B-11. Il existe une abondante documentation:

  • VB donne accès à l'aide sur un mot Clé. Si le curseur passe sur un mot clé, un carré affiche la définition de la fonction. Si je clique sur un mot et que je tape F1 l'aide s'ouvre et un long texte donne toutes les explications.
  • VB donne accès à l'aide sur les contrôles. Si le curseur est sur un contrôle et que je tape F1 l'aide s'ouvre pour donner accès à la description des différents membres de cet objet.
  • Enfin il est toujours possible de rechercher des informations
    1. Sommaire (plan , arbre de l'aide)
    2. Index (liste des mots)
    3. Recherche (rechercher un mot)

IV-B-12. Erreur.

S'il existe une erreur dans le code au cours de la conception, celle-ci est soulignée en bleu ondulé. Un carré donne la cause de l'erreur si le curseur passe sur la zone ou se trouve l'erreur.

Ici la propriété 'Text' a été mal orthographiée.

Si je lance le programme en mode 'Run' et qu'il y a des erreurs, Vb me le signale et répertorie les erreurs dans la liste des taches en bas. Vb propose des solutions pour corriger les erreurs de code. (Voir plus haut)


IV-B-13. Mode débogage (mode BREAK):

Une fois lancée l'exécution (F5), puis stoppée (Ctrl +Alt +Pause), on peut:

Voir la valeur d'une propriété d'un objet en le pointant avec la souris:

Il s'affiche un petit cadre donnant la valeur de la propriété d'un objet.

Voir la valeur d'une variable, simplement en positionnant le curseur sur cette variable.

F11 permet l'exécution pas à pas (y compris des procédures appelées)

F10 permet le pas à pas (sans détailler les procédures appelées)

Maj+F11 exécute jusqu'à la fin de la procédure en cours.

En cliquant sur le bouton droit de la souris, on peut exécuter jusqu'au curseur (Run To Cursor), voir la définition, la déclaration de ce qui est sous le curseur (Atteinte la définition:Go To Definition)...

On peut grâce au menu 'Affichage' on peut avoir accès à plein de choses :


IV-B-14. Projet Designer:

Toutes les propriétés de l'application peuvent être modifiées dans le 'Projet Designer' (Propriétés du projet), pour l'atteindre, il faut double-cliquer sur 'My Project' dans l'explorateur de solution:

Une autre manière d'ouvrir le 'Projet Designer' est de passer par les menus 'Projet' puis 'Propriétés de..'

On retrouve dans le projet designer:
  • Le nom de l'application, son icône, la fenêtre de démarrage, celle de fin. (Application)
  • Les Option Strict, Explicit.(Compiler)
  • Les références (dll liées au projet)
  • Les paramètres (valeurs liées à l'application)
  • Les ressources (texte, images, sons utilisées dans le programme)
  • La signature et la sécurité.
  • Les paramètres relatifs à la publication (distribution et installation)

IV-B-15. Conclusion:

IDE totalement fantastique, mais code beaucoup plus lent: voir les comparatifs dans le chapitre sur la vitesse. C'est comme d'habitude: le passage d'une version VB à la suivante sur une même machine entraîne un ralentissement notable du code compensé par l'accélération des machines.


IV-C. VB.NET 2005 Nouveautés 2005

Différences entre les versions. Que permet la version Express GRATUITE par rapport aux autres?

Télécharger VB Express 2005 GRATUIT à vie.

Télécharger sql Server 2005 Express

Télécharger le Service Pack 1 (SP1) New

Développer en VB 2005 pour Vista (Framework 3) New


IV-C-1. Le matériel:

Support des plateformes 64 bits.(Pas dans la version Express)

Support du 'multi monitor'


IV-C-2. L'IDE


IV-C-2-a. On peut créer des fenêtres toutes faites, avec les contrôles..:

Il y a des fenêtres toutes faites pour accélérer le travail (les templates) comme les 'AboutBox' les 'Explorer Form'...


IV-C-2-b. Edit and Continue:

Il y a maintenant le 'Edit and continue': en mode Debug, on peut modifier une ligne et poursuivre le programme qui tiendra compte de la modification (Sauf pour les déclarations).


IV-C-2-c. Il y a des exemples de code.

Les Snippets (bride, morceau de code) permettent d'insérer du code tout fait.

Dans le code d'une procédure, le click droit de la souris ouvre un menu. Cliquer sur Insérer un extrait (Insert Snipper) puis double-cliquer sur la rubrique que vous cherchez.

On obtient le code suivant:

' Copy the active window.

SendKeys.SendWait("{PRTSC}")

System.Threading.Thread.Sleep(1000)

Dim window As Bitmap

window = CType(Clipboard.GetDataObject().GetData("Bitmap"), Bitmap)

' Copy the entire screen.

SendKeys.SendWait("+{PRTSC}")

System.Threading.Thread.Sleep(1000)

Dim screen As Bitmap

screen = CType(Clipboard.GetDataObject().GetData("Bitmap"), Bitmap)
Génial!!


IV-C-2-d. Il est proposé des solutions pour corriger les erreurs de code:

Une fenêtre vous indique les corrections à faire.

Si je veux afficher une valeur numérique (avec option Strict=On),il y a erreur, VB me propose la correction:


IV-C-2-e. Le Projet Designer:

Toutes les propriétés de l'application peuvent être modifiées dans le 'Projet Designer', il est directement accessible dans l'explorateur de solution (My Projet)ou par le menu Affichage-> Page de propriétés:

Le nom de l'application , son icône,

Le formulaire de démarrage (startUp Form),

L'écran de démarrage (Splash Screen), il suffit d'indiquer son nom (VB l'affiche et le fait disparaître quand le formulaire de démarrage s'ouvre).

Le mode d'arrêt de l'application: A la fermeture du formulaire de démarrage ou lorsque tous les formulaires sont fermés.

Les Option Strict, Explicit.(Onglet Compiler)

On peut utiliser aussi les paramètres (Settings), et les ressources....


IV-C-2-e-i. a- Exemple de ressource.
Onglet 'Ressources' , créons une ressource nommée 'toto' et contenant '2' (c'est une string)

Pour l'utiliser dans le programme, on fera:

My.Resources.toto

Les ressources sont en Read-Only.

On vient de créer une ressource 'chaines' mais en déroulant la liste en haut à gauche , on voit qu'il y a des ressources Image, Icône, Audi, Fichier, Autre.


IV-C-2-e-ii. b- Exemple de paramètre.
Onglet 'Paramètres' , créons un paramètre nommé 'Para1' et contenant '1' (c'est une string)

Pour l'utiliser dans le programme, on fera:

My.Parametre.Para1

Les Paramètres sont en Read-Only si la portée est 'Application', et en Read-Write si la portée est 'Utilisateur'.

Ces 'variables paramètres utilisateur' ont des valeurs qui seront conservées et enregistrées automatiquement dans l' 'environnement' d'un utilisateur. Si on en modifie la valeur, on retrouve la valeur modifiée lors d'une utilisation ultérieure ce qui permet de conserver les habitudes des utilisateurs.


IV-C-2-f. Pour l'utiliser dans le programme, on fera:

Si on modifie la taille ou l'emplacement d'un contrôle, VB signale par un trait bleu que le contrôle modifié et le contrôle voisin sont alignés:

Voir les exemples???????????????????????????????????????????????????


IV-C-2-g. Le déplacement des contrôles ou l'accès aux principales tâches est amélioré:

La croix à gauche permet de déplacer le contrôle, la petite flèche à droite permet d'ouvrir un menu qui donne accès aux tâches les plus fréquentes.


IV-C-2-h. Renommer un nom: modification automatique.

On nomme cela 'Refactoring': Cliquer sur une variable, puis bouton droit, dans le menu cliquer sur 'Renommer'. Modifier le nom de la variable, valider. Dans toute la Classe la variable est renommée.


IV-C-2-i. Commentaire en Xml

On peut ajouter des commentaires en xml

Exemple:

Pour une Sub: sur une ligne blanche au dessus de 'Sub', tapez "'''" (3 "'").

ou

Pour une variable: curseur sur la variable , bouton droit puis 'Insérer un commentaire' dans le menu.

Un bloc Xml <Summary> se crée automatiquement; Ajouter 'Fonction Calculant le total' entre les basiles <summary>

Quand ensuite on tape le nom de la Sub , le commentaire s'affiche. Pratique quand on travaille en equipe.

De plus Visual Basic génère automatiquement un fichier de documentation XML lorsque vous créez le projet. Ce fichier apparaît dans le répertoire de sortie de l'application sous le nom AssemblyName.xml.


IV-C-3. Les nouveaux Objets

My: le SUPER RACCOURCI.

My permet d'avoir accès rapidement à certaines fonctionnalités:

My.Application

Permet d'accéder rapidement aux propriétés de l'application en cours.

Vous pouvez ainsi récupérer des informations sur l'assembly, la culture (langue) de l'application.

MsgBox(My.Application.Culture.ToString) 'affiche 'fr-FR'

(My.Application.ChangeCulture 'permettra de changer la culture )

MsgBox(My.Application.Info.DirectoryPath) 'affiche le nom du répertoire ou est l'exécutable.

My.Application.SetCurrentUser() retourne l'utilisateur
My.Application.SetCurrentUser()
My.Application.OpenForms qui retourne les formulaires ouverts.
Exemple: rajouter le texte 'ouvert' à la barre de tache des formulaires ouverts:
For Each F As System.Windows.Forms.Form In My.Application.OpenForms
F.Text += "[ouvert]"
Next
My.Computer
Permet d'accéder aux propriétés de l'ordinateur, du hardware.
Aux ressources logicielles et/ou matérielles de l'ordinateur.
Audio : permet de jouer des fichiers wav, ainsi que les sons systèmes de windows.

My.Computer.Audio.Play("c:\mysound.wav")

Clipboard : permet de récupérer des informations sur le contenu du presse-papier, de récupérer et de définir son contenu.

If My.Computer.Clipboard.ContainsImage Then
    PictureBox1.Image = My.Computer.Clipboard.GetImage
ElseIf My.Computer.Clipboard.ContainsText Then
    TextBox1.Text = My.Computer.Clipboard.GetText
End If
Clock : permet de récupérer l'heure courante ainsi que le nombre de millisecondes écoulées depuis le démarrage.

MsgBox(My.Computer.Clock.LocalTime.ToString) 'Affiche date et heure

FileSystem : permet d'effectuer les opérations d'entrées/sorties standards.

Récupérer le nom des disques:

MsgBox(My.Computer.FileSystem.Drives.Item(0).ToString)'affiche 'A:'

(la collection Drives contient des items indiquant les disques)

Un répertoire existe t-il?

MsgBox(My.Computer.FileSystem.DirectoryExists("c:\").ToString) 'affiche True si c:\ existe.

Possibilité de copier, créer, effacer répertoires ou fichiers:

Exemple: copie d'un répertoire:

My.Computer.FileSystem.CopyDirectory(sourcedirectory, destinationdirectory)

Voir les sous répertoires:

FileSystem.GetDirectories("c:\").item(0) permet de voir le premier sous répertoire.

GetFiles fait de même avec les fichiers.

Mettre le contenu d'un fichier texte dans une variable:

Dim LeTexte As String = My.Computer.FileSystem.ReadAllText("c:\devicetable.log")
(Il existe aussi WriteAllText)

Info : Obtient des informations concernant l'ordinateur et le système d'exploitation (mémoire vive libre, nom de l'os, version de l'os, etc).

MsgBox(My.Computer.Info.TotalPhysicalMemory.ToString) 'affiche la mémoire physique

Il y a aussi AvailablePhysicalMemory, OSVersion, OSFullName..

Keyboard : permet de tester l'état des touches CTRL, ALT, etc… et de simuler l'appuie de touche grâce à la méthode Sendkeys.

MsgBox(My.Computer.Keyboard.AltKeyDown.ToString)' teste si la touche Alt est enfoncée.

My.Computer.Keyboard.SendKeys("a")' simule l'appuie d'une touche.

Mouse : permet de récupérer des informations sur la souris (présence de la souris, présence de molette, boutons inversés, etc.)

MsgBox(My.Computer.Mouse.WheelExists.ToString) 'affiche True s'il y a une molette.

Name : récupère le nom de l'ordinateur

MsgBox(My.Computer.Name.ToString)
Network : permet de télécharger et d'uploader des fichiers, de vérifier si l'ordinateur est connecté à Internet, d'effectuer des pings, et de récupérer les évènements lors des connexions et déconnexions.

Charger un fichier à partir du réseau:

My.Computer.Network.DownloadFile(AdresseCompleteFichierACharger, DestinationFileNane)

With My.Computer.Network
    If .IsAvailable And .Ping(txtIpAdress.text) Then
        .UploadFile("c:\filetupload.ext", txtIpAdress.Text)
    End If
End With
Ports : permet de récupérer la liste des ports séries, et de les ouvrir.

Printers : permet de récupérer la liste des imprimantes installées et de définir l'imprimante par défaut. (absent dans la version bêta)

Registry : permet de manipuler la base de registre facilement.

Screen : permet de récupérer les informations concernant les écrans installés.

My.User

Permet de récupérer les informations sur l'utilisateur courant.

My.User.Identity.Name

My.User.IsInRole("Administrators") 'contient l'administrateur

My.Ressources

Permet de manipuler et récupérer très facilement les ressources incorporées à l'assembly.

My.Setting
Fichiers de configuration.
My.Forms

Donne accès à tous les formulaires.

	My.Forms.HelpForm.Show()
My.WebService
Permet de manipuler directement les services web référencés dans le projet.

GZIPStreamClass

Permet d'enregistrer ou de lire des fichiers compressés au format zip .

Support du SMTP et du FTP


IV-C-4. Les instances de Forms:

En VB2003 il fallait instancier une Form avant de l'utiliser.

    Dim newForm1 As NewForm1
    newForm1.BackColor = System.Drawing.Color.Green
    newForm1.Show()
On peut toujours le faire en 2005 mais on peut aussi utiliser la Class Form1 sans instancier:

    Form1.ForeColor = System.Drawing.Color.Coral
    Form1.BackColor = System.Drawing.Color.Cyan
    Form1.Show()
Comme il n'y a pas d'instance de Form1, VB en crée une.


IV-C-5. Les nouveaux Contrôles


IV-C-5-a. DataGridView

Il remplace le DataGrid dans VB.Net 2005 Il est bien plus simple à utiliser surtout pour modifier directement la grille sans passer par un DataSet.

MyDataGridView.ColumnCount = 5 indique le nombre de colonne.

MyDataGridView.Columns(0).Name = "Date" met un texte dans le haut de la colonne.

MyDataGridView.Rows.Add(t) 'Ajout de ligne; t est un tableau de 5 strings.

MyDataGridView.CurrentCell est la cellule courante (CurrentCellAdress contient les numéro de ligne et colonne)

MyDataGridView.EditMode = DataGridViewEditMode.EditOnEnter autorise de modifier les cellules.


IV-C-5-b. MaskedTextBox

Permettant d'utiliser un masque pour la saisie de caractères. Le masque indique quels caractères interdire ou permettre.

La propriété Mask permet d'indiquer le masque de saisie.

On peut la modifier en mode 'Design' :

On voit bien dans la fenêtre ci dessus: le masque '00:00' permet de saisir 2 groupes de 2 chiffres. L'utilisateur voit que qu'il y a dans l'aperçu '__:__' et est obligé de taper 2 chiffres puis 2 chiffres.

On peut utiliser des masques tout faits (Heure, date..) ou créer un masque personnalisé.

On peut aussi modifier le masque par code:

maskedTextBox1.Mask = "LL"
 
Pour le masque personnalisé on utilise:

0 Chiffre requis (lettres refusés) 
9 Chiffre ou espace optionnel. (lettres refusés) 
# Chiffre ou espace optionnel. (+) (-) sont permis. 
L Lettre requise. (chiffres refusés) 
? Lettre requise optionnelle. (chiffres refusés) 
& Caractère requis.(Chiffres et lettres permises)   
C Caractère, requis optionnel.(Chiffres et lettres permises %*& permis)  
A Alphanumérique requis opt.(Chiffres et lettres permises %*& refusés)  
. Point Decimal; celui de la culture. 
, Séparateur de millier; celui de la culture. 
: Séparateur de temps; celui de la culture. 
/ Séparateur de date; celui de la culture. 
$ Symbole monétaire; celui de la culture. 
< Convertir les caractères qui suivent en minuscule.  
>  Convertir les caractères qui suivent en majuscule. 
| Stop la conversion minuscule ou majuscule. 
\ Escape. Le caractère qui suit devient un littéral.\\” affichera '\'. 
Autres caractères Littéraux. Affichés tels quels

Exemple:

"00/00/0000" permet de saisir une date.

"LLL" permet de saisir trois lettres (pas des chiffres)

/ $ , : sont dépendant de la culture en cours:

Si le Mask="0$" il apparaîtra "_€ en culture française.

On peut modifier cela par FormatProvider property.

MaskCompleted indique si la saisie est conforme.

Dim returnValue As Boolean
returnValue = maskedTextBox1.MaskCompleted
MaskedTextBox1.text permet de lire le contenu du texte.

L'évènement le plus souvent utilisé est TextChanged

Private Sub MaTextBox_TextChanged(sender As Object, _ 
  e As EventArgs) Handles MaTextBox.TextChanged
End Sub 

IV-C-5-c. SoundPlayer

Pour écouter des sons .Wav


IV-C-5-d. SplitContainer:

Permettant de créer facilement une séparation déplaçable entre 2 zones.

On met le SplitContainer, dans les 2 zones on met par exemple 2 textbox. Il faut mettre la propriété Dock de ces 2 textbox à Fill.

En mode Run, cela marche : si je déplace la zone de séparation centrale, cela agrandit un textbox et diminue le second.

Margin indique la largeur de la séparation.

Orientation permet une séparation horizontale ou verticale.


IV-C-5-e. ListView


IV-C-5-f. WebBrowser:

Pour ouvrir une zone internet.


IV-C-5-g. LayoutPanel:

Permettent de positionner les contrôles dans une Form en conception.

FlowLayoutPanel: Place les contrôles à droite du précédent, passe 'à la ligne' si nécessaire, c'est génial pour créer plusieurs lignes de label, TextBox, Bouton:

TableLayoutPanel:On crée un tableau de panel, puis on met les contrôles dans les cellules:


IV-C-5-h. MenuStrip :

Remplace les MainMenu

On peut même mettre des images dans les menus. Il peut y avoir des combobox et des zones de texte.

Il y a aussi les ContextMenuStrip qui remplace les ContextMenu.


IV-C-5-i. ToolStrip:

Création de barre n'importe ou dans le formulaire.

Exemple de barre de menu comprenant:

Un bouton.

Un label

Un bouton déroulant un menu.

Un comboBox

Une zone texte

Une barre de progression.

Images possible dans les menus, il peut y avoir des séparateurs.


IV-C-5-j. StatuStrip:

Pour créer une barre d'état en bas d'un formulaire; remplace les StatusBar.

Peut contenir des LabelStrip (Label ou LinkLabel), des ProgressBar, DropDownButton et ToolsStripButton.


IV-C-5-k. ProgesBarr:

Idem le contrôle de 2003 avec des fonctionnalités en plus:

La propriété Style permet la progression par blocks, en continue, ou en oscillation droite gauche ( comme lors de l'ouverture de Windows XP.

Il y a aussi le toolstripcontainer et un contrôle permettant l'usage port série.


IV-C-6. Les nouvelles 'Variables'.

VB 2005 prend en charge les types non signés:

UInteger Entier codé sur 32 bits pouvant prendre les valeurs 0 à 4 294 967 295.

ULong Entier codé sur 64 bits :0 à 18 446 744 073 709 551 615

UShort Entier sur 16 bits 0 à 65 535.

et

SByte Codé sur 1 octet, valeur de -128 à 127


IV-C-7. Les nouvelles 'Collections'.

On peut utiliser des collections 'génériques'

System.Collections.Generic.List(Of String)
On peut ainsi créer des collections fortement typées.

Il y a en plus les Collections spécialisées (nouveau type de collection):

L'espace System.Collections.Specialized fournit ce nouveau type de collection:

Exemple: ListDictionary avec Clé et Valeur:

Dim l As New System.Collections.Specialized.ListDictionary

IV-C-8. Dans le Code: les nouvelles instructions

  • Continue dans une boucle Do While ou For permet de passer à l'itération suivante sans effectuer le code.
    While condition

    ..Continue While

    End While

    Continue For existe aussi.

  • IsNot simplifie l'écriture:
    If Not (Objet1 Is Nothing ) Then..

    devient

    If Objet1 IsNot Nothing Then

  • Using
    Permet de créer un bloc qui libère les ressources en fin de bloc:
    
        Using sqc As New System.Data.SqlClient.SqlConnection(s)
            MsgBox("Connected with string """ & sqc.ConnectionString & """")
        End Using
    
  • TryCast
    En plus de CType et de Cast, il y a maintenant TryCast qui retourne Nothing si la conversion est impossible.

  • Procédures avec paramètres différents.
    On peut 'overloader' une procédure afin de pouvoir l'appeler avec des paramètres différents.
    
    Overloads Sub LireEnregistrement(ByVal Name As String, ByVal amount As Single)
    
    ' Code permettant de rechercher l'enregistrement à partir du nom.
    
    End Sub
    
    Overloads Sub LireEnregistrement(ByVal Numero As Integer, ByVal amount As Single)
    
    ' Code permettant de rechercher l'enregistrement à partir du numéro
    
    End Sub
    

IV-C-9. Les nouveautés dans les Classes:

Les classes 'Partielles' sont possible.

Partial Class MaClasse

End Class
Ainsi une Classe peut être scindée en plusieurs parties situées dans des endroits différents du code.

On peut surcharger les opérateurs + - * / mais aussi _ ^ & Like And Or Xor Not < > = << >> Ctype IsTrue, IsFalse

Exemple: surchargeons l'opérateur +

Public Structure height
    ...
    Public Shared Operator +(ByVal h1 As height, ByVal h2 As height)As height
        Return New height(h1.feet + h2.feet, h1.inches + h2.inches)
    End Operator
End Structure
La routine doit être Shared, de plus si on surcharge certains opérateurs, il faut aussi surcharger leur inverse: si on surcharge '>' , il faut surcharger '<'.

Surcharge de IsTrue, IsFalse Ctype

Si on teste un boolean, il a la valeur True ou False.

Si par contre je crée une classe nommée 'Personne', je peux définir comment une instance sera considérée comme égale à True. Il faut surcharger l'opérateur IsTrue en lui indiquant dans quelle condition l'instance sera considérée comme =True:

Exemple:

J'ai une instance e de type Personne, si e.Present =True, dans ce cas je veux que e soit considéré comme True; il faut écrire dans la Classe 'personne':

Public Shared Operator IsTrue(ByVal e As Personne) As Boolean

If e Is Nothing Then

    Return False

Else

    Return e.Present

End If

End Operator
Pour définir l'opérateur IsFalse, c'est simple: c'est Not e

Public Shared Operator IsFalse(ByVal e As Personne) As Boolean

    Return Not e

End Operator
Ensuite je pourrais utiliser des instructions de la forme:

If e then.. 
Surcharge de Ctype:

Je peux définir dans une classe comment CType va fonctionner:

Pour cela dans la classe Personne, je vais définir les 3 possibilités:

Public Shared Widening Operator CType(ByVal e As Personne) As String

Return e.Nom + " " + e.Prenom

End Operator

 

Public Shared Widening Operator CType(ByVal  e As Personne) As Date

If e Is Nothing Then

    Return Nothing

Else

    Return e.DateDeNaissance

End If

End Operator

 

Public Shared Widening Operator CType(ByVal  e As Personne) As Boolean

    If e Is Nothing Then Return False Else Return e.Present

End Operator
Ainsi

Ctype(UnePersonne,String) retourne Nom Prenon

Ctype(UnePersonne,Date) retourne la date de naissance

Ctype(UnePersonne,Boolean) retourne True ou False.

On peut créer des Property avec une portée différente pour le Set et le Get:

Public Class employee
    Private salaryValue As Double
    Protected Property salary() As Double
        Get
            Return salaryValue
        End Get
        Private Set(ByVal value As Double)
            salaryValue = value
        End Set
    End Property
End Class
Utilisation des 'générics'

Un type 'generic' permet de créer une Classe ayant des Data Types non définis au départ.

Créons une classe MyClasse; Of permet d'indiquer le genéric:

Public Class MyClasse(Of t)
    Public Sub NewItem(ByVal newItem As t)
        Dim tempItem As t
        ' Insert code that processes an item of data type t.
    End Sub
End Class
On peut ensuite utiliser cette classe avec des Integer ou des String:

Public UneClass As New MyClasse(Of Integer)
Friend stringClass As New MyClasse(Of String)
voir la rubrique 'générique' pour le détails.


IV-D. IDE SharpDevelop (alternative gratuite) MAJ version 2.1)

C'est l'IDE (Integrated Development Environment): Environnement de développement intégré GRATUIT, alternative à VisualStudio.

Oui, vous pouvez faire du Visual Basic.Net gratuitement et légalement.

Depuis sa version 2 #develop est un très bon produit et n'a rien à envier à Visual Studio.

VB 2005 Express de Microsoft est gratuit; la prochaine version sera t-elle aussi gratuite?

#Develop sera toujours gratuit.

C'est un logiciel libre en Open Source (GPL), fonctionne officiellement sous Windows XP et 2000 (Pas officiellement sous ME et 98)

Il parait que SharpDevelop fonctionne sous Windows 98 (non testé, si vous avez essayé, m'en faire part), Millenium (testé), NT 4, Windows 2000 (testé) , XP (testé). Alors que Visual Studio ne fonctionne pas sur un PC non NT (exit Windows 98 et Millenium).


IV-D-1. Où le trouver? Comment l'installer?.

SharpDevelop 2.. et le FrameWork 2

Respecter l'ordre d'installation.
  1. Télécharger et installer le FrameWork. (impérativement en premier)
    Installer Microsoft .NET version 2 Redistibutable package.

    C'est le Framework (la couche logiciel entre l'application et le système), il est téléchargeable sur le Net sur le site Microsoft.

    Télécharger le FrameWork puis l'installer. (Gratuit)

    warning Attention, changer la langue (French) avant le téléchargement.
  2. Télécharger et installer le SDK 2.
    C'est le Kit de Développement Microsoft .NET Framework: SDK du Framework 2.

    En bas de la page précédente ou par le lien suivant:

    Télécharger le SDK (Gratuit) Attention, changer la langue (French).

  3. Télécharger et installez SharpDevelop 2.1 (beta3 le 2/2/2007)
    Télécharger SharpDevelop 2.1 (Gratuit)

    L'installer en exécutant le fichier 'SharpDevelop_2.1.0.2201_Setup.exe'.

  4. Configurer SharpDevelop
    Lancer Sharpdevelop 2.1

    Aller dans le menu 'Outils' - 'Options'

    La langue de l'utilisateur est 'French', si cela n'est pas le cas, modifier la langue.

    Dans 'Style visuel' : Choisir VBNET dans la liste.

    'Codage' : Éditer les en-têtes standard: VB.Net

    'Codage' : Modèle de code: extension '.vb

    'Editeur de texte' : Surlignement, VB.net dans la liste de gauche.

    Le Framework, le SDK et #develop suffisent pour faire des programmes.


IV-D-1-a. Quelques liens

Site SharpDevelop

Didacticiel sur #develop utilisant C# en anglais

WikiSharpDevelop (en anglais)

WikiDeboguage (en anglais)


IV-D-2. Fenêtre Projet.

Lancer SharpDevelop:

Au lancement de l'application, on peut :
  • ouvrir une solution existante: Bouton 'Ouvrir une solution' (ou cliquer sur le nom d'un projet récent en haut)
  • créer un nouveau projet (une nouvelle solution) .
Si l'on veut rajouter des fichiers à notre projet faire :
'Fichier'-'Ouvrir'-'Fichier' et catégorie VB

Détaillons la création d'un nouveau projet.

Bouton 'Nouvelle solution' ou

Menu 'fichier'-'Nouveau'-'Solution'

Sélectionner la catégorie 'VBNET' et choisir le type d'application à créer.(Dans le cas d'une création d'un projet Visual Basic, il faudra choisir dans les 'Modèles': Application Windows.) On remarque que #Develop permet aussi d'écrire du C#, du C++ du ILAsm un setup.

Puis il faut donner un nom au projet (il n'y a pas de nom par défaut), modifier si nécessaire le chemin de l'emplacement du projet qui est par défaut ' C:\Documents and Settings\NomUtilisateur\Mes documents\SharpDevelop Projects' ( cocher si nécessaire 'Créer le répertoire source') enfin valider sur le bouton 'Créer'. Une fenêtre 'MainForm' apparaît.

Si, comme dans notre exemple, on a tapé 'Prog2', #develop crée une 'solution' nommée 'SolutionProg2'(ensemble, groupe de projets) contenant un projet (Prog2) contenant un formulaire nommé 'MainForm'

L'écran principal se présente ainsi:

Au centre, sont visible les écrans du code et des formulaires ; on peut changer d'écran grâce aux onglets du haut. Ici on voit 'MainForm'.

A gauche, les onglets du bas donnent accès au projet en cours (les solutions, projets, formulaires, autres fichiers: ressources, assembly..) ou aux outils : Table ascii, Presse papier et surtout (si on a un formulaire au centre et non du code) aux objets (bouton, texteBox, ListBox...)

A droite, en bas , les classes et surtout la fenêtre de Propriétés (Name, Text..) de l'objet sélectionné au centre.

En bas les fenêtres de 'sortie' (affichage de la console) liste des 'erreurs' des 'taches', définitions', 'Résultat des recherches'..


IV-D-3. Dans un nouveau projet, créer une fenêtre :

Pour ajouter un fenêtre (un formulaire) ouvrir le gestionnaire de projet et solution (Onglets en bas à gauche), il donne le nom de la solution (solutionprog2) et du projet (prog2 ici) Cliquer avec le bouton droit sur prog2 puis dans les menus sur 'Ajouter', 'Nouveau fichier'. Cela ouvre la fenêtre 'Nouveau fichier'.

Dans la fenêtre qui s'ouvre , à gauche, choisir 'VB' puis 'Application Windows' , à droite 'Formulaire' , taper un nom de formulaire (Form1 par exemple)puis 'Créer' , une fenêtre ‘Form1' apparaît. La première fenêtre qui s'ouvre automatiquement quand on crée un projet se nomme 'MainForm'.

La zone de travail se trouve au centre de l'écran: On voit les onglets MainForm, Form1.vb pour chaque formulaire (fenêtre)

En bas les onglets 'Source' et 'Design' permettent de passer de l'affichage du code('Source') à la conception de l'interface utilisateur ('Design'): affichage de la fenêtre et de ses contrôles permettant de dessiner l'interface.


IV-D-4. Ajouter des contrôles au formulaire.

Ajoutons un bouton par exemple:

Cliquer sur l'onglet ‘Outils' à gauche en bas , bouton 'Windows Forms', puis sur ‘Button',cliquer dans la MainForm, déplacer le curseur sans lâcher le bouton, puis lâcher le bouton :


IV-D-5. Modifier les propriétés d'un contrôle ou du formulaire.

Quand une feuille ou un contrôle est sélectionné dans la fenêtre Design, ses propriétés sont accessibles dans la fenêtre de propriétés à droite en bas:(Si elles ne sont pas visible, cliquer sur l'onglet 'Propriètés' en bas ).

Ici ce sont les propriétés du contrôle 'Button1' (BackColor, Image, Texte..)

Un petit texte d'aide concernant la propriété en cours apparaît en bas.

(on peut modifier les propriétés directement.)


IV-D-6. Voir les procédures:

L'onglet 'Source' en bas donne accès aux procédures (au code) liées à Form1.

La combo déroutante de droite donne la liste des objets. Si on en choisit un, le pointeur va sur les procédures liées à cet objet.

Malheureusement, contrairement à Visual Studio, la combo de gauche ne contient que les formulaires et pas les objets. Par exemple, on aura MainForm, mais pas Label1... Du coup la recherche se fait directement dans la combo de droite et c'est forcément beaucoup moins clair dès qu'il y a beaucoup de contrôles sur un formulaire...

Il est possible en double-cliquant dans le formulaire ou sur un contrôle de se retrouver directement dans le code de la procédure correspondant à cet objet.

Si la procédure n'existe pas (ButtonClick par exemple),le fait de double-cliquer sur le bouton la crée.

Pour créer les autres procédures évènements, utiliser le bouton qui est sur la fenêtre des propriétés à droite, il fait apparaître la liste des évènements, double-cliquant sur un évènement cela permet d'ouvrir la fenêtre de code et de créer les procédures.


IV-D-7. Voir tous les composants d'un projet:

Pour cela il faut utiliser La fenêtre Projet à gauche (Si elles ne sont pas visible, cliquer sur l'onglet 'Propriètés' en bas), elles permettent de voir et d'avoir accès au contenu du projet:

le gestionnaire de projet et solution donne le nom de la solution (solutionprog2) et du projet (prog2 ici) Cliquer sur les '+' pour développer: vous verrez apparaître les formulaires, les modules.. et:

Références qui contient les espaces de nom.

Assembly: info nécessaire pour générer le projet..


IV-D-8. Remarque relative aux fenêtres de l'IDE:

Pour faire apparaître une fenêtre qui a disparu (fenêtre projet par exemple) utiliser le menu 'Affichage' puis 'projet'.

Quand le fenêtre est ancrée (accrochée aux bords), le fait de la déplacer avec sa barre de titre la 'dé ancre', et elle devient autonome.

Pour la 'ré ancrer', il faut double-cliquer dans sa barre de titre.


IV-D-9. Tester son logiciel:

On peut compiler le projet avec le premier bouton ci-dessous. Créer le projet avec le second. Lancer l'exécution avec le bouton flèche verte (débogueur actif), le point d'exclamation lance l'exécution sans débogage, le rond à droite (qui devient rouge pendant l'exécution) sert à terminer l'exécution.

La liste déroutante permet de choisir la configuration des fenêtres de l'IDE:

Défaut: c'est les fenêtres habituelles précédemment décrites.

Débogage: ouvre les fenêtres: variables locales, points d'arrêt, modules chargés..

Texte simple: uniquement les fenêtres centrales.

Editer: ouvre la fenêtre Edit Layout?

La sauvegarde du projet se fait comme dans tous les logiciels en cliquant sur l'icône du paquet de disquettes.


IV-D-10. Fichiers, Chemins des sources.

Avant, en #develop 1:

.prjx est le fichier de projet.

.cmbw est le fichier solution.

Avec Sharpdevelop 2 c'est comme en VB: les solutions sont maintenant des fichiers .sln

.vb sont tous les fichiers Visual Basic (Feuille module...)

Les sources sont par défaut dans ' C:\Documents and Settings\NomUtilisateur\Mes documents\SharpDevelop Projects'

Si on compile le projet l'exécutable est dans un sous répertoire \Bin\Debug ou \Bin\Realese

Si vous avez plusieurs versions du framework sur votre machine (version 1.0, version 1.1 voire version 2.0 Bêta), il vous est possible de choisir le compilateur dans les options du projet.

Visual Studio 2003 à version 1.1 du framework.

Visual Studio 2005 à version 2.0 du framework.


IV-D-11. Propriétés du projet.

Menu 'Projet', 'Option du projet' permet l'accès aux propriétés du projet en cours.

Le quatrième onglet (Compiler) est le plus intéressant:

On peut:

Compiler le programme en mode 'Debug' ou 'Release'.

Forcer le programmeur a travailler en Option Strict= On ( empêcher les conversions automatiques)

Option Explicit=On (Forcer la déclaration des variables)

Choisir le Framework avec lequel on travaille (1 ou 2, pas le trois encore)

...

Dans l'onglet Import, on peut importer des espaces de noms.


IV-D-12. #Develop propose des AIDES.

La fenêtre d'aide à droite donne accès à des aides:

De #develop en anglais, non à jour!!

Du Framework

De zipLib

Si vous avez installé le SDK (SDK Framework .Net et/ou SDK Direct X) , vous avez accès à l'aide (partie en haut à droite de l'écran) , et donc également à l'intellisense, qui affiche les propriétés, les méthodes des objets, les paramètres des fonctions, des types, … , des différents objets.

Ici par exemple on a tapé MessageBox. , la liste des membres (Equals, Show...) est affichée.


IV-D-13. Erreur de compilation :

Si on fait une faute dans le code, elle est détectée lorsque l'on lance l'exécution.

Ici on a tapé 'Texte' à la place de 'Text'.

La ligne en cause est soulignée en rouge et la fenêtre des erreurs située en bas s'ouvre, elle indique et décrit l'erreur:.

L'aide dynamique à droite propose des liens en rapport avec le contexte.


IV-D-14. Erreur d'exécution: Exceptions

Si il y a une erreur d'exécution (division par zéro par exemple), l'exécution s'arrête et la fenêtre d'exception s'ouvre:

On peut choisir d'arrêter le programme, de continuer, d'ignorer.


IV-D-15. Débogage :

Le deboguer est maintenant intégré dans la version 2.

Une fois l'exécution lancée, on peut:

Suspendre l'exécution par ALT+CTRL+B , reprendre par F6

Ajouter des points d'arrêt.

grâce à des points d'arrêt (pour définir un point d'arrêt en mode de conception, cliquez en face d'une ligne dans la marge grise, cela fait apparaître un rond et une ligne rouge. Quand le code est exécuté, il s'arrête sur cette ligne).

(Recliquer sur le rond pour l'enlever).

Ajouter des marques pages.

On peut ajouter des marques pages, en cliquant (quand on est sur la ligne à marquer) sur le petit carré bleu de la barre d'outils:

Ensuite, on peut se déplacer de marque en marque avec les 2 boutons qui suivent.

En mode 'Run', si on clique sur l'onglet 'Points d'arrêt' à droite, on voit la liste des points d'arrêt et des marques; on peut rendre inactif tous les points d'arrêt (3eme bouton) ou un seul en le décochant dans la liste.

Voir la valeur d'une variable, simplement en positionnant le curseur sur cette variable.

En plus en mode Run , la fenêtre 'Variables locales' située en bas affiche la valeur de toutes les variables de la procédure. (Y compris 'e' et 'sender' qui sont les paramètres de la Sub)

Enfin à droite on peut voir les modules chargés et les threads.

Exécution pas à pas:

F11 permet l'exécution pas à pas (y compris des procédures appelées)

F10 permet le pas à pas (sans détailler les procédures appelées)

Maj+F11 exécute jusqu'à la fin de la procédure en cours.

On peut aussi utiliser les boutons :

warning Attention, comme dans Visual Studio, il n'est pas possible de modifier les fichiers sources à partir du moment où vous avez démarré le débogage.
Fonctions présentes dans #develop 1 mais pour l'instant absente dans #develop 2: C++ NProf Wix NAnt, générateur de MessageBox

Créer un installateur.(en anglais)


IV-D-16. Conclusion:

Programme permettant de faire du VB.net gratuitement (rapport qualité/prix infiniment élevé).

CONCLUSION D'UN UTILISATEUR:

SharpDevelop est un IDE agréable à utiliser, pour le développement des programmes .NET, en mode WYSIWYG.

Il est possible d'atteindre un niveau de qualité équivalent à Visual Studio ou à Borland C# Builder en faisant une installation complète. Très ouvert, on peut lui rajouter des plugins. Certains programmes externes peuvent être utilisés également avec Visual Studio ou Borland C# Builder.

SharpDevelop est en perpétuelle évolution.

Un forum permet de déposer le descriptif des erreurs rencontrées mais également de vos demandes de modifications, si vous pensez à une évolution qu'il serait bien que SharpDevelop possède. En plus vous pouvez récupérer le code source et pouvez donc modifier à loisir l'IDE.

Bien sur, pour les débutants, il manque les assistants de Visual Studio (Crystal report, ADO .NET, …). Le problème avec les assistants est qu'une fois qu'on pratique un peu, ils deviennent vite un gêne, et souvent, il faut repasser derrière eux, pour enlever le superflu de code qu'ils ont écrit (souvent ils n'optimisent pas le code).

Il manque également la partie UML de Visual Studio Architecte, mais là on attaque le haut du panier des développeurs.

Par contre SharpDevelop apporte en plus:

Aide à la génération automatique des MessageBox
Aide à la conversion C# vers VB.NET et de VB.NET vers C#
Aide à la génération d'expression régulière.
Il fournit les logiciels:

NDoc : permet de faire des fichiers d'aide compilée au format MSDN, à partir de lignes commentées dans le code.
NUnits : permet de faire des tests unitaires (!).
SharpQuery : Permet de se connecter aux bases de données .

IV-D-17. J'ai besoin d'aide:

Comment créer facilement un installateur (SetUp) avec #develop?

Comment utiliser NDoc NUnits?

Comment utiliser simplement des ressources?

Comment utiliser des bases de données?

Qui utilise le menu 'Outils' et ses différentes options?

Merci à Fabrice SAGE pour son aide.

Merci à Hubert WENNEKES, CNRS Institut de Biologie de Lille pour son aide.

Remarque pour les forts:

On peut s'étonner qu'il n'y aie pas Handles Button1.Click à la fin de la ligne suivante (comme dans VB 2005)

Sub Button1Click(ByVal sender As Object, ByVal e As EventArgs)

End Sub
En fait si on va voir dans InitializeComponent, il y a un AddHandler après la description du bouton.

Private Sub InitializeComponent()

...

AddHandler Me.button1.Click, AddressOf Me.Button1Click

V. Langage Visual Basic


V-A. Introduction

Nous allons étudier:

Le langage Visual Basic.Net qui est utilisé dans les procédures.

Comme nous l'avons vu, le langage Visual Basic sert à
  • agir sur l'interface (Afficher un texte, ouvrir une fenêtre, remplir une liste, un tableau, poser une question).
    Exemple afficher 'Bonjour" dans un label:
    
    Label1.Text="Bonjour"
    
  • effectuer des calculs, des affectations en utilisant des variables.
    Exemple: Mettre da la variable B la valeur de A+1

    B=A+1

  • Faire des tests avec des structures de décision: évaluer des conditions des comparaisons et prendre des décisions.
    Exemple: SI A=1 ..
    
    If A=1 Then...End If
    
  • travailler en boucle pour effectuer une tache répétitive.
    Exemple faire 100 fois..
    
    For I=0 To 100... Next I
    
Tout le travail du programmeur est là.

Dans VB.Net nous avons à notre disposition 2 sortes de choses:


V-A-1. Les Classes du FrameWork

On travaille sur des objets en utilisant leurs propriétés, leurs méthodes.

Il existe des milliers de 'Classes': les plus utilisées sont les classes String (permettant de travailler sur des chaînes de caractères), Math (permettant d'utiliser des fonctions mathématiques), Forms (permettant l'usage de formulaire, de fenêtre et donnant accès aux contrôles: bouton, case à cocher, liste..)

Elles sont communes à tous les langages utilisant le FrameWork.

Ces Classes ont de multiples méthodes (rappel de la syntaxe: Classe.Methode)

Exemple d'utilisation de la Class TextBox (contrôle contenant du texte) et de sa méthode Text:

TextBox1.Text="Hello" ‘Affiche "Hello" dans le textbox.


V-A-2. Les instructions de Microsoft.VisualBasic

(Un autre constituant de Visual Basic, et de lui seul).

Il s'agit d'instructions, de mots clé qui ont la même syntaxe qu'en VB6 mais qui sont du VB.Net.

Exemple:

A = Mid(MaString, 1, 3) 'Mid retourne une partie de la chaîne de caractères.

Il y a aussi les Classes de compatibilité VB6. Elles ne dépayseront pas ceux qui viennent des versions antérieures de VB car elles reprennent la syntaxe utilisée dans VB6 et émulent les fonctions VB6 qui ont disparues de VB.Net.

Ajoute à VB.Net des fonctions VB6. L'outils d'import automatique de VB6 vers VB.Net en met beaucoup dans le code. Il faut à mon avis éviter de les utiliser car ce n'est pas vraiment du VB. Ce cours 'pur' VB.Net n'en contient pas.

Pour le moment cela peut paraître un peu compliqué, mais ne vous inquiétez pas, cela va devenir clair.


V-A-2-a. Saisir, Afficher.

Dans l'étude du langage VB, on s'occupe du code, on ne s'occupe pas de l'interface (les fenêtres, les boutons, l'affichage du texte...), mais parfois, on a besoin

  • de saisir une valeur, pour cela on utilise une InputBox, c'est une boite qui s'ouvre,l'utilisateur y tape un texte puis il clique sur 'ok'; on retrouve ce qu'il a tapé dans la variable Réponse.
Réponse= InputBox()

  • d'afficher des résultats, pour le moment on affichera du texte de la manière suivante:
dans une fenêtre, dans des TextBox: TextBox1.Text="TextBox1"


ou un label: Label1.Text="Résultat"

ou

sur la console: Consol.Out.WriteLine ("Résultat")

ou

dans une Boite de message: MsgBox("Voulez vous continuer?")



V-B. Les 'Algorithmes'.


V-B-1. A- Pour écrire un programme.

Pour écrire un programme, aller du problème à résoudre à un programme exécutable, il faut passer par les phases suivantes:
  • Analyse du cahier des charges.
    Il doit être clair, exhaustif, structuré.

  • Analyse générale du problème.
    Il existe des méthodes pour professionnels (MERISE, JACKSON..), nous utiliserons plutôt l'analyse fonctionnelle: Le problème global est découpé en sous problèmes nommés fonctions. Chaque fonction ne contient plus qu'une partie du problème. Si une fonction est encore trop complexe, on itère le processus par de nouvelles fonctions à un niveau plus bas.

    Cela se nomme la 'Conception structurée descendante'. La 'Conception ascendante' existe aussi: en assemblant des fonctions préexistantes, on résout le problème: attention, il faut que les fonctions préexistantes soient cohérentes. (Pour le moment on ne fait pas de programmation objet)

  • Analyse détaillée.
    Chaque fonction est mise en forme, la logique de la fonction est écrite dans un pseudo langage (ou pseudo code) détaillant le fonctionnement de la fonction. Ce pseudo code est universel , il comporte des mots du langage courant ainsi que des mots relatifs aux structures de contrôle retrouvées dans tous les langages de programmation.

  • Codage.
    Traduction du pseudo code dans le langage que vous utilisez.

  • Test
    Car il faut que le programme soit valide.


Exemple simpliste:
  • Analyse du cahier des charges.
    Création d'un programme affichant les tables de multiplication, d'addition, de soustraction.

  • Analyse générale du problème.
    Découpons le programme en diverses fonctions:

    Il faut créer une fonction 'Choix de l'opération', une fonction 'Choix de la table', une fonction 'TabledeMultiplication', une fonction 'TabledAddition', une fonction 'Affiche'...

  • Analyse détaillée.
    Détaillons la fonction 'TabledeMultiplication'

    Elle devra traiter successivement (pour la table des 7 par exemple)

    1X7
    2X7
    3X7..

    Voici l'algorithme en pseudo code.
    
    Début
    
        Pour i allant de 1 à 10
    
            Ecrire (i*7)
    
        Fin Pour
    
    Fin 
    
  • Codage.
    Traduction du pseudo code en Visual Basic, en respectant la syntaxe du VB.
    
    Sub MultiplicationPar7
    
    Dim i As Integer
    
    For i=1 to 10
    
        Call Affiche(i*7)
    
    next i.
    
    End Sub
    
  • Test
    Ici il suffit de lancer le programme pour voir si il marche bien..

Pour des programmes complexes, il existe d'autres méthodes.


V-B-2. B- Définition de l'algorithme.

Un problème est traitable par informatique si :
  • on peut parfaitement définir les données (entrées) et les résultats (sorties),
  • on peut décomposer le passage de ces données vers ces résultats en une suite d'opérations élémentaires exécutables.
idea L'algorithme détaille, en pseudo code, le fonctionnement de ce passage et en décrit la logique.
L'algorithme est une succession de tests, décisions et actions dans le but de décrire le comportement d'une entité (objet, programme, personne). Définition du Dicodunet.

Etudions cette logique valable pour tous les langages de programmation (ceux qui sont des langages impératifs):

Pour représenter n'importe quel algorithme, il faut disposer des trois possibilités suivantes:
  • la séquence qui indique que les opérations doivent être exécutées les unes après les autres.
  • le choix qui indique quelles instructions doivent être exécutées en fonction de circonstances.
  • la répétition qui indique que des instructions doivent être exécutées plusieurs fois.
Exemple d'algorithme principalement composé d'une répétition:

Pour i allant de 1 à 10
        Ecrire (i*7)
Fin Pour
Voyons cela en détails:


V-B-3. C- Principe généraux

Le langage algorithmique et son pseudo-code n'est pas vraiment standardisé, chacun l'écrit à sa manière, aussi vous verrez des notations différentes dans les divers cours d'algorithme. Cela n'a pas d'importance car un programme en pseudo-code ne sera jamais exécuté sur une machine.

L'intérêt de d'étude des algorithmes est didactique: elle permet de comprendre la logique d'un programme totalement indépendamment du langage: ce qui suit est valable en C++, Delphi, Java, Visual Basic, Assembleur...


V-B-3-a. Séquences

Au sein d'un programme, la structure est généralement séquentielle.

Le code est fait d'une succession de lignes (ou instructions) qui seront lues et traitées les unes après les autres.

Instruction 1

Instruction 2

Instruction 3

..

En VB on peut mettre plusieurs instructions sur la même ligne séparées par ":"

Instruction1 : Instruction2


V-B-3-b. Les variables, leur 'Type':

Elles contiennent les informations les données nécessaires au déroulement du programme (C'est le même sens qu'en mathématique, a la différence qu'en informatique une variable ne contient qu'une valeur).

Chaque variable a un Nom (identifiant) et un Type. Ce dernier indique la nature de l'information que l'on souhaite mettre dans la variable:

Un type indique:

Les valeurs que peut prendre la variable.

Les opérations possibles.

Exemple: un Type 'Entier' (Integer en VB) correspond au valeur entière, positive ou négative, les opérations possibles sont l'addition, la soustraction, la multiplication...

La nature, le type peut être:

Type numérique:

'Entier', 'réel'.. (Integer, Single en VB) Exemple d'un entier: 123

Type alphanumérique:

'Caractère' (Char en VB) contient 1 caractère Exemple d'un caractère: 'a' (avec des guillemets)

'Chaîne de caractères',(String en VB), contient plusieurs caractères. Exemple: 'toto' (avec des guillemets)

Autres Type:

Booléen (Boolean en VB) ne peut contenir que 'Vrai' ou 'Faux'

Objet. (Object en VB)

Monétaire (Décimal en VB)

Date (Date en VB)

A partir des types précédents on peut créer des types complexes (ou structurés):

Les tableaux (Array)

Les Collections.

Exemple: la variable nommée 'Total' contient un réel dans un programme de comptabilité.

on remarque qu'il ne faut pas confondre 1 qui est une valeur numérique( sans guillemets) et "1" qui est le caractère '1' (avec des guillemets).

Utilisation des variables:

Les variables numériques serviront à faire des calculs:

Les variables alphanumériques serviront entre autres à afficher du texte:

Comment afficher les résultats de calcul?

On apprendra à transformer des variables numériques en variables alphanumériques.

Pour utiliser une variable, il faut qu'elle existe, il faut donc la créer, on dit il faut la déclarer:

Dans un algorithme: Variable A en Numérique 'crée une variable nommée A et de Type Numérique.

En VB: Dim A As Integer 'crée une variable nommée A et de Type Integer.

On peut aussi initialiser une variable c'est à dire définir sa valeur initiale.

On peut utiliser un littéral: c'est une donnée utilisée directement.

X <- 2 veut dire: donner à la valeur X la valeur 2 ( 2 est une littéral)


V-B-3-c. Affectation ( ou Assignation):

C'est une instruction consistant à donner une valeur à une variable.

En langage algorithmique on l'indique par '<-'

X <- 2 veut dire: donner à la valeur X la valeur 2 ( 2 est une littéral)

Z <- X veut dire: donner à la variable Z la valeur de la variable X .

Z <- X+1 veut dire: donner à la variable Z la valeur de la variable X à laquelle on ajoute 1 (Z prendra la valeur 2+1 =3).

Cela revient à évaluer l'expression de droite et à en mettre la valeur dans la variable de gauche.

En VB le signe d'affectation est '=' on écrit donc:

Z=X+1

warning Attention ce n'est pas le même sens qu'en mathématique.
Exemple Visual Basic: A=B


warning Attention ce n'est pas une égalité mais une affectation.
L'affectation ne marche que si le type de variable est le même:

Variable A en Numérique

Variable B en Numérique

B<-12

A<-B 'fonction B contient 12, on met 12 dans A

Variable A en Numérique

Variable B en Alphanumérique

B<-'toto'

A<-B 'ne fonctionne pas car on tente de mettre le contenue de B qui est alphanumérique dans une variable numérique.

L'affectation sert à effectuer des calculs:

Variable A en Numérique

A<-3+4-2 'L'expression à droite est évaluée et son résultat est affecté à la variable A.

Ici les + - sont des opérateurs; il y en a d'autres: * (multiplier) / (diviser)....


V-B-3-d. Booléens

On a parfois besoin de savoir si une assertion est vraie ou Fausse.(True ou False)

Pour stocker une information de ce type, on utilise une variable de type booléen. Une variable de ce type ne peut contenir que True ou False.

Le terme booléen vient de "l'algèbre de Boole", cette algèbre ne travaille que sur les valeurs 1 ou 0 (True ou False)

Soit B une variable booléenne:

On peut écrire B<-True (B=True en VB)

On peut aussi tester cette variable:

Si B=False alors (If B=False Then.. en VB)

L'expression après Si est évaluée, si elle est vraie 'alors' se produit.

Autre exemple:

Si C=2 alors.. (If C=2 Then ..en VB)

L'expression C=2 est évaluée, si C est effectivement égal à 2, C=2 est évalué et prend la valeur True; dans ce cas le programme se poursuit après Then.

si C est différent de 2, C=2 est évalué et prend la valeur False; dans ce cas le programme ne se poursuit pas après Then.


V-B-3-e. Les choix: Si..Alors

Le programme doit pouvoir choisir parmi deux ou plusieurs possibilités en fonction d'une condition :


Si Condition Alors

      Action 1

Sinon

      Action 2

Fin Si
Si Condition est vraie Action 1 est effectuée, sinon Action 2 est effectué.

Parfois il n'y a pas de seconde branche :

Si Condition Alors

      Action 1

Fin Si
ou sur une seule ligne:

Si Condition Alors Action 1

Il peut y avoir plusieurs conditions imbriquées :

Si Condition 1 Alors

      Si Condition 2 Alors

            Action 1

Sinon

            Action 2

Fin Si

Sinon

      Action 3

Fin Si
Noter bien le retrait des lignes de la seconde condition afin de bien visualiser la logique du programme :

Action 2 est effectuée si la Condition 1 est remplie et la Condition 2 n'est pas remplie.

En VB cela correspond à l'instruction IF THEN

If Condition 1 Then

      Action 1

Else

      Action 2

End If
Remarque sur les conditions

Une condition contient 2 valeurs et un opérateur:

Si C>2 Alors est correcte.

Si B=3 Alors est correcte.

Si 2<B<7 Alors est incorrecte car il y a 2 opérateurs, il faut dans ce cas utiliser plusieurs conditions et des opérateurs logiques:

Si B>2 Et B<7 Alors est correct (If B>2 And B<7 Then en Visual Basic)

La condition est évaluée:

Exemple : Soit l'expression Si C>2 Alors , elle sera évaluée; si C contient 3, C>2 est vérifié donc Vrai.

Exemple: Trouver le plus grand nombre entre x et y et le mettre dans max

Variable x en Numerique

Variable y en Numerique

Variable max en Numerique

Si x>y Alors

    max<-x

Sinon

    Max<-y

Fin Si
En VB

Dim x As Integer

Dim y As Integer

DIm max As Integer

if x>y Then

    max=x

else

    max=y

End if

V-B-3-f. Les choix: Décider entre :

Il est parfois nécessaire d'effectuer un choix parmi plusieurs solutions :


Décider Entre

      Quand Condition 1 Alors

            Action 1

      FinQuand

 

      Quand Condition 2 Alors

            Action 2

      FinQuand

      ..

      ..

      Autrement

            Action 4

      FinAutrement

FinDécider
Si la condition 1 est remplie Action 1 est effectuée puis le programme saute après FinDécider.

Si la condition 1 n'est pas remplie, on teste la condition 2..

Si aucune condition n'est remplie on saute à Autrement, on effectue Action 4.

On pourrait aussi parler de sélection :

Sélectionner.

      Le cas : condition 1

            Action 1

      Le cas : condition 2

            Action 2

      ..

      Les autres cas

FinSélectionner
En VB cela correspond à

Select Case Valeur

      Case condition 1

            Action 1

      Case condition 2

            Action 2

      ..

      Case Else

            Action 4

End Select
Si Valeur=Condition 1 Action 1 est effectuée,si Valeur=Condition 2 Action 2 est effectuée...


V-B-3-g. Les répétitions: Pour...Répéter

Permet de répéter une séquence un nombre de fois déterminé :

Le cas le plus classique est :

Pour I variant de 0 à N Répéter

      Action

FinRépéter
I prend la valeur 0, 'Action' est effectuée,

puis I prend la valeur 1, Action est effectuée,

puis I prend la valeur 2..

cela jusqu'à N

La boucle tourne N+1 fois (car ici on commence à 0 )

Cela se nomme une itération.

Intérêts?

Au lieu de faire

Afficher (1*7)

Afficher (2*7)

Afficher (3*7)

Afficher (4*7)

...

on remarque qu'un élément prend successivement la valeur 1, 2, 3, ..

Une boucle peut faire l'itération:

Pour i allant de 1 à 10 Répéter

    Affiche (i*7)

Fin répéter
La variable dite 'de boucle' prend bien les valeurs 1 puis 2 puis 3.. ; elle est utilisée dans le corps de la boucle.

Une instruction Sortir permet de sortir prématurément de la boucle.

En VB

For i=0 To N

      ..

Next i
L'instruction Exit For permet de sortir prématurément de la boucle.

On peut aussi boucler en parcourant tous les éléments d'une collection.

(Une collection est une liste d'objets, liste de taille variable en fonction de ce qu'on ajoute ou enlève.)

Pour Chaque élément de la liste

      Action

Fin Pour
En VB :

For eachIn

 

Next

V-B-3-h. Les répétitions: Tant que :

Permet de faire une boucle sans connaître le nombre d'itérations à l'avance.


Tant Que Condition

      Action

Fin Tant Que
L'action qui est dans la boucle doit modifier la condition afin qu'à un moment ‘Tant que' ne soit pas vérifié et que l'on sorte de la boucle. Sinon la boucle tourne sans fin.

Pour plus cadrer avec la réalité :

Faire tant que condition

      Action

Boucler
En VB :

Do while Condition

      Action

Loop
Il existe une boucle équivalente :

Répéter

      Action

Jusqu'à Condition

 

En VB :

Do

      Action

Loop Until Condition
Une instruction Exit Do permet de sortir prématurément de la boucle.


V-B-3-i. Structuration: 'Sous-programme' ou 'procédure':

On a déjà vu cette notion.

Quand on appelle une procédure, le logiciel ‘saute' à la procédure, il effectue celle-ci puis revient effectuer ce qui suit l'appel.

Et VB les sous-programmes (ou procédures) sont des Sub ou des Function. Pour appeler une procédure on utilise Call NomProcedure() ou NomProcedure()

Le programme effectuera les instructions 1, 2, 3, 10, 11, 4, 5.

Une opération complexe peut être découpée en plusieurs procédures ou sous-programmes plus petits et plus simples qui seront appelés.

Chaque procédure résout un problème .

On peut fournir aux procédures des paramètres, ce sont des variables qui seront transmises à la procédure.

Exemple:

Création d'une Procédure 'MaProcédure' recevant 2 paramètres:

Sub MaProcédure(paramètre1, paramètre2)

..

End Sub
Exemple d'appel de la procédure 'Maprocédure' en envoyant 2 paramètres:

Call MaProcédure(premierparamètre, secondparamètre)

Exemple : si j'écris Call MaProcédure(2,3)

dans la procédure MaProcédure paramètre1=2 et paramètre2=3.

Il est nécessaire de définir le type des paramètres:

Sub MaProcédure(paramètre1 As Integer, paramètre2 As Integer) indique que la procédure attend 2 entiers.

Il y a 2 manières d'envoyer des paramètres :

Par valeur : (By Val)c'est la valeur, le contenu de la variable qui est envoyé.

Par référence :(By Ref) c'est l'adresse (le lieu physique où se trouve la variable) qui est envoyée. Si la Sub modifie la variable, cette modification sera visible dans la procédure appelante après le retour.

Parfois on a besoin que la procédure appelée retourne une valeur dans ce cas il faut créer une fonction:

Function MaFonction()  As Integer    'MaFonction qui retourne un entier

..

    Return Valeur

End Function
Pour appeler la fonction:

ValeurRetournée=MaFonction()

Donc ValeurRetournée est aussi un entier

Exemple de fonction: créer une fonction qui retourne le plus petit nombre:

Fonction Minimum (x en Numerique, y en Numérique) en numérique

Si x<y Alors

    Retourner x

Sinon

    Retourner y

Fin Si

Fin Fonction
Pour l'utiliser:

Variable Min en Numerique

Min<-Minimum (5,7) 'Appelle la fonction en donnant les 2 paramètres 5 et 7.

Min contient maintenant 5
En Vb

Function Minimum(x As Integer, y As Integer) As Integer

    If x<y Then

        Return x

    Else

        Return y

    End If

End Function
Pour l'utiliser:

Dim min As Integer

Min= Minimum (5,7)
La fonction résout un problème et plus précisément à partir de données, calcule et fournit un résultat.


V-B-3-j. Tableaux

Un tableau de variables permet de stocker plusieurs variables de même type sous un même nom de variable, chaque élément étant repéré par un index ou indice.

C'est une suite finie d'éléments.

Soit un tableau A de 4 éléments

3
12
4
0
Pour accéder à un élément il faut utiliser l'indice de cet élément.

L'élément d'index 0 se nomme A[0] et contient la valeur 3.

On remarque que le premier élément est l'élément d'index 0 (ZERO).

L'élément d'index 1 se nomme A[1] et contient la valeur 12.

Quand on crée un tableau, il a un nombre d'éléments bien défini: 4 dans notre exemple d'index 0 à 3.

Pour donner une valeur à un des éléments , on affecte la valeur à l'élément.

A[2] <- 4
Pour lire une valeur dans un tableau et l'affecter à une variable x:

x <- A[2]
Traduction en VB

A(2)=4

x = A(2)
Pour parcourir tous les éléments d'un tableau on utilise une boucle:

Exemple: afficher tous les éléments du tableau tab qui contient n éléments.

début
          Pour i allant de 0 à n-1 Répéter
              écrire(tab[i])
          Fin Répéter
fin
En VB:

       For i=0 to n-1

            Affiche ( tab(i))    'routine d'affichage

       Next i 
Il existe des tableaux multidimensionnels avec plusieurs index:

Voyons les index de chaque élément:

B(0,0) B(0,1) B(0,2)
B(1,0) B(1,1) B(1,2)
B(1,2) B(2,1) B(2,2)
B[1,0] désigne l'élément rouge (ligne 2, colonne 1).

Voyons par exemple,le contenu de chaque élément:

3 12 0
18 4 5
12 2 8
Ici B[1,0] =18


V-B-3-k. Notion de 'Collection':

Une collection permet de stocker plusieurs variables ou objets, chaque élément étant repéré par un index ou indice.

Soit la collection Col, au départ elle est vide.

J'ajoute des éléments (ou items) à cette collection.

Col.Ajouter ("Toto")

Voici la collection:

Toto
La collection a maintenant 1 élément.

Col.Ajouter("Lulu")

Col.Ajouter("Titi")
Toto
Lulu
Titi
La collection a 3 éléments maintenant.

Col.Retirer(2) enlève l'élément numéro 2

Toto
Titi
La collection n'a plus que 2 éléments maintenant.

On voit que le nombre d'éléments n'est pas connu à l'avance, il varie en fonction des éléments ajoutés (ou retirés)

Un élément est repéré par un indice.

En VB

Col.Add    'Ajoute un élément

Col.Remove 'Enlève une élément
Il existe des collections avec des clés permettant de retrouver la valeur d'un élément rapidement.


V-B-3-l. Erreur d'exécution: Notion de 'Sécurisation' du code:

Des instructions doivent protéger certaines parties du code afin d'éviter d'effectuer des opérations incohérentes.

Si l'utilisateur entre 2 nombres X et Y et qu'une instruction exécute Z<=X/Y , alors que Y=0 ,la division par 0 n'existant, le logiciel 'plante': Il s'arrête et donne un code d'erreur( du genre 'Erreur division par 0 interdite')

Il s'agit d'une 'Erreur d'exécution'.

En VB on dit 'lever une exception'.

Il appartient au programmeur, une fois l'algorithme écrit, de le sécuriser: Des instructions doivent protéger certaines parties du code afin d'éviter d'effectuer des opérations incohérentes.

On ajoute donc un choix: si Y est différent de 0 alors on effectue la division.

Si Y<>0 Alors

    Z<=X/Y

Sinon

...

Fin Si

V-B-3-m. Flag et variables d'état.

Un Flag (ou drapeau) est une variable utilisée pour enregistrer un état, la valeur de cet état servant à déclencher ou non des actions. C'est une manière de retenir qu'un évènement s'est produit.

Si le drapeau est abaissé, les voitures roulent..

Exemple: Utiliser un Flag pour sortir d'une boucle:

On utilise flagSortir.

flagSortir=Faux 

Tant que  flagSortir =Faux

      Si on doit sortir de la boucle, on met la valeur de flagSortir à Vrai

Boucler
En VB:

flagSortir=Faux 

Do while flagSortir =Vrai

     ' Si on doit sortir de la boucle, on met la valeur de flagSortir à Vrai

Loop
Tant que flagSortir =Faux la boucle tourne.

On peut généraliser cette notion en parlant de variable d'état.

Un variable d'état sert à décrire l'état du programme.

Exemple:

fileIsOpen est une variable indiquant si un fichier est ouvert ou fermé.


V-B-4. D -Quelques algorithmes.


V-B-4-a. Recherche dans un tableau

Soit un tableau A() de 4 éléments

3
12
4
0
Je veux parcourir le tableau pour savoir s'il contient le chiffre '4'.

Il faut faire une itération afin de balayer le tableau: la variable dite de boucle ( I ) va prendre successivement les valeurs: 0 ,1 ,2 ,3. (Attention: dans un tableau de 4 éléments, l'index des éléments est 0,1,2,3)

Pour I variant de 0 à 3 Répéter

      ..

FinRépéter
Dans la boucle il faut tester si la valeur de l'élément du tableau est bien la valeur cherchée.

Pour I variant de 0 à 3 Répéter

      Si A(I)= 4 Alors..

FinRépéter
Si on a trouvé la bonne valeur, on met un flag (drapeau) à Vrai.

flagTrouvé<-Faux

Pour I variant de 0 à 3 Répéter

      Si A(I)= 4 Alors flagTrouvé<-Vrai

FinRépéter
Ainsi si après la boucle flagTrouvé= Vrai, cela veut dire que le chiffre 4 est dans le tableau.

En VB

flagTrouve=False

For I=0 To 4

    If A(I)=4 Then flagTrouve=True

Next I

V-B-4-b. Tri de tableau

Pour trier un tableau de chaînes de caractères (des prénoms par exemple), il faut comparer 2 chaînes contiguës, si la première est supérieure (c'est à dire après l'autre sur le plan alphabétique: "Bruno" est supérieur à "Alice"))on inverse les 2 chaînes, sinon on n'inverse pas. Puis on recommence sur 2 autres chaînes en balayant le tableau jusqu'à ce qu'il soit trié.

Tableau non trié:

Bruno
Alice
Agathe
On compare les lignes 1 et 2, on inverse

Alice
Bruno
Agathe
On compare les lignes 2 et 3, on inverse

Alice
Agathe
Bruno
Le tableau n'étant pas encore trié, on recommence:

On compare les lignes 1 et 2, on inverse

Alice
Agathe
Bruno
On compare les lignes 2 et 3, on n'inverse pas.

Le tableau est trié.

Tout l'art des routines de tri est de faire le moins de comparaisons possible pour trier le plus vite possible.

On a utilisé ici le Bubble Sort (ou tri à bulle); on le nomme ainsi car l'élément plus grand remonte progressivement au fur et à mesure jusqu'au début du tableau comme une bulle. ("Agathe" est passé de la troisième à la seconde puis à la première position).

Une boucle externe allant de 1 à la fin du tableau balaye le tableau N fois ( La boucle varie de 0 à N-1), une seconde boucle interne balaye aussi le tableau et compare 2 élément contigus (les éléments d'index j et j+1)et les inverse si nécessaire. La boucle interne fait remonter 1 élément vers le début du tableau, la boucle externe le fait N fois pour remonter tous les éléments.

Pour i allant de 0 à N-1

    Pour j allant de 0 à N-1

        Si T(j)>T(j+1) Alors 

            Temp<-T(j) 

            T(j)<-T(j+1)

            T(j+1)<-Temp

        Fin Si

    Fin Pour

 Fin Pour
En Visual Basic:

Dim i, j , N  As Integer    'Variable de boucle i, j ; N= nombre d'éléments-1

Dim Temp  As String

N=4  'tableau de 5 éléments.

Dim T(N) As String  'élément de 0 à 4

For i=0 To N-1

    For j=0 To N-1

        If T(j)>T(j+1) then 

            Temp=T(j): T(j)=T(j+1):T(j+1)=Temp

        End if

    Next j

 Next i
info Remarque: pour inverser le contenue de 2 variables, on doit écrire
Temp=T(j): T(j)=T(j+1):T(j+1)=Temp (L'instruction qui faisait cela en VB6 et qui se nommait Swap n'existe plus)

Cet algorithme de tri peut être optimisé, on verra cela plus loin.

Les algorithmes s'occupent aussi de décrire la manière de rechercher des données dans des tableaux, de compresser des données... Nous verrons cela au fur et à mesure.


V-B-5. Lexique anglais=>Français:

If = Si.

Then= Alors

Step=Pas

Do (To)= faire

While= tant que

Until= Jusqu'à ce que.

Loop= boucle


V-C. L'affectation.

C'est l'instruction la plus utilisée en programmation.

On peut aussi utiliser le terme 'Assignation' à la place de l'affectation.

Variable=Expression est une affectation.

Elle transfère le résultat de l'expression située à droite du signe 'égal' dans la variable (ou la propriété) à gauche du signe égal.

Exemple:

A=B est une affectation (ou assignation.)

A=B affecte la valeur de la variable B à la variable A, la valeur de B est mise dans A.


Si

A=0

B=12

A=B entraîne que A=12 (B n'est pas modifié)

Si nécessaire l'expression à droite du signe = est évaluée, calculée avant d'être affectée à la variable de gauche.

Si

A=0

B=12

A=B+2 entraîne que A=14

L'affectation permet donc de faire des calculs :

Si nombrdHeure=100 et tauxHoraire=8

paye= nombredHeure * tauxhoraire

paye prend la valeur 800 (notez que '*' , l'étoile veut dire : multiplication.)

warning Attention dans le cas de l'affectation "=" ne veut donc pas dire 'égal'.
A=A+1 est possible

Si A=1

A=A+1 entraîne que A=2

On verra qu'il existe des variables numériques ('Integer' 'Single') et alphanumériques (chaîne de caractères ou 'String'), l'affectation peut être utilisée sur tous les types de variables.

Le second membre de l'affectation peut contenir des constantes, des variables, des calculs dans le cas de variables numériques.

A=B+2+C+D

On ne peut pas affecter une variable d'un type à une variable d'un autre type:

si A est numérique et B est alphanumérique (chaîne de caractères) A=B n'est pas accepté.

Ecriture compacte:

A=A+1 peut s'écrire de manière plus compacte : A += 1

A=A*2 peut s'écrire de manière plus compacte : A *= 2

A=A&"Lulu" pour une variable chaîne de caractère peut s'écrire de manière plus compacte : A &= "Lulu"

L'affection marche pour les objets, leurs propriétés..

Bouton1.BackColor= Bouton2.BackColor

Signifie que l'on donne au Bouton1 la même couleur de fond que celle du bouton2: on affecte la valeur BackColor du Bouton2 au Bouton1.

warning Attention le signe '=' signifie par contre 'égal' quand il s'agit d'évaluer une condition, par exemple dans une instruction If Then (Si Alors):
If A=B then 'signifie: Si A égal B alors...


V-C-1. Permutation de variables:

C'est un petit exercice:

J'ai 2 variables A et B contenant chacune une valeur.

Je voudrais mettre dans A ce qui est dans B et dans B ce qui est dans A.

Si je fais

A=B

B=A

Les 2 variables prennent la valeur de B!!

Comment faire pour permuter?

Et bien il faut utiliser une variable intermédiaire C qui servira temporairement à conserver le contenu de la variable A:

C=A

A=B

B=C

  A B C
Départ 1 2 0
C=A 1 2 1
A=B 2 2 1
B=C 2 1 1
Voila, on a bien permuté.


V-D. Les variables.


V-D-1. Les variables.

C'est le même sens qu'en mathématique.

Une variable sert à stocker un nombre, du texte (chaîne de caractères), une date, un objet..

Une variable a un nom et un type qui indique ce que l'on peut y mettre.

Si myString est une variable de type chaîne de caractère (ou String) : je peux y mettre une chaîne de caractère (« TOTO » par exemple)

myString="TOTO"

Si age est une autre variable de type numérique, je peux y stocker un nombre (45,2 par exemple).

age=45,2


V-D-1-a. Nom des variables :

On peut utiliser dans les noms de variable des majuscules ou des minuscules mais pour VB il n'y a pas de différence.

Exemple :

On ne peut pas déclarer une variable VB et une variable vb.

Si on déclare une variable nommée 'VB' et si ultérieurement on tape 'vb', le logiciel le transforme automatiquement en 'VB'.

  • On peut mettre des chiffres et des lettres dans les noms de variable mais pas de chiffres en premier caractère.
    2A n'est pas un nom valide
    Nom2 l'est.

  • Certains caractères de ponctuation (‘ »..) ne peuvent pas être utilisés, d'autres "_" et "–" sont permis :
    nom_Utilisateur est valide.
    L'espace n'est pas permis.

  • Bien sur, les mots clé de VB ne peuvent pas être utilisés : On ne peut pas nommer une variable Form ou BackColor
Il est conseillé de donner des noms explicites qui rappelle ce que contient la variable:

nom_Utilisateur est explicite, pas NU.

Parfois on indique en début de nom, par une lettre, le type de variable ou sa portée (la zone de code où la variable existe).

s_Nom 'Le s indique qu'il s'agit d'une variable String (Chaîne de caractères)

iIndex 'Le i indique qu'il s'agit d'une variable Integer (Entier)

gNomUtilisateur 'g indique que la variable est globale

Il est possible de 'forcer' le type de la variable en ajoutant un caractère spécial à la fin du nom de la variable.

Dim c$ = "aa" ' $ force c a être une variable String.

De même % force les Integer, & les long..

Cette notation est moins utilisée.

Voir en annexe, en bas de page des recommandations supplémentaires.

Majuscules ++++:

info On conseille, quand le nom d'une variable est composé de plusieurs mots, de mettre la première lettre de chaque mot en majuscule, sauf pour le premier mot.
Exemple:

nom_Utilisateur


V-D-1-b. Déclaration, initialisation:

Avant d'utiliser une variable, il faut la déclarer, la créer, pour cela on utilise l'instruction Dim:

Dim a As Integer    'Déclare une variable nommée 'a' de type Entier
Avant la ligne, a n'existait pas, après le DIM, a existe et contient 0.

L'instruction Dim crée la variable et lui alloue un espace de stockage.

Il faut aussi parfois l'initialiser, c'est à dire lui donner une valeur de départ : a=3

On peut déclarer et initialiser en même temps:

Dim a As Integer =3
Rien n'empêche d'utiliser une expression , une fonction pour initialiser.

Dim a As Integer = CalculMaVariable(4,3)
Ici pour initialiser la variable, on appelle une fonction CalculMaVariable qui retourne une valeur pour a.

info Il est toujours préférable d'initialiser rapidement une variable.
On peut déclarer plusieurs variables en même temps; il faut les séparer par des virgules:

Dim a, b, c As Integer        'a, b et c sont maintenant des variables de type integer.

V-D-1-c. En pratique: Exemple.

Les variables après avoir été déclarées, vont servir à stocker des données, à effectuer des calculs, on peut afficher ensuite leur valeur.

Exemple simpliste d'utilisation de variables:

Dim varA As Integer 'Création d'une variable varA

Dim varB As Integer 'Création d'une variable varB

Dim total As Integer 'Création d'une variable total

varA=3 'Mettre '3' dans a

varB=2 'Mettre '2' dans b

total=varA + varB 'Mettre dans la variable 'total' la valeur de varA et de varB

LabelTotal.Text= total.ToString 'Afficher le total dans un label (un label est une zone permettant d'afficher du texte), pour cela transformer la variable total qui est un entier en chaîne de caractères (à l'aide de ToString) puis mettre la string dans le texte du label.

Noter bien la différence entre :

Dim total As Integer
total= 123 'Total est une variable numérique (Integer ou Entier) contenant le nombre 123

et

Dim total2 As String
total2= "123" 'Total2 est une variable string contenant la chaîne de caractère "123" c'est à dire les caractères "1" , "2" et "3"

idea On peut afficher les chaînes de caractères (ou String), pas les variables numériques.
On fait des calculs avec les variables numériques.
Il faudra donc parfois convertir le contenu d'une variable d'un type dans un autre type.( convertir une variable numérique en String pour l'afficher par exemple ou convertir une variable String en numérique pour faire un calcul) on apprendra cela plus loin.

L'exemple simpliste juste au dessus en montre un exemple: il faut convertir total qui est un entier en string pour l'afficher.

Concernant les variables numériques:

Les variables numériques peuvent être signées (accepter les valeurs négatives ou positives) ou non signées ( Comme le Type 'Byte' qui ne contient que des valeurs positives)


V-D-1-d. Les différents types de variable:

En Visual Basic:

Nom : Contient :
Boolean Contient une valeur Booléenne (logique): True ou False.
Byte Contient les nombres entiers de 0 à 255 (sans signe)
Short Entier sur 16 bits (-32768 à 32768)
Integer Entier sur 32 bits (-2147483648 à 2147483647)
Long Entier sur 64 bits (-9223372036854775808 à 9223372036854775807)
Single Nombre réel en virgule flottante (-1,401298 *10^-45 à 1,401298 10^45)
Double Nombre réel en virgule flottante double précision. (..puissance 324)
Decimal Nombre réel en virgule fixe grande précision sur 16 octets.
Char 1 caractère alphanumérique
String Chaîne de caractère de longueur variable (jusqu'a 2 milliard de caractères)
DateTime Date plus heure
Object Peut contenir tous les types de variables mais aussi des contrôles, des fenêtres..
Structure Ensemble de différentes variables définies par l'utilisateur.
Dans la version 2005 il y a aussi les Unsigned ( non signé: pas de valeur négative):
UInteger Entier codé sur 32 bits pouvant prendre les valeurs 0 à 4 294 967 295.
ULong Entier codé sur 64 bits :0 à 18 446 744 073 709 551 615
UShort Entier sur 16 bits 0 à 65 535.
et  
SByte Byte mais signé. Codé sur 1 octet, valeur de -128 à 127

V-D-1-e. Détaillons :

Contient une valeur Booléenne : True ou False (Vrai ou Faux pour les sous doués en anglais!)

Exemple:

Dim myBoolean As Boolean

myBoolean = True

V-D-1-f. Variable entière:

Byte Contient les nombres entiers de 0 à 255 (sans signe)
Short Entier sur 16 bits (-32768 à 32768)
Integer Entier sur 32 bits (-2147483648 à 2147483647)
Long Entier sur 64 bits (-9223372036854775808 à 9223372036854775807)
Pour une variable entière il n'y a pas de possibilité de virgule!! attention, une division de 2 entiers donne un entier.

Pour le mathématicien, les Integer correspondent au nombres entiers naturels: Entiers positif ou négatif et 0 (..-3 -2 -1 0 1 2 3...), mais avec une limite.

warning Attention ,les variables numériques en informatique ne peuvent pas contenir de nombre infiniment grand: Il y a une limite maximum : un Integer est par exemple codé sur 32 bits ce qui fait qu'il peut varier de -2147483648 à 2147483647. Si on utilise une valeur trop grande, une erreur se produit. Les entiers peuvent être positifs ou négatifs (Sauf les Bytes et les 'Unsigned': UInteger, ULong, UShort).
Plus on augmente le type (Long au lieu de Integer) plus on peut y mettre des grands nombres. Mais cela prend aussi plus de place et le traitement des opérations est plus long.

Les processeurs travaillant sur '32 bits', utilisez plutôt les Integer (qui sont codés sur 32 bits aussi), c'est plus rapide, que les short.

On utilise largement les 'Integer' comme variable de boucle, Flag, là ou il y a besoin d'entier...(Les calculs sur les réels en virgule flottante sont beaucoup plus lent.)

Exemple:

Dim i As Integer

i=12
Le type de données Byte est utilisé pour contenir des données binaires (octet codant de 0 à 255) non signé.


V-D-1-g. Variable avec virgule:

Un réel peut avoir une partie fractionnaire: 1,454 est un réel.

Pour le mathématicien, les Single, Double.. correspondent au nombres réels ou fractionnaires: mais avec des limites ( sur le précision et le fait qu'il ne sont pas infinis.

Single, Double, Decimal.

Single Nombre réel en virgule flottante (-1,401298 *10^-45 à 1,401298 10^45)

Double Nombre réel en virgule flottante double précision. (-1,79769313486231570E+308 et -4,94065645841246544E-324 pour les valeurs négatives et entre 4,94065645841246544E-324 et 1,79769313486231570E+308 pour les valeurs positives)

Decimal Nombre réel en virgule fixe grande précision sur 16 octets: Avec une échelle 0 (aucune décimale), la plus grande valeur possible correspond à +/-79 228 162 514 264 337 593 543 950 335. Avec 28 décimales, la plus grande valeur correspond à +/-7,9228162514264337593543950335

Les variables en virgule flottante ou notation scientifique:

(Single, Double)

La variable peut être positive ou négative.

Le 'Double' est, bien sur, plus précis et peut atteindre des nombres plus grand que le 'Single'.

Le 'Single' comporte 7 chiffres significatifs maximum.

Le 'Double' comporte 18 chiffres significatifs maximum.

Le nombre est codé en interne sous forme scientifique, exemple:1,234568E+008.

Mais en pratique, on travaille et on les affiche de manière habituelle, en notation normale avec un point comme séparateur décimal:

Dim poids As Single

poids=45.45

Format Scientifique, Mantisse et exposant:

Voici 3 nombres:

14500000
0,145
0,0000145

Ils comportent tous les 3, deux informations:
  • le nombre entier 145
  • la localisation du premier chiffre par rapport à la virgule
8
-1
-5 dans nos exemples.

Donc un réel peut être stocké sous la forme d'un couple:
  • Partie entière
  • Localisation de la virgule
Il est codé en interne avec une mantisse (la partie entière) et un exposant (position de la virgule), sous la forme mmmEeee, dans laquelle mmm correspond à la mantisse (chiffres significatifs: partie entière) et eee à l'exposant (puissance de 10).

En fait, en notation scientifique (en codage interne) un chiffre précède toujours la virgule: 1,234568E+008.

warning Attention ,les variables numériques réelles ne peuvent pas contenir de nombre infiniment grand: Il y a une limite maximum comme pour les entiers. La valeur positive la plus élevée d'un type de données Single est 3,4028235E+38 et celle d'un type de données Double est 1,79769313486231570E+308. Si on dépasse cette valeur VB le signale en déclenchant une erreur.
Quand on travaille avec des nombres ayant beaucoup de chiffres significatifs, il peut y avoir des erreurs d'arrondi. Le type 'Single' comporte par exemple une mantisse de 7 chiffres significatifs seulement. Si on utilise des nombres (même petit: avec un exposant négatif par exemple)avec 8 chiffres significatifs il peut y avoir des erreurs d'arrondi.

Le type de données en Virgule fixe (Decimal) prend en charge jusqu'à 29 chiffres significatifs et peut représenter des valeurs jusqu'à 7,9228 x 10^28. Ce type de données est particulièrement adapté aux calculs (par exemple, financiers) qui exigent un grand nombre de chiffres, mais qui ne peuvent pas tolérer les erreurs d'arrondi.

info Pour les calculs financiers ont utilisera les 'Decimal' ou les 'Double'
Pour les petits calculs du genre résultats d'examen biologique ont utilisera les 'Single' ou les 'Double' qui sont les plus rapides.
Pour les variables de boucle, les index, on utilise habituellement des Integers.


V-D-1-h. String, Char:

Le type 'String' peut contenir une 'chaîne de caractères' (alphanumérique) comme du texte. La longueur de la chaîne n'est pas fixe et une String peut avoir un nombre de caractère allant de 0 jusqu'à environ 2 milliards de caractères.

Les chaînes de longueur fixe n'existent pas (plus).

Le Type 'Char' contient un seul caractère. On utilise souvent des tableaux de 'Char'.

Pour information Char et String contiennent des caractères au format Unicode (dans la variable,chaque caractère est codé sur 2 octets) et pas de l'ASCII ou de l'ANSI..(ancien codage ou chaque caractère était codé sur un octet).

Les premiers caractères ont le même code Unicode et Ascii.

Exemple:

Caractère Code
"a" 65
"b" 66
" " 32
Il y a aussi des caractères non affichable:

RC 13 retour chariot
LF 10 Line Feed
  9 Tabulation
Pour passer à la ligne , on utilise les codes 13 puis 10. Il y a une constante toute faites pour cela: ControlChars.CrLf Chr$(13)+Chr$(10)


V-D-1-i. Annexe 1:Place occupée en mémoire:

Les types de variable ont un nom en VisualBasic et un nom dans le Framework.

Exemple:

Integer et System.Int32 sont équivalents pour designer le type 'entier', Integer est le type VB, System.Int32 est le type 'NET'

Exemple de place occupée par une variable (et le nom de sa Classe dans NET).

Type VB Place occupée Type NET correspondant
Boolean 2 octets System.Boolean
Byte 1 octet System.Byte
Short 2 octets System.Int16
Integer 4 octets System.Int32
Long 8 octets System.Int64
Single 4 octets System.Single
Double 8 octets System.Double
Decimal 16 octets System.Decimal
Date 8 octets System.DateTime
Char 2 octets System.Char
Objet 4 octets System.Objet
String dépend de la chaîne System.String
La méthode GetType permet de savoir de quel type, de quelle Classe est une variable.

Dim x As String 

MessageBox.Show(x.GetType.ToString)    'Affiche: Systeme.String
Prend le type de x, le transforme en String, l'affiche dans une MessageBox.


V-D-1-j. Annexe 2: Type primitif

Mise à part Objet, Structure, Class tous les autres types sont dit 'Primitif'( Byte, Boolean, Short, Integer, Long, Single, Double, Decimal, Date, Char, String)

  • Tous les types primitifs permettent la création de valeurs par l'écriture de littéraux. Par exemple, i=123 ou i=123I (le I force 123 a être entier) est un littéral de type Integer.
  • Il est possible de déclarer des constantes des types primitifs.
  • Lorsque qu'une expression est constituée de constantes de type primitif, le compilateur évalue l'expression au moment de la compilation. C'est plus rapide.

V-D-1-k. Annexe 3: Choix des noms de variable

  • La plupart des noms sont une concaténation de plusieurs mots, utilisez des minuscules et des majuscules pour en faciliter la lecture.
  • Pour distinguer les variables et les routines (procédures), utilisez la casse Pascal (CalculTotal) pour les noms de routine (la première lettre de chaque mot est une majuscule).
  • Pour les variables,la première lettre des mots est une majuscule, sauf pour le premier mot (documentFormatType).
  • Les noms de variables booléenne doivent contenir Is qui implique les valeurs Yes/No ou True/False, Exemple fileIsFound.
  • Même pour une variable à courte durée de vie qui peut apparaître uniquement dans quelques lignes de code, utilisez un nom significatif. Utilisez des noms courts d'une seule lettre, par exemple i ou j, pour les index de petite boucle uniquement.
  • N'utilisez pas des nombres ou des chaînes littérales telles que For i = 1 To 7. Utilisez plutôt des constantes nommées, par exemple For i = 1 To Nombre_jour_dans _semaine, pour simplifier la maintenance et la compréhension.
  • Utilisez des paires complémentaires dans les noms de variables telles que min/max, begin/end et open/close ou des expressions min max si nécessaire en fin de nom.

V-D-2. Variables 'String' et 'Char'


V-D-2-a. A- STRING

Il faut déclarer une variable avant de l'utiliser, pour cela on utilise l'instruction DIM

DIM STR As String 
‘Déclare une variable nommée Str et qui peut contenir une chaîne de caractère.

Cette variable peut être utilisée pour conserver une chaîne de caractère.

STR= "TOTO"

'On met la chaîne de caractères "TOTO" dans la variable STR

On peut afficher le contenu de la chaîne dans un label (zone présente dans une fenêtre et ou on peut afficher du texte) par exemple :

      Label.text = STR
Cela affiche 'TOTO' dans le label.

Remarquons que pour définir une chaîne de caractères il faut utiliser des " " : Ce qui est entre " et " est la chaîne de caractères. On parle de chaîne littérale: (une représentation textuelle d'une valeur particulière)

warning Après avoir été créée, une String contient 'Nothing' c'est à dire rien (même pas une chaîne vide: ""); il faudra l'initialiser pour qu'elle contienne quelque chose.

DIM str As String    'str contient Nothing 
(pas le texte "Nothing"!! cela signifie qu'elle ne pointe sur 'rien'

str= ""              'str contient "" : chaîne vide de longueur 0

str= "TOTO"          'str contient "TOTO"
Notez bien l'importance des guillemets:

A est la variable A

"A" est une chaîne de caractères contenant le caractère "A"

Exemple:

Dim A As String= "Visual"

Dim B As String= "Basic"

Label.text = "A+B"  affiche bêtement la chaîne  « A+B »

Label.text =  A+B    affiche "VisualBasic"on affiche les variables.    
Notez enfin que " ", l‘espace est un caractère à part entière.

Si je veux inclure un caractère " dans la chaîne il faut le doubler pour qu'il ne soit pas considérer comme caractère de fin de chaîne:

A=" Bonjour ""Monsieur"" "    'Afficher cela donne :  Bonjour "Monsieur"
On peut initialiser la variable en même temps qu'on la déclare.

Dim Chaine as string = "Toto"
On peut déclarer plusieurs variables d'un même type sur une même ligne.

Dim x, y, z As String    'Déclare 3 variables 'String'
On utilise GetType pour connaître le type d'une variable.

x.GetType.ToString

y.GetType.ToString

z.GetType.ToString
donne

System.String

System.String

System.String
Ce qui prouve que les 3 variables sont bien des Strings. (ce qui n'était pas le cas en VB6)


V-D-2-a-i. 1- System.String est une Classe du Framework:
Le type System.String ou String (Chaîne de caractères) est une Classe qui a des méthodes.

info Pas besoin de connaître toutes les méthodes, il suffit (Après déclaration de la String par DIM réponse AS String) de taper "." .Et vous voyez apparaître toutes les propriétés et méthodes :
Par exemple la méthode .ToUpper

Mettre en majuscules une chaîne de caractère

      str=str.ToUpper()

                Si str contenait "abc"   il contiendra "ABC"
.ToLower transforme par contre la chaîne en minuscule.

Quel intérêt ? Exemple

Je dois comparer 2 string pour savoir si elle sont égales, la première a été saisie par l'utilisateur et je ne sais pas si l'utilisateur a tapé en majuscule ou en minuscules.

Si je compare A = "Vb" et B= "vb" elles sont différentes.

Si je compare A.ToLower et B.ToLower elles sont égales.

.Trim

Permet de supprimer des caractères en début et fin de chaîne.

Dim a As String = "#@Informatique@#"

Dim b As Char() = {"#", "@"}    'b est un tableau de Char contenant les caractères à supprimer.

a=a.Trim(b)  Donne a= "Informatique" 
warning Attention : Bien utiliser Char() qui est un tableau de caractères pour définir les caractères à supprimer.
(Dim b As String= "#@" est déconseillé car produisant des résultats curieux.)

Pour enlever les espaces avant et après la chaîne (Cas le plus fréquent) :

a=" Bonjour "

a=a.Trim(" ")    'donne a="Bonjour"
Il existe aussi TrimStart et TrimEnd pour agir seulement sur le début ou la fin de la chaîne.

Length : Taille d'une chaîne en nombre de caractère.

Afficher la taille de la chaîne « VB »

Dim s As String= "VB"

MsgBox(s.Length.ToString) ‘Affiche 2 
Concat :

Concaténation de plusieurs chaînes : mise bout à bout :

s=String.Concat(a,b)
Il est plus rapide de faire : s= a & b

(s=a+b marche mais est déconseillé)

Insert :

Insère une chaîne dans une autre.

Dim s As String= "VisualBasic"

s= s.Insert(6,"  " ) ‘Donne s= "Visual  Basic" 
Noter: le premier caractère a la position 0.

Remove :

Enlève des caractères à une certaine position dans une chaîne.

Dim s As String= "VisualBasic"

s= s.Remove(2,7 ) ‘Donne s= "Viic" 
Replace :

Remplace dans une chaîne de départ, toutes les occurrences d'une chaîne par une autre.

Resultat=ChaineDépart.Replace(ChaîneARemplacer,ChaîneQuiRemplace)

Dim s As String= "Visual_Basic"

s= s.Replace("_"," " ) ‘Donne s= "Visual  Basic"
Autre exemple:

L'utilisateur a tapé une date, mais avec comme séparateur des ".", comme on le verra plus loin, il est nécessaire d'utiliser plutôt les "/", pour cela on utilise Replace

Dim ladate as string= "12.02.1990"

ladate= ladate.Replace(".","/" ) ‘Donne ladate= "12/02/1990"
Split :

Découpe en plusieurs sous chaînes une chaîne de départ, cela par rapport à un séparateur.

Exemple :

Je récupère dans un fichier une chaîne de mots ayant pour séparateur « ; », je veux mettre chaque mot dans un tableau.

‘Chaîne contenant les mots séparés par « ; »

Dim s As String= "Philippe;Jean ;Toto"  

Dim separateur As Char = ";"

Dim nom() As String

nom=s.Split(separateur)
Donne :

      nom(0)= "Philippe"

      nom(1)= "Jean"

      nom(2)= "Toto"
info Remarque: Quand on déclare le tableau nom(), on ne donne pas le nombre d'élément, c'est Split qui crée autant d'élément qu'il faut.
En Framework 2, on peut utiliser plusieurs séparateurs différend:

nom=s.Split( New Char() {" "c, ","c, "."c }) ici on a 3 séparateurs: l'espace, la virgule et le point.
le c après chaque séparateur veut dire Char, car les séparateurs sont des caractères.

On peut ajouter 2 paramètres permettant d'indiquer le nombre de ligne maximum et forcer l'élimination des lignes vides.

Dim sep() As Char={" "c, ","c, "."c}

Dim nom() As String = S.Split ( sep, 100, StringSplitOptions.RemoveEmptyEntries ) 

Allons encore plus loin: avant et après le séparateur il peut y avoir des espaces:

Il faut dans ce cas utiliser la méthode Split de la classe Regex:

Imports System.Text.RegularExpressions

Dim S As String = "abc ; def ; ghi"

' On crée un Regex

Dim R As New Regex("\s*;\s*")

' décomposition de ligne en champs

Dim Nom As String() = R.Split(S)
.Join

Concatène tous les éléments d'un tableau et peut ajouter des séparateurs.

Si myLines() est un tableau de String , je veux ajouter ces lignes bout à bout en les séparant d'un retour à la ligne.

Dim myText As String = String.Join ( ControlChars.CrLf, myLines)
.IndexOf .LastIndexOf

Indique le numéro du caractère, la position (la première occurrence) ou une chaîne à chercher est trouvée dans une autre. Recherche en commençant par la fin avec LastIndexOf

Dim a As String= "LDF.EXE"

Dim r As Char()={"."}

a.IndexOf(r)  retourne 3
warning Se souvenir : le premier caractère est en position 0 en .Net.
.LastIndexOf retourne la dernière occurrence.

.IndexOfAny .LastIndexOfAny (Framework 2)

Indique le numéro du caractère, la position (la première occurrence) ou une chaîne à chercher est trouvée dans une autre avec en plus possibilité d'indiqué la position de départ.

Dim a As String= "LDF.EXE"

Dim r As Char()={"."}

a.IndexOfAny(r)  recherche à partir du début de chaîne.

a.IndexOfAny(r,2)  recherche à partir du deuxième caractère.
Autre exemple: On recherche ici plusieurs caractères (en fait un tableau de Char)

Dim str As String ="gfdjzak;,vdqsygeak"

Dim start As Integer =2

Dim at As Integer 

Dim count As Integer =5

Dim target As String = "ou" 'chaîne à chercher 

Dim anyOf As Char() = target.ToCharArray() 'on transforme la chaîne en tableau de char 

at = str.IndexOfAny(anyOf, start, count) 'on cherche le tableau de Char anyOf dans str à partir de la position start et sur count caractères.
.Compare

Compare 2 chaînes :

Dim rep As Integer

rep=String.Compare(a,b)
Retourne un entier

      Négatif si a<b

      0 si a=b

      Positif si a>b
On peut comparer des sous chaînes et indiquer la sensibilité à la casse (Framework 2):

rep= String.Compare(a, 2, b, 2, 10, True)
Ici on compare 10 caractères en commençant par le deuxième caractère de chaque chaîne en mode sensible à la casse (majuscules<>minuscule).

.Contains

Permet de savoir si une chaîne apparaît dans une autre: (Framework 2)

Dim trouve As Boolean

trouve = a.Contains( "123")
Retourne True ou False

.Substring

Extrait une partie d'une chaîne.

Le premier paramètre indique la position de départ; le second, le nombre de caractères à extraire.

Dim a As String= "Informatique"

MessageBox.show(a.Substring(2,3)) ‘Affiche  for
Le premier paramètre indique la position du caractère où doit commencer la sous-chaîne, en commençant à la position 0. (les caractères sont comptés 0, 1, 2, 3....

Le second paramètre la longueur de la sous-chaîne.

Exercice 1: comment obtenir les 4 caractères de droite:

Dim a As String= "Informatique"

MessageBox.show(a.Substring(A.Length-4)) ‘Affiche  ique
Ici on omet le second paramètre,la longueur de la sous-chaîne, va jusqu'a la fin de la chaîne.

Exercice 2: comment obtenir les 3 caractères de gauche:

Dim a As String= "Informatique"

MessageBox.show(a.Substring(0, 3)) ‘Affiche  inf
.Chars

Une chaîne peut être perçue comme un tableau de caractères (instances Char) ; vous pouvez extraire un caractère particulier en faisant référence à l'index de ce caractère par l'intermédiaire de la propriété Chars. Par exemple :

Dim maString As String = "ABCDE"
Dim monChar As Char
monChar = maString.Chars(3) ' monChar = "D"
On peut créer des chaînes avec la Classe String:

myString = New String(" ", 15)    'Créer une chaîne de 15 espaces
.PadRight

Aligne les caractères de cette chaîne à gauche et remplit à droite en ajoutant un caractère Unicode spécifié pour une longueur totale spécifiée.

Dim str As String
Dim pad As Char
str = "Nom"
pad = Convert.ToChar(".") 
Console.WriteLine(str.PadRight(15, pad)) ' Affiche Nom............
PadLeft fait l'inverse.

.StartsWith() et EndsWith()

Permettent de tester si une string commence ou se termine par une string, retourne True ou False.

Tester si la String s commence par "abc" et se termine par "xyz":

If s.StartWith ("abc") And s.EndWith ("xyz") then
En VB 2005, on peut ajouter un argument gérant la culture ou la casse.

.IsNull , IsNullOrEmpty() Framework 2

Il est parfois nécessaire de vérifier si une chaîne est égale à Nothing ou de longueur égale à 0 (vide).

If S Is Nothing AndOr S.length=0 then
Ou

If String.IsNullOrEmpty( S) then

V-D-2-a-ii. 2- On peut aussi utiliser les instructions 'Visual Basic':
Si vous débuter, laisser de coté ces instructions Visual Basic: elle font double emploi avec la classe String, elle ne sont pas toujours cohérentes avec le reste et cela embrouille.

Utiliser uniquement la classe String.

Elles sont bien connues des 'anciens' et font partie intégrante de VisualBasic) et sont parfois plus simples. Mais elles ne fonctionnent pas comme des Objets mais comme des instructions.

Elle font partie de l'espace de nom Microsoft.VisualBasic, il est 'chargé' par défaut et il n'y a pas lieu de l'importer. Par contre quand certains 'mots' sont communs à plusieurs classes ou instructions, il peut y a avoir ambiguïté et il faut utiliser dans ce cas la syntaxe complète. Cela semble le cas pour left qui est un mot clé Vb mais aussi une propriété des contrôles. Pour lever l'ambiguïté il faut écrire Microsoft.VisualBasic.left(C,i) par exemple.

Ces méthodes font souvent double emploi avec les méthodes de la classe String:

warning Attention : le premier caractère est en position 1 dans les instructions VB.
Mid:

Permet de récupérer une sous-chaîne.

MaString = "Mid Demonstration" 
a = Mid(MaString, 1, 3) ' Retourne "Mid".
Retourne 3 caractères à partir du premier

Le premier paramètre indique la position du caractère où doit commencer la sous-chaîne, en commençant à la position 1. (les caractères sont comptés 1, 2, 3...; on rappelle qu'avec SubString la sous-chaîne, commence à la position 0.

a = Mid(MaString, 14) ' Retourne "tion": du 14ème à la fin (pas de 3ème argument)

Mid permet aussi de remplacer une string dans une string

Mid(MaString, 1, 3) = "Fin" => MaString="Fin Demonstration"

Left, Right (Pas d'équivalent dans le Framework)

Retourne x caractères de gauche ou de droite:

a=Right(MaString,2) 'a="on"

a=Microsoft.VisualBasic.Left(MaString,2) 'a="Mi"

Notez bien que, pour lever toute ambiguïté avec les méthodes left d'autres classes, il faut indiquer Microsoft.VisualBasic.Left.

Len.

Retourne la longueur de la chaîne:

MyLen = Len(MaString) ' Retourne 17.

LTrim, RTrim

Enlève les espaces à gauche ou à droite d'une chaîne.

a=LTrim(" RRRR") ' a="RRR"

InStr

Retourne un entier spécifiant la position de début de la première chaîne à l'intérieur d'une autre.

n=InStr(1,"aaaaRaa","R")        'retourne 5
Recherche à partir du premier caractère, à quelle position se trouve 'R' dans la chaîne "aaaaRaa"

Si la chaîne n'est pas trouvée , retourne 0

InStrRev

Recherche aussi une chaîne mais de droite à gauche. la position de départ est le 3ème argument.

InStrRev (Ch1, Ch2 , PosDépart)

StrComp Compare 2 chaînes.

Space

Retourne une chaîne d'espace: Space(10) retourne " "

StrDup

Retourne une chaîne de caractères par duplication d'un caractère dont on a spécifié le nombre.

maString = StrDup(5, "P") ' Retourne "PPPPP"
Asc

Retourne le code de caractère du caractère entré. Il peut être compris entre 0 et 255 pour les valeurs du jeu de caractères codé sur un octet (SBCS) et entre -32 768 et 32 767 pour les valeurs du jeu de caractères codé sur deux octets (DBCS). La valeur retournée dépend de la page de codes

AscW retourne le code Unicode du caractère entré. Il peut être compris entre 0 et 65 535.

x=Asc("A") 'retourne 65

x=Asc("ABCD") 'retourne 65 : Seul le premier caractère est pris en compte

Chr et ChrW

Retourne le caractère associé au code de caractère.

Chr(65) retourne "A" 'cela dépend de la page de code.

On peut donner le numéro du caractère en hexadécimal, dans ce cas on le fait précéder de &H

Chr(&H20) est équivalent de Chr(32) et retourne un caractère " ".

ChrW retourne le caractère correspondant à l'Unicode

GetChar

Retourne le caractère d'une chaîne à une position donnée.

Dim maString As String = "AIDE"
Dim monChar As Char
monChar = GetChar(maString, 3) ' monChar = "D"
 
LCase Ucase

Retourne la chaîne en minuscule ou majuscule:

Lowercase = LCase(UpperCase)
Lset Rset

Retourne une chaîne alignée à gauche avec un nombre de caractère.

Dim maString As String = "gauche"
Dim r As String
r = LSet(maString, 2) ' Retourne "ga" 

Si la chaîne de départ est plus courte que la longueur spécifiée, des espaces sont ajoutés.
r = LSet(maString, 8) ' Retourne "gauche  "
StrRevers

Retourne une chaîne ou les caractères ont été inversés:

Dim maString As String = "STRESSED"

Dim revString As String

revString = StrReverse(myString)    ' Retourne "DESSERTS"
Marrant l'exemple!!

Filter (VB2005)

Passe les Strings d'un tableau dans un autre tableau, si elles contiennent ou non une chaîne.

TableauResultat= Filter( TableauChaine, Match, Include, Compare) 
Match: chaîne à chercher.

Include: Filtre sur la présence ou non de la chaîne a chercher.

Compare: en binaire ou en texte (majuscules = minuscules dans ce cas)

Dim TestStrings(2) As String
TestStrings(0) = "Ici"
TestStrings(1) = "Si"
TestStrings(2) = "si"
Dim subStrings() As String	'Chaîne des résultats

subStrings = Filter(TestStrings, "i", True, CompareMethod.Text)
'Retourne "Ici","Si","si"

subStrings = Filter(TestStrings, "si", True, CompareMethod.Binary)
' Retourne "si".

subStrings = Filter(TestStrings, "si", False, CompareMethod.Binary)
'Retourne "Ici","Si"
Like:

Instruction hyper puissante: Like, elle compare une chaîne String avec un modèle (Pattern), elle permet de voir si la chaîne contient ou ne contient pas un ou des caractères, ou une plage de caractères. (c'est l'équivalent des expressions régulières du Framework)

result = String Like Pattern

Si string correspond à pattern, la valeur de result est True ; s'il n'y a aucune correspondance, la valeur de result est False. Si string et pattern sont une chaîne vide, le résultat est True. Sinon, si string ou pattern est une chaîne vide, le résultat est False.

L'intérêt de Like est que l'on peut y mettre des caractères génériques:

? veut dire tout caractère unique

* veut dire * ou plusieurs caractères.

# veut dire tout chiffre.

[caractères] veut dire tout caractères présent dans la liste.

[!caractères] veut dire tout caractères NON présent dans la liste.

- trait d'union permet de spécifier un début et une fin de plage.

Exemple:

Dim R As Boolean
R = "D" Like "D" ' Est ce que "D" est égal à "D"? => True.


R = "F" Like "f" ' Est ce que "F" est égal à "f"? => False.


R = "F" Like "FFF" ' Est ce que "F" est égal à "FFF"? => False.


R = "cBBBc" Like "c*c" ' Est ce que "cBBBc" répond au pattern (avoir un "c" au 
'début, un  "c" à la fin, et des caractères au milieu? Retourne True.


R = "J" Like "[A-Z]" ' Est ce que "J" est contenu dans les caractères allant de
'  A à Z? Retourne True.


R = "I" Like "[!A-Z]" ' Est ce que "I" n'est PAS dans les caractères allant de
'  A à Z? Retourne  False.


R = "a4a" Like "a#a" ' Est ce que "a4a" commence et finie par un
' "a" et à un nombre entre les 2? Retourne True.


R = "bM6f" Like "b[L-P]#[!c-e]" ' Est ce que "bM6f" 

'commence par  "b",

'a des caractères entre L et P

'un nombre

'se termine par un caractère non compris entre c et e

'retourne True

V-D-2-a-iii. 3- Un exemple:
Combinaison de chaînes de caractères, de variables..

Souvent, on a besoin d'afficher une combinaison de chaînes littérales, le contenu de variables, des résultats de calcul; c'est possible.

Exemple :

Pour afficher dans un label le carré de X est X2, avec une valeur dans la variable x :

Dim X As Integer = 2

Label1.text= "Le carré de " & X & "  est " & X * X
Ce qui est entre guillemets est affiché tel quel. C'est le cas de "Le carré de " et de " est "

Ce qui n'est pas entre guillemets est évalué, le résultat est affiché. C'est le cas de X et X*X

Pour ne faire qu'une chaîne on ajoute les bouts de chaînes avec l'opérateur '&'.

Notez l'usage d'espace en fin de chaîne pour que les mots et les chiffres ne se touchent pas.

Dim X As Integer

X=2
Label1.text= "Le carré de " & X & " est " & X * X

Affiche dans le label : « Le carré de 2 est 4 »

Voir des exemples de code dans ve1-1


V-D-2-a-iv. 4- Comparaison de caractères et 'Option Compare'
On peut comparer 2 String

Dim s1 As String ="ABCD"

Dim s2 As String ="XYZ"
Dans ce cas s1<s2 est vraie.

Par défaut (Option Compare Binary)

Les caractères sont classés dans un ordre croissant (l'ordre de leur code unicode)

Voyons l'ordre des certains caractères particuliers:

" " +,-./ 0123456789 :;ABCDEF abcdef èéê

On constate que l'ordre est espace puis quelques caractères spéciaux, les chiffres, les majuscules puis les minuscules, les accentués.(voir le tableau d'unicode)

Ainsi B<a

En utilisant Option Compare Binary, la plage [A–E] correspond à A, B, C, D et E.

Avec Option Compare Text

Les caractères sont classées dans un ordre qui reflète plus la réalité d'un texte:

Toutes les types de a: A, a, À, à, puis tous les types de b: B, b...

Avec Option Compare Text, [A–E] correspond à A, a, À, à, B, b, C, c, D, d, E et e. La plage ne correspond pas à Ê ou ê parce que les caractères accentués viennent après les caractères non accentués dans l'ordre de tri.

Ainsi B>a

L'ordre des caractères est donc défini par Option Compare et aussi les paramètres régionaux du système sur lequel s'exécute le code.

Grande règles de comparaison:

La comparaison s'effectue de gauche à droite.

La comparaison s'effectue sur le premier caractère de chaque chaîne.

Si le premier caractère est identique, la comparaison se fait sur le deuxième caractère...

"zz" > "za" est vrai

En cas de chaîne du type "zz" et "zzz" , la seconde est supérieure

"zz" < "zzz" est vrai

Il y a quelques pièges:

Si je veux créer des chaînes du genre 'un nombre puis le mot string' et qu'elles soient classées dans un ordre logique pour l'humain.

Je vais taper: "1string", "2string", "10string", "11string", "100string"

Le classement par Vb sera 'surprenant' car les chaînes seront classées dans cet ordre:

"100string", "10string", "11string", "1string","2string"

Pourquoi? c'est l'application stricte des règles de comparaison: regardons le troisième caractère des 2 premières chaînes (les 2 premiers caractères étant égaux), "0" est bien inférieur à "s" donc "100string" < "10string" est vrai!!

Pour résoudre le problème et obtenir un classement correct, il faut écrire des blocs numériques de même longueur et alignés à droite:

Écrire 010string et non 10string.

"001string", "002string", "010string", "011string", "100string" ' ici le trie est dans le bon ordre.


V-D-2-a-v. 5- Unicode:
Les variables string sont stockées sous la forme de séquences de 16 bits (2 octets) non signés dont les valeurs sont comprises entre 0 et 65 535. Chaque nombre représente un caractère Unicode. Une chaîne peut contenir jusqu'à 2 milliards de caractères.

L'unicode est donc un codage de caractères sur 16 bits qui contient tous les caractères d'usage courant dans les langues principales du monde.

Les premiers 128 codes (0–127) Unicode correspondent aux lettres et aux symboles du clavier américain standard. Ce sont les mêmes que ceux définis par le jeu de caractères ASCII (ancien codage sur un octet). Les 128 codes suivants (128–255) représentent les caractères spéciaux, tels que les lettres de l'alphabet latin, les accents, les symboles monétaires et les fractions. Les codes restants sont utilisés pour des symboles, y compris les caractères textuels mondiaux, les signes diacritiques, ainsi que les symboles mathématiques et techniques.

Voici les 255 premiers

Le petit carré indique un caractère non imprimable (non affichable), certains caractères sont des caractères de contrôle comme le numéro 9 qui correspondant à tabulation, le numéro 13 qui correspond au retour à la ligne..


V-D-2-b. B- CHAR.

Les variables Char sont stockées sous la forme de nombres 16 bits (2 octets) non signés dont les valeurs sont comprises entre 0 et 65 535. Chaque nombre représente un seul caractère Unicode. Pour les conversions entre le type Char et les types numériques il y a les fonctions AscW et ChrW qui peuvent être utilisées..

L'ajout du caractère de type littéral C à un littéral de chaîne force ce dernier a être un type Char. A utiliser surtout si Option Strict (qui force à être strict..) est activé.

Exemple:

Option Strict On
' ...
Dim C As Char
C = "A"c
String.ToCharArray:
Permet de passer une string dans un tableau de Char:

Dim maString As String = "abcdefghijklmnop"
Dim maArray As Char() = maString.ToCharArray
La variable maArray contient à présent un tableau composé de Char, chacun représentant un caractère de maString.

Pour mettre le tableau de Char dans une String:

Dim maNewString As String (maArray)
 
String.Chars():
vous pouvez extraire un caractère particulier en faisant référence à l'index de ce caractère par l'intermédiaire de la propriété Chars. Par exemple :

Dim maString As String = "ABCDE"

Dim monChar As Char

monChar = maString.Chars(3) ' monChar = "D"
Un caractère est-il numérique? un chiffre? une lettre? un séparateur? un espace?....

	Dim chA As Char
        chA = "A"c
        Dim ch1 As Char
        ch1 = "1"c
        Dim str As String
        str = "test string"

        Console.WriteLine(chA.CompareTo("B"c))          ' Output: "-1" '  A est plus petit que B
        Console.WriteLine(chA.Equals("A"c))             ' Output: "True" ' Egal?
        Console.WriteLine(Char.GetNumericValue(ch1))    ' Output: 1	 'Convertir en valeur numérique (double)
        Console.WriteLine(Char.IsControl(Chr(9)))       ' Output: "True"'  Est une caractère de contrôle?
        Console.WriteLine(Char.IsDigit(ch1))            ' Output: "True"'  Est un chiffre
        Console.WriteLine(Char.IsLetter(","c))          ' Output: "False"' Est une lettre
        Console.WriteLine(Char.IsLower("u"c))           ' Output: "True" ' Est en minuscule
        Console.WriteLine(Char.IsNumber(ch1))           ' Output: "True" ' Est un nombre
        Console.WriteLine(Char.IsPunctuation("."c))     ' Output: "True" ' Est un caractère de ponctuation
        Console.WriteLine(Char.IsSeparator(str, 4))     ' Output: "True" ' Est un séparateur
        Console.WriteLine(Char.IsSymbol("+"c))          ' Output: "True" ' Est un symbole
        Console.WriteLine(Char.IsWhiteSpace(str, 4))    ' Output: "True" ' Est un espace
        Console.WriteLine(Char.ToLower("M"c))           ' Output: "m"	 ' Passe en minuscule
   
Existe aussi IsLetterOrDigit, IsUpper.

Bien sur si on est en 'Option Strict' il faut ajouter .ToString à chaque ligne:

Console.WriteLine(Char.ToLower("M"c).ToString) 
On note que l'on peut tester un caractère dans une chaîne: Char.IsWhiteSpace(str, 4)

Autre manière de tester chaque caractères d'une String:

Dim V as string

For Each C As Char in V    'Pour chaque caractère de V..

      C...

Next
Ici la String est considérée comme une collection de Char. (C'est aussi une collection de String)

Mais on verra plus loin les collections et les boucles For Each.

Conversions Char <->Unicode

On rappelle que l'unicode est le mode de codage interne des caractères.

Dim monUnicode As Short = Convert.ToInt16 ("B"c) ' le code Unicode  de B est 66.
Dim monChar As Char = Convert.ToChar (66) '   monChar="B"
Si vous souhaiter utiliser Asc et Chr de VisualBasic:

Dim monAscii As Short = Asc("B") 'donne le code Ascii ou l'Unicode (Ascw fait de même?)
Dim monChar As Char= Chr(66) 
Voir des exemples de code dans ve1-1


V-D-2-b-i. Et les Chaînes de longueur fixe:
On a vu que les chaînes de longueur fixe n'existent pas en VB.NET (compatibilité avec les autres langages oblige), mais il y a moyen de contourner le problème:

On peut utiliser la Classe de compatibilité VB6: à éviter

(Il faut charger dans les références du projet Microsoft.VisualBasic.Compatibility et Compatibility Data)

Dim MaChaineFixe As New VB6.FixedLengthString(100)
Pour afficher la chaîne fixe utilisez MaChaineFixe.Tostring

Mais pour mettre une chaîne dans cette chaîne de longueur fixe!! galère!!!

MaChaineFixe="ghg" n'est pas accepté: on ne peut pas mettre une String dans une chaîne fixe

MaChaineFixe = CType("hg", Microsoft.VisualBasic.Compatibility.VB6.FixedLengthString) 'pas accepté non plus!!

Enfin ce type de chaîne fixe ne peut pas être utilisée dans les structures, mais il y a un autre moyen pour les structures. On verra cela plus loin.

Donc les chaînes fixes sont à éviter.


V-D-3. Variables Numériques

4815162342

Une variable numérique peut contenir des données numériques.

On a vu qu'une variable numérique peut être entière:
  • Integer (entier signé)
  • Short (entier court signé)
  • Long (Entier long signé)
  • Byte (entier non signé de valeur 0 à 255)

Mais aussi en VB2005
  • UInteger (entier non signé)
  • UShort (entier court non signé)
  • ULong (Entier long non signé)
  • SByte (entier signé)
mais aussi
  • Single (virgule flottante simple précision)
  • Double (virgule flottante double précision)
  • Decimal (virgule fixe haute précision)
On déclare une variable numérique avec Dim, on peut l'initialiser en même temps :

Dim i As Integer= 3
Si la variable est numérique, il faut la transformer en String avant de l'afficher :

Dim I As Integer=12

Label.text = I.ToString
.ToString fait partie des méthodes. Il y en a d'autres:

.GetType retourne le type de la variable

Dim i As Integer

Label1.Text = i.GetType.ToString  'Affiche: System.Int32
.MaxValue .MinValue donne le plus grand et le plus petit nombre possible dans le type de la variable.

On verra qu'on peut utiliser des opérateurs + - * / .

Dim I As Integer=2

Dim J As Integer

J=I+3 ‘ J est égal à 5 car on affecte à J la valeur I+3
On rappelle que le séparateur est le point :

J=1.2 veut dire J=1,2 en bon français !!


V-D-3-a. La Classe MATH du Framework est disponible:

Pour qu'elle soit disponible il faut d'abord importer l'espace de nom 'Math'du FrameWork :

Pour cela il faut taper en haut de la fenêtre (au dessus de public Class)

Imports System.Math
Si on n'a pas importé il faut ajouter Math. avant le nom de a fonction. Exemple: R=Math.Abs(N)

On verra plus loin ce que cela signifie.

Dim N As Single

Dim R As Single

 

R=Abs(N)    ‘retourne la valeur absolu

            ‘Si N=-1.2  R=1.2

R=Sign(N)   ‘retourne le signe

            ‘Si N=-1.2  R=-1 (négatif) ; retourne 1 si nombre positif

 

R=Round(N)  ‘retourne le nombre entier le plus proche

            ‘ N=1.7     R=2

            ‘ N=1.2     R=1

            ‘ N=1.5     R=2
Si nombre <0.5 retourne 0 si > ou = à 0.5 retourne 1; c'est la manière d'arrondir les nombres en Euros, comme sur la feuille d'impots.

On peut donner en second paramètre le nombre de digit: Math.Round(Valeur, 2)donne 2 décimales après la virgule.


R=Truncate(N)  ‘retourne la partie entière entier (enlève les chiffres après la virgule, arrondi à l'entier le plus proche en allant vers zéro))

            ‘ N=1.7     R=1

 

R=Floor(N)  ‘retourne le plus grand entier égal ou inférieur. ( arrondi à l'entier inférieur le plus proche en allant vers l'infini négatif)

            ‘ N=1.7     R=1

 

R=Ceiling(N)  ‘retourne le plus petit entier égal ou supérieur. ( arrondi à l'entier  supérieur le plus propre en allant vers l'infini positf)

            ‘ N=1.2     R=2

R=Max(2,3)  ‘retourne le plus grand des 2 nombres.

            ‘retourne 3

R=Min(2,3)  ‘retourne le plus petit des 2 nombres.

            ‘retourne 2

R=Pow(2,3)  ‘retourne  2 puissance 3.

            ‘retourne 8

R=Sqrt(9)   ‘retourne la racine carré.

            ‘retourne 3

longResult = Math.BigMul(int1, int2) 'BigMul donne le résultat de la multiplication de 2 entiers sous forme d'un long.
 
Il existe aussi Log, Log10, Exp.

Bien sur il y a aussi Sin Cos Tan, Sinh Cosh Tanh (pour hyperbolique) Asin Acos Atan Atan2.

Prenons un exemple:

Imports System.Math
Dim MonAngle, MaSecant As Double
MonAngle = 1.3 '  angle en  radians.
MaSecant = 1 / Cos(MonAngle) ' Calcul la sécante.
 
On remarque que les angles sont en radians.

Rappel:2p=360° ; Angle en radians= (2p/360)*Angle en degrés


V-D-3-b. Il existe aussi les instructions du langage VisualBasic comme:

Int et Fix qui suppriment toutes deux la partie fractionnelle et retournent l'entier .

Dim R As Single= 1.7

Int(R)    ‘retourne 1
Si le nombre est négatif, Int retourne le premier entier négatif inférieur ou égal au nombre, alors que Fix retourne le premier entier négatif supérieur ou égal au nombre. Par exemple, Int convertit -8,4 en -9 et Fix convertit -8,4 en -8.


V-D-3-c. Dépassement de capacité, 'Non Nombre'.

Testé en VB2005

On a vu que , codées sur un nombre de bits défini, les variables numériques ne peuvent pas avoir des valeurs très très grandes. .MaxValue donne le plus grand nombre possible dans le type de la variable. (MinValue le plus petit nombre) Que se passe t-il , si on dépasse la valeur maximum?

  • Si on affecte à une variable entière une valeur supérieure à .MaxValue cela déclenche une erreur (on dit une exception de type OverFlow) et cela plante.
  • Si on affecte à une valeur à virgule flottante(un Single par exemple), une valeur supérieure à .MaxValue, la variable prend la valeur 'infinie' ( +ou - infinie: Single.NegativeInfinity ou Single.PositiveInfinity))
Exemple:

IsInfinity, IsNegativeInfinity, IsPositiveInfinity permettent de tester si le résultat d'un calcul dépasse les valeurs autorisées pour le Type virgule flottante.

Dim s As Single = 2147483647 ^ 33

If Single.IsInfinity(s) Then MsgBox("infinie")
s prend la valeur Single.PositiveInfinity

Les opérations en virgule flottante retournent NaN pour signaler que le résultat de l'opération est non défini. Par exemple, le résultat de la division de 0,0 par 0,0 est NaN.

On peut tester une expression par IsNan

Exemple:

If Single.IsNaN(0 / 0) Then

V-D-4. Conversion, séparateur décimal

4815162342

On a vu qu'on peut afficher les chaînes de caractères (des 'String'), par ailleurs, on fait des calculs avec les variables numériques (Integer, Single..).

On a donc besoin sans arrêt de faire des calculs avec des variables numériques et de transformer le résultat en String pour l'afficher et vice versa.

Est-il possible de convertir une variable d'un type à un autre? OUI!!

On aura donc besoin de savoir transformer des variables de tous types en d'autres types.


V-D-4-a. Conversion numérique=>String

Quel intérêt de convertir?

On veut afficher un résultat numérique.

On ne peut afficher que des String (chaîne de caractères) dans un label ou un TextBox par exemple.

Aussi, il faut transformer cette valeur numérique en chaîne avant de l'afficher, on le fait avec la méthode ".ToString":

     Dim i As Integer=12        'On déclare une variable I qu'on initialise à 12

     Label.text = i.ToString 
La valeur de i est transformée en String puis affectée à la propriété Text du label, ce qui affiche '12'

On verra plus loin qu'on peut ajouter des paramètres.


V-D-4-b. Conversion String=>numérique

A l'inverse une chaîne de caractères peut être transformée en numérique :

Par exemple, l'utilisateur doit saisir un nombre, il saisit un nombre dans une boite de saisie (InputBox), mais il tape des caractères au clavier et c'est cette chaîne de caractères qui est retournée, il faut la transformer en numérique.

Dim s as String

Dim i as Integer

s= InputBox ("Test", "Taper un nombre") 'Saisie dans une InputBox  d'un nombre par l'utilisateur.

's contient maintenant une chaîne de caractères, "45" par exemple

i=Integer.Parse(S)     'on transforme la chaîne s en Integer                   
Bizarre cette syntaxe!! en fait c'est le type Integer qui a une méthode (Parse) qui transforme une chaîne en entier.

Il y a aussi:

Transformation d'une chaîne en Long Long.Parse(chaine) ou Int64.Parse(chaine)

Transformation d'une chaîne en Double Double.Parse(chaîne)

Transformation d'une chaîne en Single Single.Parse(chaîne)

On peut aussi utiliser, et c'est plus simple, CType pour convertir n'importe quel type en n'importe quel type :

Il suffit de donner à cette fonction la variable à modifier et le type à obtenir.

Dim i As Integer

Dim s As String= "12"

 i=CType(s,Integer)  ' s est la variable à modifier, Integer est le type à obtenir.
i contient maintenant l'entier 12.


V-D-4-c. CType pour toutes les conversions

Ctype peut aussi servir à convertir de la même manière un single en double, un Short en Integer....

Il est donc possible de convertir un type de variable en un autre.

Il suffit de donner à cette fonction la variable à modifier et le type à obtenir.

 Dim d As Double = 2.65

 Dim i As Integer

 i=CType(d,Integer)    'conversion en entier 
Pour les forts:

DirectCast fait de même mais on doit utiliser une variable ByRef.

i=DirectCast(s,Integer) 'S doit être ByRef

Par contre DirectCast nécessite que le type d'exécution d'une variable objet soit identique au type spécifié.

' nécessite Option Strict Off.
Dim Q As Object = 2.37   ' crée un objet contenant un double.
Dim K As Integer =CType(Q, Integer)       'Marche

Dim J As Integer = DirectCast(Q, Integer)   ' échoue 
DirectCast échoue car le type d'exécution de Q est Double. CType réussit car Double peut être converti en Integer, mais DirectCast échoue car le type d'exécution de Q n'est pas encore Integer.

TryCast de VB 2005 (Framework 2)

TryCast fonctionne comme DirectCast mais retourne Nothing si la conversion est impossible (et ne plante pas!).


V-D-4-d. Fonctions spécifiques

CType fait toutes les conversions, mais on peut aussi utiliser des fonctions qui sont spécifiques au type de la variable de retour: Le nom de ces fonctions contient le nom du type de la variable de retour.

CBool()  Pour convertir en Booléen
CByte()  Pour convertir en octet
CChar()  Pour convertir en Char
CDate()  Pour convertir en Date
CDbl()   Pour convertir en Double
CDec()   Pour convertir en Decimal
CInt()   Pour convertir en Integer
CLng()   Pour convertir en Long
CObj()   Pour convertir en Objet
CShort() Pour convertir en  Short
CSng()   Pour convertir en Single
CStr()   Pour convertir en String
Et en VB 2005
CSByte()   Pour convertir en SByte
CUShort() Pour convertir en  UShort
CUInt()   Pour convertir en UInteger
CULng()   Pour convertir en ULong
Exemple CDbl  retourne un 'Double'.

Dim I As Integer=123

Dim D As Double

D=CDbl(I)    'donnera D=123  D est un Double (réel double précision)
Ces fonctions sont plus rapides car elles sont spécifiques.

Remarque:

Les fonctions CInt et CLng arrondissent les parties décimales égales à 0,5 au nombre pair le plus proche. Par exemple, 0,5 s'arrondit à 0 et 1,5 s'arrondit à 2. Bizarre!!


V-D-4-e. Val et Str (de MicroSoft.VisualBasic) existe aussi:

Ouf pour les anciens!!

Ces fonctions permettent aussi la conversion String=>Numérique et Numérique=>String

Val donne la valeur numérique d'une expression String.

Dim i As Integer

i=Val("5")    ' i=5
Val s'arrête au premier caractère non numérique.

Val("12er") retourne 12

Val reconnaît le point (et pas la virgule)


Dim i As Double

i=Val("5.45")    ' donnera i=5,45

i=Val("5,45")    ' donnera i=5
Str transforme une valeur numérique en String:

Dim s As String

s=Str(1999)    ' s=" 1999"
Noter bien: Str ajoute un espace à gauche ou le signe'-' si le nombre est négatif.

Str ne reconnaît que le point comme séparateur décimal. (Pour utiliser les autres séparateurs internationaux, il faut utiliser la fonction CStr() ).


V-D-4-f. La Classe System.Convert:

La Classe System.Convert permet la conversion d'un type de base vers un autre:

.ToString en fait partie

Exemple

Pour convertir un Single en Byte (entier 8 bits non signé)

.ToByte

Pour convertir un Byte en Single:

.ToSingle

singleVal = System.Convert.ToSingle(byteVal)
en Decimal

.ToDecimal

On a des méthodes pour pratiquement convertir tous les types en tous les types. Cherchez!!

On verra plus loin, la fonction Format utilisée pour convertir les valeurs numériques que vous voulez mettre aux formats dates, heures ou monnaie ou dans d'autres formats définis par l'utilisateur.


V-D-4-g. Pour résumer et faire très simple, retenir ++++:

ToString pour les conversions en String des variables numériques(pour afficher).

Ctype pour convertir tout en tout.

Le fait de convertir d'un type dans un autre s'appelle ' effectuer un cast'


V-D-4-h. Conversion Explicite et Implicite.

A noter que dans cette page , on a étudié la conversion Explicite: est permet de forcer la conversion vers un type à l'aide de mots clés.

Exemple

Dim d As Double = 2.65

Dim i As Integer

 i=CType(d,Integer)
Il existe aussi la conversion implicite effectuée automatiquement sans syntaxe particulière et de manière transparente.

VB peut le permettre ( Si Option Explicit Off dans la configuration )

Exemple

Dim d As Double = 2.65

Dim i As Integer

 i=d  'Pour affecter à i le Double d, Vb a transformé le double d en Integer.
On verra que ce mode de travail n'est pas recommandé.


V-D-4-i. Conversion restrictive.

warning Attention, la conversion est dite restrictive si le type final ne peut pas convertir toutes les valeurs du départ:
Si je convertis un Single en Integer, la partie décimale peut être tronquée, c'est une conversion restrictive.

L'inverse (conversion Short en Single par exemple) est dite étendue.


V-D-4-j. Séparateur décimal: le point ou la virgule?

Les fonctions Val () et Str () ne reconnaissent que le point (.) comme séparateur décimal.

Dim s As Single

s=Val ("123.4")    'est accepté, c'est 123,4 en français.
On rappelle aussi que le séparateur d'un littéral est le point (un littéral sert à donner une valeur à une variable):

Dim s As Single

s= 456.67
Les fonctions CDbl, CType, CSng ou Parse ainsi que ToString utilisent le séparateur des paramètres locaux de la machine . Ils reconnaissent la culture.

Le symbole de séparateur décimal (ainsi que celui des milliers ) est donc spécifique à la culture.
  • En France, sur votre ordinateur,le séparateur décimal est la virgule.
    
    Dim s As Single
    
    s = CType("123,4", Single)
    
    Console.Out.WriteLine(s.ToString)
    
    Affiche: '123,4'

    Par contre s = CType("123.4", Single) est refusé.

  • Au Usa le séparateur décimal est le point.
    
    s = CType("123.4", Single) est accepté
    
    Console.Out.WriteLine(s.ToString)
    
    'Affiche '123.4'
    
On remarque donc que ToString utilise aussi le séparateur spécifique à la culture.

Console.Out.WriteLine(s.ToString)
Affiche: '123,4' en France

Lors de l'utilisation d'autres séparateurs décimaux (applications internationales, par exemple), convertissez la chaîne en nombre à l'aide de la fonction CDbl ou CType CSng ou Parse.

Pour voir quel est le séparateur en cours:

Menu Démarrer->Paramètres->Panneau de configuration>Options régionales et linguistiques.

Obtient le séparateur décimal en fonction des paramètres locaux de la machine par du code.

SeparateurDécimal = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator
On peut modifier le CultureInfo:

On peut, si on est en CultureInfo Français, afficher en mode Us

Dim i As Single = 45.78

' Afficher dans la CultureInfo courante: Français 

Console.WriteLine(i.ToString)    'Affiche 45,78

' Créer un CultureInfo en anglais  U.S.
Dim us As New CultureInfo("en-US")


' Afficher sur la console  en CultureInfo Us.
Console.WriteLine(i.ToString("c", us))    'Affiche 45.78
Il s'agit ici d'une surcharge de ToString , "c" signifie NumberFormatInfo


V-D-4-k. IsNumeric

On utilise la fonction IsNumeric pour déterminer si le contenu d'une variable peut être évalué comme un nombre.

Exemples:

Dim MyVar As Object
Dim R As Boolean

MyVar = "45" 
R = IsNumeric(MyVar) ' R= True.
' ...
MyVar = "678.92" 
R = IsNumeric(MyVar) ' R= True.
' ...
MyVar = "45 Kg"
R = IsNumeric(MyVar) ' R= False.
warning 'Attention le dernier exemple indique que "45 Kg" n'est pas purement numérique, mais Val("45 Kg") retourne 45 sans déclencher d'erreur car Val transforme les caractères numériques à partir de la gauche, en s'arrêtant dès qu'il y a un caractère non numérique.

V-D-4-l. Lexique anglais=>Français:

To Cast = Mouler, couler.

Type = Type, genre.

To parse = analyser.


V-D-5. Les 'Tableaux'

C'est un beau tableau, mais en VB, c'est pas ça un tableau!!

Les tableaux permettent de regrouper des données de même type.

Les tableaux vous permettent de faire référence à un ensemble de variables par le même nom et d'utiliser un numéro, appelé index ou indice, pour les distinguer.

Comment déclarer un tableau :

Dim Tableau(3) As Integer 'déclare un tableau de 4 entiers

On remarque que, dés la déclaration du tableau, le nombre d'éléments est bien défini et restera toujours le même.

Dim Tableau(3) As Integer entraîne la création des variables 'Integer' suivante:

Tableau (0)

Tableau (1)

Tableau (2)

Tableau (3)

Contenu du tableau:

0
0
0
0
soit 4 éléments

Noter que comme c'est un tableau d'entier, juste après la création du tableau les éléments sont initialisés à 0.

warning Le tableau commence toujours par l'indice 0
Le nombre d'éléments dans le tableau est toujours égale à l'indice de dimension + 1 (ou l'indice du dernier élément+1)
Dim Tableau(3) comporte 4 éléments (éléments d'index 0 à 3).

Tableau(1)= 12 permet d'affecter le nombre 12 au 2eme élément du tableau.

0
12
0
0
S=Tableau(1) permet d'affecter à la variable S le 2eme élément du tableau.

Un tableau peut avoir plusieurs dimensions :

Dim T(2,2)      3 X 3 éléments
Pour un tableau à 2 dimensions le premier argument représente les lignes, le second les colonnes.

Voyons pour chaque élément du tableau le numéro de ligne et celui de la colonne: (pas le contenu des éléments ici mais leur index)

élément:0,0 élément:0,1 élément:0,2
élément:1,0 élément:1,1 élément:1,2
élément:2,0 élément:2,1 élément:2,2
Exemple:

La première ligne comporte les 3 éléments: T(0,0) T(0,1) et T(0,2)

Pour mettre 33 dans l'élément central:

Dim T(2,2) As Integer

T(1,1)=33
voyons le contenu du tableau:

0 0 0
0 33 0
0 0 0
Il est possible de créer des tableaux à 3, 4 ..dimensions:

Exemple:

Dim T(4,2,3) crée un tableau de 4X2X3 éléments.

On peut créer des tableaux de tableaux:

Dim T(2),(2) Il a autant d'élément que le tableau T (2,2) (mais pour l'accès à un élément, ils fonctionnent plus vite)

Il est possible de créer des tableaux avec tous les types de variable (y compris les structures)

Dim Mois(11) As String    'tableau de String de 12 éléments
Notez que dans ce cas les éléments contiennent Nothing car le tableau contient des String et quand on déclare une String, elle contient Nothing au départ.

On peut initialiser un tableau (Donner une valeur aux éléments):

En effet après dimensionnement d'un tableau, il contient:

la valeur 0 si c'est un tableau de numérique.

Nothing si c'est un tableau de String ou d'Objet.

Dim mois(11) As String 

'mois (1) contient Nothing

mois(0)="Janvier"

mois(1)="Février"

mois(2)="Mars"
ou lors de sa déclaration :

Dim Mois() As String ={Janvier,Février,Mars}
On remarque ici, que le nom d'élément n'est pas indiqué; comme on initialise 3 éléments, le tableau en aura 3.

On verra dans un des exemples que l'on peut créer un tableau avec la méthode CreateInstance.

Autre syntaxe:

Dim t As String()    'déclaration

t = New String(1) {"One", "Two"} ' on affecte au tableau un nouveau tableau de String contenant "One" et "Two"

 

Dim R(,) as Integer ={{0, 1}, {1, 2}, {0, 0}, {2, 3}}
On déclare et on initialise en même temps un tableau à 2 dimensions, remarquez qu'on rentre les éléments 2 à 2.(Equivalent à R(0,0)=0 R(0,1)=1 R(1,0)=1 R(1,1)=2 ..)

Redim permet de redimensionner un tableau (modifier le nombre d'éléments d'un tableau existant), si on ajoute Preserve les anciennes valeurs seront conservées.

warning Attention , on ne peut pas modifier le nombre de dimension, ni le type des données. Un tableau à 2 dimensions de 20 fois 20 string pourra être redimensionné en tableau de 30 fois 30 String, mais pas en tableau d'entiers ou à 3 dimensions.

Dim T(20,20) As String

...

Redim Preserve T(30,30)
Il est possible d'écrire Dim T( , ) As String

Dim T( , ) As String 'Sans donner les dimensions du tableau: il est déclaré mais n'existe pas car T(1,1)="toto" déclenche une erreur. Il faut avant de l'utiliser écrire Redim T(30,30), (sans remettre As String).

Certaines instructions comme Split redimensionne elle-même le tableau au nombre d'élément nécessaire.

Dim Nom() as String

Nom=S.Split(Separateur)
Erase efface le tableau et récupère l'espace.

Erase Tableau (équivalent à tableau= Nothing )

Clear réinitialise le tableau. (remise à 0 d'un tableau de numérique par exemple)

Array.Clear(t, 2, 3) réinitialisation tableau t à partir de l'élément 1 et pour 3 éléments.

Comment parcourir un tableau?

Pour parcourir un à un tous les éléments d'un tableau, on utilise une boucle:

Exemple: créer un tableau de 11 éléments et mettre 0 dans le premier élément, 1 dans le second, 2 dans le troisième...

Dim T(10) As Integer

Dim i As Integer

 

For i = 0 To 10    'Pour i allant de 0 à 10

         T(i)=i

Next i
La variable de boucle i est utilisée pour parcourir le tableau: on utilise l'élément T( i ) donc successivement T(1) puis T(2)...et on affecte i donc 1 puis 2 puis 3..

On peut aussi utiliser For Each:( un tableau hérite de la classe System.Array)

Dim amis() As String = {"pierre", "jean", "jacques", "toto"}

For Each nom As String In amis

    Console.Out.WriteLine(nom)

Next
L'exemple affiche sur la console (menu Affichage->Fenêtre->Sortie) les noms qui sont dans le tableau.

VB alloue de l'espace mémoire pour chaque élément crée. Ne dimensionnez pas un immense tableau si vous avez besoin d'un tableau de 4*4 car cela utilise de la mémoire inutilement.


V-D-5-a. Un tableau est un objet !!

Créons 2 tableaux et examinons les principales méthodes.

Dim a(3) As String

Dim b(3) As String

b=a         ‘Copie le tableau a dans b

b=a.copy    ‘Est équivalent
warning Attention: il copie les références (l'adresse, l'endroit ou se trouve la variable) et non pas la valeur de cette variable, ce qui fait que si vous modifiez b(3), a(3) sera aussi modifié.
Car lorsque vous assignez une variable tableau à une autre, seul le pointeur (l'adresse en mémoire) est copié.

Pour obtenir une copie ‘indépendante' faire :

b=a.clone

Dans ce cas si vous modifié a(2), b(2) ne sera pas modifié.

Par contre a(1)=b(1) n'affecte que l'élément a(1)


V-D-5-b. La Classe Array.

Tous les tableaux viennent de la classe Array; vous pouvez accéder aux méthodes et propriétés de System.Array de chaque tableau Par exemple, la propriété Rank retourne le nombre de dimension du tableau et la méthode Sort trie ses éléments.

Exemple :

Soit un tableau Mois()

Clear

Array.Clear(Mois,0,2) ‘Efface 2 éléments du tableau Mois à partir de l'élément 0

Reverse

Array.Reverse(Mois, 1, 3) inverse les 3 éléments à partir de l'élément 1

Copy

Array.Copy(Mois,1,Mois2,1,20) copie 20 éléments de Mois vers Mois2 à partir du 2eme élément.

Sort

Array.sort(Mois) Trie le tableau Mois

Malheureusement cette méthode marche sur des tableaux unidimensionnels uniquement.

Au lieu d'utiliser un tableau à 2 dimensions (sur lequel la méthode 'Sort' ne marche pas, on peut ruser et créer 2 tableaux et surcharger la méthode sort pour trier les 2 tableaux (un servant de clé, le second d'items):

Array.Sort(myKeys, myValues) (Voir un exemple plus bas)

Equals compare 2 tableaux.

Binarysearch recherche un élément dans un tableau trié unidimensionnel.(algorithme de comparaison binaire performant sur tableau trié)

Exemple :

I=Array.BinarySearch(Mois, "Février") ‘retourne I=1  se souvenir le premier élément est Mois(0)
BinarySearch effectue une recherche dichotomique: il regarde l'élément du milieu, si l'élément cherché est plus petit, il regarde l'élément du milieu du haut du tableau.....

C'est rapide mais le tableau doit être trié.

S'il trouve un élément il retourne sous index.

Si la recherche échoue, il retourne un nombre négatif, si on effectue un Not sur ce nombre retourné, on a l'index où on doit insérer l'élément

IndexOf

Recherche un objet spécifié dans un tableau unidimensionnel (trié ou non), retourne l'index de la première occurrence.

Dim myIndex As Integer = Array.IndexOf(myArray, myString)
 
Retourne -1 si l'élément n'est pas trouvé.

LastIndexOf fait une recherche à partir de la fin.

Ici la recherche est linéaire: on compare l'élément recheché avec le premier puis le deuxième, puis le troisième élément...C'est long , mais le tableau n'a pas besoin d'être trié.

On a probablement intérêt à trier le tableau et à faire un Binarrysearch. (Cela se dit mais je ne l'ai pas vérifié)

Ubound

Retourne le plus grand indice disponible pour la dimension indiquée d'un tableau

Dim Indice, MonTableau(10, 15, 20)
Indice = UBound(MonTableau, 1) ' Retourne 10. (1 indique la première dimension du tableau)
 
GetUpperBound même fonction

Indice = MonTableau.GetUpperBound(0) '( 0 pour première dimension!!) Retourne 10.
Lbound existe (plus petit indice) mais est inutile car toujours égal à 0.

Length retourne un entier qui représente le nombre d'éléments total dans le tableau.

Pour un tableau à une dimension Lenght-1 retourne l'indice du dernier élément.

Cela est souvent utilisé pour parcourir tous les éléments du tableau:

 Dim t(10) As String

 Dim i As Integer

 For i = 0 To t.Lenght-1

   t(i)=..

 Next t
On remarque que dans un tableau multi dimension Lenght n'est pas égal à Ubound

GetLength(x) retourne un entier qui représente le nombre d'éléments dans la dimension x.

GetValue et SetValue permettent de connaître ou de modifier la valeur d'un élément du tableau:

Mois.GetValue(0) est équivalent à Mois(0)

Dans un tableau à 2 dimensions comment modifier l'élément (0,3):

myArray.SetValue("fox", 0, 3)
C'est équivalent à myArray(0,3)="fox"

ArraySegment permet de définir un segment, une plage dans une Array.(framework 2)

Dim myArrSegMid As New ArraySegment(Of String)(myArray, 2, 5) 'ici le segment débute au second élément et contient 5 éléments.
(Si on modifie un élément de myArrSegMid cela modifie myArray car le segment définie une plage du tableau et non un nouveau tableau)

Sur des tableaux, les actions à effectuer sont principalement:

Rechercher un élément.

Trier le tableau.

Insérer un élément.

Enlever un élément.

On a déjà évoqué cela , mais pour étudier le détail voir les tableaux et collections

Pour les super pro (débutant passe ton chemin), on peut utiliser des méthodes génériques.

Exemple recherche dans un tableau de short nommé monTab l'élément 2

index= Array.indexOf (Of Short)(monTab, 2) est hyper plus rapide que

index= Array.indexOf (monTab, 2) car la première version avec généric est directement optimisée pour les Short.

Il est est de même pour Binarysearch et Sort.

Cela est valable pour les types 'valeur' (peu d'intérêts pour les strings par exemple).


V-D-5-c. Exemple:

Exemple détaillé:

Créer un tableau de 6 éléments, mettre dans chaque élément du tableau le carré de son indice, afficher le contenu du tableau.

Cela montre l'intérêt d'utiliser une boucle pour balayer tous les éléments d'un tableau. Première boucle pour remplir le tableau, seconde boucle pour afficher.(Une boucle For ..Next est ici utilisée, on verra cela plus loin.)


      Dim arr(5) As Integer

      Dim i As Integer

      For i = 0 To arr.GetUpperBound(0)' GetUpperBound(0) retourne 5

         arr(i) = i * i

      Next i

 

     For i = 0 To arr.GetUpperBound(0)

         Console.WriteLine("arr(" & i & ") = " & arr(i))

      Next i
Faire une boucle allant de 0 au dernier élément du tableau (For i=0 to ..)

Dans chaque élément du tableau mettre le carré de son indice (arr(i)=i*i )

Nouvelle boucle pour afficher les noms des différents éléments et leur contenu. (Console.WriteLine() affiche sur la console le nom de l'élément et son contenu)

Le programme génère la sortie suivante :

arr(0) = 0

arr(1) = 1

arr(2) = 4

arr(3) = 9

arr(4) = 16

arr(5) = 25
Exemple de recherche dans un tableau:

Dans un tableau de String rechercher dans quel élément et à quelle position se trouve la string "MN".

Dim Tableau() As String = {"ABCDEFG", "HIJKLMNOP"}
Dim AChercher As String = "MN"
Dim i As Integer
Dim position As Integer
For i = 0 To Tableau.Length - 1 'on parcourt chaque élément du tableau
    position = Tableau(i).IndexOf(AChercher) 'dans l'élément  du tableau on cherche la sous-chaîne
    If position >= 0 Then Exit For
Next i
Exemple de tri de 2 tableaux:

On crée un tableau de clés et un tableau des valeurs, à chaque clé est liée une valeur.

On trie à partir du tableau des clés myKeys , le tableau myValues est modifié pour 'suivre' le tri des clés. La Sub PrintKeysAndValues affiche les résultats.

Public Shared Sub Main()

' ****************Création des tableaux.

Dim myKeys() As String = {"red", "GREEN", "YELLOW", "BLUE", "purple", "black", "orange"} 'Tableau des clé

Dim myValues() As String = {"strawberries", "PEARS", "LIMES", "BERRIES", "grapes", "olives", "cantaloup"} 'tableau des éléments

 

'Affichage du tableau non trié

Console.WriteLine("Tableau non trié:")

PrintKeysAndValues(myKeys, myValues)


' Tri les éléments 1 à 3 puis affichage.

Array.Sort(myKeys, myValues, 1, 3)

Console.WriteLine("Après tri d'une partie du tableau:")

PrintKeysAndValues(myKeys, myValues)


    ' Tri la totalité du tableau.

Array.Sort(myKeys, myValues)

Console.WriteLine("Après tri de la totalité du tableau:")

PrintKeysAndValues(myKeys, myValues)

End Sub 'Fin de Main

 

    ' Routine affichant dans la console les clés et valeurs

Public Shared Sub PrintKeysAndValues(ByVal myKeys() As [String], ByVal myValues() As [String])

Dim i As Integer

For i = 0 To myKeys.Length - 1

    Console.WriteLine(" {0,-10}: {1}", myKeys(i), myValues(i))

Next i

Console.WriteLine()

End Sub 'PrintKeysAndValues
Création de tableau avec CreatInstance

' Créons un tableau d'entier (Int32) comprenant 5 éléments.
Dim myArray As Array = Array.CreateInstance(GetType(Int32), 5)
Dim i As Integer
For i = myArray.GetLowerBound(0) To myArray.GetUpperBound(0)
    myArray.SetValue(i + 1, i)
Next i 
Merci Microsoft pour les exemples.


V-D-6. Les 'Collections'

Une alternative aux tableaux est l'usage de Collection.

Il y a:
  • les collections VisualBasic (Collection)
  • les classes du Framework (ArrayList, Stack, Queue, BitArray, HashTable, SortedList, StringCollection)
  • les classes de collections génériques de VB 2005
Une collection fonctionne plutôt comme un groupe d'éléments dans laquelle il est possible d'ajouter ou d'enlever un élément à n'importe quel endroit sans avoir à se préoccuper de la taille de la collection, ni ou se trouve l'élément.

Le nombre d'élément n'est pas défini au départ comme dans un tableau. Dans une collection il n'y a que les éléments que l'on a ajouté.

Les éléments sont repérés grâce à un index ou avec une Clé unique

Les items affichées dans une ListBox donnent une idée concrète de ce qu'est une collection.


V-D-6-a. Exemple simpliste permettant de comprendre la notion de collection:

Soit la collection Col, au départ elle est vide.

J'ajoute des éléments (ou items) à cette collection.

Col.Add ("Toto")

Voici la collection:

Toto
La collection a maintenant 1 élément.

Col.Add("Lulu")

Col.Add("Titi")

Toto
Lulu
Titi
La collection a 3 éléments maintenant.

Col.Remove(2) enlève l'élément numéro 2

Toto
Titi
La collection n'a plus que 2 éléments maintenant.

On voit que le nombre d'éléments n'est pas connu à l'avance, il varie en fonction des éléments ajoutés (ou retirés)

Un élément est repéré par son indice.

Col.Item(2) contient "Titi" (le second Item de la collection)

Remarque:

J'ai pris une collection de 'Base 1': le premier élément à l'indice 1, il existe aussi des collections (celles venant des classes .Net) de Base 0.


V-D-6-b. L'objet 'Collection' c'est du VisualBasic:

'Collection' existait déjà en VB6!!

L'objet collection utilise un couple Clé-Valeur, pour chaque élément.

Ici le premier élément a pour clé: 69, pour valeur:'Rhône'

C'est pratique car cela permet de retrouver une valeur à partir de la clé.

Pour utiliser une collection d'objets, vous devez premièrement créer l'objet maCollection.

Dim maCollection As New Collection
Dès que cet objet est créé, vous pouvez ajouter (avec Add), enlever ou manipuler des éléments.

On utilise la syntaxe: NomCollection.Add( élément, Clé)

maCollection.Add("Bonjour", "30")

maCollection.Add("Monsieur", "31")

maCollection.Add("Et", "32")

maCollection.Add("Madame", "33")

Il peut y avoir 2 autres paramètres:

maCollection.Add(Element, Clé, Before, After)

Before ou After peuvent être utilisés pour placer l'élément à insérer avant ou après un élément de la collection. Si Before ou After est un nombre c'est l'index des éléments qui est utilisé, si c'est une string c'est la clé.

Pour récupérer un objet de la collection, on peut utiliser
  • l'index:
    
    Label1.Text = maCollection.Item(2) 'Affiche le second élément: Monsieur
    
    warning Attention le premier élément est ici l'élément 1 (l'index va de 1 à Count); c'est hérité du VB!!
  • La clé
    
    Label1.Text = maCollection.Item("33") 'Affiche Madame
    
    Pour effacer un objet de la collection, on peut utiliser

  • l'index:
    
    maCollection.Remove(2) 'Efface le second élément: Monsieur
    
  • La clé
    
    maCollection.Remove("33") 'Efface Madame
    
    On peut utiliser For each pour parcourir la Collection:
    
    For Each S As string In maCollection
    
        MsgBox(i)
    
    Next S
    
Remarque pour les 'bons':

Noter que Collection peut contenir des Objets donc n'importe quoi.

Label1.Text = maCollection.Item(2)
Est accepté si Option Strict=Off car il y a y a conversion implicite.

Si Option Strict=On, il faut écrire:

Label1.Text = CType(maCollection.Item(2), String) pour convertir explicitement l'objet en String

V-D-6-c. Liste d'objets: ArrayList : c'est une Classe .Net.

Fait partie de System.Collections

La ArrayList est une collection particulière: On peut y mettre des objets : chaînes, nombres… rien n'empêche que le premier élément soit un entier, le second une chaîne…Il n'y a pas de clé.

warning Attention le premier élément est ici l'élément 0 (l'index va de 0 à count-1) ; c'est du .NET!!

Dim L As New ArrayList()     'On crée une collection ArrayList

Dim L As ArrayList = ArrayList.Repeat("A", 5) 

'On crée une ArrayList de 5 éléments contenant chacun  "A" (on répète "A")
 

L.Add("Bonjour")             'On ajoute un élément à la collection

MsgBox(L(0))                 'On affiche le premier élément
On affiche le premier élément L(0)

On pourra aussi écrire L.Item(0) pour pointer le premier élément.

      MsgBox(L.Count.ToString)     'On affiche le nombre d'élément.
warning Attention c'est le nombre d'éléments. S'il y a 3 éléments dans la ArrayList ce sont les éléments d'index 0,1,2.

      L.Remove("Bonjour")          'On enlève un élément de la liste

      L.RemoveAt(0)                'On enlève l'élément 0 de la liste

      L.Sort()                     'Trie la collection

L.Clear()                    'Efface tous les éléments

      L.Containts (élément)        ' Retourne True si la liste contient élément.   

Insert permet d'insérer à un index spécifié.

     L.Insert( position, Ainserrer)

      InsertRange insère une ArrayList dans une Autre ArrayList.

      L.Containts (élément)  ' Retourne True si la liste contient 'élément'.

 
Recherche d'un élément dans une collection NON TRIEE avec IndexOf:

Dim l As New ArrayList

Dim i As Integer

l.Add("toto")

l.Add("lulu")

i = l.IndexOf("lulu")

MsgBox(i.ToString)    'Affiche 1
On rappelle qu'il existe aussi LastIndexOf qui démarre par la fin et une surcharge permettant de débuter la recherche à partir d'un indice donné (i = l.IndexOf(3,"lulu") recherche à partir du 3ème élément).

Recherche d'un élément dans une collection TRIEE avec BinarySearch:

Dim l As New ArrayList

Dim i As Integer

l.Add("toto")

l.Add("lulu")

l.Sort()'Il est nécessaire que le tableau soit trié 

i = l.BinarySearch("lulu")

MsgBox(i.ToString)
Pour parcourir une collection, 3 méthodes :

-Avec l'index de l'item

For i=0 to L.Count-1

      A=L.Item(i)

Next i
NB: Comme vu plus haut, on utilise Count pour trouver le nombre d'élément, aussi la boucle doit balayer de 0 à count-1.

-Avec For Each

Dim o As Objet

For Each o in L

      A=o

Next
-Avec l'objet IEnumerator (débutant passe ton chemin)

On crée un objet C de type IEnumerator pour parcourir la collection, cet objet a 3 propriétés:

MoveNext qui avance d'un élément dans la collection. S'il ne peut plus avancer (s'il est déjà après le dernier) il retourne False

Reset qui place l'élément courant au début, avant le premier élément (Comme au départ)

Current désigne l'élément courant.

Exemple montrant la seule manière de faire pour parcourir la collection:

Dim L As New ListArray

Dim C As IEnumerator= L.GetEnumerator()

While C.MoveNext())

     A=C.Current

End While
warning -Attention, si Option Explicit=On
Les éléments de la ListArray étant des objets, on ne peut pas les affecter à une variable String par exemple, il faut écrire:

Str = CType(L(0), String)    'on convertit (on cast) l'objet en String.
Remarque:

L.Add(Nothing)    'est accepté: on ajoute un élément vide

V-D-6-d. StringCollection: c'est une Classe .Net

Ne peut contenir que des chaînes (cela devrait aller plus vite)

' Créer une StringCollection.
Dim myCol As New StringCollection()

'Créer un tableau de String, l'ajouter( en fin) à la collection.
Dim myArr() As [String] = {"rouge", "vert", "orange", "vert",)
myCol.AddRange(myArr)

'Ajouter un élément à la fin de la collection
myCol.Add("marron")

'Insérer un élément à l'index 3
myCol.Insert(3, "bleue")

'Enlever une élément
myCol.Remove("orange")


' chercher et enlever tous les éléments "vert" 
Dim i As Integer = myCol.IndexOf("vert")
While i > - 1
myCol.RemoveAt(i)
i = myCol.IndexOf("vert")
End While

' La collection contient t'elle "jaune"?
If myCol.Contains("jaune") Then..

' Copie la collection dans un tableau.
Dim myArr2(myCol.Count) As [String]
myCol.CopyTo(myArr2, 0)

' Efface toutes les strings de la Collection.
myCol.Clear()
 

'Afficher la liste des Strings

Dim myEnumerator As System.Collections.IEnumerator = myCol.GetEnumerator()

While myEnumerator.MoveNext()
Console.WriteLine(" {0}", myEnumerator.Current)
End While
'C'est un peu complexe!! on y reviendra.
warning Attention le premier élément est ici l'élément 0 (l'index va de 0 à count-1) ; c'est du .NET!!

V-D-6-e. HashTable c'est une Classe .Net

C'est un 'Dictionnaire' qui comporte des couples clé-élément, des paires clé-valeur.

La clé toujours unique permet de retrouver la valeur, La clé ne doit pas être vide non plus.

H.Add(Clé,Valeur) Ajoute un élément

H.Item(Clé) Retourne l'élément correspondant à une clé.

H.ContainsKey(Clé) Retourne True si la Clé est dans la table.

H.ContainsValues(Valeur)Retourne True si la valeur est dans la table.

H.Clear Efface tous les éléments

H.Remove(Clé) Supprime l'élément ayant une clé spécifiée.

Les collections H.Values et H.Keys contiennent les valeurs et les clés.

warning Attention le premier élément est ici l'élément 1 (index allant de 1 à count)
Exemple:

'  Creation d'une Hashtable.
Dim myHT As New Hashtable()

' Mettre des éléments dans la HashTable
myHT.Add("un", "premier")
myHT.Add("deux", "second")
myHT.Add("trois", "troisième")
myHT.Add("quatre", "quatrième")
 

'Recherche la valeur correspondant à la clé "trois"

myReponse=myHT.Item("trois")     'Retourne "troisième"
 

'Parcourir la HashTable

'Création d'un IDictionaryEnumerator
Dim myEnumerator As IDictionaryEnumerator = myHT.GetEnumerator()

While myEnumerator.MoveNext()

'Afficher clé et valeur
    MsgBox( myEnumerator.Key+ myEnumerator.Value)
End While

V-D-6-f. SortedList: c'est une Classe .Net

Il permet l'accès aux valeurs par l'intermédiaire des clés associées ou des index.

C'est un hybride de HashTable et de Array.

On ajoute un élément par mySL.Add(Clé,Valeur)

La séquence d'index est basée sur la séquence de tri. Quand un élément est ajouté, il est inséré dans l'ordre de tri adéquat, et l'indexation s'ajuste en conséquence. Le tri est donc automatique.

On peut donc lire une valeur par sa Clé ou son Index:
  • Quand la clé d'un élément permet d'accéder à celui-ci à l'aide de la propriété d'indexeur Item, l'élément se comporte comme Hashtable.
    
    mySL.Item(CLE) 'retourne la valeur correspondant à la clé CLE
    
  • Quand l'index d'un élément permet d'accéder à celui-ci à l'aide de GetByIndex ou de SetByIndex, l'élément se comporte comme Array (tableau avec un Index).
    
    mySL.GetKey(3) 'retourne la Clé qui est dans l'élément d'index 3
    
    mySL.GetByIndex(3) 'retourne la valeur qui est dans l'élément d'index 3
    
SortedList maintient en interne deux tableaux , un tableau pour les clés et un autre pour les valeurs associées.

Index de base 0: Le premier élément est 0.

Exemple:

Dim mySL As New SortedList()
mySL.Add("1", "Hello")
mySL.Add("2", "World")
mySL.Add("3", "!")


Console.WriteLine(" Count: {0}", mySL.Count)    'Nombre d'éléments
Console.WriteLine(" Capacity: {0}", mySL.Capacity) 'nombre d'éléments possible mais il augmente automatiquement, on n'a pas à s'en occuper.
 

Dim i As Integer
For i = 0 To mySl.Count - 1
    Console.WriteLine( myList.GetKey(i)& myList.GetByIndex(i))  'affiche les éléments de la collection

                                                                ' par index croissant.
Next i

V-D-6-g. Queue: c'est une Classe .Net

Collection d'objets de type FIFO (First In, First Out)

Premier arrivé premier servi.

C'est la queue devant un cinéma, le premier arrivé, prend son billet le premier.

Les objets (String, Integer,....) stockés dans Queue sont insérés à une extrémité et supprimés à l'autre.

Le nombre d'élément de la queue est géré automatiquement.

DeQueue supprime et retourne l'objet de début de liste

EnQueue ajoute un objet en fin de liste

Peek retourne l'objet de début sans le supprimer


Dim myQ As New Queue()
myQ.Enqueue("One")
myQ.Enqueue("Two")
myQ.Enqueue("Tree")


Console.WriteLine ( myQ.Count) 'Affiche le nombre d'éléments.
 

Console.WriteLine (myQ.Dequeue()) 'Affiche le premier sorti en le sortant. "one" dans notre exemple.
'S'il n'y a plus d'élément cela lève une exception (une erreur), il faut donc gérer l'exception ou contrôler le nombre d'élément avec la propriété Count.

If MyQ.Count>0 then

    myQ.Dequeue..

End If

Console.WriteLine (myQ.Peek()) 'Affiche le premier élément sans l'enlever de la Queue
 

myQ.Clear() 'Efface tous les éléments de la queue

V-D-6-h. Stack: c'est une Classe .Net

Collection d'objets de type pile ( ou stack) LIFO (Last In, First Out)

Dernier entré, premier sortie.

Ce type de stack (pile) est très utilisé en interne par les programmes informatiques: on stocke dans une stack les adresses de retour des procédures appelées, au retour on récupère l'adresse du dessus.

Push insère un objet en haut de la pile

Pop enlève et retourne un objet en haut de la pile

On peut utiliser une pile dans un programme pour gérer le déplacement de l'utilisateur dans un arbre, les éléments en cours sont stockés par Push, pour remonter en chemin inverse, on Pop.

warning Attention le premier élément est ici l'élément 1 (élément d'index 1 à count)
Exemple:

Dim MaPile As New Stack()

Dim Str As String

'Ajouter des éléments à la pile

MaPile.Push ("A")

MaPile.Push ("B")

MaPile.Push ("C")

'Récupérer un objet de la pile:

 Srt =MaPile.Pop()
Str est maintenant égal à "C"

warning Attention, si Option Explicit=On, les éléments de la pile étant des objets, on ne peut pas les affecter à une variable String, il faut écrire:

Str = CType(MaPile.Pop(), String)    'on convertit (cast) l'objet en String
Si la pile est vide et que l'on 'Pop', une exception non gérée du type 'System.InvalidOperationException' se produit.(une erreur se produit et cela plante!!), là aussi vérifier que MaPile.Count (qui indique le nombre d'éléments dans la pile) n'est pas égale à 0 avant de 'Poper'.

Mapile.Clear()     'Supprime tous les objets.

V-D-6-i. BitArray: c'est une Classe .Net

Crée une collection de booléens (codés sur un bit). La valeur de chaque élément est True ou False.

 Creation de BitArray.
Dim myBA As New BitArray(5)    'BitArray de 5 bits

Dim myBA As New BitArray(5, False) 'BitArray de 5 bits à False

Dim myBA() As Boolean = {True, True, False, False, False}
Dim myBA As New BitArray(myBytes) 'on crée un  tableau de Booleans que l'on met dans le BitArray
Le premier élément est l'élément 0.

On peut mettre tous les bits à True avec SetAll:

myBA.SetAll(True)

' Mettre le dernier Bit à False avec Set.
myBA.Set(myBA.Count - 1, False)
 

'Obtenir la valeur du second Bit

myBA.Get(1)
 
myBA(1) ou myBA.Item(1) donnent aussi la valeur du second Bit.

On peut effectuer des opérations logiques entre 2 BitArray (Or, Xor, And Not):

Exemple pour Or:

myBA1.Or(myBA2)
Count et length donnent le nombre d'éléments, mais count est en lecture seule, Length permet, lui, de modifier le nombre d'éléments.


V-D-6-j. En VB 2005 :il y a les Collections 'generic' ou 'Specialized'

Collections génériques:

On peut créer une collection générique (System.Collections.Generic) et lui imposer un type.

Exemple: créons une collection de String (List(Of String)): Elle est typée car elle ne peut contenir que des 'String'.

Dim l As New System.Collections.Generic.List(Of String)
Il s'agit d'une List avec Index.

l.Add("toto")    'On ajoute une string

Dim S As String = l.Item(0) ' l'item est bien typé : même avec 'Option Strict=on' pas besoin de CType. 
Il y a aussi de nouveaux types de collections génériques

Les Dictionnary(Of..) avec Clé et valeur

Les SortedDictionnary(Of..) avec Clé et valeur trié.

Les LinkedList(Of..) Liste Chaînée, chaque élément comportant une propriété Value, Next et Previous.

Les SortedList(Of..)..

Les Stack(Of..)

Les Queue(Of..)

Collections spécialisées:

L'espace System.Collections.Specialized fournit de nouveau type de collection très spécifiques:

Exemple: ListDictionary avec Clé et Valeur:

Dim l As New System.Collections.Specialized.ListDictionary

l.Add(2, "toto")
On peut aussi créer des collections 'composées'

Dim genericColl As New System.Collections.Generic.Dictionary(Of String, String)
genericColl.Add("PremiereClé", item1)
BitVector32 est un type de collection qui contient des Booléens ou des entiers.
StringCollection est un type de collection String.

Intérêts de ses collections est qu'elle sont fortement typées: Elle n'acceptent que des éléments d'un type: des String dans le dernier exemple.


V-D-6-k. Généralisation de la notion de collection.

Certains objets ont une liste de données, d'items, Vb les organise en Collections.

Une collection peut donc faire partie des propriétés d'un objet.

Exemple:

On verra plus loin qu'un contrôle nommé TextBox peut contenir du texte, ce contrôle à une collection nommée .lines qui contient chaque ligne du texte (s'il y en a plusieurs)

Si le texte contient 3 lignes, elles seront dans la collection .lines

Texbox1.lines(0)    'remarquer, ici le premier élément est 0!!

Textbox1.lines(1)

Textbox1.lines(2) 
L'indice des éléments va de 0 à count-1

Autres exemple:

Les contrôles ListBox possèdent une collection Items dans laquelle est placé tous les éléments contenus dans la liste. Pour ajouter un élément on utilise la méthode Add de la collection Items: ListBox.Items.Add( )

Un tas d'objets possèdent des collections.

Encore plus: chaque formulaire possède une Collections Controls. Il s'agit d'une collection qui contient tous les contrôles de ce formulaire.


V-D-6-l. Pourquoi le premier élément est 0 ou 1?

warning Le .NET Framework normalise les collections comme étant des collections de base zéro (ArrayList par exemple). Les Collections de Visual Basic fourni des collections de base 1.

V-D-6-m. Exemples sur les collections:

Créer une ArrayList, une queue, ajouter la queue à la ArrayList, chercher un élément, insérer un élément.

Les collections font partie de l'espace de nom Systeme.Collections

Imports System.Collections


' Créer une ArrayList.
Dim myAL As New ArrayList()
myAL.Insert(0, "un")
myAL.Insert(1, "deux")

' Créer une Queue.
Dim myQueue As New Queue()
myQueue.Enqueue("trois")
myQueue.Enqueue("quatre")


' Copies la Queue dans ArrayList à l'index 1.
myAL.InsertRange(1, myQueue)


' Chercher "deux" et ajouter "moins de deux" avant .
myAL.Insert(myAL.IndexOf("deux"), "moins de deux")


' Ajouter "!!!" à la fin.
myAL.Insert(myAL.Count, "!!!")

V-D-6-n. Lexique anglais=>Français:

Array = tableau, table.

lenght= longeur

Key= clé

Remove (to)= enlever

Stack= tas


V-D-7. Les 'Structures'

Permet de regrouper des données de type différent:

(En Vb6 il y avait les types définis par l'utilisateur, ils sont remplacés par les structures.)

info Les structures sont intéressantes quand vous voulez utiliser des variables contenant plusieurs informations de différent type.
Exemple :

Vous voulez définir une variable contenant une adresse composée d'un numéro, de la rue,de la ville.

Il faut d'abord définir la structure (au niveau Module ou Class, pas dans une procédure)

Public Structure Adresse

   Dim Numero     As Integer

   Dim Rue        As String

   Dim Ville      As String

End Structure
Puis dans une procédure il faut déclarer la variable :

Dim MonAdresse As Adresse
La variable MonAdresse est déclaré comme une adresse, elle contient donc:

un numéro 'stocké' dans MonAdresse.Numero

une nom de rue 'stocké' dans MonAdresse.Rue

un nom de ville 'stocké' dans MonAdresse.Ville

On pourra enfin l'utiliser :

MonAdresse.Numero=2

MonAdresse.Rue= "Grande rue"

MonAdresse.Ville= "Lyon"
On peut aussi utiliser le mot clé With pour ne pas avoir à répéter le nom de la variable (et cela va plus vite).

With MonAdresse

    .Rue= "Grande rue"

    .Ville= "Lyon"

End With
With est utilisable sur tous les objets.

Il est possible de travailler sur un tableau de structures:

Dim Adresses(99) as Adresse    'Permet de travailler sur un tableau de 100 adresses

Adresses(33).Rue="Place de la mairie"
On peut utiliser une variable déclarée par une structure comme paramètre d'une fonction:

Sub AfficheAdresse( ByVal  Une Adresse As Adresse)

...Imprimer l'adresse

End sub
Pour imprimer l'adresse 33 on écrira AfficheAdresse ( Adresse(33))


V-D-7-a. Attention quand dans une structure il y a un tableau, il faut l'initialiser:

on veut définir une structure dans laquelle il y a 25 données DriveNumber.

On aurait tendance à écrire:

Public Type DriveInfo

   DriveNumber(25) As Integer FAUX

   DriveType As String

End Type
' En Visual Basic .NET il y a 2 méthodes:

1-Méthode par initialize

Une structure peut comporter une méthode.

Ici, on a crée une méthode Initialize qui redimensionne le tableau interne à la structure.

Public Structure DriveInfo

   Dim DriveNumber() As Short

   ' Noter que le nombre d'élément a disparu.

   Dim DriveType As String

   ‘maintenant on instance les 25 éléments.

   Public Sub Initialize()

      ReDim DriveNumber(25)

   End Sub

End Structure
Exemple de routine utilisant la structure.

Function AddDrive(ByRef Number As Short, ByRef DriveLabel As String) As Object

   Dim Drives As DriveInfo

   Drives.Initialize()

   Drives.DriveNumber(0) = 123

   Drives.DriveType = "Fixed"

End Function
2-Autre manière de faire:

Public Structure DriveInfo

   Dim DriveNumber() As Short

   Dim DriveType As String

End Structure

 

Function AddDrive(ByRef Number As Short, ByRef DriveLabel As String) As Object

   Dim Drives As DriveInfo

   Redim Drives.DriveNumber(25)

   Drives.DriveNumber(3)=12

   Drives.DriveType = "Fixed"

End Function
Si on utilise 100 variables Drives, il faudrait 'Redim' le tableau pour chaque variable!!

Dim Drives (100) As DriveInfo

 

For i as Integer =0 to 100

Drives (i).Initialize                    'Dur dur!!

Next i
En plus si Dim Drives (100) est en tête d'un module, il faut mettre la boucle dans une procédure.


V-D-7-b. Allons plus loin:

Une structure hérite de System.ValueType


V-D-7-b-i. Les structures sont des types 'valeur'.
Une variable d'un type structure contient directement les données de la structure, alors qu'une variable d'un type classe contient une référence aux données, ces dernières étant connues sous le nom d'objet.

Cela a de l'importance: si je crée une variable avec une structure, que je copie cette variable dans une seconde, le fait de modifier la première variable ne modifie pas la seconde.

Prenons l'exemple donné par Microsoft:

Structure Point
   Public x, y As Integer
   Public Sub New(x As Integer, y As Integer)
      Me.x = x
      Me.y = y
   End Sub
End Structure 
On définie une structure Point et on définie une méthode New permettant de saisir les valeurs:

Public Sub New est un constructeur.

Pour saisir les valeurs de x et y ont peut utiliser:

Dim a As Point
a.x=10
a.y=10
ou utiliser le constructeur:

Dim a As New Point(10,10)  
En partant de la déclaration ci-dessus, le fragment de code suivant affiche la valeur 10 :

Dim a = new Point(10, 10)
Dim b = a
a.x = 100
Console.WriteLine(b.x)	'b est donc bien différent de a
L'assignation de a à b crée une copie de la valeur, et b n'est donc pas affecté par l'assignation à a.x. Si, en revanche, Point avait été déclaré comme une classe, la sortie aurait été 100 puisque a et b auraient référencé le même objet.

Enfin, les structures n'étant pas des types 'référence', il est impossible que les valeurs d'un type structure soient nulles ( elles sont égales à 0 après la création).


V-D-7-b-ii. Les structures peuvent contenir plein de choses:
On a vu qu'elle peuvent contenir:

Des variables de différent type.

Des tableaux.

Des méthodes : on a vu l'exemple de Initialize et de New.

Mais aussi

Des objets.

D'autres Structures.

Des procédures.

Des propriétés.

Exemple donné dans l'aide (et modifié par moi) :

Débutant: A relire peut-être ultérieurement quand vous saurez utiliser les Classes.

Cet exemple définit une structure Employee contenant une procédure CalculBonus et une propriété Eligible.

Public Structure Employee
Public FirstName As String
Public LastName As String
' Friend members, accessible partout dans le programme.
Friend EmployeeNumber As Integer
Friend WorkPhone As Long
' Private members, accessible seulement dans la structure.
Private HomePhone As Long
Private Level As Integer
Public Salary As Double
Public Bonus As Double
  ' Procedure .
  Friend Sub CalculateBonus(ByVal Rate As Single)
   Bonus = Salary * CDbl(Rate)
  End Sub
' Property pour retourner l'éligibilité d'un employé.
  Friend ReadOnly Property Eligible() As Boolean
    Get
      Return Level >= 25
    End Get
  End Property
End Structure
Utilisons cette structure:

Dim ep As Employee    'Déclaration d'une variable Employee

ep.Salary = 100       'On saisit le salaire 

ep.CalculateBonus(20) 'On calcul le bonus

TextBox1.Text = ep.Bonus.ToString    'On affiche le bonus
Cela ressemble aux Classes !! Non?


V-D-7-b-iii. Portée:
Vous pouvez spécifier l'accessibilité de la structure à l'aide des mots clé: Public, Protected, Friend ou Private ou garder la valeur par défaut, Public. Vous pouvez déclarer chaque membre en spécifiant une accessibilité. Si vous utilisez l'instruction Dim sans mot clé, l'accessibilité prend la valeur par défaut, Public.

Private Mastructure

    Public i As Integer

    ...

End Structute
En conclusion les structures sont maintenant très puissantes et peuvent contenir autant de choses que les modules de Classes , on verra cela plus loin. Mais les structures sont référencées par valeur alors que les Classes le sont par référence


V-D-8. Attention type valeur ou référence

Résumons la notion très importante de variable par valeur ou par référence.


V-D-8-a. La variable 'par Valeur':

Contient réellement une valeur.

Prenons pour exemple une variable de type 'Long'

Dim L As Long

L= 1456 
L occupe 8 octets nécessaire pour coder un long, ici L a une valeur de 1456, donc dans ces 8 octets il est codé 1456.

Sont des variables par 'Valeur':

Les Integer, les Long les Short

Les Single, Double, Decimal

Les Booleans, Char, Date

Les Structures

Les énumérations


V-D-8-b. La variable 'par Référence':

Elles ne contiennent pas la valeur de l'objet mais son adresse en mémoire, sa référence.

Dim O As Object
O contient l'adresse de l'objet codée sur 4 octets.

Sont des variables par référence:

Les Objets

Les Strings

Les tableaux

Les Classes


V-D-8-c. Influence sur l''Affectation':

Posons le problème:

Travaillons sur A et B, 2 variables ayant la même 'nature'.

A existant déjà, faisons:

Dim B=A
Puis modifions la valeur de A, cela modifie t-il B?

Les variables par Valeur ou par Référence ne réagissent pas de la même manière:

Si le type de variable est par valeur (valable pour les entiers, les Long.. les structures..), chaque variable ayant sa valeur, B n'est pas modifié.

Si le type de variable est par référence (valable pour les tableaux, les objets, les string..), chaque variable est définie par sa référence (son lieu physique); faire A=B entraîne que A et B ont même référence. Si on modifie A, B est modifié car il pointe au même endroit.

Voyons des exemples:

Même si on affecte une variable par valeur à une autre, les deux variables restent différentes: elles conservent leur propre espace de stockage:

Dim L As Long

Dim P As Long

L=0

L=P     'on affecte P à L

P=4     'on modifie P

=> L=0 P=4    Modifier P n'a pas modifié L
Par contre si on affecte une variable par référence à une autre, elle pointe toutes les 2 sur le même endroit mémoire: si j'en modifie une, cela modifie l'autre.

'Créons une Classe contenant un entier (Exemple à relire quand vous aurez étudié les Classes)

Class Class1
   Public Value As Integer = 0
End Class

Dim C1 As New Class1()
Dim C2 As Class1 =C1    'on crée C2, on affecte C1 à C2
C2.Value = 123          'on modifie C2
=> C1.Value=123 C2.Value=123 Modifier C2 a modifié C1 car elles pointent sur le même endroit mémoire.


V-D-8-d. On se méfiera donc du type 'référence ' ou 'Valeur' des données que l'on utilise: exemple des Tableaux

Exemple sur les tableaux qui sont 'Par référence':

Dim A(3) As String

A(1) = "a"

Dim B(3) As String

B(1) = "b"

B = A

A(1) = "c"

Label1.Text() = B(1)    'Affiche 'c'
En effet un tableau est 'par référence' et le fait de faire A=B donne la même adresse mémoire aux 2 tableaux, aussi , modifier l'un modifie l'autre.

B= A.Clone aurait copié le tableau A dans B en conservant 2 tableaux distinct et la dernière instruction aurait affiché 'a'.

Remarque: A(2)=B(2) affecte un élément d'un tableau à un élément d'un autre tableau, cela ne modifie que la valeur d'un élément et n'affecte pas le tableau.


V-D-8-e. Le cas particulier des 'String' qui sont 'Par référence':

warning Attention: par contre :

Dim A As String

A = "a"

Dim B As String

B = "b"

B = A

A = "c"

Label1.Text() = B    'Affiche 'a'
Bien que cela soit par référence, B=A affecte simplement la valeur de A à B, si on modifie ultérieurement A, B n'est pas modifié. (idem pour clone et copy!!) Pour une string qui est 'par référence', il parait donc impossible de la dupliquer, elle se comporte comme une variable par valeur!! Avez -vous des idées pour expliquer cela?

L'opérateur d'affectation "=" de deux strings "A=B" a simplement été défini de manière restrictive pour les strings. Les créateurs de vb .net lui ont permis uniquement une copie de la valeur de la string et non de la référence.
Il vaut mieux ne pas permettre l' affectation de la même référence pointant sur le même objet c'est dangereux pour les débutants et cela serait totalement incompatible avec les versions précédentes.. Ensuite, parce que la copie de la valeur d'une string dans une autre est une opération extrêmement courante chez les programmeurs. Ce qui n'est pas le cas de l'affectation de la même référence pointant sur le même objet.

En conclusion, rien de choquant dans le fait qu'un type string se comporte comme un type par valeur: car c'est juste la définition de l'opérateur d'affectation "=" qui a été redéfinie, et c'est tout. Tout ce qui concerne l'implémentation du type string est strictement comme tous les types par référence. (Merci Sabri)


V-D-8-f. Déclaration avec New ?

En théorie, il faut utiliser New quand on déclare une variable 'par référence':

Il faut écrire:

Dim L As Long    'un long est 'par valeur'

Dim F As New Button    'un bouton est un objet 'par référence'
En fait

Dim L As New Long  'est accepté

Dim O As Object    'est accepté.

Dim S As String    'est accepté.
Pour les Classes ou les objets graphiques , il faut par contre bien taper New pour créer l'objet:

Dim F As New Button
Si on tape Dim F As Button on crée une référence vide, mais pas d'objet Button.


V-D-8-g. Valeur après déclaration:

Apres création (avant initialisation) une variable numérique 'par Valeur' contient 0,

Dim L As Long    'L contient 0
Par contre une String (par référence) qui a été créée par Dim et non initialisée contient Nothing.

Dim O As Object    'O contient Nothing: il ne pointe sur aucun objet.
On peut le tester par If IsNothing( O ) then.. ou If O Is Nothing..

Pour les tableaux, bien que le tableau soit 'par Référence', c'est le type de variable utilisé dans le tableau qui décide de la valeur des éléments après déclaration.

Dim T(3) As Long    '=>T(0)=0 

V-D-8-h. Comparaison:

1-Une variable par Valeur peut être comparée à une autre par "=",

Dim L As Long=12

Dim P As Long=24

If L=P Then..
2-Par contre une variable par référence peut être comparée à une autre par "Is".

Dim O As Object

Dim Q As Object   

If O Is Q then..
NB: pour les String '=' et 'Is' peuvent être utilisés.

3-Equals peut être utilisé pour comparer les 2 types de données:

Obj1.Equals(Obj2))  'Retourne True si Obj1 et Obj2 ont le même pointeur.
ou

N1.Equals(N2)    'Retourne True si la valeur de N1= la valeur de N2
 
Pour les types référence, l'égalité est définie comme une égalité d'objets, c'est-à-dire si les références renvoient ou non au même objet. Pour les types valeur, l'égalité est définie comme une égalité au niveau du bit.


V-D-8-i. Il existe une instruction permettant de voir si une variable est de type 'Par référence'

Cet exemple utilise la fonction IsReference pour vérifier si plusieurs variables font référence à des types référence.

Dim R as Boolean

Dim MyArray(3) As Boolean

Dim MyString As String
Dim MyObject As Object
Dim MyNumber As Integer
R = IsReference(MyArray) '  R= True. Tableau
R = IsReference(MyString) ' R= True. String
R = IsReference(MyObject) ' R= True. Objet
R = IsReference(MyNumber) ' R= False. Entier

V-D-9. Variable 'Object' et autre

Il existe un autre type de variable: le type 'Object'.


V-D-9-a. Le Type 'Object':

Parfois on ne sait pas ce que va contenir une variable: un Integer? une String? un Single?

Pour résoudre ce problème on utilise une variable de type 'Object'

Cela remplace le type 'Variant' de VB6

Dim myObjet As Object
Ensuite:

myObjet=12
est accepté, et myObjet sera considéré comme un type Integer

myObjet=12.6
est accepté, et myObjet sera considéré comme un type Single

myObjet="Visual Basic"
est accepté aussi, et myObjet sera considéré comme un type String

Les 3 affectations myObjet= peuvent se suivre sans planter, l'objet contenant successivement un type Integer, Single et String.

On rappelle qu'une variable objet est une variable 'Par référence'.

On peut, suite au dernier exemple, récupérer l'objet et le transformer en String.

Dim maString As String

maString= CType(myObjet, String)
Comment savoir quel type de variable contient la variable 'Objet'?

Si on fait myObjet.GetType.ToString cela retourne 'System.string' indiquant que myObjet contient bien une String.

myObjet.GetType.Name retourne 'String'

Pour tester si myObjet est une String, il y a une autre manière avec TypeOf Is:

If TypeOf myObjet Is String Then

 

End if
warning Attention, TypeOf Is retourne True aussi pour les Classes d'objet parent.

Dim monlabel As New Label

If TypeOf monlabel Is Control Then ' est vérifié car label dérive de control
monlabel est bien un label mais c'est aussi un control.(On verra que tous les objet visuel comme Label dérive de la classe Control).

Comment utiliser les membres d'une variable objet?

Exemple: mettre une string dans une variable Objet, connaître la longueur de la String.

  • Si Option strict=Off (On force VB à ne pas être trop Strict!!! On verra cela plus loin)

Dim myObjet As New Object

myObjet="VB"

MessageBox.Show(myObjet.length)  'affiche 2 
  • Si Option strict=On (On force VB à ne rien tolérer)
MessageBox.Show(myObjet.length) déclenche une erreur: les liaisons tardives ne sont pas acceptées.

MessageBox.Show(V.GetType().GetField(n).GetValue(V).ToString) déclenche une exception.

Il faut écrire simplement:(Merci le forum de developpez.com)

Dim myObjet As New Object

myObjet="VB"

MessageBox.Show(DirectCast(myObjet, String).Length.ToString)
ou

MessageBox.Show(CType(myObjet, String).Length.ToString)
DirectCase et CType transforme un type de variable en un autre, DirectCase est moins 'tolérant' car la variable qui reçoit doit être du bon type.

Une autre méthode consiste à transformer par Ctype le contenu de l'objet vers une variable String, puis à afficher la longueur de cette variable String.

Dim myObjet As New Object

myObjet="VB"

Dim  myString  As String

myString = CType(myObjet, String)

MessageBox.Show(myString.Length.ToString)
info Du fait que les membres utilisés avec une variable Objet ne sont pas définis à l'écriture du programme (on ne sait même pas quel type de variable sera dans l'objet, on n'en connaît donc pas les membres), la recherche du membre se fait à l'exécution, c'est plus long, de plus les contrôles et vérifications se font à l'exécution.
Cela se nomme une liaison tardive, à éviter donc. On évitera donc d'utiliser si possible des variables 'Objet'.
Utilisez plutôt des variables typées (des variables String , Integer..) au départ, quand on les utilise, les contrôles et appels sont vérifiés dés le départ, on appelle cela une liaison anticipée ou précoce.

V-D-9-a-i. Comparaison d'objet.
Is permet de savoir si 2 variables objet se rapportent à la même instance.

Dim o1 As New Objet = monObjet

Dim o2 As Objet

o2= o1

If o1 Is o2 Then..

V-D-9-a-ii. Nothing.
Après:

Dim myObjet As Object
myObjet contient Nothing, c'est à dire 'Rien': pas de référence à une instance.

Après avoir utiliser myObjet=12

On peut faire myObjet=Nothing.

Lorsque vous assignez Nothing à une variable objet, cette dernière ne fait plus référence à une instance d'objet, elle ne pointe sur rien.

Si la variable avait fait référence à une instance au préalable, l'assignation de Nothing à la variable ne met pas fin à l'instance. L'instance se termine, et les ressources mémoire et système qui lui sont associées sont libérées uniquement lorsque le garbage collector (qui fait le ménage) détecte l'absence de toute référence active restante.

On peut tester si un Objet contient Nothing avec .IsNothing


V-D-9-b. Les variables d'autres types:

On verra que l'interface utilisateur est composée de contrôles, ces contrôles étant des objets, et bien, on peut déclarer une variable de type 'contrôles': bouton, ou textbox ou formulaire.

Dim myButton As New Button    'crée une variable myButton de type Button

 
Ensuite on peut utiliser les membres de la classe Button

myButton.BackColor


 

Dim myTextBox As New TextBox    'crée une variable myTextBox de type TextBox

V-D-9-c. Utilisez donc des variables le plus typées possible.

Eviter les Object.

Si une variable doit contenir des boutons, créer une variable Button.

Si une variable doit être utilisée pour contenir divers choses: Button, ListBox... plutôt que la déclarer en Objet, il est préférable de la déclarer en System.Windows.Forms.Control

Dim fistControl As New System.Windows.Forms.Control

fistControl= New Button

V-D-9-d. Attention quand on met un objet dans un autre objet:

Si je met un Button dans une variable Object.

Dim MyObjet As Object

MyObjet = Button1
MyObjet donne accès aux propriétés des Object (Equals, GetType, ToString...); pour utiliser les propriétés de Button (comme Text par exemple, il faut d'abord transformer l'objet en Button en écrivant : CType(MyObjet, Button).

Par exemple, pour mettre le texte du button contenu dans MyObjet dans la variable MyTexte, il faut écrire:

Dim MyTexte As String = CType(MyObjet, Button).Text

V-D-10. Variable Booléenne

Mr Georges Boole 1805-1864
Mr Georges Boole 1805-1864
Il existe un autre type de variable: le type 'Booliens 'ou 'Booléens'. (Boolean)


V-D-10-a. Introduction:

L'algèbre de Boole est la partie des mathématiques, de la logique de l' électronique et de l'informatique qui s'intéresse aux opérations et aux fonctions sur les variables logiques. En logique propositionnelle, une expression est soit vraie soit fausse. (le vrai (1) et le faux (0)).

Georges Boole (1815-1864), physicien Anglais définit en 1847 un algèbre qui est applicable au raisonnement logique, qui traite des fonctions à variables binaires (deux valeurs). Mais il ne s'applique pas aux systèmes à plus de deux états d'équilibre.

Une variable booléenne, ou logique, ou binaire ne prend que deux valeurs (elle est généralement stockée sous la forme d'un bit).

Vers la fin des années 30, Claude Shannon démontra qu'à l'aide d'interrupteurs fermés pour « vrai » et ouverts pour « faux » il était possible d'effectuer des opérations logiques en associant le nombre 1 pour « vrai » et 0 pour « faux ».

Ce codage de l'information est nommé base binaire. C'est avec ce codage que fonctionnent les ordinateurs. Il consiste à utiliser deux états (représentés par les chiffres 0 et 1) pour coder les informations.

Il permet d'étudier les circuits logiques.


V-D-10-b. Les booléens:

On a parfois besoin de savoir si une assertion est vraie ou Fausse.(True ou False)

Pour stocker une information de ce type, on utilise une variable de type booléen. Une variable de ce type ne peut contenir que True ou False.

Le terme booléen vient de "l'algèbre de Boole", cette algèbre ne travaille que sur les valeurs 1 ou 0 (True ou False)

Soit myBoolean une variable booléenne:

Dim myBoolean As Boolean
On peut écrire myBoolean = True

On peut aussi tester cette variable:

If myBoolean = False Then..
L'expression après If est évaluée, si elle est vraie 'Then' se produit.

Autre exemple:

If maValeur=2 Then ..

End If
L'expression 'maValeur=2' est évaluée, si maValeur est effectivement égal à 2, l'expression prend la valeur True; dans ce cas le programme se poursuit après Then.

si maValeur est différent de 2, maValeur=2 est évaluée et prend la valeur False; dans ce cas le programme se poursuit après End If.

Un booléen peut donc prendre deux états (vrai/faux, oui/non, 1/0, etc.). Il s'agit donc d'une "valeur binaire". Techniquement, un booléen peut être représenté par un seul bit (binary digit = chiffre binaire).

Dans les langages n'ayant pas de variables booliennes, on se servait souvent d'un entier, avec pour convention que la valeur 0 représente "faux", tandis que toute valeur non nulle représente "vrai". En VB6 vrai était égale à -1. En VB.Net vrai = 1. Mais on s'en fiche car:

info un Booléen est un Booléen, en VB.Net on utilise donc True ou False comme seules valeurs pour un Booléen.
Il n'empêche que si on utilise une expression, un nombre et qu'on l'évalue comme si c'était un booléen (C'est pas bien!!), la valeur 0 représente "False", tandis que toute valeur non nulle représente "True".


V-D-10-c. Les conditions:

Après If, While, Do Loop il faut une condition qui est une expression booléenne.

Exemple:

If Condition Then    'Si 'condition'..

  ...

End if

 

 

Do Until condition    'Boucler jusqu'à ce que 'condition'

      ...

Loop

 

While Condition        'Tant que 'condition' boucler

...

End While
Pour écrire une condition, on utilise les opérateurs:

= égal

> supérieur à

 < inférieur à

>= supérieur ou égal

<= inférieur ou égal

<> Différent de
L'évaluation d'une condition donne True (Vrai) ou False (Faux) car on l'a dit c'est une expression booléenne.

Exemple :

      Dim valeur1 As Integer=2

      Dim valeur2 As Integer=3  

      If valeur1=valeur2 Then

        ...

      End if  
valeur1 étant différent de valeur2, la condition 'valeur1=valeur2' prend la valeur False et le programme passe à la ligne après End If).

Ici le signe = n'indique pas une affectation mais 'égale' dans une expression à évaluer.

On peut combiner les opérateurs et mettre des parenthèses:

 If (valeurC <> valeurD )AND (valeurD =2)

V-D-10-d. Les opérateurs logiques:

Si on a plusieurs expressions logiques, on peut les combiner avec des opérateurs logiques.

Si A et B sont des expressions Booléens:

A And B     retourne True si A et B sont vrais

A Or B      retourne True si une des 2 est vrai

A Xor B     retourne True si une et une seule est vrai

Not A       retourne True si A est faux et vice versa
On entend par expression Booléen le résultat de l'évaluation d'une condition:

c=d retourne True si c égal d et False si c différent de d.

Exemple

Si A différent de B.. peut s'écrire If Not(A=B) Then..

Si A compris entre 2 et 5 peut s'écrire If A>=2 And A<=5 Then..

Comment faire une bascule:

Il faut écrire A= Not A

A chaque fois que l'on effectue cette instruction A bascule à True s'il était à False et vice versa.

Les opérateurs AndAlso et OrElse sont plus rapide car ils n'évaluent pas la seconde expression si ce n'est pas nécessaire.

Parfois les expressions sont complexes et on peut les simplifier en utilisant des transformations:

Originale Transformation
Not A And Not B Not (A Or B)
Not A And B Not (A Or Not B)
A And Not B Not (Not A Or B)
A And B Not (Not A Or Not B)
Not A Or Not B Not (A And B)
Not A Or B Not (A And Not B)
A Or Not B Not (Not A And B)
A Or B Not (Not A And Not B)
Exemple pratique:

Si A compris entre 2 et 5 peut s'écrire If A>=2 And A<=5 Then..

ou If Not (A<2 Or A>5) Then...

Une remarque:

Avec une expression Booléenne, on peut écrire:

Dim a As Boolean= True

If a = True Then..
ou

If a Then..
Exemple:

If (x=15)=True  Then..

ou If x=15 Then...
Donc, avec une expression booléenne, et uniquement avec une expression booléenne, il est possible de se passer du = True après un If car de toutes façons , l'expression est évaluée.

Voir aussi le chapitre sur l'algèbre de Boole.


V-E. Soyons strict et explicite.

VB peut être tolérant ou pas

Option Strict=On et Option Explicit=On le rendent totalement intolérant, et c'est tant mieux!! Voyons cela.


V-E-1. Notion de conversion Explicite et Implicite:

La conversion Explicite: est permet de forcer la conversion d'un type de données vers un autre type à l'aide de mots clés.

Exemple

Dim d As Double = 2.65

Dim i As Integer

 i=CType(d,Integer)  'conversion d'une valeur double en Integer
Il existe aussi la conversion implicite effectuée automatiquement sans syntaxe particulière et de manière transparente.

VB peut le permettre ( Si Option Explicit Off dans la configuration )

Exemple

Dim d As Double = 2.65

Dim i As Integer

 i=d  'Pour affecter à i le Double d, Vb a transformé le double d en Integer.

V-E-2. Option Strict


V-E-2-a. 1-Avec Option Strict=On VB refuse les conversions implicites qui pourraient entraîner des pertes de données.

VB est naturellement très arrangeant (trop sympa !!) quand il est configuré avec Option Strict Off :

Par défaut il transforme, quand c'est possible, et si nécessaire un type de variable en un autre type.

Si je passe un nombre qui est en double précision (Double) dans une variable en simple précision (Single), VB accepte, au risque de perdre de la précision (s'il y a un très grand nombre de chiffre significatif).

Ainsi :

Dim D As Double

Dim S As Single

D=0.123456789

S=D

MessageBox.Show(s) ' affiche 0,1234568   le 9 est perdu car un single à 7 chiffres significatifs.
Cela peut être ennuyeux si c'est des calculs d'astronomie !! et le programmeur ne s'en rend pas forcément compte !!

Pour éviter cela il faut activer l'OPTION STRICT à ON (Elle est par défaut à Off)

Menu Projet > Propriétés de Nom de projet.

Page de propriétés de Langage VB.

Propriétés communes, génération.

En face de Option Strict, mettre On

Maintenant seules les conversions effectuées explicitement seront autorisées.

S=D est souligné dans le code pour signaler une conversion interdite.

(Par contre D=S est accepté car on passe d'une variable à une variable plus précise)

Il faudra maintenant, pour notre exemple, écrire :

S= CType(D,Single)
Cela entraîne une conversion de la valeur Double en Single ; s'il y a perte de précision, elle se produit quand même, MAIS le programmeur SAIT qu'il y a conversion, il prendra ou pas EN CONNAISSANCE DE CAUSE le risque.

Avec Option Strict le langage VB.Net devient bien moins tolérant:

Ecrire un programme avec Option Strict à Off, ça passe; mettre Option Strict à On un tas d'instruction coince!! même certains exemples Microsoft!! Car sans s'en rendre compte on passe d'un type de variable à l'autre sans arrêt!!


V-E-2-b. 2-Avec Option Strict=On VB refuse les conversions String<->numériques implicites.

Avec Option Strict=Off

Dim n As Integer=12

MessageBox(n)
Affiche 12 : le contenu de l'entier 'n' a été transformé automatiquement en String pour être affiché.

Avec Option Strict=On

Dim n As Integer=12

MessageBox(n)
Plante

Il faut transformer explicitement n en String et écrire:

MessageBox(n.ToString)

V-E-2-c. 3-Avec Option Strict=On VB refuse les 'Liaisons tardives':

Avec Option Strict=On VB refuse les liaisons tardives:

Dim V As Object

V="VB"
MessageBox.Show(V.Length) est refusé

Il faut écrire

MessageBox.Show(CType(V, String).Length.ToString)

'Option Strict Off' permet n'importe quoi. C'est du Basic au mauvais sens du terme.  

'Option Strict On' oblige à une grande rigueur. C'est du VB.Net  

V-E-2-d. 4-Avec Option Strict=On VB est plus rapide

La vérification est effectuée lors de la compilation, à l'exécution il y a moins de contrôle de type.


V-E-3. Option explicit

Pour la déclaration des variables nous avions dit que toute variable utilisée devait être déclarée.

Par défaut c'est vrai.

Ouvrir Menu Projet > Propriétés de Nom de projet.

Page de propriétés de Langage VB.

Propriétés communes, génération.

En face de Option Explicit, il y a On

On pourrait (c'est fortement déconseillé) mettre cette option à Off.

Cela ne rend plus obligatoire la déclaration des variables.

MaVariable=10 sans déclaration préalable est acceptée.

Cela présente certains inconvénients : Si on fait une faute de frappe en tapant le nom d'une variable, VB accepte le nouveau nom et crée une nouvelle variable objet distinct.

Dim MaVariable         MaVariable avec un b

MaVariabble=10         Faute de frappe(bb)Je crois avoir mis 10 dans Mavariable
En fait j'ai mis 10 dans une nouvelle variable nommée MaVariabble

Mavariable à toujours une valeur=0

Donc, c'est clair et sans appel : Laisser Option Explicit à On, ce qui oblige à déclarer toutes les variables avant de les utiliser Dans ce cas si vous tapez le nom d'une variable non déclarée, elles est soulignée en bleue.


V-E-4. Option strict et Explicit dans un module:

On peut aussi indiquer dans un module les options; ces instructions doivent être tapées avant toutes les autres.


V-F. Les constantes, les énumérations.

Les constantes.

Les énumérations.

Généralisations, énumérations fournies par VB.


V-F-1. Constantes:

Comme les variables, elles ont un nom et un type, mais leurs valeurs sont 'constantes'.

On les déclare par le mot Const, on peut les initialiser en même temps avec =

Exemple :

Const NOMDUPROGRAMME= "LDF"   ‘constante chaîne de caractères.

Const NOMBREDECASE As Integer = 12             ‘constante Integer
Ensuite on peut utiliser la constante:

For k= 0 To NOMBREDECASE

...

Next k
Si on utilise: For k=0 To 12, à la lecture c'est moins clair.

Si on écrit: NOMBREDECASE=13 cela déclenche une erreur!!

Habituellement, les constantes sont créées en début de programme.

info Il est conseillé par convention d'écrire le nom des constantes en majuscules.

V-F-1-a. Intérêt des constantes ?

  • Améliore la lisibilité et évite d'utiliser des constantes littérales:
    Il faut éviter:
    
    For i=0 To 100    'A quoi correspond 100?
    
    ..
    
    Next i
    
    Il faut écrire
    
    Const NBMAXPATIENT As Integer= 100
    
    For i=0 To NBMAXPATIENT
    
    ..
    
    Next i
    
  • Modifications du code facilitées:
    Si une constante doit être modifiée ultérieurement, il suffit en mode conception, de modifier sa valeur ce qui modifie sa valeur dans l'ensemble du code de l'application.

    Const NBMAXPATIENT As Integer= 200 'Si j'introduis une modification de valeur
    
    For i=0 To NBMAXPATIENT            'Toutes les boucles utilisant NBMAXPATIENT seront à jour
    
    Next i
    
  • Amélioration la vitesse.
    
    Const NBMAXPATIENT As Integer= 100 
    
    Dim nombre= NBMAXPATIENT
    
    est plus rapide que:
    
    Dim nbpatient As Integer= 100 
    
    Dim nombre= nbpatient
    
    Car le compilateur code directement nombre=20 dans le premier cas.

On rappelle que seuls les types primitifs peuvent avoir des constantes ( Byte, Boolean, Short, Integer, Long, Single, Double, Decimal, Date, Char, String)


V-F-1-b. Constantes prédéfinies dans le langage:

Les constantes de Visual Basic sont toujours là:

vbOk    'retourné par une MessageBox quand l'utilisateur a cliqué sur Ok.

vbBack

vbCancel

vbCrLf     'caractère numéro 13 (Cr) puis numéro 10 (Lf)

V-F-1-c. True False:

On rappelle que True et False sont des valeurs Booléens faisant partie intégrante de VB.

Pour les anciens de VB6 ne plus utiliser -1 et 0 (D'ailleurs c'est maintenant 1 et 0).

Mais, en plus, dans Visual Basic .NET, la plupart des constantes sont remplacées par des énumérations dans le .NET Framework.

(Voir plus bas )

idea Utiliser largement ces constantes fournies par VB, cela améliore la lisibilité et la maintenance.

V-F-2. Enumération:

Les énumérations sont utilisées lorsque l'on a un jeu de constantes liées logiquement.

Un bloc Enum permet de créer une liste (une énumération) de constantes:

Enum TypeFichier

    DOC

    RTF

    TEXTE

End Enum
Les constantes ainsi créées sont

TypeFichier.DOC

TypeFichier.RTF

TypeFichier.TEXTE

Le bloc Enum doit être dans l'en-tête du module (en haut).

C'est bien pratique car en écrivant le code, dès que je tape TypeFichier. la liste (DOC RTF TEXTE) apparaît.

Ensuite, on peut utiliser dans le programme les constantes créées.

fichierEnCours= TypeFichier.DOC par exemple.

On peut ensuite tester:

If fichierEnCours= TypeFichier.RTF then par exemple.

Il est conseillé par convention d'écrire le nom des énumérations en minuscules avec la première lettre en majuscules.

Ce qui suit concernant les énumérations est un peu plus complexe:

Chaque constante littérale de l'énumération a une valeur par défaut.

Par défaut

TypeFichier.Doc =0  

TypeFichier.RTF =1 

TypeFichier.TEXTE=2

..
La première valeur est 0.

Si on ne spécifie rien, les valeurs sont des Integers

Parfois le nom utilisé dans l'énumération (la constante littérale) est suffisant en soi et on n'utilise pas la valeur : Dans un programme gérant des fichiers, une variable prendra la valeur TypeFichier.Doc pour indiquer qu'on travaille sur les fichiers .DOC. Peu importe la valeur de la constante.

Mais d'autres fois il faut que chaque constante de l'énumération possède une valeur particulière.

Je peux imposer une valeur à chaque constante de l'énumération :

Enum TypeFichier

    DOC=2

    RTF=4

    TEXTE=8

End Enum
Cela évite d'écrire fichierEnCours= 15 (en retenant que 15=fichier doc, 30= fichier rtf...)

Je peux même donner plusieurs valeurs avec And et Or à condition d'utiliser l'attribut Flags.

<Flags()> Enum TypeFichier

    DOC=2

    RTF=4

    TEXTE=8

    TOUS= DOC AND RTF AND TEXTE

End Enum
L'attributs 'Flags() indique que les valeurs sont codées en bits, ce qui permet les combinaisons de valeurs. (pour 2 le second bit est à 1, pour 4 le troisième bit est à 1, pour 8, le quatrième bit est à 1...) (voir chapitre sue l'algèbre de Boole.)

Les énumérations sont des types qui héritent de System.Enum et qui représentent symboliquement un ensemble de valeurs. Par défaut ses valeurs sont des 'Integer' mais on peut spécifier d'autres types: Byte, Short, Integer ou Long. L'exemple suivant déclare une énumération dont le type sous-jacent est Long :

Enum Color As Long
 Red
 Green
 Blue
End Enum
Habituellement, on utilise les énumérations dans le code, comme des constantes.

Exemple:

Enum TypeFichier

    DOC=2

    RTF=4

    TEXTE=8

End Enum

' affecter à une variable:

Dim monFichier As TypeFichier = TypeFichier.RTF 
On remarque qu'on crée une variable de type énumération dans laquelle on ne peut mettre q'une énumération (en fait un Integer).

' affichage d'une valeur

Console.Out.WriteLine("Numéro type du fichier=" & monFichier)
Affiche: 4

Console.Out.WriteLine("Type du fichier=" & monFichier.ToString)
Affiche: RTF

' test avec la constante de l'énumération

If (monFichier = TypeFichier.RTF) Then

    Console.Out.WriteLine("C'est du RTF")

End If
Affiche:"C'est du RTF"

Mais parfois on a besoin de récupérer la liste des éléments d'une énumération.

Comment relire la liste des énumérations?

Il faut utiliser une méthode statique (ne nécessitant pas d'instanciation) GetValues pour obtenir toutes les constantes littérales ou valeurs d'un type énuméré que l'on passe en paramètre.

' liste des mentions littérales (Constantes)

For Each t As TypeFichier In [Enum].GetValues(monFichier.GetType)

    Console.Out.WriteLine(t.ToString)

Next

' liste des mentions entières (Valeurs)

For Each t As Integer In [Enum].GetValues(monFichier.GetType)

    Console.Out.WriteLine(t)

Next
Affiche:

DOC

RTF

TEXTE

2

4

8
Si on affecte un élément d'une énumération à une variable Integer, on récupère la valeur, si on utilise ToString on récupère la constante littérale.

Dim n As Integer

n = TypeFichier.RTF

Console.Out.WriteLine(n.ToString)

Dim st As String

st = TypeFichier.RTF.ToString

Console.Out.WriteLine(st)

Affiche

2

RTF
Comment récupérer dans une énumération une constante à partir de sa valeur ou une valeur à partir de la constante?

Ici il faut instancier:

Dim s As Type = GetType(TypeFichier)

Console.Out.WriteLine(CType([Enum].GetName(s, 15), String))

Console.Out.WriteLine(CType([Enum].Parse(s, "DOC"), String))
Affiche:

DOC

2

V-F-3. Généralisation de la notion d'énumération:

Noter que VB.Net contient, comme on l'a vu, un tas de constantes classées à l'aide d' Enum.


V-F-3-a. ControlChars:

Cette énumération contient les caractères de contrôle.

ControlChars.CrLf Chr$(13)+Chr$(10) qui sert à sauter à la ligne dans une chaîne de caractères :

Si on affiche "VISUAL" & ControlChars.CrLf & "BASIC"

On obtient à l'écran :

VISUAL

BASIC

 

ControlChars.Tab        Chr$(9) = caractère de tabulation 

ControlChars.NullChar   Aucun caractère

ControlChars.Nothing    Chaîne vide

ControlChars.Back
Taper ControlChars. Et comme d'habitude vous obtiendrez la liste des constantes.


V-F-3-b. Couleurs:

On peut aussi utiliser l'énumération des couleurs définies par le Framework

System.Drawing.Color.Blue    ‘Pour le bleu
ou en simplifiant (si Imports System.Drawing a été écrit)

Color.Chocolate

Color.Black

..

V-F-3-c. Math:

Si Import System.Math est présent en haut du module,

PI contient 3,14…

E contient la base log naturel


V-F-3-d. Touche du clavier dans le Framework:

Il est parfois nécessaire de savoir si une touche précise à été tapée par l'utilisateur au clavier, pour cela il faut connaître les touches, mais pas besoin de se souvenir du codes des touches, il suffit de taper Keys. et la liste des touches s'affiche. Cliquer sur le nom de la touche recherchée et vous obtenez la constante correspondant à la touche:

Keys.Right    'Désigne le code de la touche '->'

Keys.D8       'Désigne le code de la touche '8'

Keys.Delete   'Désigne le code de la touche 'Suppr'

Keys.D   'Désigne le code de la touche 'D'

Keys.Shift   'Désigne le code de la touche 'Majuscule'

Keys.SnapShot   'Désigne le code de la touche 'Impression écran'

V-F-3-e. Autre Enumération, un exemple:

Quand on ferme une MessageBox. (une fenêtre qui affiche un message), cela retourne une valeur qui contient:

MsgBoxResult.Yes

MsgBoxResult.No    ou

MsgBoxResult.Cancel 
En fonction du bouton qu'a utilisé l'utilisateur pour sortir de la fenêtre MessageBox (appuie sur les boutons Oui, Non, Cancel) .


V-G. Les opérateurs.

+-*/And OrMod&
+-*/And OrMod&
Pour travailler sur les variables on utilise des opérateurs (addition, soustraction...).


V-G-1. Addition :+

Dans le cas de variables numériques.

A=B+C

si B=2 et C=3 => A=5

On peut écrire:

A=A+1

Dans ce cas, on affecte à la variable A son ancienne valeur +1, si A=2 au départ il aura ensuite pour valeur 3.

A+=1 est équivalent à A=A+1

Cela incrémente la variable A.

On peut utiliser '+' pour ajouter une string à une autre, il est préférable d'utiliser '&'.


V-G-2. Soustraction : -

B=C-D

A-=1 est équivalent à A=A-1


V-G-3. Multiplication :*

C'est une étoile: *

B= C*D


V-G-4. Division : /

On remarque que « : » n'est pas l'opérateur de division.(Ce signe sert de séparateur quand plusieurs instructions sont sur la même ligne.)

B=C/D

Voir en bas de page, des informations complémentaires car "/" retourne un Double.


V-G-5. Division entière:\

Si A=10\3 => A=3

Voir en bas de page, des informations complémentaires car "\" retourne un Integer.


V-G-6. Puissance : ^


A=B^3        'A=B*B*B

V-G-7. Modulo :

C'est le reste de la division par un nombre :

10 Mod 3 donne 1

Exemple A est-il multiple de 3 ?

Si A Mod 3 =0 , A est un multiple de 3

If A Mod 3 = 0 then...

V-G-8. Concaténation : &

C'est une mise bout à bout des chaînes de caractères.

Si

A= "VISUAL"

B= " "

C= "BASIC"

D=A & B & C donne D="VISUAL BASIC"

Le signe + peut aussi être utilisé mais il est plutôt réservé aux additions de variables numériques.

&= permet aussi la concaténation A&=B est équivalent à A= A&B


V-G-9. Priorités :

info L'ordre des calculs se fait en fonction de la priorité des opérateurs.
S'il y a plusieurs opérateurs, '^' a la priorité la plus forte puis * et / puis + et –

Pour être complet, voyons les priorités par ordre décroissant:

^ élévation à la puissance

- négation unaire 

/ et * multiplication et division

\ division entière

mod  modulo

+ et -  addition et soustraction.
Exemple 2+3^3 donne 29 car VB effectue (3^3)+2 et non pas 125 (2+3)^3

S'il y a plusieurs opérateurs de même priorité, l'ordre des calculs se fait de gauche à droite.

info Pour éviter toute faute d'interprétation utiliser des parenthèses :
2+(3^3) lève toute ambiguïté.


V-G-10. Comparaison :


 = égal

 > supérieur à

 < inférieur à

>= supérieur ou égal

<= inférieur ou égal

<> Différent de
Le résultat d'une comparaison est True (Vrai) ou False (Faux)

Exemple :

      Dim A As Integer=2

      Dim B As Integer=3  

      If A=B then

        ..

      End If 
A étant différent de B, A=B prend la valeur False et le programme passe à la ligne en dessous de End If (pas après then).

Ici le signe = n'indique pas une affectation mais une expression à évaluer.

Ici aussi on peut combiner les opérateurs et mettre des parenthèses:

R= (C<>D)AND (D=2)   'Si C différent de D  et si D égal 2
Comparaison de chaînes de caractères:

Les chaînes de caractères sont comparées en fonction du tri alphabétique.

 A<B<C……<Y<Z<a<b<c……y<z<à<é.. 

      Dim A As String="A"

      Dim B As String="Z"  

      If A<B then..
A est bien inférieur à B, donc A<B prend la valeur True et le programme saute après Then.

La casse (majuscules ou minuscule) est différenciée.

Si on veut comparer sans tenir compte du fait que c'est en majuscule ou minuscule, il faut d'abord transformer les 2 chaînes en minuscule par exemple.

On veut comparer A= "aaa" et B= "AAA"

Normalement A est différent de B :

A=B retourne False

Par contre A.ToLower=B.ToLower retourne True (Vraie)

En utilisant Option Compare Text en début de module, on ne différencie plus la casse: "A" devient égal à "a".


V-G-11. Logique : Not And Or ElseOr Xor

  • Si A et B sont des expressions Booléens:
    A And B retourne True si A et B sont vrais

    A Or B retourne True si une des 2 est vrai

    A Xor B retourne True si une et une seule est vrai

    Not A retourne True si A était faux et vice versa

    On entend par expression Booléen le résultat de l'évaluation d'une condition:

    A=B retourne True si A=B et False si A différent de B.

    Exemple

    Si A différent de B.. peut s'écrire IF Not(A=B)..

    Si A compris entre 2 et 5 peut s'écrire IF A>=2 And A<=5..


    Comment faire une bascule:

    Il faut écrire A= Not A

    A chaque fois que l'on effectue cette instruction A bascule à True s'il était à False et vice versa.

  • Si A et B sont des nombres (Integer par exemple):
    L'opération est effectuée sur chaque bit.

    A = 7 'en décimal ( 0111 en binaire)

    B = 12 'en décimal( 1100 en binaire)

    Que donne A And B?

    On effectue l'opération bit à bit:

    Pour le premier bit de chaque nombre 0 And 1 = 0

    Pour le second bit de chaque nombre 1 And 1 = 1...

    Cela donne 0100.

    A And B = 4 'en décimal( 0100 en binaire)

    Autre exemple:

    A And 1 indique si le bit le moins significatif (le plus à droite) est a 1

    Exemple: si A = 7 'en décimal ( 0111 en binaire) A And 1 retourne 1

Rentrons dans les détails:

Les opérateurs And, Or et Xor sont évalués en fonction du type d'opérandes :
  • Pour le type Boolean :
    • Une opération And logique est effectuée sur les deux opérandes.
    • Une opération Or logique est effectuée sur les deux opérandes.
    • Une opération Or exclusif logique est effectuée sur les deux opérandes.
  • Pour les types Byte, Short, Integer, Long et tous les types énumérés, l'opération spécifiée est réalisée sur chaque bit de la représentation binaire des deux opérandes :
    • And : Le bit de résultat est 1 si les deux bits sont 1. Sinon, le résultat est 0.
    • Or : Le bit de résultat est 1 si l'un des deux bits est 1. Sinon, le résultat est 0.
    • Xor : Le bit de résultat est 1 si l'un des deux bits est 1 mais pas les deux. Sinon, le bit de résultat est 0 (c'est-à-dire 1 Xor 0 = 1, 1 Xor 1 = 0).
    Les opérateurs AndAlso et OrElse sont uniquement définis sur le type Booléen, ils sont plus rapide car ils n'évaluent pas la seconde expression si ce n'est pas nécessaire.


V-G-12. Déplacement de bits: << et >>

Les opérateurs binaires << et >> effectuent des opérations de déplacement de bits. Ces opérateurs sont définis pour les types Byte, Short, Integer et Long.

L'opérateur << décale à gauche les bits du premier opérande du nombre de positions spécifié. Les bits de poids fort situés en dehors de la plage du type de résultat sont éliminés, et les positions libérées par les bits de poids faible sont remplies par des zéros.

L'opérateur >> décale à droite les bits du premier opérande du nombre de positions spécifié. Les bits de poids faible sont éliminés et, si l'opérande de gauche est positif, les positions libérées par les bits de poids fort sont mises à zéro ; s'il est négatif, elles sont mises à un. Si l'opérande de gauche est de type Byte, les bits de poids fort disponibles sont remplis par des zéros.

A quoi cela sert?

Exemple décaler à gauche un Byte revient à faire une multiplication par 2.

3 en décimal= 11

Je décale à gauche, j'obtient 110 , c'est 6 en décimal.


V-G-13. Remarque 1: Allons plus loin avec / \ :

"/", la division retourne un double:

Avec Option Strict=Off

Dim i As Integer = 4

Dim j As Integer = 2

Dim k As Integer = i / j 'est accepté
Avec Option Strict=On, il faut écrire:

Dim i As Integer = 4

Dim j As Integer = 2

Dim k As Integer = CType(i / j, Integer) 'on est obligé de caster le double en Integer. 
De même "\" retourne un Integer.


V-G-14. Remarque 2: Division par zéro:

La division par zéro est impossible mathématiquement.
  • Si on divise un double (ou un nombre en virgule flottante) par un double égal à zéro, on obtient NaN :nombre non défini ou PositiveInfinity ou NegativeInfitiny selon le dividende.
  • Pour les entiers, Integer , Byte.. une division par zéro déclenche une erreur ( on dit une exception) DivideByZeroException.
En pratique les choses ne sont pas si évidentes; voyons des exemples:

Dim i As Integer = 4

Dim j As Integer = 0

TextBox1.Text = (i/j).ToString 'Affiche " +Infini"
Le résultat de l'opération (i/j) qui est un long est directement affiché.

Par contre:

Dim i As Integer = 4

Dim j As Integer = 0

Dim k As Integer = CType(i / j, Integer) 'retourne une exception (une erreur) Overflow.Exception
Car le résultat de l'opération est l'infini donc plus grand que MaxValue des Integers.

Il faut donc, si on risque d'avoir la valeur zéro, faire un contrôle avant la division:

If j<>0 Then

    k=i/j

End If

V-H. Les structures de contrôle: Choix et boucles

Elles permettent de gérer le déroulement du code.


V-H-1. If Then

Permet de créer une structure décisionnelle :

If Condition Then

End if

Si la Condition est vraie alors……

Une instruction (ou un bloc d'instructions) peut être exécutée si une condition est vraie.

Exemple:

If A=B then 

    MsgBox("A=B")

End If
Si A = B alors on exécute le bloc de code entre Then et End If, il affiche dans une fenêtre MessageBox « A=B »

'Noter que, si on le désire, on peut écrire sur la même ligne après Then (Pas besoin de End If).

If A=B Then MsgBox("A=B")

 'C'est équivalent 
On peut tester une condition fausse et dans ce cas utiliser Not.

If Not A=B Then MsgBox("A différent de B")
Si A et B sont différent (Not A=B signifie NON égaux) afficher "A différent de B".

(On aurait pu écrire If A<>B Then...)

Il peut y avoir des opérateurs logiques dans la condition:

If A=B And C=D then..    'Si A égal B et si C égal D 
Autre exemple :

Dim n As String ="33" ' on crée une String , on y met les caractères "33"

If Not IsNumeric(n) then

            MsgBox ("n n'est pas un nombre")

            Exit Sub

End if
Si n n'est pas numérique alors afficher dans une boite de dialogue: « n n'est pas un nombre » puis quitter la procédure (Exit Sub)

Noter bien que comme il y a plusieurs instructions après Then on crée un bloc d'instruction de plusieurs lignes entre Then et End If.

Simplification d'écriture:

Au lieu de

If Condition = True Then

End if
On peut écrire:

If Condition Then   

End if
Condition étant de toute manière évaluée pour voir si elle est égale à True.

On peut aussi utiliser la structure :

Si..Alors..Sinon
 

If condition then

.. ‘effectué si condition vraie

..

Else

      ..'effectué si condition fausse

      ..

End if
Exemple:

If A=B then 

    MsgBox("A=B")

Else

    MsgBox("A différend de B")

End If
Des structures If Then peuvent être imbriquées :

If..

      If..

      ..

      Else

            If..

     ..

End if

      End if

End If
Pour bien repérer les différents niveaux, utiliser les tabulations et décaler le ‘If then' et son code au même niveau.

Pour vérifier s'il n'y a pas d'erreur, compter les ‘If', il doit y en avoir autant que des ‘End If'. VB souligne le ‘If' si il n'y a pas de ‘End if'.

Dernière syntaxe:

If Condition1 Then

    ..

ElseIf condition2 Then

    ..

ElseIf condition3 Then

    ..

end if
Si condition1...

Sinon si condition2

Sinon si condition3

Fin Si


V-H-2. Select Case

Créer une structure décisionnelle permettant d'exécuter un grand nombre de blocs de code différents en fonction de la valeur d'une expression :


Select Case expression

Case valeur1

      ‘code effectué si expression=valeur1

      ……

Case valeur2

      ‘code effectué si expression=valeur2

      ……

Case valeur3

      ‘code effectué si expression=valeur3

      ……

..

Case Else

      ‘code effectué dans tous les autres cas

 

End Select
warning Attention si expression=valeur1 le code entre Case Valeur1 et Case valeur2 (et uniquement celui là) est effectué, puis l'exécution saute après End Select.
Exemple d'un code affichant le jour de la semaine :

J est un entier contenant le numéro d'ordre du jour

N=J Mod 7     ‘ contient le reste de la division entière de J par 7 

Select Case N

Case 1                        'Si N=1

      MsgBox "Lundi"          'Afficher 'Lundi'  

 

Case 2

      MsgBox "Mardi"

 

Case 3

      MsgBox "Mercredi"

..

..

Case Else

      MsgBox "Nombre pas entre 1 et 7"

End select
Nous venons d'utiliser une expression simple après chaque Case mais on peut utiliser des expressions plus complexes :

Plusieurs clauses d'expression peuvent être séparées par des virgules.

Select Case N

Case 8,9,10

      ‘Effectuer le code  si N=8 ou N=9 ou N=10
Le mot clé To permet de définir les limites d'une plage de valeurs correspondantes pour N.

Select Case N

Case 8 To 20

      ‘Effectuer le code  si N est dans la plage 8 à 20
Le mot clé Is associé à un opérateur de comparaison (=, <>, <, <=, > ou >=) permet de spécifier une restriction sur les valeurs correspondantes de l'expression. Si le mot clé Is n'est pas indiqué, il est automatiquement inséré.

Select Case N

Case Is >= 5

      ‘Effectuer le code  si N supérieur ou égal à 5.
Vous pouvez utiliser plusieurs expressions ou plages dans chaque clause Case (séparées par des virgules). Par exemple, la ligne suivante est valide :

Case 1 To 4, 7 To 9, 11, 13, Is > MaxNumber
Vous pouvez aussi indiquer des plages et des expressions multiples pour des chaînes de caractères. Dans l'exemple suivant, Case correspond aux chaînes qui sont absolument identiques à « aaa », aux chaînes comprises entre «ccc» et «ddd» dans l'ordre alphabétique, ainsi qu'à la valeur de Var :

Case "aaa", "ccc" To "ddd", Var
Pour les 'Pro':

Les "Case" peuvent contenir n'importe quelle expression. Aussi il est possible de tester dans les conditions, non pas les valeurs d'une même variable, mais divers fonctions totalement indépendantes ou comme ici des fonctions travaillant toutes sur une même variable. C'est un usage méconnu du Select Case qui clarifie l'écriture et qui évite de multiples If Then ou Goto.

Ici une routine reçoit une String contenant un nom de fichier, elle teste si le nom n'est pas vide puis si le fichier existe..

Sub TestFichier (File As String)

Select Case true

        Case len(File) = 0 

            msgbox "Pas de nom de fichier"    

        Case Not Exit(File)

            errorState=File.NotExist

        Case Not Open(File)

            errorState=File.NotOpen

        Case Not Overwrite(File) 

            errorState=File.NotOverwrite

        Case else

        'placer les exceptions ici

End Select

End Sub

V-H-3. For Next

Permet de faire des boucles.

Les boucles sont très utilisées pour parcourir une plage de valeur qui permet par exemple de parcourir tous les éléments d'un tableau ou pour effectuer de manière itérative un calcul.

Le nombre de boucle va être déterminé par une variable qui sert de compteur.

Le nombre d'exécution est déterminé au départ de la boucle car le compteur a une valeur de départ, une valeur d'arrêt.

Pour variable allant de 'début' à 'fin'

Boucler

donne en VB

For variable=début To fin

..

Next variable

 

Dim i as Integer

For i=1 to 10

MsgBox i.toString

Next i
En langage courant : Pour i allant de 1 à 10, afficher la valeur de i dans une MessageBox.

La variable compteur va prendre successivement les valeurs 1 puis 2 puis 3…… jusqu'à 10 et effectuer à chaque fois le code qui est entre For et Next.

Si on décompose :

i=1 Affiche « 1 », arrivé à Next, remonte à For, i =2 , affiche « 2 »……

…… i=10 , affiche « 10 » poursuit après Next.

En effet i augmente d'une unité à chaque 'tour'.

Il peut y avoir un pas (Step), le compteur s'incrémente de la valeur du pas à chaque boucle.

Dim i as Integer

For i=1 to 10 Step 2

MsgBox i.toString

 Next i
Affiche 1 puis 3 puis 5 puis 7 puis 9

warning Attention si la valeur de sortie de boucle est inférieure à celle d'entrée il faut indiquer un pas négatif

Dim i as integer

For i=10 to 1 Step -2

MsgBox i.toString

 Next i
Affiche 10 puis 8 puis 6 puis 4 puis 2

Bien sur on peut utiliser des expressions calculées :

For i=A to B*10 Step X-2

	MsgBox i.toString

Next i
La variable boucle peut être déclarée après For, dans ce cas cette variable n'existe que dans la boucle:

For K As Integer = 1 To 10
    ...
Next K
On peut quitter prématurément la boucle avec Exit For

For K As Integer = 1 To 10
    ...
    If A=2 Then Exit For

Next K
Dans ce cas la boucle s'arrête de tourner, on poursuit après Next.

Remarque:

Le nom de la variable de boucle est facultatif après Next:

For K As Integer = 1 To 10
    ...
Next
Est correct.

Dans la version 2005 il existe aussi Continue For qui permet de sauter au prochain Next et de poursuivre la boucle.


V-H-4. Do Loop

Permet aussi de faire des boucles mais sans que le nombre de boucle (d'itération) soit déterminé au départ.

C'est la condition d'arrêt qui détermine la sortie de la boucle :

Après Do on doit mettre Until (Jusqu'à ce que) ou While (Tant que)

Do Until condition    

      Code

Loop

 'Boucler jusqu'à ce que : condition est une condition de sortie.
Si condition est fausse, effectuer le code, boucler et recommencer le code jusqu'à ce que condition soit égale à True.

A chaque boucle la condition est évaluée.

Exemple pour chercher un mot dans une liste :

Lire Premier Mot

Do Until MotCherché=MotPointé

      Pointer Mot suivant

Loop
On peut aussi utiliser While (Tant que)

Lire Premier mot

Do While MotCherché<>MotPointé

      Pointer Mot suivant

Loop
Tant que le mot cherché est différent du mot pointé, boucler.

La condition peut être mise en fin de boucle, cela permet d'effectuer au moins une fois le code. Cela évite aussi d'avoir à démarrer le processus avant la boucle : dans notre exemple cela permet d'éviter de lire le premier mot :

Les mots sont dans un tableau Mot(); premier élément Mot(0)

IndexMot=-1 

Do 

     IndexMot=IndexMot+1

Loop While MotCherché<>Mot(IndexMot)
Il faudrait en plus boucler jusqu'à la fin du tableau et pas plus.

Exemple complet : Imposer la saisie d'un nombre négatif à l'utilisateur :

On utilise InPutBox qui ouvre une fenêtre et attend une réponse.

Dim Reponse as Single

Do

      Reponse=InPutBox(« Entrer un nombre négatif. »)

Loop  While Reponse>=0 
Si le nombre n'est pas négatif, la boucle fonctionne et la boite InPutBox s'ouvre de nouveau.

Comment créer une boucle qui tourne sans fin?

Do

   ...   

Loop  While True 

V-H-5. While End While

Permet une boucle qui tourne tant qu'une condition est vraie.


While Condition

...

End While
Exemple: on incrémente un compteur, on sort quand il est égal à 20.

Dim Counter As Integer = 0
While Counter < 20 ' Test la valeur du compteur.
   Counter += 1 ' Incrémente le compteur.
End While 

V-H-6. For Each

C'est une variante de la boucle For mais elle permet de parcourir les objets d'une collection.

Prenons un contrôle ListBox il a une collection Items qui contient tous les éléments de la ListBox

ListBox.item(0) contient la première ligne

ListBox.item(1) contient la seconde ligne

ListBox.item(2)…contient la troisième.

Parcourir tous les éléments de la ListBox et les mettre dans une variable V s'écrirait :

Dim V as string

Dim item as objet

For Each item in ListBox.items

      V=V+item

Next
La variable de boucle peut être déclarée après For:

Dim V as string

For Each item As Objet in ListBox.items

      V=V+item

Next
Au lieu de déclarer Item comme un objet, on aurait pu le déclarer comme un ListBox.Item

Cette notion de collection est beaucoup plus large que je le pensais:

Dim chaine As String = "aeiou"

Dim c As String

For Each car As String In chaine

    c = car....

Next
Ici pour tester chaque caractère dans une String, on peut utiliser For Each.


V-H-7. Switch

Switch est utilisé avec des couples d'arguments, si le premier est vrai, le second est retourné.

Réponse=Switch( Expression1, Reponse1, Expression2, Reponse2)

Si Expression2 est vrai Reponse2 est retourné.

Monnaie= Microsoft.VisualBasic.Switch(Pays = "USA", "Dollar", _
Pays = "FRANCE", "Euro", Pays = "Angleterre", "Livre")
 
Si Pays="FRANCE", cette expression est vrai, le second objet du couple est retourné.

Retourne Euro


V-H-8. IIF

IIf est utilisé avec 3 arguments.

Si le premier argument est vrai , le second est retourné.

Si le premier argument est faux c'est le troisième qui est retourné.

Reponse = IIf( Nombre > 0, "Positif", "Négatif ou 0")
 
Comme dans Switch on peut utiliser des procédures comme argument.


V-I. Les procédures et leurs paramètres.

On se souvient qu'en programmation fonctionnelle (ou procédurale) on découpe les problèmes en fonctions: les Sub et les Function.

Revenons sur les procédures et leurs paramètres.

Quand on appelle une procédure (un sous-programme, une routine), le logiciel ‘saute' au sous-programme, il effectue celui-ci puis revient effectuer ce qui est sous l'appel.

En VB les procédures sont des Sub ou des Function.

On peut fournir aux procédures des paramètres qui sont envoyés à la fonction.

Exemple:

Function Carré ( v as Single) as Single

    Return v*v

End Function
Cela crée une fonction qui se nomme 'Carré' , on peut lui envoyer un paramètre (elle accepte un Single)

Cette fonction retourne le carré du paramètre fourni.

Pour l'utiliser :

Dim resultat As Single

resultat= Carré(2)        'resultat est alors égal à 4
On appelle la fonction carré avec le paramètre 2, elle retourne 4.

Les paramètres peuvent être des variables:

Dim resultat as Single

Dim valeur as Single=3

resultat= Carré(valeur)   
Remarque: ici, on a un paramètre nommé 'valeur'; on appelle la fonction Carré avec ce paramètre. Dans la fonction Carré on retrouve ce paramètre; il se nomme 'v': Ce paramètre est passé à la fonction, mais il a un nom différent dans la fonction.

info On conseille, quand le nom d'une procédure est composé de plusieurs mots, de mettre la première lettre de chaque mot en majuscule.
Exemple:

MyCalcul()

V-I-1. Les parenthèses.

Rappel, même s'il n'y a pas de paramètre, mettre des () lors de l'appel de procédure.

MaRoutine()

V-I-2. Par Valeur, Par Référence.

Il y a 2 manières d'envoyer des paramètres :

Par valeur : (By Val)c'est la valeur (le contenu de la variable) qui est envoyée.

(La variable est copiée dans une autre partie de la mémoire pour être utilisée par la routine appelée.)

Par référence :(By Ref) c'est l'adresse (le lieu physique ou se trouve la variable) qui est envoyée. Si la Sub modifie la variable, cette modification sera visible dans la procédure appelante après le retour.

Exemple de procédures:

Sub MaProcedure (ByRef x as Long, ByVal y As Long)

End Sub
Si j'appelle cette procédure à partir d'une procédure nommé Main() :

Sub Main()

         MaProcedure (A, B)

End sub
C'est l'adresse de A qui est envoyée et la valeur contenue dans la variable B. Elles se retrouvent dans les variables x et y de la procédure MaProcedure.

Si dans cette dernière je modifie x , A est modifié dans la Sub Main (puisque x et A pointe sur le même endroit). Si dans Maprocedure je modifie y , B n'est pas modifié.

Exemple permettant de bien différencier By Val et By Ref:

Exemple avec ByVal:

Sub MaProcedure

Dim A As Integer                                'On créer une variable A

A=1                                             'On met 1 dans A

Call MaProcedure(  A  ) 'On appelle la procédure MaProcedure  en envoyant le paramètre A 

Label1.Text= A.ToString 'On affiche la valeur de A

End Sub

 

Sub MaProcedure ( ByVal Variable As Integer )    'La procédure reçoit la valeur de A donc  1

                                                 ' et la met dans 'Variable' 

    Variable=Variable+1                           'Variable=2 mais A=1

End Sub
Après l'appel de la procédure A=1, Labe1 affiche '1'

Exemple avec ByRef:

Sub MaProcedure

Dim A As Integer                                'On créer une variable A

A=1                                             'On met 1 dans A

Call MaProcedure(  A  ) 'On appelle la procédure MaProcedure en envoyant le paramètre A 

Label1.Text= A.ToString 'On affiche la valeur de A

End Sub

 

Sub MaProcedure ( ByRef Variable As Integer )    'La procédure reçoit l'adresse de A ; Variable et A ont donc même adresse

                                                 'Variable et A contiennent 1 

    Variable=Variable+1                          'Variable=2 mais A=2 aussi

End Sub
Après l'appel de la procédure A=2, , Labe1 affiche '2'

Compris!!

warning L'avantage de passer un argument ByRef est que la procédure peut retourner une valeur au code qui a appelé la procédure en modifiant la valeur de la variable qui a été passée en argument.
L'avantage de passer un argument ByVal est que cette variable est 'protégée' dans le code qui a appelé la procédure; elle ne peut pas être modifiée par la procédure.

V-I-3. Par Défaut que se passe t-il?.

Si on n'indique pas By Val ou By Ref:

warning ATTENTION: Pas défaut les paramètres sont transmis PAR VALEUR
Pour la clarté du code et pour éviter toute ambiguïté, spécifier ByRef ou ByVal, c'est plus lisible , plus clair.

Taper Sub MaProcedure (ByRef x as Long, ByVal x As Long)

Plutôt que Sub MaProcedure ( x as Long, x As Long)


V-I-4. Optional

Un paramètre ou argument peut être Optional, c'est à dire facultatif.

Indique que cet argument n'est pas requis lorsque la procédure est appelée. Si ce mot clé est utilisé, tous les arguments suivants doivent aussi être facultatifs et déclarés à l'aide du mot clé Optional. Chaque déclaration d'argument facultative doit indiquer une valeur par défaut qui sera utilisée dans la routine s'il n'y a pas de paramètre.

Sub MaRoutine (Optional X As Integer=0)

V-I-5. Tableau de paramètres.

Il est possible d'envoyer un tableau comme paramètre.

Exemple:

Dim Reponses(10) As Integer

'Appel de la Sub
Affiche( Reponses())

La Sub 'Affiche' débute par:

Sub Affiche ( R() As Integer )

End Sub

V-I-6. ParamArray

Parfois il faut envoyer des paramètres de même type mais dont on ne connaît pas le nombre, dans ce cas on utilise ParamAray (Liste de paramètres):

Function Somme ( ByVal ParamArray Valeurs() as Integer) As Integer

    Dim i as Integer

    Dim Total as Integer

    For i=0 to Valeurs.Length-1

        Total += Valeurs(i)

    Next i

    Return  Total

End Sub
Pour appeler cette fonction:

Dim LeTotal As Integer

LeTotal= Somme (2, 5, 6, 8 ,5)
A noter que le paramètre ParamArray doit être le dernier des paramètres, c'est obligatoirement un paramètre ByVal et comme on l'a dit, tous les paramètres sont de même type.


V-J. Portée des variables.

Quand on déclare une variable, jusqu'où est-elle visible?

Quand une variable est visible, on peut l'utiliser.


V-J-1. Dans les procédures.

On déclare une variable avec Dim.

Si on déclare une variable dans une procédure (une Sub ou une Function), elle est visible uniquement dans cette procédure, c'est une variable locale:

Sub MaProcedure (ByRef X As Integer)

    Dim Y As Integer

    ...

End sub
Y est déclaré en début de procédure, on pourra travailler avec Y dans la procédure jusqu'à End Sub

Dans une autre procédure Y ne sera pas visible (l'utilisation de Y déclencherait une erreur.)

Après End Sub Y n'existe plus, son contenu est perdu.

Il en est de même pour X qui est déclaré sur la ligne Sub (X reçoit la valeur envoyée comme paramètre).

Une autre procédure pourra déclarer et utiliser une variable Y, mais, même si elle a le même nom cela ne sera pas la même: chaque variable Y est uniquement visible dans sa procédure.

Variable statique:

Si à la place de Dim on utilise Static, la variable est dite 'Statique': A la sortie de la procédure, la variable et sa valeur continue d'exister et on garde sa valeur; lors des appels suivants de la procédure, on retrouve la valeur de la variable.

Exemple

Sub compteur

    Dim A as integer

    Static B as integer

    A +=1

    B +=1

End sub
A chaque appel de cette procédure A prend la valeur, 0 puis 1 puis disparaît.

B prend les valeurs 0, puis 1, puis 2... (incrémentation à chaque appel)


V-J-2. Dans un bloc d'instruction.

Si vous déclarez une variable dans un bloc, elle ne sera visible que dans ce bloc:

Do

Dim Compteur A integer

 Compteur +=1

...

Loop
La variable Compteur existe uniquement entre Do et Loop

Cela est aussi valable pour les blocs If:

Exemple:

If A=0 Then

    Dim risk As String = "Haut"

Else

    Dim risk As String = "Bas"

End If

Console.WriteLine("Le risque est " & Risk)
Dans la dernière ligne Risk est souligné comme contenant une erreur car il est considéré comme non déclaré. En effet les 2 déclarations Dim risk sont dans les blocs 'If..Else' et 'Else..End If'.


V-J-3. Dans la section déclaration d'un Module.

Dans la section déclaration d'un module (en haut du module juste après la ligne 'Module'), on utilise à la place de Dim:

Private; dans ce cas la variable est propre au module, elle est visible dans toutes les procédures du module, pas dans les autres modules.

Public; dans ce cas la variable est accessible dans la totalité du programme.

Module Module1

    Public A as String

    ....

 Sub MaRoutine

 End Sub

End Module
A est accessible partout dans la totalité du programme.

(On parle dans ce cas de variable dite 'Globale')


V-J-4. Dans la section déclaration d'une fenêtre, d'un formulaire.

Dans la section déclaration d'un formulaire (en haut du formulaire juste après la ligne 'Inherits')

Private; indique dans ce cas que la variable est propre au formulaire , elle est visible dans toutes les procédures du formulaire, pas dans les autres modules ou formulaires.

Public; indique de même une variable UNIQUEMENT visible dans le formulaire.

Elle est visible hors du formulaire a condition de la préfixer avec le nom du formulaire.

Class Class1

   Inherits System.Windows.Forms

    Public A as String

    ....

 Sub MaRoutine

 End Sub

End Class
Exemple:

On peut atteindre la zone de déclaration en déroulant le menu de droite.

Dans l'exemple ci dessus:

MaVariable est visible dans le formulaire. et hors du formulaire à condition d'utiliser NomFormulaire.MaVariable.

MaVariable2 est visible dans le formulaire .

MaVariable3 n'est visible que dans la procédure Button1_Click.


V-J-5. En pratique:

Pour se repérer et se souvenir quelle est la portée d'une variable, on utilise une lettre en début du nom de la variable:

g_MaVariable sera public (g comme global).

m_Variable2 sera accessible au niveau du module.

Dans un module standard, on peut mettre 'Public' toutes les variables que l'on veut rendre accessible à tout le programme. Ce sont les variables (et constantes) générales utilisées dans la totalité de l'application: état du programme, utilisateur en cours...Pour des raisons que nous verrons plus loin, il faut éviter ce type de variable publiques dites 'globale'.

Dans chaque formulaire on met dans la section déclarations, les variables du module: état du formulaire. Variable permettant l'affichage...

Dans chaque procédure les variables locales, compteur de boucle...

Pour les variables locales on peut donc utiliser un même nom dans différentes procédures, par exemple, on nomme souvent I les variables de boucle dans toutes les procédures, par contre

warning il faut éviter de donner un même nom à des variables dont la portée se recoupe.
VB l'accepte et utilise la variable la plus proche, celle du bloc ou du module...mais c'est dangereux et générateur de bugs.


V-K. Les nombres aléatoires

Comment obtenir un nombre aléatoire?


V-K-1. A- Avec les instructions Rnd() et Randomize() de Visual Basic.Net

Rnd() fournit un nombre aléatoire entre 0 et 1 (sans jamais atteindre 1):valeur inférieure à 1 mais supérieure ou égale à zéro; ce nombre aléatoire est un Single.

En fait ,si on fait des Rnd() successifs, le nombre aléatoire précédemment généré est utilisé pour le calcul du nombre aléatoire suivant (avec une formule mathématique complexe), ce qui fait que la suite de nombre aléatoire est toujours la même et qu'elle est périodique (au bout d'un grand nombre de tirage, on recommence la même suite).

Randomize() initialise le générateur de nombres aléatoires. Si on ne donne pas d'argument, Randomize utilise la valeur de l'horloge interne pour initialiser; cette valeur est dû au hasard, aussi le Rnd qui suit va être dû au hasard.

Si on n'utilisait pas Randomize() avant Rnd(), la fonction Rnd() fournirait toujours les mêmes nombres aléatoire dans le même ordre.

En résumé:

Rnd , si il n'y a pas d'argument, fournit une suite de nombre pseudo aléatoire (le suivant étant calculé à partir du précédent), la suite est toujours la même, seule le premier change et est initialisé par Randomize qui est basé soit sur l'horloge système (et qui à priori initialise à une valeur toujours différente) s'il n'y a pas d'argument soit sur un argument.

Pour obtenir plusieurs fois les mêmes séries de nombres , utiliser Randomize avec un argument numérique puis appelez Rnd() avec un argument négatif.


V-K-1-a. Simuler un jeu de lancé de dé.

Comment obtenir un nombre entier entre un et six au hasard?

Dim MyValue As Integer

Randomize   ' Initialise le générateur de nombre aléatoire.

MyValue = CInt(Int((6 * Rnd()) + 1)) ' Génère un nombre aléatoire entre 1 et 6.
Rnd() fournissant un nombre aléatoire entre 0 et 1, je le multiplie par 6 et j'ajoute 1 pour qu'il soit entre 1 et 7 sans atteindre 7 (il peut être entre 1 et 6,999), je prend sa valeur entière: il est maintenant entre 1 et 6, enfin je le transforme en Integer.


V-K-2. B- Avec la classe Random du Framework

Il existe une classe (faisant partie de System ) nommée Random.

La méthode Next() retourne un Integer positif entre 0 et 2 147 483 647

La méthode NextDouble() retourne un Double entre 0 et 1.

La méthode NextBytes() retourne un Byte (octet)

On peut surcharger ces méthodes pour définir des bornes.

Exemple:

J'instancie une objet à partir de la classe.

Dim Al As New Random
L'objet Al est initialisé avec une valeur probablement liée au temps, à l'horloge interne, aussi l'initialisation est 'aléatoire'.

Pour obtenir un nombre (un double) entre 0 et 1 (toujours inférieur à 1)j'écris:

MonNombrealeatoire=Al.NextDouble
Ensuite chaque NextDouble génère le nombre aléatoire suivant (à partir d'une formule)

Noter bien que dans ce qui précède, si on fait plusieurs fois Dim Al As New Random , le nombre obtenu par NextDouble n'est jamais le même.

Par contre si on fait:

Dim Al As New Random(1)

MonNombrealeatoire=Al.NextDouble

MonNombrealeatoire=Al.NextDouble
On obtient toujours:

'0.248668584157093'

'0.110743977181029'

On obtient donc la même série car on a imposé avec Random(1) une valeur de départ qui est fonction de (1) et non du temps.

Pour obtenir un nombre aléatoire entre 0 et 10, on utilise Next:

Dim Al As New Random()

MonNombrealeatoire=Al.Next(10)

MonNombrealeatoire=Al.Next(10)
On obtient la série: 2, 1, 4, 7, 6, 4, 3, 9

On travaille sur des 'Integer'

Pour obtenir un nombre aléatoire entre 5 et 10 (mais < à 10), on utilise Next:

Dim Al As New Random()

MonNombrealeatoire=Al.Next(5,10)

MonNombrealeatoire=Al.Next(5,10)
La série comportera les nombres integers 5, 6, 7, 8, 9 (pas 10)

Pour remplir un tableau d'octets avec des octets aléatoires, on utilise NextBytes:

Dim rnd As New Random()
Dim b(10) As Byte
rnd.NextBytes(b)

V-K-3. C- En cryptographie avec le Framework

Pour remplir un tableau d'octets avec des octets aléatoires forts d'un point de vue cryptographique (pour générer un mot de passe par exemple), on utilise plutôt la classe RNGCryptoServiceProvider()

L'exemple suivant crée une séquence aléatoire de 100 octets de long et la stocke dans ra.

Imports System.Security.Cryptography

Dim ra() As Byte = New Byte(100) {}
Dim rng As New RNGCryptoServiceProvider()
rng.GetBytes(ra) ' les octets dans ra sont maintenant aléatoires.
 
Il existe aussi GetNonZeroBytes pour ne pas avoir d'octet=0.


V-K-4. D - Un peu de théorie (creusons).

Un nombre aléatoire est obtenu par tirage au sort à égalité des chances, il est impossible de prévoir le tirage suivant.

Il existe des procédures physiques permettant de générer des nombres aléatoires: comptage de désintégration par compteur Geiger, analyse de bruit..

En informatique, on utilise les nombres pseudo aléatoires générés par des algorithmes.

L'implémentation actuelle de la classe Random est basée sur l'algorithme du générateur de nombres aléatoires soustractif de Donald E. Knuth. Pour plus d'information, consultez D. E. Knuth. « The Art of Computer Programming, volume 2: Seminumerical Algorithms. » Addision-Wesley, Reading, MA, deuxième édition, 1981.

Soit un nombre de départ x (nommé' graine'ou seed en anglais)

Le nombre est utilisé pour le calcul du nombre aléatoire suivant (avec une formule mathématique complexe), ce qui fait que la suite de nombre aléatoire est toujours la même pour une même graine et qu'elle est périodique.

La formule, dite générateur à congruence linéaire, pour trouver le nombre suivant, est de la forme:

Xn+1 = (aXn+b) mod m

xn+1 = (1 664 525 xn + 1 013 904 223) mod 232 (générateur de Knuth & Lewis)

Voir l'excellent article sur les nombres pseudo aléatoires:Article de P larbier

et l'excellent site de D. Müller

On a vu que le générateur est périodique: au bout d'un certain nombre de tirage pseudo aléatoire,des qu'un nombre apparaît la seconde fois, on recommence la même série. En théorie, la période maximale serait m de mod m dans la formule soit 232.

Quelle est la période de la Classe Random en pratique?

Période: 81 672 063 avec Next (Integer)

Période: 562 183 903 avec NextDouble (Double)

C'est un ordre de grandeur car en fonction de la graine (valeur de départ), la série et la période sont différentes (j'ai essayé!).

Tout l'art est de choisir la graine (le premier nombre) aléatoirement!!Cela est effectué par Randomize en VB ou l'instanciation d'un objet Random. Randomize utilise par exemple la valeur de l'horloge interne pour initialiser; cette valeur serait dû au hasard

Amélioration :

Comment générer des nombres plus aléatoires que les pseudo aléatoires?

1- Solution créée par le programmeur:

Le nombre aléatoire est la combinaison d'un nombre pseudo aléatoire et d'un nombre probablement aléatoire par exemple:

Position de la souris

Temps entre 2 pressions sur des touches

Statistique d'activité du disque dur.

Temps écoulé depuis.. (Ce que fait randomize).

Exemple:

Le nombre aléatoire est le produit d'un nombre pseudo aléatoire et du nombre de seconde écoulé depuis une date:

        Dim pAlea As Double    'Nombre pseudo aléatoire 

        Dim second As Double   'Nombre de secondes depuis le 30/12/96 

        Dim Alea  As Double    'Nombre aléatoire 

        Randomize 

        pAlea = Int((1000000 * Rnd) + 1) 

        second = DateDiff("s", "12/30/96", Now) 

        Alea =  second *pAlea
Il y a des biais, en particulier, si on utilise régulièrement cette routine, le nombre de seconde est régulièrement croissant. On pourrait améliorer en utilisant second Mod quelque chose.

2- Solution proposée par le Framework:

Méthode utilisée dans la classe System.Security.Cryptography

Le générateur doit être capable de produire des nombres aléatoires résistant à des attaques ou à des analyses statistiques qui permettraient de prédire la suite.

Les méthodes courantes pour générer des nombres aléatoires en cryptographie consiste à utiliser diverses sources disponibles sur un ordinateur: temps entre deux accès au disque, taille de la mémoire, mouvements du pointeur de la souris... et à faire passer le résultat dans une fonction de hachage cryptographique comme MD5 ou SHA-1 puis à utiliser cette valeur comme graine puis...


V-L. La 'Récursivité'

La récursivité c'est quoi?

Exemple trouvé sur developpeur.journaldunet.com :

"C'est l'histoire d'un petit garçon qui ne voulait pas dormir et dont la mère lui raconte l'histoire de la petite grenouille qui ne voulait pas dormir et dont la mère lui raconte l'histoire de l'ourson qui ne voulait pas dormir et dont la mère lui raconte l'histoire du bébé écureuil qui s'est endormi, et l'ourson s'endormi, et la petite grenouille s'endormi, et le petit garçon s'endormi."

Cette histoire, permet de mieux voir ce qui se produit lors de la récursivité: la procédure (le petit qui ne dort pas et à qui on raconte une histoire) appelle, la même procédure (le petit qui ne dort pas et à qui on raconte une histoire) qui appelle la même procédure..... on passe au "niveau" suivant puis au suivant tant qu'on n'a pas atteint la condition d'arrêt (ici, l'endormissement). Celle-ci atteinte, la récursion se termine pour les autres niveaux en sens inverse en remontant.

info Une procédure est récursive si elle peut s'appeler elle même.
VB accepte les procédures récursives:

Sub Calcul()

..

    Calcul()

..

End Sub
On voit ici que la procédure Calcul() s'appelle elle même: la ligne centrale appelle de nouveau la procédure Calcul() avec nouveaux paramètres, nouvelles variables locales, à la sortie de la procédure (après End Sub), retour à la 'version' précédente de la procédure Calcul() ou on retrouve les variables de la précédente version.

info Une procédure non récursive appelle , elle, d'autres procédures.
Pourquoi utiliser la récursivité?

Une procédure récursive découpe le problème en morceaux plus petits et s'appelle elle même pour résoudre chacun des plus petits morceaux, elle résout une petite partie du problème elle même.

Sub Calcul(Gros)

        If.. 

           Résout petit problème

        Else

           Découpe

           Calcul(Petit)

        End If

End Sub
Ici 'Résout petit problème' s'appelle le point terminal ou le point d'arrêt, c'est la branche qu'une condition qui n'appelle pas de nouveau la fonction Calcul(). C'est indispensable.

Ou bien elle découpe le problème en plus petit morceaux et pour chaque morceau on appelle de nouveau le procédure:

Sub Calcul(Gros)

        If.. 

           Découpe

           Calcul(Petit)

        End If

End Sub
A un moment donné, la condition n'est pas remplie, cela correspond au point terminal.

On se rend compte qu'une bouche For Next peut être transformée en procédure récursive:

Exemple :

Créons une procédure qui ajoute N éléments par ordre décroissant (ajoute l'élément N puis N-1 puis ... 2 puis 1)

On l'appelle avec Calcul(10) par exemple:

Avec For:

Function Calcul(N As Integer)

    Dim total As Integer

    For i= N to 1 Step-1 

         total=total + i 

     Next i 

    Calcul=total       

End Function

 

Avec la récursivité:

Function Calcul(N As Integer)

    Dim total As Integer

    If N>0 Then

         total= N+ Calcul (N-1)

     End If

    Calcul= total

End Fonction
On l'appelle avec Calcul(10)

Mais la récursivité ne sert pas seulement à cela, elle sert à résoudre aussi des problèmes qui seraient extrêmement complexes en programmation non récursive.


V-L-1. Exemple 1: calcul de 'Factorielle'.

On rappelle que N! (factorielle N)= 1*2*3*...*(N-2)*(N-1)*N

Exemple Factorielle 3 =1*2*3

Dim R As Long

R=Factorielle(3)    'retournera 6
Cette fonction n'est pas fournie par VB, créons une fonction Factorielle SANS récursivité:

Function Factorielle (ByVal N as Long) As Long

    Dim i As Long

    Resultat=1

    For i= 1 to N

        Resultat=i* Resultat

    Next i

    Return Resultat

end Function
Cela crée une fonction recevant le paramètre N et retournant un long.

La boucle effectue bien 1*2*3...*N-1*N.

Factorielle avec 'Récursivité':

Une autre manière de calculer une factorielle est d'utiliser la récursivité.

Comment faire?

On sait que N!= N * (N-1) * (N-2).... 3 * 2 * 1

on remarque donc que Factorielle N!= N * Factorielle(N-1)

N!= N*(N-1)! : en sachant que 1!=1

Créons la fonction:

Si N=1 la fonction retourne 1 sinon elle retourne N* factorielle(N-1)

Function Factorielle (ByVal N as Long) As Long

    If N=1 then

        Return 1

    Else

        Return N* Factorielle(N-1)

    End If

end Function
Dans la fonction Factorielle on appelle la fonction Factorielle, c'est bien récursif.

Pour N=4:

La fonction 'descend' et appelle chaque fois la factorielle du nombre inférieur.

La fonction Factorielle est appelée 4 fois :

Factorielle (4) appelle Factorielle(3) qui appelle Factorielle(2) qui appelle Factorielle (1)

Puis la fonction remonte en retournant le résultat de chaque factorielle.

Factorielle (1) retourne 1

Factorielle (2)retourne 2 '2*factorielle(1)

Factorielle (3)retourne 6 '3*factorielle(2)

Factorielle (4) retourne 24 '4*factorielle(3)

Vb gère cela avec une pile des appels. il met dans une pile les uns aux dessus des autres les appels, quand il remonte, il dépile de haut en bas (Dernier rentré, premier sortie)

warning Attention: La pile a une taille maximum, si N est trop grand, on déclenche une erreur de type StackOverflow.

V-L-2. Exemple 2: calcul d'une expression avec parenthèses multiples:

Comment calculer la valeur de la chaîne "(4+2(2*8)-(5/(8+1)))"

Une partie du code nommée Calculsimple sait calculer une chaîne de type "8+1" ou "4+2" sans parenthèses.

Il faut gérer les parenthèses,: la sub découpe ce qui est entre parenthèse et s'appelle elle même pour calculer ce qui est entre parenthèses:

La sub calcul fait 2 choses:

Si il y a des parenthèses: appelle Calcul() avec comme paramètre la chaîne entre parenthèse puis remplace la chaîne entre parenthèse par sa valeur

Si il n'y a pas de parenthèses calcule l'expression simple (= - * /).

Sub Calcul(Chaine As String) As String

    Si  Chaine contient  "("

        Decouper ValeurEntreParenthese

        Resultat=Calcul (ValeurEntreParenthese)        'Appel récursif

        Remplacer (ValeurEntreParenthese) par Resultat

    Sinon

        CalculSimple

    Fin Si

End Sub 

V-L-3. Exemple 3: PGCD

On rappelle que le PGCD est le 'Plus Grand Commun Diviseur'.

Soit a et b 2 nombres:

Si b divise a => PGCD=b. sinon, PGCD(a,b) = PGCD(b, a mod b)

Function PGCD(ByVal P As Long, ByVal Q As Long) As Long

If Q Mod P = 0 Then

Return P

Else

     Return PGCD(Q, P Mod Q)

End If

V-L-4. Exemple 4: Tri récursif:

Tri récursif

Le principe est que la fonction récursive scinde le tableau en 2 et pour chaque partie appelle de nouveau le tri récursif, la condition d'arrêt survient quand le dernier élément est < ou = au premier.

Dans un premier temps on range le tableau de telle sorte que tous les éléments inférieurs à l'élément d'indice pivot se trouvent placés à la gauche de celui-ci et donc tous les éléments supérieurs à sa droite.Ensuite on appelle à nouveau (récursivement) la procédure QuickSort pour chacun des deux sous-tableaux.

Cette méthode de tri récursif qui se nomme QuickSort est proportionnellement efficace au désordre du tableau à trier. Cette méthode mettra plus de temps (qu'une autre méthode) à trier un tableau qui est déjà en parti trié qu'un tableau rangé au hasard... Mais en cas de désordre intégral, c'est certainement la plus rapide.

Sub QuickSort(debut As Integer, fin As Integer)
Dim pivot, gauche, droite, temp  As Integer

  pivot  = debut
  gauche = debut
  droite = fin
  do
    if t(gauche) >= t(droite) then
    'échanger si nécessairet(droite) et t(gauche)
      temp = t(gauche)
      t(gauche) = t(droite)
      t(droite) = temp
      pivot = gauche + droite - pivot 'nouvelle position du pivot
                     'pivot est alors égal à droite ou à gauche car pivot était avant égal
                     'à gauche ou à droite
    End If
    if pivot = gauche then droite=droite-1 else gauche=gauche+1
  loop until gauche = droite
  if debut < gauche - 1 then QuickSort(debut, gauche - 1) ' //appel récursif sur la partie gauche
  if fin > droite + 1 then QuickSort(droite + 1, fin)  'appel récursif sur la partie droite
End Sub
Comment l'utiliser:

On crée un tableau Public d'integer contenant les valeurs à trier:

Public t() As Integer = {10, 2, 7, 4, 1, 3, 12, 6}

Dim i As Integer

Call QuickSort(0, 7) 'paramètre= premier et dernier élément du tableau
Affichage du tableau trié dans une texteBox1

For I = 0 To 7

TextBox1.Text = TextBox1.Text + ControlChars.CrLf + t(i).tostring

Next

V-L-5. Exemple 5: Parcours de répertoires et sous répertoires:

On veut afficher dans une ListBox les noms des répertoires, sous-répertoires et fichiers:

On crée une routine AfficheTree qui affiche

Le nom du répertoire courant.

Le nom des fichiers du répertoire courant.

Qui parcourt les sous-répertoires et pour chacun d'eux appelle AfficheTree

Imports System.IO

 

Sub  AfficheTree ( ByVal myDir As String, ByVal Optional Niveau As Integer =0)

 

'Affiche le répertoire myDir

List1.Items.Add(New String (" ", niveau *2) & myDir)

 

'Affiche les fichiers

For Each fichier As String  In Directory.GetFiles( myDir)

    List1.Items.Add(New String (" ", niveau *2+2) & fichier)

Next

 

'Parcourt les sous-répertoires

For each sousRepertoire As String In Directory.GetDirectories( myDir)

    'Appel de manière récursive 'AfficheTree pour afficher le contenu des sous répertoires.

    AfficheTree (sousRepertoire, niveau+1)

Next

 

End Sub

V-L-6. Exemple 6: Evaluation d'un nombre écrit en chiffre romain:

On veut taper III et voir s'afficher 3

taper M et voir s'afficher 1000

taper XLVIII et voir s'afficher 48

On remarque (je l'ai pas fait tout seul!!) que:

Pour un caractère romain, il a une valeur (I=1, V=5, X=10, L=50, C=100, D=500, M=1000)

Pour deux caractères, on compare leurs valeurs:

Si le premier est plus petit, on le soustrait au second: IX = 10 - 1 = 9

Si le premier est plus grand, on l'ajoute au second: VI = 5 + 1 = 6

Pour une suite de n caractères: en partant de la gauche, si le premier chiffre a une valeur inférieure au deuxième, alors on le soustrait de la valeur de tout le reste, sinon on l'additionne à la valeur de tout le reste..

Le programme va donc comparer la valeur des 2 caractères de gauche; il va ajouter (si la valeur du premier est plus grande) ou soustraire (si la valeur du premier est plus petite) la valeur du premier caractère à la valeur de la chaîne raccourcie du premier caractère.

Exemple: pour XLVIII

X plus petit que L  donc  -10 +valeur de (LVIII)

L plus grand que V  donc  -10 +50 + valeur de (VIII)

V plus grand que I  donc  -10 +50 + 5 + valeur de (III)

...    
Il faut créer un routine nommée valeur qui calcule la valeur d'un caractère.

Et la routine Eval qui calcule l'expression

S'il y a un caractère dans la chaîne c passée en paramètre, on retourne sa valeur, s'il y en a plusieurs, on compare les 2 premiers caractères, et on additionne ou soustrait à la valeur du premier caractère l' Eval (appel récursif) du reste de la chaîne.


Function valeur(ByVal c As Char) As Integer

Select Case c

Case "M"c : valeur = 1000

Case "D"c : valeur = 500

Case "C"c : valeur = 100

Case "L"c : valeur = 50

Case "X"c : valeur = 10

Case "V"c : valeur = 5

Case "I"c : valeur = 1

End Select

End Function

 

 

Function eval(ByVal s As String) As Integer

 

Dim n As Integer

 

If s.Length = 1 Then

    eval = valeur(s.Chars(0))

Else

    n = valeur(s.Chars(0))

    If n < valeur(s.Chars(1)) Then n = -n

        eval = n + eval(s.Substring(1, s.Length - 1))

    End If

End Function
Si on veut tester: créer dans une form 2 texteBox: TextDecimal, TextRomain et un bouton Button1

Private Sub Button1_Click

  TextDecimal.Text = eval(TextRomain.Text).ToString

End Sub

V-L-7. Exemple 7: Suite de Fibonacci

« Possédant initialement un couple de lapins, combien de couples obtient-on en douze mois si chaque couple engendre tous les mois un nouveau couple à compter du second mois de son existence ? »

On suppose que :

On suppose que :
  • le premier mois, il y a juste une paire de lapins ;
  • les lapins ne sont pubères qu'à partir du deuxième mois ;
  • chaque mois, toute paire susceptible de procréer engendre effectivement une nouvelle paire de lapins ;
  • les lapins ne meurent jamais (donc la suite de Fibonacci est strictement croissante).
Sont notés en rouge, les couples productifs.

En janvier : 1 couple
En février : 1 couple
En mars : 1 + 1 = 2 couples
En avril : 1 + 2 = 3 couples
En mai : 2 + 3 = 5 couples
En juin : 3 + 5 = 8 couples
En juillet : 5 + 8 = 13 couples
En août : 8 + 13 = 21 couples
En septembre : 13 + 21 = 34 couples
En octobre : 21 + 34 = 55 couples
En novembre : 34 + 55 = 89 couples
En décembre : 55 + 89 = 144 couples

Les réponses constituent les nombres de la suite de Fibonacci : 1 - 1 - 2 - 3 - 5 - 8 - 13 - 21 - ..., dont chaque terme à partir du 3ème est la somme des deux précédents.

Function Fibonacci(ByVal n As Integer)

' si n > 91, cela entraîne un overflows sur les long.

Dim result As Long = 0

 

If n < = 2 Then

    result = 1

Else

    result = Fibonacci(n - 1) + Fibonacci(n - 2)

End If    

 

Return result


End Function
Programme itératif correspondant:

Function Fibonacci2(ByVal n As Integer)

Dim u, v, w, i As Long

 

If n <= 0 Then Return 0

If n = 0 Then Return 1

 

u = 0

v = 1

For i = 2 To n

w = u + v

u = v

v = w

Next

 

Return v

End Function

V-L-8. Autres exemples:

Recherche de chemin dans un labyrinthe.

Le principe est que la fonction récursive teste le déplacement à droite, à gauche, en haut, en bas. La condition d'arrêt se produit quand on a trouvé la sortie; les endroits ou on est déjà passé sont notés.

Calculs de fractales

Les fonctions fractales sont des fonctions récursives théoriquement infinies...

il n'y a pas d'arrêt.


V-L-9. On en déduit les règles fondamentales d'une fonction récursive:

  1. La récursivité doit s'arrêter à un moment donné.
    Il doit y avoir un point terminal (ou point d'arrêt)

    Il doit y avoir dans la fonction récursive, une expression conditionnelle dont au moins un des cas conduit à une expression évaluable.

    Il doit donc y avoir un chemin non récursif (chemin ou la fonction ne s'appelle pas de nouveau).

    Il doit y avoir un test qui survient obligatoirement et qui arrête le fonctionnement récursif sinon la fonction tourne sans fin (ou du moins, elle plante quand la pile est pleine).

    Dans notre exemple 1, quand n=1 la récursivité s'arrête.

    Dans notre exemple 2, quand il n'y a plus de parenthèse, on n'appelle plus la fonction Calcul, on fait le calcul simple et on sort de la fonction ce qui la fait 'remonter'.

  2. A aucun moment les paramètres appelant de nouveau la fonction doivent être les mêmes que l'appel précédent.
    Sinon cela tournera indéfiniment.

  3. Le nombre d'appel récursif ne doit pas être très grand.
    Sous peine de 'StackOverflow'

    Certains ajoute dans le code de la fonction récursive 'un compteur de sécurité':
    
    Sub Calcul(ByRef Compteur As Long)
    
    If Compteur> LIMITE Then  Exit Sub
    
    Compteur= Compteur+1
    
    ..
    
        Calcul(Compteur)
    
    ..
    
    End Sub
    
    Noter que le compteur est un paramètre ByRef, ce qui permet de toujours incrémenter la même variable.

  4. La fonction récursive ne doit pas déclarer un grand nombre de variables ou d'objets.
    Sous peine d'occuper une place trop importante en mémoire.

  5. Limiter les fonctions récursives à une seule procédure, éviter plusieurs fonctions récursives imbriquées.
  6. Chaque fois qu'elle est appelée de manière récursive (par elle-même, donc), un ou plusieurs des arguments qui lui sont transmis doivent se rapprocher de la condition d'arrêt.
    Sinon il n'y aura pas d'arrêt.

  7. La complexité du problème doit être réduite à chaque nouvel appel récursif.
Parfois une boucle simple remplace avantageusement une fonction récursive. Dans ce cas utiliser la boucle!!

C'est le cas de la fonction factorielle!!

L'article http://recursivite.developpez.com/ donne des exemples et des explications extraordinaires de programme récursifs EN PASCAL. Si vous avez le courage de les traduire en VB , envoyez les moi!!

Exemple trouvé sur developpeur.journaldunet.com


V-M. Faut-il oublier le GoTo

Et hop!! On saute..
Et hop!! On saute..
Le Goto c'est quoi?

Faut-il utiliser le GoTo ?


V-M-1. Goto.

L'instruction GoTo permet de transférer le contrôle à l'emplacement d'une étiquette (on dit parfois un label) locale.
Une étiquette permet de localiser un endroit du code Les étiquettes sont toujours terminées par deux points(:).

Goto permet un saut non conditionnel : aller à, sauter vers une étiquette:

...

GoTo FIN

A=2

B=A+2

FIN:
FIN: est une étiquette, un mot en début de ligne qui désigne un endroit du code; pour créer une étiquette, taper en début de ligne un mot suggestif de l'endroit, puis ajouter ":".

Le programme saute de la ligne GoTo FIN à l'étiquette FIN: puis se poursuit après FIN (Les instructions entre Goto FIN et FIN: ne sont pas exécutées :

Le GoTo est souvent utilisé avec une instruction If (pour rendre le saut conditionnel):

If A=0 Then GoTo FIN

..

FIN:

V-M-2. Pourquoi éviter le 'GoTo'.

L'utilisation du GoTo est peu élégante et à éviter:

Cela casse la structure du code qui se déroule de haut en bas, le cheminement du programme est moins évident, moins visible; s'il y a plusieurs GoTo le programme devient vite illisible.

On parle dans ce cas de "code spaghetti" ou de "code kangourou" (à cause des sauts).
Dans la programmation structurée il faut bannir le 'GoTo'. On le remplacera avantageusement par des If..Then et des boucles.

Exemple:

On peut remplacer avantageusement la ligne:

If A=0 Then GoTo FIN 

B=1

FIN:
par:

If A<>0 Then 

    B=1

End if
Autre exemple:

Saisir à l'aide d'une InPutBox un nombre. S'il n'est pas entre 1 et 31, ressaisir.

Avec GoTo:

Dim reponse As String 

Question:

reponse= InPutBox ("Donner un nombre entre 1 et 31")

If Val(Reponse)<1 Or Val(Reponse) >31 Then GoTo Question
Sans GoTo:

Dim reponse As String 

While Val(Reponse)<1 Or Val(Reponse) >31

    reponse= InPutBox ("Donner un nombre entre 1 et 31")

Wend

V-M-3. Quant utiliser le 'GoTo'.

Il est cependant parfois utilisé pour la clarté du code, car il permet de sortir de plusieurs blocs de code qui se suivent.

Exemple: détection d'erreur avant l'écriture sur une fichier:

If Not Exit(File) Then

    errorState=File.NotExist

    GoTo FIN

End if

 

If Not Open(File) Then

    errorState=File.NotOpen

    GoTo FIN

End if

 

If Not Overwrite(File) Then

    errorState=File.NotOverwrite

    GoTo FIN

End if

FIN:
C'est propre.

Là aussi on aurait pu utiliser des If imbriqués:

  If  Exit(File) Then

      If  Open(File) Then

        If  Overwrite(File) Then

            errorState=File.Ok

        Else  

            errorState=File.NotOverwrite

        End if

  

      Else  

            errorState=File.NotOpen

      End if

 

  Else  

            errorState=File.NotExit

  End if
La solution avec les GoTo à l'avantage d'être plus lisible.

Pour info, il existe une autre solution élégant et originale utilisant un Select Case: Les "Case" peuvent contenir n'importe quelle expression.

Select Case true

        Case len(File) = 0 

            msgbox "Pas de nom de fichier"    

        Case Not Exit(File)

            errorState=File.NotExist

        Case Not Open(File)

            errorState=File.NotOpen

        Case Not Overwrite(File) 

            errorState=File.NotOverwrite

        Case else

        'placer les exceptions ici

End Select

V-N. Annexes:


V-N-1. Le codage de caractère ASCII ANSI UNICODE et UTF

Chaque caractère possède un code caractère numérique. Il peut être d'une longueur de 7, 8, ou 16 bits.

A ce code correspond un glyphe qui est une représentation graphique du caractère, le glyphe fait partie d'une font.

Exemple:

En ASCII (codage ASCII ),le caractère 97 correspondant au glyphe 'a' dans la font Courier New.


V-N-1-1. Codage sur 7 bits: Ascii:

L' American Standard Code for Information Interchange (ASCII) est en vigueur depuis les années 1980.

C'est un ancien codage des caractères sur 7 bits (Ascii pur) au départ correspondant au clavier américain sans accentués.

Il comporte 128 caractères.

Les codes 0 à 31 correspondent aux caractères de contrôle.(Non imprimable: 9 = tabulation, 13= retour chariot)

Les codes 32 à 64 correspondent aux opérateurs et aux chiffres.( 32=' ', 43='+', 49='1')

Les codes 65 à 90 représentent les majuscules.(65='A')

Les codes 91 à 122 représentent les minuscules.(91='a')


Il a été normalisé sous le nom d'ISO 646.


V-N-1-2. Codage sur 8 bits:

On est ensuite passé sur 8 bits (un octet) pour l'ascii étendu contenant les accentués. On peut donc coder 256 (0 à 255) caractères.

Il a été normalisé sous le nom d'ISO 8859.

L'ISO 8859 a plusieurs cartes de caractères, ou jeu de caractères, ou page de codes:

-La norme ISO 8859-1, dont le nom complet est ISO/CEI 8859-1 est appelée Latin-1 ou alphabet latin numéro 1. elle permet de représenter la plupart des langues de l'Europe occidentale: l'albanais, l'allemand, l'anglais, le catalan, le danois, l'espagnol, le féroïen, le finnois, le français, le galicien, l'irlandais, l'islandais, l'italien, le néerlandais, le norvégien, le portugais et le suédois.

-Le jeu ISO 8859-2 est appelé Latin 2 et permet de représenter les langues slaves et d'Europe centrale qui utilisent l'alphabet latin. l'allemand, le croate, le hongrois, le polonais, le roumain, le slovaque, le slovène et le tchèque.

-Le jeu de caractère ISO 8859-3 est utilisé pour l'espéranto, le galicien, le maltais et le turc.

...

-Le jeu ISO-8859-15 ou Latin 9 est une légère modification du Latin 1 qui ajoute le symbole monétaire de l'Euro, ainsi que quelques lettres accentuées qui manquaient pour le français et le finnois. Il est destiné aux mêmes langues que le Latin-1.

-Le jeu ISO-8859-1 (remarquez le tiret supplémentaire) a été validé par l'IANA (Internet Assigned Numbers Authority), pour une utilisation sur Internet, c'est un sur-ensemble de l'ISO/CEI 8859-1.Ce jeu attribue des caractères de contrôle aux valeurs 00 à 1F, 7F, et 80 à 9F. Pour compliquer un peu les choses, le nom du jeu a souvent de nombres synonymes et équivalents (Exemple: ISO-8859-1= ISO_8859-1:1987, ISO_8859-1, ISO-8859-1, iso-ir-100, csISOLatin1, latin1, IBM819, CP819)


Windows-1252 ou CP1252 est un jeu de caractères disponible sur Microsoft Windows aux États-Unis, et dans certains pays de l'Union européenne.

Windows-1252 est une extension de l' ISO 8859-1 : il en diffère par l'utilisation de caractères imprimables, plutôt que des caractères de contrôle, dans la plage 80-9F. Windows appelle ce jeux l' ANSI, mais il peut y avoir un autre nom, comme par exemple CP1252.

MacRoman ou Mac OS ROMAN est un jeu utilisé sur les ordinateurs Mac qui diffère légèrement de jeu Latin. voir différences

Pour mémoire il existait le jeu OEM sur les premiers PC.

En codage 8 bits, pour que les caractères apparaissent correctement, il faut utiliser la bonne page de code (CharSet). Il n'y a qu'une page de code par texte.


V-N-1-3. Codage sur 16 bits: Unicode:

On a ensuite crée un code de 16 bits ou plus nommé Unicode.

UCS « jeu de caractères codés universel » (Universal Coded Character Set, souvent abrégé en UCS)

Existe depuis l981.

L'Unicode dans sa version la plus récente (4.1.0) contient 245 000 codes différents, représentant 245000 caractères, symboles, etc.

Il contient tous les caractères d'usage courant dans les langues principales du monde. Il permet de mettre plusieurs langues dans une seule page, ce que ne permet pas le codage 8 bits.

Il a été normalisé sous le nom d'ISO/CEI 10646.

Les premiers 128 codes (0–127) Unicode correspondent aux lettres et aux symboles du clavier américain standard. Ce sont les mêmes que ceux définis par le jeu de caractères ASCII (ancien codage sur un octet). Les 128 codes suivants (128–255) représentent les caractères spéciaux, tels que les lettres de l'alphabet latin, les accents, les symboles monétaires et les fractions. Les codes restants sont utilisés pour des symboles, y compris les caractères textuels mondiaux, les signes diacritiques, ainsi que les symboles mathématiques et techniques.

Voici les 255 premiers

Le petit carré indique un caractère non imprimable (non affichable), certains caractères sont des caractères de contrôle comme le numéro 9 qui correspondant à tabulation, le numéro 13 qui correspond au retour à la ligne..

La valeur d'un caractère Unicode est appelée point de code. Ainsi le caractère 'f' a un point de code égal à 102.

L'Unicode regroupe ainsi la quasi-totalité des alphabets existants (arabe, arménien, cyrillique, grec, hébreu, latin, ...) et est compatible avec le code ASCII.


Encoding:

Pour écrire de l'Unicode dans un fichier (web, html, xml..), cela serait trop simple de mettre 2 octets pour chaque caractère. Aussi pour des problèmes de compatibilité entre plate formes les codes Unicode sont transformée en UTF.

UTF = UCS Transformation Format.(Format de transformation d'Unicode)

Il existe plusieurs méthodes de transformation l'UTF-8, l' UTF-16, l' UTF-32 qui sont des manières d'écrire de l'Unicode dans un fichier.


UTF-8

Taille variable: 1 à 4 octets, plus le nombre est grand, plus il y a d'octets.

Les caractères de numéro 0 à 127 sont codés sur un octet dont le bit de poids fort est toujours nul.

0xxxxxxx 1 octet codant 7 bits maximum

'A'= 65 en Unicode = 01000001 en UTF-8 soit 1 octet.

On remarque que dans ce cas Ascii= UTF-8

Les caractères de numéro supérieur à 127 sont codés sur plusieurs octets. Dans ce cas, les bits de poids fort du premier octet forment une suite de 1 de longueur égale au nombre d'octets utilisés pour coder le caractère, les octets suivants ayant 10 comme bits de poids fort.

110xxxxx 10xxxxxx 2 octets codant 8 à 11 bits 
1110xxxx 10xxxxxx 10xxxxxx 3 octets codant 12 à 16 bits 
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 4 octets codant 17 à 21 bits 
Les autres bits (notés 'x' ) codent le nombre.

Exemple

€= 8364= 11100010 10000010 10101100

Il est utilisé sur Unix et le WEB.

il est économique en terme d'octet car il permet de stocker la majorité des caractères sur un seul octet. Pour les caractères dont le point de code a une forte valeur valeurs, l'UTF-8 se chargera de déterminer s'il est nécessaire d'utiliser 1, 2, 3 ou 4 octets pour représenter sa valeur.


UTF-16

Taille fixe: 2 ou 4 octets

Il existe l'UTF-16LE et l'UTF-16BE

ils ont la même taille.(Accès rapide au caractère de position x)

L'UTF-16 est utile lorsque la place en mémoire n'est pas un facteur très important. Il facilite la manipulation de textes car le processeur sait qu'il doit analyser les deux premiers octets dans la plupart des cas (parfois 4).

Il est utilisé en Java et dans les API Windows pour la manipulation des chaînes.


UTF-32

Taille fixe: 4 octets?

Mais peu économique en mémoire, il gaspille des octets.

Tous les caractères de la terre y sont, ils ont la même taille.(Accès rapide au caractère de position x)

Gourmant en mémoire, peu utilisé.


V-N-1-4. Représentation graphique des caractères: Glyphe, Font, Police:

Un glyphe est une représentation graphique (un dessin) d'un signe typographique, autrement dit d'un caractère (glyphe de caractère) ou d'un accent (glyphe d'accent).

Une fonte de caractères, est un ensemble de glyphes, c'est-à-dire de représentations visuelles de caractères d'une même famille, de même style, corps et graisse.

La place d'un glyphe dans une fonte est déterminée par le codage des caractères dans la fonte. Ainsi, dans une fonte encodée en ASCII le glyphe du caractère « a » se trouvera en 97e position.

Une police regroupe tous les corps et graisses d'une même famille.

Le glyphe présente le dessin, alors que le caractère( son code en informatique) représente le sens.

'A, A, A' sont 3 glyphes en fonte Courier New, Arial et Comic sans MS du même caractère A majuscule (le caractère) de code 97.

En informatique on utilise les caractères (leur code) pour stocker du texte en mémoire, les glyphes pour imprimer ou afficher ces caractères.


V-N-1-5. Sur le Web:

Un document contient le nom du type de caractères utilisés dans le document: le type d'UTF (codage en 16 bits) ou le nom de la table de caractère (une seule) associée à ce document (codage 8 bits).


Par exemple pour un document HTML une balise indique que le document utilise une table des caractères .(Caractères codé sur 1 octet, c'est de l'ascii étendu dans cet exemple)

<meta http-equiv="content-Type" content="text/html; charset=iso-8859-1" />  
ou

<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
S'il n'y a pas de charset spécifié, c'est la table de caractère du système d'exploitation qui est utilisée. Si elle ne correspond pas à celle du document l'affichage est incohérent.

Le problème est aussi (si on utilise un codage 8 bits) l'impossibilité de mélanger dans un même document des alphabets qui ne sont pas définis par la même table. Par exemple le français et l'hébreu.

La solution est de passer à Unicode.


Par exemple pour un mail:

Content-Type: text/plain; charset=ISO-8859-1

ou

Content-Type: text/plain; charset="UTF-8"


Par exemple pour un fichier XML:

<?xml version="1.0" encoding="utf-8"?>

V-N-1-6. En VB:

Les variables string sont stockées sous la forme de séquences de 16 bits (2 octets) non signés dont les valeurs sont comprises entre 0 et 65 535. Chaque nombre de 16 bis représente le point de code (son numéro et non l'UTF) du caractère Unicode.

Les variables Char sont stockées sous la forme d'un mot de 16 bits (2 octets).

Dim monUnicode As Short = Convert.ToInt16 ("B"c) ' le code Unicode de B est 66.
 

En Net, il existe des fonctions d'encodage et de décodage à bas niveau sur les points de code (byte) et les caractères (char), on peut ainsi transformer une chaîne de Latin-1 en UTF-8, par exemple.

Fonctions d'encodage :

GetBytes() Convertit une chaîne ou un caractère en un tableau de byte dans le charset choisi


Comment obtenir un tableau de Bytes contenant le code ascii d'un texte?

Dim  ascii As System.Text.Encoding = System.Text.Encoding.ASCII

Dim MyString As String= "mon texte"       

Dim  MesByte() As Byte = ascii.GetBytes( MyString ) 
(les caractères non gérés en ascii sont transformés en " ? ", portant la valeur numérique 63.)

Fonctions de décodage :

GetChars() Convertit un tableau de byte en un tableau de char


Pour afficher ces caractères, on utilise des fontes.


L'Unicode est donc un codage de caractères sur 16 bits qui contient tous les caractères d'usage courant dans les langues principales du monde.


V-N-2. Nom des objets visuels (recommandation microsoft)

Il est conseillé de débuter le nom d'un objet visuel par un mot évoquant sa nature:


Microsoft conseille:

btn pour les Boutons

lst pour les ListBox

chk pour les CheckBox

cbo pour les combos

dlg pour les DialogBox

frm pour les Form

lbl pour les labels

txt pour les Textbox

tb pour les Toolsbar

rb pour les radiobutton

mm pour les menus

tmr pour les timers

Exemple:

btnOk par exemple pour un bouton sur lequel il y a 'Ok'.


V-N-3. Couleur disponible dans VB

Le plus simple est, pour modifier la couleur d'un objet par du code, d'utiliser les constantes VB qui contiennent le code d'une couleur toute faite (en RGB sans composante Alpha):

Color.Back,

Color.Fuchsia

Color.Chocolate 

Color.Red ...
Voici toutes les couleurs à votre disposition:

Elles font partie de System.Drawing


V-N-4. Format de fichier texte: le Rtf

Qu'est ce que RTF?

Un texte peut être enregistré en brut (en Ascii sans enrichissement en '.txt' par exemple) en RTF ('.Rtf') , dans un format propriétaire: format Word (.doc)…


RTF= Rich Text Format = Format de Texte Enrichi

Le RTF est un format de fichier texte assez universel. Il permet de mettre dans un fichier du texte, mais aussi d'indiquer l'enrichissement de ce texte: texte en gras, italique, souligné, en couleur, en Arial...

Les fichiers Rtf ont l'extension '.Rtf'. Ils sont lisibles dans la plupart des traitements de texte (Word, Open Office, NotePad..)


Le format du texte que l'on peut mettre dans une RichTextBox est le format RTF.


Les bases du codage RTF

Le texte doit débuter par '{' et se terminer par '}'.

Il peut aussi débuter par "{\rtf1\ansi " et se terminer par '}'.

Cela indique que le texte est en rtf et le codage des caractères est en ansi.


Ensuite les enrichissements s'effectuent par des balises qui indiquent le début et la fin de l'attribut.


Une balise commence par le caractère '\' .

Toujours mettre un espace après la balise.


Entre \b et \b0 le texte sera en gras (Bold)


Exemple :

Ajoute le texte "Ce texte est en gras." à un contrôle RichTextBox existant.

RichTextBox1.Rtf = "{\rtf1\ansi Ce texte est en \b gras\b0 .}"

Voici les principaux attributs :

\b   \b0      ce qui est entre les 2 balises est en gras

\i    \i0     ce qui est entre les 2 balises est en italique

\par          fin paragraphe (passe à la ligne)

\f            font    \f1 .. \f0  font numéro 1 entre les 2 balises

\plain        ramène les caractères par défaut

\tab          caractère de tabulation

\fs           taille de caractère   \fs28 = taille 28
Mettre un espace après la balise:

Ecrire: \b bonjour \b0 et non \bbonjour \b0


Mettre un texte en couleurs, utiliser plusieurs polices :

Mettre la table des couleurs en début de texte :

    { \colortbl \red0\green0\blue0;\red255\green0\blue0;\red0\green255\blue0;} 
Après Colortbl (Color Table) chaque couleur est codée avec les quantités de rouge vert et bleue.

Les couleurs sont repérées par leur ordre: couleur 0 puis 1 puis 2.. et séparées par un ';'


Dans notre exemple couleur 0=noir; couleur 1=rouge; couleur 2=vert

Pour changer la couleur dans le texte on utilise \cf puis le numéro de la couleur :

    « \cf1 toto   \cf0 } » ‘toto est affiché en rouge.
Pour modifier les polices de caractère, le procédé est similaire avec une Font Table :

{\fonttbl

{\fo\froman Symbol;}

{\f1\fswiss Arial;}

}
Pour passer en Arial \f1 ..\f0

Exemple complet :

"{\rtf1\ansi 

 { \colortbl 

\red0\green0\blue0;

\red255\green0\blue0;

\red0\green255\blue0;}

{\fonttbl

{\fo\froman Symbol;}

{\f1\fswiss Arial;}

}

Ce qui suit est en \f1 \cf1 \i Arial Rouge Italique \f0 \cf0 \i0

} »
Cela donne:

Nb : Si vous voulez copier coller l'exemple pour l'essayer, enlever les sauts à la ligne.


VI. Classes

Voir la vidéo au format 'Flash': ou au format AVI en Visual Basic 2005.

La vidéo (identique à celle du chapitre 0-1)contient:

1)Objets, Classes.

2)Références, espaces de noms.


VI-A. Espace de noms, Classes, Objet


VI-A-1. Classes.

Nous avons vu qu'on utilise des objets.

Il existe des 'types' d'objet qui définissent les caractéristiques communes des objets. Ces types se nomment les Classes.

Exemple:

La Classe System.Windows.Forms contient les 'Forms' et les 'Control'

On rappelle que se sont ces classes que l'on utilise comme ‘moule' pour instancier (créer) un objet, une instance.

Dim B As New Form ‘ crée un formulaire( une instance de formulaire) à partir de la Classe Form (Fenêtre).
B hérite de toutes les caractéristiques de la Classe Form.

Les classes sont regroupées en bibliothèques sous la dénomination ‘Espace de noms'


VI-A-1-a. Essayons de comprendre:

Pour utiliser un objet en VB (fourni par le Framework par exemple), il faut:
  1. Que la DLL correspondante soit chargée dans le projet. (La DLL c'est un fichier exécutable '.dll' qui contient le code nécessaire). En VB.NET on appelle cela la 'Référence' (Dans ‘Explorateur de solutions')Exemple de DLL:
    
                System.dll
    
  2. Que l'espace de nom soit importé: une DLL contient des espaces de noms dans lesquelles se trouvent les Classes. Pour utiliser une Classe il faut inclure l'espace de noms correspondant dans le programme donc il faut l'importer à partir de la DLL . On va par exemple importer l'espace de nom 'System.Windows.Forms' ( il est dans System.dll et contient les Classes 'Form' et 'Control'):
    
                 Import System.Windows.Forms    
    
  3. On peut maintenant utiliser les Classes contenues dans cet espace de nom et créer un objet. par exemple on va créer une fenêtre avec la Classe Form contenue dans System.Windows.Forms.
    
                Dim Form1 As New Form
    
    Form1 est donc un objet formulaire qui hérite de tous les membres (Propriétés, méthodes) de la Classe Form, on peut donc utiliser une méthode de cet objet:
    
                Form1.Show()    'pour faire apparaître la fenêtre
    
    ou une propriété:
    
                Form1.BackColor=Color.Red 'pour modifier la couleur de fond
    
info Les Classes les plus courantes sont déjà chargées et disponibles, ce qui simplifie un peu les choses.

VI-A-1-b. A - Détails en VB 2003:


VI-A-1-b-i. - Les Références:
Pour qu'une classe soit utilisée, il faut que le composant correspondant (la DLL) soit chargé; on a vu que par défaut quelques composants du Framework (System.dll..) et le CLR ( mscorlib.dll) étaient chargés.

Dans 'Explorateur de solutions':

Double-cliquez la rubrique références pour voir les DLL (références déjà chargées).

Si vous souhaitez utiliser un autre composant dans votre application et qu'il n'est pas chargé, il faut ajouter la référence de ce composant. Dans la fenêtre de l'explorateur de solutions, cliquez le bouton droit de la souris puis cliquez sur 'Ajouter une référence'. La boîte de dialogue 'Ajouter une référence de Visual Studio .NET' propose trois options :

  • .NET - Répertorie tous les composants .NET Framework pouvant être référencés. (Certains sont déjà chargé comme System..) et les composants extérieurs NET.
  • COM - Répertorie tous les composants COM pouvant être référencés (ceux qui fonctionnaient en VB6).
  • Projets - Répertorie tous les composants réutilisables créés dans des projets locaux.

VI-A-1-b-ii. - Importation d'espace de noms:
Certains espaces de noms ne sont pas chargés, l'espace de noms Math n'est pas chargé par exemple. (Bien que la référence, la dll qui se nomme System soit présente dans le projet.)

Si je veux utiliser Round pour arrondir un nombre il faut d'abord importer l'espace de nom 'Math':

Pour cela il faut taper en haut de la fenêtre (au dessus de public Class)

Imports System.Math

Ensuite, on peut écrire:

      Label1.Text = (Round(1.2)).ToString 'qui affiche 1.
Si l'Import n'a pas été fait, System.Math.Round(1.2) est accepté aussi. (A condition que la Dll soit chargée)

Noter bien que dans notre exemple, comme Math fait partie de System, la référence (la DLL correspondante) est déjà chargée.

Autre exemple: si on veut utiliser les fichiers, il faut importer System.IO.


VI-A-1-c. B - Détails en VB 2005:


VI-A-1-c-i. - Les Références:
Pour qu'une classe soit utilisée, il faut que le composant correspondant (la DLL) soit chargé; on a vu que par défaut quelques composants du Framework (System.dll..) et le CLR ( mscorlib.dll) étaient chargés.

Dans 'Explorateur de solutions' double-cliquez sur 'My Projet', ou dans le menu Projet, cliquez sur propriétés de..

Puis choisir l'onglet 'Références'

On voit la liste des références chargées dans le projet: ici System, System.Data..

Si vous souhaitez utiliser un autre composant dans votre application et qu'il n'est pas chargé, il faut ajouter la référence de ce composant. Cliquez le bouton 'Ajouter...'. La boîte de dialogue 'Ajouter une référence' s'ouvre:

Elle propose:
  • .NET - Répertorie tous les composants .NET Framework pouvant être référencés. (Certains sont déjà chargé comme System..) et les composants extérieurs NET.
  • COM - Répertorie tous les composants COM pouvant être référencés (ceux qui fonctionnaient en VB6).
  • Projets - Répertorie tous les composants réutilisables créés dans des projets locaux. (D'autres programme VB)
  • Parcourir permet de rechercher ; Récent liste les DLL récemment chargées.
En cliquant sur une référence puis sur 'Ok', cela charge la référence.


VI-A-1-c-ii. - Importation d'espace de noms:
Certains espaces de noms ne sont pas chargés, l'espace de noms Math n'est pas chargé par exemple. (Bien que la référence, la dll qui se nomme System soit présente dans le projet.)

Si je veux utiliser Round pour arrondir un nombre il faut d'abord importer l'espace de nom 'Math':

Pour cela il faut taper en haut de la fenêtre (au dessus de public Class)

Imports System.Math
Ensuite, on peut écrire:

      Label1.Text = (Round(1.2)).ToString 'qui affiche 1.
Si l'Import n'a pas été fait, System.Math.Round(1.2) est accepté aussi. (A condition que la Dll soit chargée)

Noter bien que dans notre exemple, comme Math fait partie de System, la référence (la DLL correspondante) est déjà chargée.

On peut aussi importer les espaces de noms directement depuis l'onglet références (Après avoir cliqué sur 'My Projet'):

Il suffit de choisir la dll en haut pour voir l'afficher les espaces de noms contenus dans cette dll en bas et de cocher ceux que l'on veut charger.


VI-A-1-d. Portée de l'espace de noms:

Si un seul espace de noms est spécifié (Import System), tous les membres à nom unique de cet espace de noms sont présents. Si un espace de noms et le nom d'un élément de l'espace de noms sont spécifiés (Import System.Math), seuls les membres de cet élément sont disponibles sans qualification.

Exemple:

Import System

Permet d'utiliser System.ArgumentException mais pas Systeme.Math.round

Pour utiliser Round il faut Importer System.Math


VI-A-1-e. Propriété ambiguë:

Certaines propriétés sont communes à plusieurs classes, il peut y a avoir ambiguïté et il faut utiliser dans ce cas la syntaxe complète.

Cela semble le cas pour left qui est une propriété de Microsoft.VisualBasic.Strings mais aussi une propriété des contrôles.

MonControle.left=250  'est accepté

Chaine= left(C,2)     'pose des problèmes.
Pour lever l'ambiguïté il faut écrire Microsoft.VisualBasic.left(C,i) par exemple quand on utilise left pour manipuler des chaînes. (Car left fait partie de l'espace Microsoft.VisualBasic )

Chaine= Microsoft.VisualBasic.left(C,2) est accepté.


VI-A-1-f. Alias:

Parfois pour simplifier l'écriture ou pour éviter des ambiguïtés on peut utiliser des Alias:

Imports STR= Microsoft.VisualBasic.Strings importe l'espace de nom String mais le désigne sous le nom de STR (STR est un Alias); STR est utilisé ensuite:

 Chaine=STR.left(C,i)
info En résumé:
Les Classes sont dans des espaces de nom qui sont dans des Dll (références).
ou
Les 'Dll' contiennent des 'Espaces de noms' contenant des 'Classes'.
Les références ( Dll) permettent de charger des composants, des Classes du Framework ou d'autres classes.
L'instruction 'Imports' permet d'importer des espaces de nom venant de ses références.
Cela donne accès dans le programme à des classes . on pourra donc instancier des objets grâce à ces Classes puis utiliser des méthodes.
Noter que dans les Classes, il existe une structure arborescente.

La premier Classe (en haut) est System.

Dessous il y a entre autres System.WindowsForms

Dessous System.Windows.Forms.Control

Enfin System.Windows.Forms.Control.Name par exemple.


VI-A-1-g. Héritage:

Héritage:

Les classes héritent des membres (propriétés, méthodes) dont elles sont issues:

Exemple :

Un contrôle Button hérite de System.Windows.Forms.Control car tous les composants avec représentation visuelle héritent de 'Control'.

Et bien les propriétés Name, Left, Right, Visible, Enabled qui sont des membres de Control deviennent aussi des membres de Button.


VI-A-1-h. Membres d'instance et membres partagés.

Un objet a des membres (propriétés et méthodes) :

  • Un membre peut être accessible directement sur un instance : on appelle cela un membre d'instance.
    Exemple:

    Dim A As String crée une variable A , en fait une instance, un objet à partir de la Classe String.

    Ensuite on peut utiliser
    
    B=A.Trim(" ") 'ici Trim enlève les blancs en début et fin de chaîne.
    
    Trim est bien une méthode qui s'applique à une instance (A).

  • Un autre membre peut être accessible par les méthodes de la classe (en non pas de l'instance) :
    • La Classe de sa nature, de son type.
      Dans la classe 'String' j'utilise la méthode Compare pour comparer 2 chaînes.

      c=String.Compare(a,b)

      J'utilise 2 paramètres, mais j'appelle la méthode directement à partir de la Classe String.

    • La Classe de l'opération à effectuer
    Dans la Classe Math j'utilise la méthode Abs (Valeur absolue)

    c=Math.Abs(-12)

On appelle cela une méthode partagée (shared) car on l'utilise directement à partir du nom de la classe sans avoir à instancier.

On remarque que la Classe String a des membres d'instance et aussi des membres partagés.

La syntaxe est parfois bizarre mais obéit donc à une certaine logique.


VI-A-1-i. Classes statiques ou non

Ici on parle des classes et non des membres.

Certaines Classes sont dites Statiques car elles existent d'emblé et on peut travailler dessus sans que l'on aie besoin de les instancier:

Exemple:

La Classe Directory (répertoire):

Directory.GetCurrentDirectory    'est utilisable directement pour obtenir le répertoire courant. 
Par contre avec une Classe non statique il faut instancier l'objet que l'on va utiliser:

Pour la classe DirectoryInfo (information sur le répertoire), on doit instancier avant usage un DirectoryInfo particulier:

Dim D As DirectoryInfo

D= New DirectoryInfo( MonDossier)
C'est un peu théorique, mais on verra au fur et à mesure des exemples pratiques de cela.


VI-A-2. Les différentes Classes, le Framework. MAJ

Il y a les Classes du Framework, et les autres.

Il y a les Framework 1, 2, 3.

Annexe1: Les Classes du Framework 1

Annexe2: Bibliothèque de Visual Basic.Net

Annexe3: Classe de compatibilité.


VI-A-2-a. Les différentes 'Classes'.

Il existe 3 types de Classes


VI-A-2-a-i. 1- Les Classes spécifiques.
Le programmeur peut les créer de toute pièce dans les modules de Classe.(On verra cela plus loin)

En VB, on peut créer une classe, ses propriétés, méthodes.. et l'utiliser dans le corps du programme.

Ces classes peuvent être internes dans un module de Classe.


VI-A-2-a-ii. 2- Les classes prédéfinies du Framework fournies par Microsoft.
Il existe ainsi de manière générale des classes

pour les formulaires Windows (WindowsForms),

pour le Web (WebForms),

pour l'accès aux données,

les réseaux,

la sécurité....

Il y a aussi la Classe VisualBasic.

info Quand on crée un nouveau projet, les Classes le plus souvent utilisées sont automatiquement chargées dans le projet:

VI-A-2-a-iii. 2-Les classes fournies par des tiers.
On peut ajouter des références (DLL) permettant d'ajouter des classes nouvelles, cela permet d'ajouter de nouvelles fonctionnalités à VB: Exemple: les pilotes de base de données..

Vous pouvez vous aussi créer une Classe, la compiler, puis dans un autre projet référencer la Dll de la classe que vous avez créée et l'utiliser dans le nouveau projet.


VI-A-2-b. Dans Visual Basic.Net.

Dans VB.Net il y a donc possibilité de travailler avec ce que fourni Microsoft:
  • Les Classes du Framework, leurs propriétés, leurs méthodes. Les Forms, Controls, les classes des variables (String, Int32..) sont disponibles par défaut. (voir annexe 1)
  • Les instructions VB.Net de Microsoft.VisualBasic disponible par défaut. Ce sont des instruction VB bien connues (left, int, IsNumeric.. ) (voir annexe 2)
  • Les instructions de la bibliothèque de compatibilité VB6. il faut dans ce cas importer Microsoft.VisualBasic. Compatibility et Microsoft.VisualBasic. Compatibility.Data, ces instructions sont là pour aider à la conversion, elles permettent d'utiliser des fonctions qui n'existent plus en VB.Net (comme les chaînes fixes par exemple), il faut les éviter impérativement car ce n'est pas du VB.Net et elles disparaîtront probablement dans les futures versions. (voir annexe 3)
Exemple:

Pour la manipulation des nombres

'Int' 'Randomize' et 'Rnd' font partie de VB.Net,

'Round' fait partie de la classe Math donc du Framework,

'Imp' fait partie de la bibliothèque de compatibilité VB6.

Parfois certaines fonctions font double emploi et ont des équivalents dans les 2 ou 3 catégories.

Lesquelles utiliser?

Les Classes sont souvent plus riches avec multiples surcharges et, si j'ai bien compris, sont communes à tous les langages utilisant le Framework .Net. Si vous voulez passer au C#, les classes sont les mêmes.

Les instructions VB.Net sont propres à VB , c'est du VB et du .Net.

Par contre, les instructions devant de la compatibilité VB6 sont à éviter absolument. Seront-elles conservées dans les futures versions de VB.NET?


VI-A-2-c. Lors de la création d'un nouveau projet:

Sont automatiquement chargé:

Une partie du Framework (System.dll) et le CLR la couche qui fait tourner le programme ( mscorlib.dll)

Sont donc à disposition:

  • Quelques classes du Framework:
System,

System.data,

System.drawing,

System.Windows.forms

Ce dernier contient les Controls

et aussi:

Microsoft.VisualBasic qui contient la bibliothèque VB.Net qui permet d'utiliser les fonctions VB (MsgBox, IsNumeric, Chr, Asc.....)

Comme ces Classes sont chargées au départ cela permet d'emblée de créer des feuilles, des contrôles..(qui sont dans les WindowsForms et les Controls).Cela permet aussi d'utiliser les instructions VB.

Si on a besoin d'autres classes, il faut les importer:

Imports System.Math par exemple pour utiliser les fonctions mathématiques.

Imports System.IO. pour les fichiers.

..

Eviter d'importer Microsoft.VisualBasic.Compatibility qui apporte la compatibilité VB6


VI-A-2-d. Framework 1, 2, 3.

Un Framework est donc un ensemble de Classes.

Le framework 1.0 est utilisé par VB 2003

Le framework 2.0 est utilisé par VB 2005

Il contient des classes supplémentaires.

Le framework 3.0 peut être utilisé par VB 2005

Le framework 3.0 est composé du framework 2.0 auquel s'ajoute WCF (Windows Communication Foundation), WF (Windows Workflow Foundation), WPF (Windows Presentation Foundation) et infocard pour l'authentification des utilisateurs.
Windows Presentation foundation permet de gérer l' affichage des fenêtres. Celui-ci est basé sur direct x (version 10).

Sous Windows 98, XP, il faut installer le framework (avant d'utiliser l'environnement VisualBasic ou un exécutable VB)

Sous Windows Vista le Framework 3 fait partie de Vista et est installé nativement.


VI-A-2-e. ANNEXE 1: Les principales Classes du Framework 1.

Voir les détails des classes sur MSDN Le Framework (Cliquez sur .NetFramework dans la liste)

Comporte les classes de base et les classes fondamentales.

Classes de base: qui définissent des types de données valeur et référence, des événements et des gestionnaires d'événements, des interfaces, des attributs (non listés ici), ainsi que des exceptions (non listés ici) de traitement couramment utilisés.

Classe, Description

Activator

Contient des méthodes permettant de créer des types d'objets localement ou à distance, ou d'obtenir des références à des objets distants existants.

AppDomain

Représente un domaine d'application qui est un environnement isolé dans lequel s'exécutent les applications. Cette classe ne peut pas être héritée.

AppDomainSetup

Représente des informations sur les liaisons d'assemblys qui peuvent être ajoutées à une instance de AppDomain.

AppDomainUnloadedException

Exception levée lors d'une tentative d'accès à un domaine d'application non chargé.

ApplicationException

Exception levée lorsqu'une erreur d'application non fatale se produit.

ArgumentException

Exception levée lorsqu'un argument non valide est fourni à une méthode.

Array

Fournit des méthodes pour la création, la manipulation, la recherche ainsi que le tri des tableaux et sert de classe de base pour tous les tableaux du Common Language Runtime.

Attribute

Classe de base pour les attributs personnalisés.

AttributeUsageAttribute

Spécifie l'utilisation d'une autre classe d'attribut. Cette classe ne peut pas être héritée.

BitConverter

Convertit les types de données de base en tableau d'octets et un tableau d'octets en types de données de base.

Buffer

Manipule les tableaux de types primitifs.

CharEnumerator

Prend en charge l'itération sur String et la lecture de ses caractères individuels.

Console

Représente les flux d'entrée, de sortie et d'erreur standard pour les applications console. Cette classe ne peut pas être héritée.

Convert

Convertit un type de données de base en un autre type de données de base.

Delegate

Représente un délégué qui est une structure de données référençant une méthode static ou une instance de classe et une méthode d'instance de cette classe.

Enum

Fournit la classe de base pour les énumérations.

Environment

Fournit des informations concernant l'environnement et la plate-forme en cours ainsi que des moyens pour les manipuler. Cette classe ne peut pas être héritée.

Exception

Représente les erreurs qui se produisent lors de l'exécution de l'application.

GC

Contrôle le garbage collector (ramasse-miettes) du système, un service qui récupère automatiquement la mémoire inutilisée.

Math

Fournit des constantes et des méthodes static pour des fonctions trigonométriques, logarithmiques et d'autres fonctions mathématiques courantes.

MulticastDelegate

Représente un délégué multicast, c'est-à-dire un délégué dont la liste d'appel peut comporter plusieurs éléments.

Object

Prend en charge toutes les classes de la hiérarchie des classes du .NET Framework et fournit des services de bas niveau à des classes dérivées. Il s'agit de la classe de base fondamentale parmi toutes les classes du .NET Framework. Elle constitue la racine de la hiérarchie des types.

OperatingSystem

Représente des informations relatives à un système d'exploitation, telles que l'identificateur de version et de plate-forme.

Random

Représente un générateur de nombres pseudo-aléatoires. Il s'agit d'un périphérique qui produit une séquence de nombres conformes à certains prérequis statistiques liés à l'aspect aléatoire.

SerializableAttribute

indique qu'une classe peut être sérialisée. Cette classe ne peut pas être héritée.

String

Représente du texte ; autrement dit, une série de caractères Unicode.

TimeZone

Représente un fuseau horaire.

Type

Représente les déclarations de types : types classe, types interface, types tableau, types valeur et types énumération.

Uri

fournit une représentation objet d'un identificateur URI (uniform resource identifier) et un accès simplifié aux parties de l'identificateur.

ValueType

Fournit la classe de base pour les types valeur.

Version

Représente le numéro de version d'un assembly du Common Language Runtime. Cette classe ne peut pas être héritée.

Les Classes fondamentales du Framework:

Microsoft.Win32
Fournit deux types de classes : celles qui gèrent les événements déclenchés par le système d'exploitation et celles qui manipulent la base de registres.

System.Collections
Contient des interfaces et des classes qui définissent différentes collections d'objets, telles que des listes, des files d'attente, des tableaux de bits, des tables de hachage et des dictionnaires.

System.Configuration
Fournit des classes et des interfaces qui vous permettent d'accéder par programme aux paramètres de configuration de .NET Framework et de gérer les erreurs dans les fichiers de configuration (fichiers .config).

System.Data
Se compose principalement des classes qui constituent l'architecture ADO.NET. L'architecture ADO.NET vous permet de construire des composants qui gèrent efficacement les données provenant de plusieurs sources de données.

System.Data.OleDb
Encapsule le fournisseur de données .NET Framework pour OLE DB. Le fournisseur de données .NET Framework pour OLE DB décrit une collection de classes utilisées pour accéder à une source de données OLE DB dans l'espace managé.
System.Data.OracleClient
Encapsule le fournisseur de données .NET Framework pour Oracle. Le fournisseur de données .NET Framework pour Oracle décrit une collection de classes utilisées pour accéder à une source de données Oracle dans l'espace managé.
Remarque : cet espace de noms n'est pris en charge que dans la version 1.1 du .NET Framework.
System.Data.SqlClient
Encapsule le fournisseur de données .NET Framework pour SQL Server. Le fournisseur de données .NET Framework pour SQL Server décrit une collection de classes utilisées pour accéder à une base de données SQL Server dans l'espace managé.
System.Diagnostics
Fournit des classes qui vous permettent d'interagir avec des processus système, des journaux des événements et des compteurs de performance. Cet espace de noms fournit également des classes qui vous permettent de déboguer votre application et d'effectuer le suivi de l'exécution de votre code. Pour plus d'informations, consultez les classes Trace et Debug.

System.DirectoryServices
Permet d'accéder aisément à Active Directory à partir du code managé. L'espace de noms contient deux classes de composants Component, DirectoryEntry et DirectorySearcher, qui font appel à la technologie ADSI (Active Directory Services Interfaces). ADSI, un ensemble d'interfaces fourni par Microsoft, constitue un outil flexible permettant de travailler avec une vaste gamme de fournisseurs réseau. ADSI permet à l'administrateur de rechercher et de gérer des ressources présentes sur un réseau de manière relativement simple, quelle que soit la taille du réseau.

System.Drawing
Permet d'accéder aux fonctionnalités graphiques de base de GDI+. Des fonctionnalités plus avancées sont offertes dans les espaces de noms System.Drawing.Drawing2D, System.Drawing.Imaging et System.Drawing.Text.

System.Drawing.Drawing2D
Fournit des fonctionnalités avancées de graphismes à deux dimensions et vectoriels. Cet espace de noms inclut notamment les brosses à dégradé, la classe Matrix (utilisée pour définir des transformations géométriques) et la classe GraphicsPath.
System.Drawing.Imaging
Fournit les fonctionnalités d'imagerie avancées de GDI+. Des fonctionnalités graphiques de base sont fournies par l'espace de noms System.Drawing.
System.Drawing.Printing
Fournit des services d'impression. En règle générale, vous créez une nouvelle instance de la classe PrintDocument, définissez les propriétés qui décrivent les éléments à imprimer, puis imprimez le document en appelant la méthode Print.
System.Drawing.Text
Fournit les fonctionnalités typographiques avancées de GDI+. Des fonctionnalités graphiques de base sont fournies par l'espace de noms System.Drawing. Les classes de cet espace de noms permettent aux utilisateurs de créer et d'utiliser des collections de polices.
System.EnterpriseServices
Fournit une infrastructure importante pour les applications d'entreprise. COM+ fournit une architecture de services destinée aux modèles de programmation de composants déployés dans un environnement d'entreprise.

System.Globalization
Contient des classes qui définissent des informations liées à la culture, notamment la langue, le pays ou la région, les calendriers utilisés, les formats des dates, des monnaies et des nombres, ainsi que l'ordre de tri à respecter pour les chaînes. Ces classes sont utiles pour écrire des applications globalisées (internationalisées).

System.IO
Contient des types qui permettent la lecture et l'écriture synchrone et asynchrone de flux de données et de fichiers.

System.Management
Permet d'accéder à un ensemble riche d'informations de gestion et d'événements de gestion sur le système, les périphériques et les applications instrumentés pour l'infrastructure WMI (Windows Management Instrumentation).

System.Messaging Fournit des classes qui vous permettent de vous connecter aux files d'attente de messages, de les analyser et de les gérer sur le réseau, ainsi que d'envoyer, de recevoir ou de lire des messages.

System.Net
Constitue une interface de programmation simple pour un grand nombre des protocoles réseau employés aujourd'hui. Les classes WebRequest et WebResponse constituent la base des protocoles enfichables, qui sont une implémentation de services réseau vous permettant de développer des applications qui utilisent des ressources Internet sans vous soucier des spécificités de chaque protocole.
System.Net.Sockets
Fournit une implémentation managée de l'interface Windows Sockets (Winsock) pour les développeurs qui doivent contrôler étroitement l'accès au réseau.

System.Reflection
Contient des classes et des interfaces qui fournissent une vue managée des types, des méthodes et des champs chargés, avec la possibilité de créer dynamiquement et d'appeler des types.

System.Resources
Contient des classes et des interfaces qui permettent aux développeurs de créer, de stocker et de gérer différentes ressources spécifiques à la culture utilisées dans une application.

System.Runtime.Remoting
Fournit des classes et des interfaces qui permettent aux développeurs de créer et configurer des applications distribuées.

System.Runtime.Serialization
Contient des classes qui peuvent être utilisées pour sérialiser et désérialiser des objets. La sérialisation est le processus de conversion d'un objet ou d'un graphique d'objets en séquence linéaire d'octets pour stockage ou transmission à un autre emplacement. La désérialisation est le processus consistant à accepter des informations stockées et à recréer des objets à partir de celles-ci.

System.Security
Fournit la structure sous-jacente du système de sécurité .NET Framework, y compris les classes de base pour les autorisations.
System.Security.Cryptography
Fournit des services cryptographiques, comprenant le codage et le décodage sécurisé des données, ainsi que beaucoup d'autres opérations, telles que le hachage, la génération aléatoire de nombres et l'authentification de messages.

System.ServiceProcess
Fournit des classes qui vous permettent d'implémenter, d'installer et de contrôler les applications de service Windows. Les services sont des fichiers exécutables de longue durée sans interface utilisateur. L'implémentation d'un service implique l'héritage de la classe ServiceBase et la définition d'un comportement spécifique à traiter lorsque des commandes Démarrer, Arrêter, Suspendre et Continuer sont passées, ainsi qu'un comportement personnalisé et des actions à entreprendre lorsque le système s'arrête.

System.Text
Contient des classes représentant le codage de caractères ASCII, Unicode, UTF-7 et UTF-8 ; des classes de base abstraites pour convertir des blocs de caractères en direction et en provenance de blocs d'octets ; et une classe d'assistance qui manipule et formate les objets String sans créer des instances intermédiaires de String.

System.Text.RegularExpressions
Contient des classes qui permettent d'accéder au moteur des expressions régulières du .NET Framework. Cet espace de noms fournit des fonctions d'expressions régulières qui peuvent être utilisées à partir de toute plate-forme et tout langage s'exécutant dans Microsoft .NET Framework.
System.Threading
Fournit des classes et des interfaces qui permettent la programmation multithread. En plus des classes permettant la synchronisation des activités des threads et l'accès aux données (Mutex, Monitor, Interlocked, AutoResetEvent, etc.), cet espace de noms comprend une classe ThreadPool qui vous permet d'utiliser un pool de threads fournis par le système et une classe Timer qui exécute les méthodes de rappel sur des threads du pool de threads.

System.Timers
Fournit le composant Timer qui vous permet de déclencher un événement à un intervalle spécifié.

System.Web
Fournit des classes et des interfaces permettant la communication entre le navigateur et le serveur.

System.Windows.Forms
Contient des classes permettant de créer des applications Windows qui profitent pleinement des fonctionnalités élaborées de l'interface utilisateur disponibles dans le système d'exploitation Microsoft Windows.

System.Xml
Fournit une prise en charge des normes pour le traitement du code XML.


VI-A-2-f. ANNEXE 2: Visual Basic .NET.

L'espace de noms Microsoft.VisualBasic (présent par défaut quand on crée un nouveau projet) contient les classes et les modules qui constituent la bibliothèque runtime de Visual Basic .NET. La bibliothèque fournit les fonctions, méthodes et propriétés que vous pouvez utiliser dans votre code.

Voici toutes les classes et leurs instructions:

Classe Microsoft.VisualBasic.Collection
Add Count GetEnumerator Item
Remove

Classe Microsoft.VisualBasic.ComClassAttribute
ClassID EventID InterfaceID InterfaceShadows

Module Microsoft.VisualBasic.Conversion
ErrorToString Fix Hex Int
Oct Str Val

Module Microsoft.VisualBasic.DateAndTime
DateAdd DateDiff DatePart DateSerial
DateString DateValue Day Hour
Minute Month MonthName Now
Second TimeOfDay Timer TimeSerial
TimeString TimeValue Today WeekDay
WeekDayName Year

Classe Microsoft.VisualBasic.ErrObject
Clear Description Erl GetException
HelpContext HelpFile LastDLLError Number
Raise Source

Module Microsoft.VisualBasic.FileSystem
ChDir ChDrive CurDir Dir
EOF FileAttr FileClose FileCopy
FileDateTime FileGet FileGetObject FileLen
FileOpen FilePut FilePutObject FileWidth
FreeFile GetAttr Input InputString
Kill LineInput Loc Lock
LOF MkDir Print PrintLine
Rename Reset RmDir Seek
SetAttr SPC TAB Unlock
Write WriteLine

Module Microsoft.VisualBasic.Financial
DDB Fv IPmt IRR
MIRR NPer NPV Pmt
PPmt Pv Rate SLN
SYD

Module Microsoft.VisualBasic.Globals
ScriptEngine ScriptEngineBuildVersion ScriptEngineMajorVersion ScriptEngineMinorVersion

Module Microsoft.VisualBasic.Information
Err IsArray IsDate IsDBNull
IsError IsNothing IsNumeric IsReference
LBound QBColor RGB SystemTypeName
TypeName UBound VarType VbTypeName

Module Microsoft.VisualBasic.Interaction
AppActivate Beep CallByName Choose
Command CreateObject DeleteSetting Environ
GetAllSettings GetObject GetSetting IIf
InputBox MsgBox Partition SaveSetting
Shell Switch

Module Microsoft.VisualBasic.Strings
Asc AscW Chr ChrW
Filter Format FormatCurrency FormatDateTime
FormatNumber FormatPercent GetChar InStr
InStrRev Join LCase Left
Len LSet LTrim Mid
Replace Right RSet RTrim
Space Split StrComp StrConv
StrDup StrReverse Trim UCase

Classe Microsoft.VisualBasic.VBFixedArrayAttribute
Bounds Length

Module Microsoft.VisualBasic.VbMath
Randomize Rnd

La bibliothèque runtime Visual Basic .NET fournit également les constantes et les membres d'énumération que vous pouvez utiliser dans votre code. Chaque énumération représente une catégorie particulière de fonctionnalité. Consultez Constantes et énumérations pour plus d'informations.


VI-A-2-g. ANNEXE 3: Fonctions VB6 de VisualBasic.Compatibility

Il faut d'abord importer l'espace de nom Microsoft.VisualBasic.Compatibility A EVITER, ce n'est pas du Net.

On peut importer aussi l'espace de noms Microsoft.Compatibility.Data : ils correspondent à la liaison de données ADO dans Visual Basic 6.0.

Fonction Description
CopyArray Duplique la fonctionnalité de Visual Basic 6.0 permettant d'assigner un tableau à un Variant.
CursorToIPicture Utilisé pour la conversion de format.
Eqv Duplique l'opérateur Eqv (équivalence) de Visual Basic 6.0.
FontChangeBold Utilisé pour la conversion de polices Visual Basic 6.0 en objets Font Visual Basic .NET.
FontChangeGdiCharSet Utilisé pour la conversion de polices Visual Basic 6.0 en objets Font Visual Basic .NET.
FontChangeItalic Utilisé pour la conversion de polices Visual Basic 6.0 en objets Font Visual Basic .NET.
FontChangeName Utilisé pour la conversion de polices Visual Basic 6.0 en objets Font Visual Basic .NET.
FontChangeSize Utilisé pour la conversion de polices Visual Basic 6.0 en objets Font Visual Basic .NET.
FontChangeStrikeout Utilisé pour la conversion de polices Visual Basic 6.0 en objets Font Visual Basic .NET.
FontChangeUnderline Utilisé pour la conversion de polices Visual Basic 6.0 en objets Font Visual Basic .NET.
FontToIFont Utilisé pour la conversion de format.
Format Duplique la fonction Format de Visual Basic 6.0.
FromPixelsX Utilisé pour la conversion de coordonnées.
FromPixelsY Utilisé pour la conversion de coordonnées.
FromPixelsUserHeight Utilisé pour la conversion de coordonnées.
FromPixelsUserWidth Utilisé pour la conversion de coordonnées.
FromPixelsUserX Utilisé pour la conversion de coordonnées.
FromPixelsUserY Utilisé pour la conversion de coordonnées.
GetActiveControl Duplique la propriété Screen.ActiveControl de Visual Basic 6.0.
GetCancel Duplique la fonctionnalité de la propriété Cancel d'un CommandButton de Visual Basic 6.0.
GetDefault Duplique la fonctionnalité de la propriété Default d'un CommandButton de Visual Basic 6.0.
GetEXEName Duplique la propriété App.EXEName de Visual Basic 6.0.
GetHInstance Duplique la propriété App.HInstance de Visual Basic 6.0.
GetItemData Duplique la fonctionnalité de la propriété ItemData d'un ListBox ou d'un ComboBox de Visual Basic 6.0.
GetItemString Duplique la fonctionnalité permettant d'extraire une valeur d'une liste dans un ListBox ou un ComboBox de Visual Basic 6.0 .
GetPath Duplique la propriété App.Path de Visual Basic 6.0.
IconToIpicture Utilisé pour la conversion de format.
IFontToFont Utilisé pour la conversion de format.
ImageToIPicture Utilisé pour la conversion de format.
ImageToIPictureDisp Utilisé pour la conversion de format.
Imp Duplique l'opérateur Imp (implication) de Visual Basic 6.0.
IPictureDispToImage Utilisé pour la conversion de format.
IPictureToImage Utilisé pour la conversion de format.
LoadResData Duplique la fonction LoadResData de Visual Basic 6.0.
LoadResPicture Duplique la fonction LoadResPicture de Visual Basic 6.0.
LoadResString Duplique la fonction LoadResString de Visual Basic 6.0.
PixelsToTwipsX Utilisé pour la conversion de coordonnées.
PixelsToTwipsY Utilisé pour la conversion de coordonnées.
SendKeys Duplique la fonction SendKeys de Visual Basic 6.0.
SetCancel Duplique la fonctionnalité de la propriété Cancel d'un CommandButton de Visual Basic 6.0.
SetDefault Duplique la fonctionnalité de la propriété Default d'un CommandButton de Visual Basic 6.0.
SetItemData Duplique la fonctionnalité de la propriété ItemData d'un ListBox ou d'un ComboBox de Visual Basic 6.0.
SetItemString Duplique la fonctionnalité permettant de définir une valeur d'une liste dans un ListBox ou un ComboBox de Visual Basic 6.0.
SetResourceBaseName Utilisé avec les fonctions LoadRes lorsqu'un fichier de ressources utilise une convention d'affectation de noms non standard.
ShowForm Duplique la fonctionnalité de la méthode Show d'un formulaire Visual Basic 6.0.
TabLayout Utilisé pour la conversion d'instructions Debug.Print contenant les mots clés Tab ou Spc.
ToPixelsX Utilisé pour la conversion de coordonnées.
ToPixelsY Utilisé pour la conversion de coordonnées.
ToPixelsUserHeight Utilisé pour la conversion de coordonnées.
ToPixelsUserWidth Utilisé pour la conversion de coordonnées.
ToPixelsUserX Utilisé pour la conversion de coordonnées.
ToPixelsUserY Utilisé pour la conversion de coordonnées.
TwipsPerPixelX Duplique la propriété Screen.TwipsPerPixelX de Visual Basic.
TwipsPerPixelY Duplique la propriété Screen.TwipsPerPixelY de Visual Basic.
TwipsToPixelsX Utilisé pour la conversion de coordonnées.
TwipsToPixelsY Utilisé pour la conversion de coordonnées.
ValidateControls Duplique la fonctionnalité de la méthode ValidateControls d'un formulaire Visual Basic 6.0.
WhatsThisMode Duplique la fonctionnalité de la méthode WhatsThisMode d'un formulaire Visual Basic 6.0.
Zorder Utilisé pour la conversion de l'ordre de plan des contrôles.
Objets VisualBasic.Compatibility

Objet Description
BaseControlArray Classe parente pour l'émulation de tableau de contrôles Visual Basic 6.0.
BaseOcxArray Classe parente pour les tableaux émulés des contrôles ActiveX.
ButtonArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles CommandButton.
CheckBoxArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles CheckBox.
CheckedListBoxArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles ListBox avec la propriété Style définie sur Checked.
ComboBoxArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles ComboBox.
DirListBox Émule un contrôle Visual Basic 6.0 DirListBox.
DirListBoxArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles DirListBox.
DriveListBox Émule un contrôle DriveListBox Visual Basic 6.0.
DriveListBoxArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles DriveListBox.
FileListBox Émule un contrôle FileListBox Visual Basic 6.0.
FileListBoxArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles FileListBox.
FixedLengthString Émule des chaînes de longueur fixe Visual Basic 6.0.
GroupBoxArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles Frame.
HScrollBarArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles HScrollBar.
LabelArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles Label.
ListBoxArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles ListBox
ListBoxItem Émule la propriété ItemData d'un contrôle ListBox.
MenuItemArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles Menu.
PanelArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles PictureBox contenant des contrôles enfants.
PictureBoxArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles PictureBox.
RadioButtonArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles OptionButton.
TabControlArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles TabStrip.
TextBoxArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles TextBox.
TimerArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles Timer.
VscrollBarArray Émule un tableau de contrôles Visual Basic 6.0 de contrôles VScrollBar.

VI-A-3. Procédures évènement, surcharge de méthode.


VI-A-3-a. Évènement et procédure évènement:

On a vu qu'un objet pouvait avoir un évènement.

L'objet 'Button1' à un évènement Button1.Click

Comment faire pour que l'action de cliquer sur le bouton1 exécute une procédure?

Il faut l'indiquer grâce à Handles:

Si on veut que le Click sur Button1 exécute la procédure, la Sub MaRoutine, il faut écrire:

Sub Maroutine() Handles Button1.Click

End Sub
Ainsi quand l'utilisateur clique sur le bouton, la procédure Maroutine est exécutée.

VB, qui est vraiment très sympa, écrit automatiquement le code pour vous:

En mode 'Design', créez un bouton, double-cliquez dessus, vous vous retrouvez dans la procédure:

Private Sub Button1_Click() Handles Button1.Click

End Sub
Par défaut il a nommé la procédure Button1_Click (mais elle aurait pu se nommer autrement).

Dans la réalité, il a ajouté 2 paramètres:

Sender qui contient le nom de l'objet qui a déclenché l'évènement (c'est un objet)

e un objet qui contient les arguments de cet évènement. (de type EventAgrs mais pas toujours)

Cela donne:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

End Sub
Pour les forts et pour être complet, dans Form1.InitializeComponent (c'est une routine ou il y a le code créant les contrôles), il y a la ligne:

Friend WithEvents Button1 As System.Windows.Forms.Button qui indique que le bouton a de évènements (WithEvents).

En conclusion:

VB écrit automatiquement les procédures évènement. On verra plus loin qu'il est possible de créer nous même nos objets, évènements et procédures évènement.


VI-A-3-b. Surcharge de Méthode:

Quand on utilise une méthode avec des paramètres, il y a parfois possibilité d'utiliser, avec la même méthode, un nombre différent de paramètres ou des paramètres de nature différente: on appelle cela surcharger la méthode.

Chaque manière d'écrire les paramètres s'appelle une signature.

Exemple:

Voici une fenêtre MessageBox:

pour ouvrir une fenêtre MessageBox il y a 12 signatures, en voici 2:

Reponse= MessageBox.show(TexteAAfficher,Titre, TypeBouton etIcone, BoutonParDéfaut)
Ici on donne 4 paramètres.

Reponse= MessageBox.show(TexteAAfficher)
Ici 1 seul paramètre.

On voit qu'on peut appeler la méthode MessageBox.Show avec un nombre différent de paramètres.

Comme on ne peut pas connaître toutes les signatures, VB nous aide:

Si on tape R= MessageBox.show( VB affiche dans un cadre une signature, de petites flèches permettent de faire défiler tous les autres signatures:


VI-A-4. L'écriture 'Compact'


VI-A-4-a. Comment 'compacter'?

Habituellement on écrit une instruction par ligne:

Mais:

On peut créer une variable et l'initialiser en même temps:

Au lieu de:

Dim s As String

s = "Philippe. Jean . Toto" 
On peut écrire:

Dim s As String= "Philippe. Jean . Toto" 
Rien n'empêche d'initialiser avec une expression complexe:

Dim t As Single =  (3* Int(u))-2)
Autre exemple:

Ici par exemple on découpe la string s en utilisant des séparateurs et on met les noms dans un tableau:

Version non compact:

Dim s As String= "Philippe. Jean . Toto" 

Dim sep() As Char={" "c, ","c, "."c}

Dim nom() As String 'Tableau des noms

nom = s.Split ( sep, 100, StringSplitOptions.RemoveEmptyEntries )
Mais on peut compacter le code:

Dim nom() As String = "Philippe. Jean . Toto".Split(New Char() {" "c, ","c, "."c, ":"c}, 100, StringSplitOptions.RemoveEmptyEntries)
On crée la variable nom, on l'initialise en même temps avec une méthode, les paramètres étant directement crées au niveau de l'appel de la méthode.

Même chose avec des fonctions:

Le paramètre d'une fonction peut être le résultat d'une fonction.

Soit une fonction qui se nomme 'Carré' , on peut lui envoyer un paramètre (elle accepte un Single), elle retourne le carré du paramètre:

Function Carré ( v as Single) as Single

    Return v*v

End Function
Soit une fonction qui se nomme 'Inverse' , on peut lui envoyer un paramètre (elle accepte un Single), elle retourne le paramètre après avoir inversé le signe:

Function Inverse ( v as Single) as Single

    Return -v

End Function

 
Si on veut prendre le carré de 2 puis l'inverse et enfin la partie entière du résultat:.

Dim resultat As Single

Dim resultatintermediaire1 As Single

Dim resultatintermediaire2 As Single

resultatintermediaire1= Carré(2)        

resultatintermediaire2 = Inverse (resultatintermediaire1)

resultat= Int(resultatintermediaire2)
Ou de manière compact:

Dim resultat As Single = Int(Inverse(Carré(2)))
warning L'écriture compact du code est plus ramassée, moins 'lourde', avec moins de variables intermédiaires mais on perd en lisibilité parfois.

Dim resultat As Single = Int(Inverse(Carré(2))) 'Cet exemple est compact mais lisible.

Dim nom() As String = S.Split(New Char() {" "c, ","c, "."c, ":"c}, 100, StringSplitOptions.RemoveEmptyEntries) 'C'est moins lisible

VI-A-5. Notion de flux ou 'Stream'


VI-A-5-a. Utiliser les "Stream".

Le Stream (flux, torrent, courant) est une notion générale, c'est un flux de données provenant ou allant vers un fichier, un port, une connexion TCP/IP...

Ici on utilise un Stream pour lire ou écrire dans un fichier.

L'accès est séquentiel: les données sont traitées du début à la fin du fichier.

Pour écrire dans un fichier texte:

Il faut instancier un objet de la classe StreamWriter . On écrit avec Write ou WriteLine.(ajoute un saut de ligne) Enfin on ferme avec Close.

On peut instancier avec le constructeur de la classe StreamWriter et avec New, ou par la Classe File.

Dim SW As New StreamWriter ("MonFichier.txt") ' crée ou si existe écrase
Il existe une surcharge permettant de ne pas écraser mais d'ajouter à la fin du fichier:

Dim SW As New StreamWriter ("MonFichier.txt", True) ' crée ou si existe ajoute
Avec la classe File:

Dim SW As  StreamWriter=File.CreateText ("MonFichier.txt") ' crée ou si existe écrase

Dim SW As StreamWriter = File.AppendText("MonFichier.txt") ' crée ou si existe ajoute

 
Ensuite pour écrire 2 lignes:

SW.WriteLine ("Bonjour")

SW.WriteLine ("Monsieur")
Enfin on ferme:

SW.Close()
Pour lire dans un fichier Texte:

Il faut instancier un objet de la classe StreamReader. On lit avec Read (un nombre d'octet) ReadLine (une ligne) ReadToEnd (de la position courante jusqu'à la fin). Enfin on ferme avec Close.

Avec le constructeur de la Classe Stream Reader:

Dim SR As New StreamReader ("MonFichier.txt")
Avec la Classe File:

Dim SR As  StreamReader=File.OpenText ("MonFichier.txt") '
Comment lire chaque ligne du fichier et s'arrêter à la fin?

En effet on ne sait pas habituellement combien le fichier contient de ligne, si le fichier contient 2 lignes il faut en lire 2 et s'arrêter sinon on tente de lire après la fin du fichier et cela déclenche une erreur.

3 solutions:
  1. Utiliser ReadToEnd qui lit en bloc jusqu'à la fin.
  2. Avant ReadLine mettre un Try: quand l'erreur 'fin de fichier' survient elle est interceptée par Catch qui sort du cycle de lecture et ferme le fichier.
  3. Utiliser Peek qui lit dans le fichier un caractère mais sans modifier la position courante de lecture.
    La particularité de Peek est de retourner -1 s'il n'y a plus de caractère à lire sans déclencher d'erreur, d'exception.

La troisième solution est la plus générale et la plus élégante:

Do Until SR.Peek=-1

     Ligne=SR.ReadLine()

Loop
Enfin on ferme:

SR.Close()

VI-A-6. Exemple de petites routines de code.

On prendra des exemples de routine très simple ne contenant que du code.


VI-A-6-a. Petites routines sur les chaînes de caractères


VI-A-6-a-i. Une string 'Nom' contient un nom , mettre si nécessaire la première lettre en majuscule.
  1. En utilisant les Classes String et Char:
    
    Dim Nom As String = "philippe"
    
    ' Si le premier caractère est minuscule
    
    If Char.IsLower(Nom.Chars(0)) Then
    
    ' Le transformer en majuscule et afficher
    
    MessageBox.Show(Char.ToUpper(Nom.Chars(0)) + Nom.Substring(1, Nom.Length - 1))
    
    End If
    
    On regarde si le premier caractère de la chaîne Nom.Chars(0) est minuscule (.IsLower).

    Si oui on transforme ce premier caractère en majuscule (.ToUpper) et on ajoute la sous chaîne allant du second au dernier caractère.

  2. En utilisant les instructions VB:
    
    Dim Nom As String = "philippe"
    
    Nom = UCase(Microsoft.VisualBasic.Left(Nom, 1)) & Mid(Nom, 2)
    
    On prend le premier caractère de gauche : Left(Nom,1), on le transforme en majuscule (Ucase) , on ajoute la chaîne commençant par le second caractère et allant jusqu'à la fin.


VI-A-6-a-ii. Comment voir si un caractère est une voyelle:

Dim Voy As String = "aeiouy"

Dim C As String = "p" 

If Instr( Voy, C)<>0 then

..

End If
Ici on regarde si la String C est contenue dans la String Voy (qui contient toutes les voyelles), si cela retourne 0 c'est que la String C n'y est pas.


VI-A-6-a-iii. Comment éliminer une combinaison bien précise de caractères en début de chaîne:
Exemple: éliminer une balise html de type </b ../b0> et son contenu dans une chaîne nommée Ch:

' Le premier caractère est-il '<', recherche avec StartsWith (en plus on élimine les espaces avec Trim())
If Ch.Trim().StartsWith("<") Then

' Rechercher le caractère '>', le premier
Dim lastLocation As Integer = Ch.IndexOf(">")

If lastLocation >= 0 Then
' éliminer la chaîne entre '<' et '>'
    Ch = Ch.Substring((lastLocation + 1))
End If
End If

VI-A-6-a-iv. Vous avez une chaîne de caractères, comment afficher, le premier caractère puis les 2 premiers, puis 3..?
Dans un formulaire (une fenêtre), il y a un TextBox1( zone de texte avec sa propriété Multiline=True)

Dim C As String = "DUBONET"

Dim Tx As String

Dim i As Integer

For i = 1 To Microsoft.VisualBasic.Len(C)

    Tx += Microsoft.VisualBasic.Left(C, i) + ControlChars.CrLf

Next i

TextBox1.Text = Tx
Mettre ce code dans Form_Load puis lancer le programme.

Affiche:

D

DU

DUB

DUBO

DUBON

DUBONE

DUBONET
On remarque: Tx est une string permettant de stocker temporairement la string à afficher; a chaque boucle on ajoute la nouvelle string (Tx += est équivalent à Tx=Tx+..) et un caractère de retour à la ligne.

Left fait partie de l'espace de nom Microsoft.VisualBasic.


VI-A-6-a-v. Vous avez deux chaînes de caractères, comment savoir si la second est un anagramme de la première?
Pour les nuls, un anagramme c'est les mêmes lettres dans un ordre différent.

Il faut mettre les 2 chaînes dans un tableau de caractères, trier les 2 tableaux, les remettre dans des strings et les comparer.

'créons 2 string

Dim maString1 As String = "stressed"

Dim maString2 As String = "desserts"

 

'On passe les strings dans des tableaux

Dim myChar1 As Char =mastring1.ToCharArray

Dim myChar2 As Char =mastring2.ToCharArray

 

'On trie les tableaux

Array.Sort( myChar1)

Array.Sort( myChar2)

'On passe les caractères dans des strings

Dim MyStringTrie1 As New String (myChar1)

Dim MyStringTrie2 As New String (myChar2)

'On compare les 2 Strings, si elle sont égales cela retourne 0, l'expressin 0=0 est True, on la mettre dans un Boolean

Dim anagramme As boolean =(String.Compare (MyStringTrie1 ,MyStringTrie2 )=0)

VI-A-6-a-vi. Compter combien de fois un mot apparaît dans un texte?
Calculer le nombre d'occurrences ( compteur )d'une sous-chaîne (monMot) dans une String (monTexte).

'On rappelle que .IndexOf permet de chercher une sous-chaîne dans une chaîne (il retourne 0 si la chaîne n'est pas présente ou la position de la chaîne).

Dim monTexte As String ="jfkjf...."

Dim monMot As String= "lulu"

 

Dim compteur As Integer =-1

Dim index As Integer =-1

 

Do

  compteur+= 1

  index= monTexte.IndexOf (monMot, index +1)

Loop Until index <0
On initialise le compteur à -1 car la boucle Do Loop est systématiquement effectuée une fois et incrémente le compteur une fois de trop.

On initialise l'index à -1 car dans la boucle Do Loop on utilise Index+1; sinon, si la chaîne cherchée débute au 1er caractère elle n'est pas comptée.


VI-A-6-b. Petits programmes mathématiques

On prendra des exemples de routines mathématiques simples:
  • Calcul de l'hypoténuse d'un triangle rectangle
  • Somme de N entiers
  • Afficher les tables de multiplication
  • Valeur maximum d'un tableau
  • Calcul de factorielle (avec ou sans récursivité)
  • Un nombre est-il premier?
  • Décomposition en nombre premier
  • Diviseurs d'un nombre

VI-A-6-b-i. Calcul de l'hypoténuse d'un triangle rectangle.
On crée pour cela une fonction, on envoie 2 paramètres de type Single: les 2 cotés du triangle; la fonction retourne l'hypoténuse.

Function Hypotenuse (ByVal Side1 As Single, ByVal Side2 As Single) As Single
    Return Sqrt((Side1 ^ 2) + (Side2 ^ 2))
End Function
Pour les nuls, on rappelle que le carré de l'Hypoténuse est égal à la somme des carrées des 2 autres cotés.


VI-A-6-b-ii. Somme de N entiers.
Calculer par exemple pour Nombre=20 la Somme=1+2+3+4...+18+19+20

Dim Somme As Integer    'Variable somme

Dim Nombre As Integer=20

Dim i As Integer        'Variable de boucle

 

For i=0 To Nombre

    Somme += i

Next i
On rappelle que Somme += i est équivalent à Somme =Somme + i

Pour afficher le résultat, si il existe une TextBox:

TextBox1.Text = Cstr(Somme)    'Somme est transformé en String puis affecté à la propriété Text du TextBox

VI-A-6-b-iii. Afficher les tables de multiplication.
On fait 2 boucles:

celle avec i (qui décide de la table: table des 1, des 2..)

On affiche 'table des' puis valeur de i

celle avec j (allant de 1 à 10 pour chaque table)

Pour chaque ligne, on affiche la valeur de i puis ' X ' puis la valeur de j puis ' = ' puis la valeur de i fois j

ControlChars.Crlf permet un saut à la ligne

A chaque fois que l'on a quelque chose à afficher, on l'ajoute à la variable String T

A la fin on affecte T à la propriété Text d'un TextBox pour rendre visible les tables.

Dim i As Integer

Dim j As Integer

Dim T As String

 

For i = 1 To 10

    T += ControlChars.CrLf

    T += "Table des " & i & ControlChars.CrLf

    For j = 1 To 10

        T += i.ToString & " X " & j.ToString & "=" & i * j & ControlChars.CrLf

    Next j

Next i

TextBox1.Text = T
Affiche:

Table des 1

1 X 1 =1

1 X 2 =2

...

VI-A-6-b-iv. Trouver la valeur la plus élevée d'un tableau d'entier:
Pour cela on crée une Fonction, on l'appelle en donnant en paramètre le tableau d'entier; la fonction retourne l'entier le plus grand.

Function FindMax(ByVal a() As Integer) As Integer

Dim fin As Integer = UBound(a)

Dim valeurMax As Integer = a(0)

Dim i As Integer

For i = 0 To fin

If a(i) > valeurMax Then valeurMax = a(i)

Next i

Return valeurMax

End Function
Un boucle compare chaque valeur du tableau a() avec valeurMax, si l'élément du tableau est plus grand que valeurMax, valeurMax prend la valeur de l'élément.


VI-A-6-b-v. Factorielle.
On rappelle que N! (factorielle N)= 1*2*3*...*(N-2)*(N-1)*N

Exemple Factorielle 3 =1*2*3

Dim R As Long

R=Factorielle(3)    'retournera 6
Cette fonction n'est pas fournie par VB, créons une fonction 'Factorielle':

Function Factorielle (ByVal N as Long) As Long

    Dim i As Long

    Resultat=1

    For i= 1 to N

        Resultat=i* Resultat

    Next i

    Return Resultat

end Function
Cela crée une fonction recevant le paramètre N et retournant un long.

Une boucle effectue bien 1*2*3...*N-1*N.


VI-A-6-b-vi. Factorielle avec 'Récursivité':
Une autre manière de calculer une factorielle est d'utiliser la récursivité:

Une procédure est récursive si elle peut s'appeler elle même.

VB gère la récursivité.

Comment faire pour les factorielles?

On sait que Factorielle N= N * Factorielle(N-1)

N!= N*(N-1)! : en sachant que 1!=1

Créons la fonction:

Function Factorielle (ByVal N as Long) As Long

    If N=1 then

        Return 1

    Else

        Return N* Factorielle(N-1)

    End If

end Function
Dans la fonction Factorielle on appelle la fonction Factorielle, c'est bien récursif.

Pour N=4, la fonction Factionnelle est appelée 4 fois :Factorielle (4) puis Factorielle(3) puis Factorielle(2) puis Factorielle (1)

Factorielle (1) retourne 1

Factorielle (2)retourne  2    '2*factorielle(1)

Factorielle (3)retourne  6    '3*factorielle(2)

Factorielle (4) retourne 24   '4*factorielle(3)
Vb gère cela avec une pile des appels. il met dans une pile les uns aux dessus des autres les appels, quand il remonte, il dépile de haut en bas (Dernier rentré, premier sortie)

warning Attention: La pile a une taille maximum, si N est trop grand, on déclenche une erreur de type StackOverflow.

VI-A-6-b-vii. Un nombre est-il premier?
Un nombre premier est seulement divisible par 1 et lui-même.

Pour voir si N est entier on regardera successivement si ce nombre est divisible par 2 puis 3 puis 4... jusqu'a N-1

Un nombre est divisible par un autre si la division donne un entier. N/B= A Comment voir si le nombre A est entier? Pour ma part, j'utilise la méthode suivante: A est entier si A=Int(A).

Une autre méthode pour voir si N est divisible par B: il est divisible si N Mod(B)=0.

Avec une boucle For Next:

Dim IsPremier As Boolean                

Dim j, k As Long

 

IsPremier = True

j = 2

For k = 2 To N

     If (N Mod k = 0) And (k <> N) Then

           IsPremier = False

           j = n

     End If

     j = j + 1

Next
En sortie de boucle si IsPremier= true , le nombre N est premier.

Avec un Do Loop.

Dim IsPremier As Boolean

Dim N As Double=59 'nombre à étudier

Dim I As Double

I=2:  IsPremier=True

Do

    If N/I= Int(N/I) then

        IsPremier=False

    Else

        i += 1

    End if

Loop While IsPremier=True And I<N
Pour 59 IsPremier sera égal à True.

On peut améliorer la routine en remarquant:

Si un nombre n'est pas premier il admet 2 diviseurs dont un est inférieur à racine N.

on peut donc :
  • Vérifier que le nombre n'est pas pair puis
  • Vérifier s'il est divisible par les nombres allant de 3...jusqu'à racine de N en ne tenant compte que des nombres impairs.
Remarque pour ceux qui veulent tester le code :

Pour utiliser la routine sur les nombres premiers, il faut créer une petite interface: dans un formulaire créer un bouton nommé 'Button1' et une TextBox nommée 'TextBox1', enfin mettre dans la routine Button1_Click le code ci-dessous.

Quand on lance le programme, on saisie un nombre dans le textbox , puis on clique sur le bouton , cela affiche True ou False dans une MessageBox, si le nombre est premier ou non:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim IsPremier As Boolean

Dim N As Double

Dim I As Double

N = Val(TextBox1.Text)

I = 2 : IsPremier = True

Do

If N / I = Int(N / I) Then

IsPremier = False

Else

I += 1

End If

Loop While IsPremier = True And I < N

MsgBox(IsPremier.ToString)

End Sub 

VI-A-6-b-viii. Decomposition en nombre premier?

Dim nbr As Integer = 1000 'nombre à étudier

Dim div As Integer = 2


Dim t As String = ""

While div <= nbr

While nbr / div = Int(nbr / div)

t = t & div & " x "

nbr = nbr / div

End While

div = div + 1

End While

TextBox1.Text = t

VI-A-6-b-ix. Diviseurs d'un nombre?
C'est une fonction qui retourne une collection de type List contenant des integers (tous les diviseurs de Numbre.

Si Numbre Mod i est égale à zéro c'est que i est un diviseur de Numbre; on l'ajoute à la liste.

Public Function Diviseur (ByVal Number As Integer) As List(Of Integer)

Dim Diviseur As New List(Of Integer)

For i As Integer = 1 To Number 

      If Number Mod i = 0 Then Diviseur.Add(i) 

Next 

End Function 

VI-A-6-c. Travail sur les tableaux et collections - (Tri, recherche, insertion effacement d'éléments)


VI-A-6-c-i. Utiliser les TABLEAUX
Le travail sur des tableaux est très intéressant. On étudiera plusieurs routines en comparant la méthode classique et les fonctions du Framework. Puis on utilisera les collections pour faire la même chose.


VI-A-6-c-i-a-. A- Trier un tableau.
Routine de Tri .

Pour trier un tableau de chaînes de caractères, il faut comparer 2 chaînes contiguës, si la première est supérieure (c'est à dire après l'autre sur le plan alphabétique)on inverse les 2 chaînes, sinon on n'inverse pas. Puis on recommence sur 2 autres chaînes en balayant le tableau jusqu'à ce qu'il soit trié.

Tout l'art des routines de tri est de faire le moins de comparaisons possible pour trier le plus vite possible.

Voyons une des routines les plus rapides, le Bubble Sort (ou tri à bulle); on le nomme ainsi car l'élément le plus grand descend progressivement au fur et à mesure jusqu'à la fin du tableau comme une bulle.(il faut imaginer la surface en bas et les bulles qui descendent!!

Une boucle interne balaye le tableau et compare 2 élément contigus et les inverse si nécessaire. Une boucle externe fait tourner la boucle interne N fois.

La boucle interne fait descendre l'élément le plus grand vers la fin du tableau, la boucle externe répète l'opération N fois permettant le tri de tous les éléments.

Private Sub Button1_Click

'Création du tableau et de son contenu non trié.

Dim T(5) As String 'élément de 0 à 4

T(0) = "toto"

T(1) = "tata"

T(2) = "tutu"

T(3) = "lolo"

T(4) = "lulu"

 

'Création des variables

Dim N As Integer = 5  'Nombre d'éléments

Dim i, j As Integer

Dim Temp As String    'Variable temporaire

 

'Routine de tri

For i = 0 To N - 1    'Boucle externe

For j = 0 To N - 1   'Boucle interne

If T(j) > T(j + 1) Then

  Temp = T(j) : T(j) = T(j + 1) : T(j + 1) = Temp  'Inverser si pas dans le bon ordre

End If

Next j

Next i

 

' Pour afficher le tableau trié dans un textbox

Dim tt As String= ""

For i = 0 To N

tt = tt + T(i) + ControlChars.CrLf

Next i

TextBox1.Text = tt

End Sub
Remarque: pour inverser le contenue de 2 variables, on doit écrire

Temp=T(j): T(j)=T(j+1):T(j+1)=Temp (L'instruction qui faisait cela en VB6 et qui se nommait Swap n'existe plus)

Cette routine trie bien le tableau mais n'est pas optimisée: il n'est pas nécessaire que la boucle interne tourne de 0 à N-1 à chaque fois car après une boucle ,le dernier élément, le plus grand, est à sa place. Pour i=0 la boucle interne tourne jusqu'à N-1, pour i=1 jusqu'à N-2...

Cela donne:

For i=0 To N-1

    For j=0 To N-i-1

        If T(j)>T(j+1) then 

            Temp=T(j): T(j)=T(j+1):T(j+1)=Temp

        End if

    Next j

 Next i
Il existe d'autres méthodes encore plus rapide (Méthode de Shell et Shell-Metzner), il existe aussi le QuickSort très performant pour les tableaux non triés , voir chapitre sur la récursivité.

Mais il y a plus simple:

Tri avec la méthode SORT du Framework.

Pour un tableau unidimensionnel.

Dim Animals(2) As String
Animals(0) = "lion"
Animals(1) = "girafe"
Animals(2) = "loup"
Array.Sort(Animals)
Et le tableau est trié!!

On rappelle que l'on ne peut pas trier un tableau multidimensionnelle, mais il y a des ruses.(voir rubrique:tableau)

Les Collections peuvent être triées automatiquement aussi.


VI-A-6-c-i-b-. B- Rechercher un élément dans un tableau.
Routine de recherche:

On a un tableau de string, on veut chercher ou se trouve(en quelle position) une string.

Pour une liste non triée, on n'a pas d'autres choix que de comparer la string cherchée à chaque élément du tableau, on utilisera donc une boucle:

N=4  'tableau de 5 éléments.

Dim T(N) As String  'élément de 0 à 4

T(0)="vert"

T(1)="bleu"

T(2)="rouge"

T(3)="jaune"

T(4)="blanc"

Dim i  As Integer    'Variable de boucle

Dim AChercher As String= "rouge" 'String à chercher

For i=0 To N

      If T(i)=AChercher then 

            Exit For

      End if

Next i

'i contient 2
Pour une liste triée (suite ordonnée), on peut utiliser la méthode de recherche dichotomique: On compare l'élément recherché à l'élément du milieu du tableau, cela permet de savoir dans quelle moitié se situe l'élément recherché. De nouveau on compare à l'élément recherché à l'élément du milieu de la bonne moitié...jusqu'à trouver. Pour cela on utilise les variables Inf et Sup qui sont les bonnes inférieure et supérieure de la zone de recherche et la variable Milieu. On compare l'élément recherché à l'élément du tableau d'indice milieu, si il sont égaux on a trouvé , on sort; si ils sont différents on modifie Inf et Sup pour pointer la bonne plage puis on donne à Milieu la valeur du milieu de la nouvelle plage et on recommence.

Dim N As Integer

Dim T(N) As String  'élément de 0 à 4

Dim Inf, Sup, Milieu As Integer '

Dim Reponse As Integer 'contient le numero de l'élément

                       'ou -1 si élément non trouvé 

Dim i  As Integer    'Variable de boucle

Dim AChercher As String= "c" 'String à chercher

 

N=4  'tableau de 5 éléments.

T(0)="a"

T(1)="b"

T(2)="c"

T(3)="d"

T(4)="e"

Inf=0: Sup=N

Do

    if inf>Sup then Reponse=-1: Exit Do

    Milieu= INT((Inf+Sup)/2)

    If Achercher=T(Milieu) then Reponse=Milieu:Exit Do

    If Achercher<T(Milieu) then Sup=Milieu-1

    If Achercher>T(Milieu) then Inf=Milieu+1

Loop

'Reponse =2
La recherche dichotomique est rapide car il y a moins de comparaisons.

Recherche avec les facilités du Framework.

Mais comme d'habitude VB.Net possède des propriétés permettant de rechercher dans un tableau trié ou non et cela sans avoir à écrire de routine.

Binarysearch recherche un élément dans un tableau trié unidimensionnel.(algorithme de comparaison binaire performant sur tableau trié: probablement une recherche dichotomique)

Exemple :

I=Array.BinarySearch(Mois, "Février") 

IndexOf
Recherche un objet spécifié dans un tableau unidimensionnel (trié ou non), retourne l'index de la première occurrence.

Dim myIndex As Integer = Array.IndexOf(myArray, myString)
 
Retourne -1 si l'élément n'est pas trouvé.

LastIndexOf fait une recherche à partir de la fin.


VI-A-6-c-i-c-. C- Effacer, insérer un élément dans un tableau.
1- Éliminer un élément.

Avec une routine:

Soit un tableau de 4 String T(0), T(1), T(2),T(3).

Toto
Tata
Tonton
Titi
On veut éliminer l'élément "Tata", le second élément; il faut passer le troisième dans le second, le quatrième dans le troisième... et effacer le dernier élément du tableau.

Dim N As Integer

Dim T(N) As String  'création d'un tableau de String.

Dim i As Integer

For i= 1 To N-1

    T(i)=T(i+1)

Next i

T(N-1)=""           'ne pas oublier de modifier le dernier élément  
On obtient:

Toto
Tonton
Titi
 
On remarque que la boucle démarre au niveau de l'élément à enlever et pas à la fin du tableau.

Avec les facilités du Framework:

On peut décaler les éléments d'un tableau avec la méthode Copy de la Classe Array:

Il suffit de copier le tableau sur le même tableau mais décalé d'un élément.

Array.Copy(T, 2, T, 1, T.Length - 2)

T(T.Length-1)=""
On utilise ici une surcharge de Copy:

Array.Copy(Tor, indexOrigine, td, indexDestitation, nombredElements)
Tor: Tableau d'origine; Td tableau destination.

2-Insérer un élément.

Avec une routine:

Soit un tableau de 4 String T(0), T(1), T(2),T(3).

Toto
Tonton
Titi
 
On veut insérer l'élément "Tata" en seconde position, après "Toto"; il faut d'abord décaler les éléments vers la fin du tableau. Attention : il faut le faire en commençant par la fin du tableau: il faut passer l'avant dernier élément en dernière position puis l'avant avant dernier en avant dernière position.

Dim N As Integer

Dim T(N) As String  'création d'un tableau de String.

Dim i As Integer

For i= N-1 To 1 Step -1

    T(i)=T(i-1)

Next i

T(1)="Tata"           'ne pas oublier d'ajouter
On obtient:

Toto
Tata
Tonton
Titi
On remarque que la boucle doit commencer à la fin du tableau et remonter.

Avec les facilités du Framework:

On peut déplacer les éléments avec la méthode Copy de Array:

On copie le tableau sur le même tableau mais décalé d'un élément.

Array.Copy(T, 1, T, 2, T.Length - 2)

T(1)="Tata"
On utilise ici une surcharge de Copy:

Array.Copy(Tor, indexOrigine, td, indexDestitation, nombredElements)
Tor: Tableau d'origine; Td tableau destination


VI-A-6-c-ii. Utiliser les COLLECTIONS
Relire le chapitre sur les collections.

On rappelle que nombre d'élément dans une collection n'est pas défini au départ comme dans un tableau. Dans une collection il n'y a que les éléments que l'on a ajouté.

Les éléments sont repérés grâce à un index, mais attention, si vous ajoutez un élément, cela décale l'index des éléments qui suivent.

Dim L As New ArrayList()     'On crée une collection ArrayList 

L.Add("toto")             'On ajoute un élément à la collection

MsgBox(L(0))                 'On affiche le premier élément
On pourra aussi écrire L.Item(0) pour pointer le premier élément.

      MsgBox(L.Count.ToString)     'On affiche le nombre d'élément.
warning Attention c'est le nombre d'éléments. S'il y a 3 éléments dans la ArrayList ce sont les éléments d'index 0,1,2.

VI-A-6-c-ii--. A- Trier une collection.

 L.Sort()                     'Trie la collection

VI-A-6-c-ii-b-. B- Rechercher un élément dans une collection.

L.Containts (élément)        ' Retourne True si la liste contient élément.
Recherche d'un élément dans une collection NON TRIEE avec IndexOf:

Dim l As New ArrayList

Dim i As Integer

l.Add("toto")

l.Add("lulu")

i = l.IndexOf("lulu")

MsgBox(i.ToString)    'Affiche 1
On rappelle qu'il existe aussi LastIndexOf qui démarre par la fin et une surcharge permettant de débuter la recherche à partir d'un indice donné.

Recherche d'un élément dans une collection TRIEE avec BinarySearch:

Dim l As New ArrayList

Dim i As Integer

l.Add("toto")

l.Add("lulu")

l.Sort()'Il est nécessaire que le tableau soit trié 

i = l.BinarySearch("lulu")

MsgBox(i.ToString)

VI-A-6-c-ii-c-. C- Effacer, insérer un élément dans une collection.

  L.Remove("toto")          'On enlève un élément de la liste

     L.RemoveAt(0)                'On enlève l'élément 0 de la liste
Insert permet d'insérer à un index spécifié.

     L.Insert( position, Ainserrer)

VI-A-6-c-iii. Différences tableau collection.
Un tableau peut avoir plusieurs dimensions, cela permet plusieurs indices:

Soit un tableau T(X,2) de String permettant de stocker en mémoire des patients (Nom, prénom, adresse..)

Nom Prénom Adresse

Dupont Pierre 32 rue du..
Dubout Jean 12 Place..
..    
     
...

Le premier indice est l'indice patient (ligne), Le second indice indique la colonne.

Ainsi le prénom du patient 1 est T(1,1)

Un tableau peut avoir X dimensions, toutes les éléments sont du même type.

Dim t(45,45,45) As Strings
On peut définir une structure

Public Structure Adresse

   Dim Numero     As Integer

   Dim Rue        As String

   Dim Ville      As String

End Structure
Il est ensuite possible de travailler sur un tableau de variable 'structure'

Dim Adresses(99) as Adresse    'Permet de travailler sur un tableau de 100 adresses

Adresses(33).Rue="Place de la mairie"
Un tableau a un nombre défini d'élément quand on le déclare, plus les dimensions sont grandes, plus il occupe de place, même si certains de ses éléments sont vides. Une collection ne contient que les éléments qu'on a mis.

Une collection n'a qu'une 'dimension': pour chaque indice on n'a qu'un seul élément (un seul Objet). On peut créer une collection de String ou d'Integer.

On verra plus loin qu'une collection comme ArrayList est une collection d'objets. (Collection d'objet 'Patient' par exemple, chaque objet 'Patient' ayant un nom, un prénom..)

Le travail sur les tableaux est beaucoup plus rapide que sur les collections.

Par exemple , pour stocker 1000 string dans un tableau ou une collection, l'usage du tableau est 60% plus rapide.

En programmation fonctionnelle on utilise les tableaux par habitude, en programmation Objet on utilise bien les Collections.


VI-A-6-c-iv. Utilisation particulière des tableaux.
Utiliser un tableau plutôt qu'une lourde routine permet parfois de résoudre un problème de programmation .

Le principe est: plutôt que d'utiliser une multitude de test pour trouver une valeur, il est parfois préférable de mettre judicieusement les valeurs dans un tableau et ensuite de lire la bonne 'case'.

1 - Exemple 1:

J'ai besoin de savoir le nom du jour de la semaine en fonction de son numéro.

1 doit retourner "Lundi"
2 doit retourner "Mardi"
3 doit retourner "Mercredi"
..

Avec If Then

C'est pas bien élégant, en plus il faut appeler la routine à chaque fois qu'on veut le nom.

Dim J As Integer  ' Contient le numéro du jour

Dim Nom As String    

If J= 1 Then

        Nom="Lundi"

ElseIf 2 Then

        Nom="Mardi"

...

End If
Avec Select Case

On peut faire un Select Case, c'est pas bien élégant, en plus il faut appeler la routine à chaque fois qu'on veut le nom.

SelectCase J

    Case 1 

        Nom="Lundi"

    Case 2

        Nom="Mardi"

    ..

End Select
Avec un tableau

C'est plus élégant de créer un tableau.

Dim Nom as String ={"Lundi", "Mardi", "Mercredi"...."Dimanche"}

Lenom= Nom (J-1)
C'est plus commode et le plus compact.

Notez que le premier élément du tableau étant l'élément 0 , il faut utiliser J-1.

Avec le Framework

On utilise pour cela une énumération:

Enum NomJour
    Lundi
    Mardi
    Mercredi
    Jeudi
    Vendredi
    Samedi
    Dimanche
End Enum 
puis

Dim s As Type = GetType(NomJour) 'on instance s

Nom = [Enum].GetName(s, J)    'Paramètre: une instance de l'énumération et J; retourne le nom.
2 - Exemple 2:

J'ai besoin de connaître le risque de faire un accident vasculaire en fonction du sexe et de la tranche d'age.

10 à 20 ans , Homme doit retourner 0
...
60 à 70 ans et Femme doit retourner 20
...

Avec If Then

C'est pas bien élégant, en plus il faut appeler la routine à chaque fois.

Dim S As Integer  ' Contient le sexe 0 masculin, 1 féminin

Dim A As Integer  ' Contient la tranche d'age

Dim Risque As Integer    

If S= 1 Then

     If A=1 Then

        Risque=0

     ElseIf A=2 Then

        Risque=3

    ..

    End If

Else

    If A=1 Then

        Risque=0

     ElseIf A=2 Then

        Risque=3

    ..

    End If

End If
Avec un tableau

C'est plus élégant de créer un tableau a 2 dimensions.

Les colonnes indiquent le sexe, les lignes, la tranche d'age.

Sexe Masculin Sexe Féminin

0 0
1 30
... ...

Dim Risques(,) as Integer ={{0, 0}, {1, 2}, {0, 0}, {2, 3}}

Risque= Risques(S, A)

VI-A-6-d. Calculs financiers simples


VI-A-6-d-i. Conversion Francs=>Euros.
Si un objet coute 100F, cela fait combien d'euros?

Dim Valeur As Double=100

Dim Resultat As Double

Resultat =Math.Round((Valeur / 6.55957), 2)
On divise par 6.55957 puis on arrondi à 2 chiffres après la virgule.


VI-A-6-d-ii. Coût d'augmentation de la vie.
Si un objet de 100€ augmente de 3% par an, combien coûtera -t-il dans 10 ans.

Dim Prix As Decimal=100
Dim Taux As Decimal=3

Dim Periode As Integer=10
Dim i As Integer
For i= 1 to Periode
 Prix=Prix+(Prix*Taux/100)

Next i
On peut remplacer les 3 dernières lignes par:

Prix=Prix*(1+Taux/100)^Periode
Noter que l'on utilise des variables de type décimales, c'est une bonne habitude pour faire des calculs financiers (pas d'erreurs d'arrondis).


VI-A-6-d-iii. Remboursement d'un prêt.
Quel est le remboursement mensuel d'un prêt d'une somme S durant une durée D (en année) à un taux annuel T ?

R=S x T / 1-(1+T)^-D (ici avec T en % mensuel et D en mois

Dim R, S , D, T  As Decimal   

S=5000  '5000€

D=15    'Sur 15 ans

T=4     '4% par an

T=T/12/100 'Taux au mois

D=D*12     'Durée en mois

  R=S*T/(1-(T+1)^(-D))'Formule connue par tous bon comptable!!
Si on voulait afficher le résultat dans un label (on verra cela plus loin)

Label1.text= R.ToString("C")
Ici le résultat est transformé en chaîne de caractères (grâce à ToString) au format monétaire ("C"), on obtient '36,98€' que l'on met dans le label pour l'afficher.

Ultérieurement on verra un exemple plus complet utilisant les fonctions financières de VB.


VII. Interface utilisateur.


VII-A. La console


VII-A-1. A- Faire une application purement 'Console':

Saisir et afficher sur la console qui est une simple fenêtre de type DOS. Cette méthode utilisant la console, est peu évoluée, archaïque. Pour une Application Console: Menu 'Projet'-> 'Propriétés de ...' Combo 'Type de sortie' :Application Console. Dans ce cas la console correspond à une fenêtre type DOS. Et là, on peut entrer des touches à partir du clavier.

On peut écrire du texte sur la console.


VII-A-2. B- Faire une application 'WinForm': Créer des fenêtres

(ou formulaires WinForms ), y mettre des boutons, des textbox... pour saisir et afficher. C'est l'interface habituelle des programmes Windows, nous l'étudierons en détail dans les chapitre 3.1 et suivant.

Une Application Windows (option par défaut), c'est celle que nous utiliserons dans le reste du cours. Menu 'Projet'-> 'Propriétés de ...' Combo 'Type de sortie' :Application Windows.

On utilise des fenêtres Windows: pour créer l'application.

Dans ce cas, en plus on peut aussi écrire sur la 'console'; on ne peut qu'écrire sur la 'Console'. La console correspond à la fenêtre de 'Sortie':Menu Affichage>Autres fenêtres>Sortie . (Ctrl Alt O)

Ici on est dans l'interface de développement VB. On utilise habituellement cette fenêtre de sortie pour le mise au point et pour afficher des informations de déboguage. (voir le chapitre sur le déboguage)


VII-A-3. Entrée au clavier:

Les données provenant du clavier proviennent de l'objet Console.In de type StreamReader. Ce type d'objets permet de lire une ligne de texte avec la méthode ReadLine :

Dim ligneTapée As String = Console.In.ReadLine()

Console.ReadLine() marche aussi.
La ligne tapée au clavier se retrouve dans la variable ligneTapée et peut ensuite être exploitée par le programme.

Cela semble ne marcher que pour les applications 'Console'


VII-A-4. Affichage sur la console:

Les données à afficher son envoyée à l'objet Console.Out

Console.Out.WriteLine(("ligne à afficher"))

VII-A-5. Exemple en 'Sortie console':

Affiche 'Tapez une ligne'; quand l'utilisateur a tapé du texte puis a validé, affiche: 'Ligne tapée=..'

Console.Out.Write("Tapez une ligne : ")

Dim ligne As String = Console.In.ReadLine()

Console.Out.WriteLine(("ligne tapée=" + ligne))

Console.WriteLine( ) est aussi accepté.

VII-A-6. En résumé:

On travaillera uniquement en sortie 'Application Windows', on utilisera la console uniquement pour afficher les informations de déboguage.


VII-B. Interface utilisateur et 'control'.

L'interface utilisateur (IU) correspond aux fenêtres et contrôles que voit l'utilisateur dans des fenêtres Windows.

Elle assure le dialogue entre l'homme et la machine. C'est l'Interface Homme Machine (IHM) . Sous Windows, c'est l'interface graphique.


VII-B-1. En pratique comment créer l'interface utilisateur ?

On a vu que le développeur dessine cette interface en mode conception (Design) dans l'IDE (Environnement de développement):

Exemple:

On crée une interface utilisateur avec une fenêtre, un bouton, un label (affichant du texte).

Quand on crée un nouveau projet, il y a création d'un Form1 automatiquement.

Comment rajouter une fenêtre?

Menu Projet, Ajouter un formulaire Windows, cliquer sur WindowsForm, une fenêtre ‘Form1' apparaît. On a bien crée une fenêtre avec la classe WindowsForms.Form (En fait on a crée une Classe 'Form1', on verra cela plus loin.)

Comment ajouter un bouton?

Cliquer sur ‘Boite à Outils' à gauche , bouton WindowsForms, puis bouton ‘Button',cliquer dans Form1, déplacer le curseur sans lâcher le bouton, puis lâcher le bouton : un bouton apparaît.

Comment ajouter un label?

Un label est un contrôle qui permet d'afficher un texte.

Comme pour le bouton cliquer sur ‘Boite à Outils' à gauche, bouton WindowsForms, bouton ‘Label' et mettre un contrôle label sur la fenêtre.

On obtient dans la fenêtre principale:

Modifier les propriétés des l'objets (Bouton, label..) en mode Design.

Il suffit ensuite de modifier les propriétés de l'objet pointé (celui qui est entouré de petits carrés) pour lui donner l'aspect désiré. Les propriétés sont accessibles dans la fenêtre de propriétés de droite.

Noter que pour modifier la taille des objets, on peut le faire très facilement à la souris en cliquant sur les petits carrés entourant l'objet et en tirant les bords. (on peut interdire les modifications de taille et de position des contrôles par le menu Format puis verrouiller les contrôles une fois que leurs tailles et positions est bien définies.)

Modifier les propriétés des l'objets (Bouton, label..) par code.

Dans le code des procédures les propriétés des objets sont aussi accessibles.

Button1.Text="OK"    permet par exemple de modifier la propriété Text d'un bouton.

VII-B-2. La Classe 'Control':

Les contrôles dit visuel (Button, TextBox ListBox...) héritent tous de la classe Control qui hérite elle-même de la classe System.WindowsForms.

Autrement dit, les Button, Label, TextBox... sont des 'Control'.

Tous ces objets avec représentation visuelle ont des propriétés communes héritées de la classe Control.

Nous allons voir les plus utilisées:

Name : il s'agit du nom de l'objet tel qu'il est géré par l'application.

Par défaut, VB baptise tous les objets que vous créez de noms génériques, comme Form1, Form2, Form3 pour les fenêtres, List1, List2 pour les listes...

Cette propriété est accessible en mode conception uniquement.

info Il est vivement conseillé de renommer les objets que vous venez de créer afin de donner des noms plus évocateurs.
Le bouton sur lequel est écrit « OK » sera nommé BoutonOK ou ButtonOk if you are anglophile.

La liste qui affiche les utilisateurs sera nommée ListUtilisateurs.

Il est conseillé de débuter le nom de l'objet par un mot évoquant sa nature:

BoutonOk ou BtOk ou ButtonOk, btnOk c'est comme vous voulez.

Microsoft conseille:
btn pour les Boutons
lst pour les ListBox
chk pour les CheckBox
cbo pour les combos
dlg pour les DialogBox
frm pour les Form
lbl pour les labels
txt pour les Textbox
tb pour les Toolsbar
rb pour les radiobutton
mm pour les menus
tmr pour les timers

Text : il s'agit du texte qui est associé à l'objet.

Dans le cas d'une fenêtre c'est le texte qui apparaît dans la barre de titre en haut.

Pour un TextBox ou un Label c'est évidement le texte qui est affiché.

On peut modifier cette propriété en mode conception ou dans le code :

Exemple : Avec du code comment faire pour que le bouton ButtonOk porte l'inscription ‘Ok'

ButtonOk.Text= "Ok" 
Enabled : accessible

Indique si un contrôle peut répondre à une interaction utilisateur.

La propriété Enabled permet l'activation ou la désactivation des contrôles au moment de l'exécution. Vous pouvez désactiver les contrôles ne s'appliquant pas à l'état actuel de l'application. Vous pouvez également désactiver un contrôle pour interdire son utilisation. Par exemple, un bouton peut être désactivé pour empêcher l'utilisateur de cliquer dessus. Si un contrôle est désactivé, il ne peut pas être sélectionné. Un contrôle désactivé est généralement gris.

Exemple : désactiver le ButtonOk

ButtonOk.Enabled=False
Visible :

Indique si un contrôle est visible ou non.

ButtonOk.Visible=False fait disparaître le bouton.
warning Attention pour rendre visible une fenêtre on utilisa la méthode .Show.
Exemple:

Button1.Enabled = True (il est accesible )

Button2.Enabled = False (il est grisé, l'utilisateur ne peut pas cliquer dessus)

Button3.Visible = False (on ne ne voit pas ce bouton 3)

Button4 a le focus

Button5.Text= "Ok"

Font :

Permet le choix de la police de caractères affichée dans l'objet.

TextBox1.Font = New Font("Courier New", 12, FontStyle.Italic)
Pour qu'un TextBox utilise la font "Courier New" de taille 12 en italique.

BackColor ForeColor:

Couleur du fond, Couleur de l'avant plan.

Pour un bouton Forecolor correspond au cadre et aux caractères.

ButtonOk.ForeColor=  System.Drawing.Color.Blue
Tag:

Permet de stocker une valeur ou un texte lié à l'objet. Chaque objet a un Tag qui peut contenir du texte.

On l'utilise souvent comme un Flag lié à l'objet.

Par exemple: une liste peut contenir la liste des CD ou des DVD ou des K7, quand je charge la liste des CD, je rajoute List1.Tag="CD" cela permet ultérieurement de voir ce qu'il y a dans la liste.

Il y a bien d'autres propriétés.


Un contrôle peut en contenir d'autres qui en contiennent d'autres.

Exemple: un formulaire contient un cadre qui contient des boutons:

La propriété Parent indique le contrôle conteneur : celui qui contient le contrôle en cours. FindForm retourne le formulaire conteneur.

HasChildren indique si le contrôle en cours contient d'autres contrôles, dans ce cas ils sont dans la collection Controls.

Exemple:

Si un Button1 est dans un formulaire nommé Form1 et dont la barre de titre contient 'Mon formulaire'

Button1.Parent retourne "NomProgramme.Form1 Text: Mon formulaire"

FindForm retourne la même chose ici.


VII-B-3. Évènements liés aux objets avec représentation visuelle

On a vu que les objets de l'interface utilisateur ont des procédures déclenchées par les évènement de cet objet.

2 exemples:
  1. Quand l'utilisateur clique sur un bouton Ok , la procédure BtOkClick s'effectue.
  2. Quand l'état (coché ou non coché) d'une case à cocher nommée Co change, la procédure Co.CheckedChanged est activée.
La syntaxe complète de la procédure est:

Private Sub BtOkClick (ByVal sender As System.Objet, ByVal e As System.EventArgs)  Handles BtOk.Click

End Sub
Détaillons:

Private Sub

La procédure évènement est privée donc accessible uniquement dans le module.

BtOkClick

Après le nom Sub il y a un nom de procédure. Ce nom est construit avec le nom du contrôle et l'évènement, mais cela aurait pu être n'importe quel nom car ce n'est pas ce nom qui indique ce qui déclenche la procédure.

Sender

indique le contrôle ayant déclenché l'évènement. c'est un Objet.

sender.Name contient par exemple le nom du contrôle ayant déclenché l'évènement.

e

C'est une variable de type SystemEventArgs qui permet de connaître l'évènement qui à déclenché la procédure.

Handles

Indique quel objet et évènement à déclenché la procédure. (On verra qu'il peut y en avoir plusieurs.)

Handles BtOk.Click indique que c'est l'évènement Click sur l'objet BtOk qui déclenche la procédure.

On voit que quand on crée un objet, ses procédures évènements sont automatiquement crées.

On se rend compte que dans une procédure évènement on peut modifier (en mode conception) ou lire (en mode Run) quel objet et quel évènement à déclenché la procédure. On peut même indiquer plusieurs objets liés à cette procédure.

Certains évènement sont communs à tous les contrôles:


Click

DoubleClick

GotFocus     Prise du focus

LostFocus    Perte du focus

KeyUp        Remontée d'une touche clavier

KeyPress     Pression d'une touche clavier

KeyDown      Appuie sur une touche clavier
Il y a toujours des méthodes Changed déclenchées par un changement d'état: CheckedChanged pour une case à cocher, TextChanged pour un contrôle texte.

Pour ne pas alourdir les exemples, nous écrivons souvent une version simplifiée de l'en-tête de la procédure.

Nous écrivons:

Private Sub BtOkClick ()
au lieu de:

Private Sub BtOkClick (ByVal sender As System.Objet, ByVal e As System.EventArgs)  Handles BtOk.Click

VII-B-4. En résumé:

Le programmeur dessine les fenêtres et contrôles.

Il peut modifier les propriétés des objets dessinés:

Par la fenêtre de propriétés (en mode conception).

Par du code (des instructions) dans les procédures.


VII-C. Les fenêtres ou 'Formulaires'.

Elle correspondent aux fenêtres ou 'formulaires'. Ce sont les 'Windows Forms'.


VII-C-1. Créer une fenêtre en mode conception:

Quant on ouvre un nouveau projet il y a déjà une Form1. On peut avoir besoin d'en ajouter une autre au projet.

Menu Projet, Ajouter un formulaire Windows, cliquer sur WindowsForm, une fenêtre ‘Form1' apparaît. On a bien crée une fenêtre avec la classe WindowsForms.

Toute l'interface se trouve sur des fenêtres.

En VB.net on parle de formulaire.


VII-C-2. Propriétés:

Bien sur, la fenêtre possède des propriétés qui peuvent être modifiées en mode design dans la fenêtre 'Propriétés' à droite :

Pour modifier la propriété Text par exemple, on clique sur 'Form1' en face de Text, on efface 'Form1' et on tape le nouveau texte.

On peut aussi modifier les propriétés par une ligne de code:

Form1.Text = "Nouveau texte"
Voyons les choses plus en détails:

Name :Nom du formulaire. C'est le nom qui désignera l'objet dans le code.

Donner un nom explicite. FrmDemarrage


Dès qu'une fenêtre est créée on modifie immédiatement ses propriétés en mode conception, dans la fenêtre de propriétés, pour lui donner l'aspect que l'on désire.


Text : C'est le texte qui apparaîtra dans la barre de titre en haut.

Text peut être modifié par le code : Form1.Text= "Exemple"

Icon : propriété qui permet d'associer à la Form un fichier icône. Cette icône s'affiche dans la barre de titre, tout en haut à gauche. Si la Form est la Form par défaut du projet, c'est également cette icône qui symbolisera votre application dans Windows.

Comment mettre l'icône 'euro.ico' dans la barre de titre, par code?

Dim MyIcon As Drawing.Icon = New System.Drawing.Icon("C:\euro.ico")

 Me.Icon = MyIcon
Comment créer une icône?

Dans l'IDE de VB (pas en VB Express 2005!!).

Menu Fichier>Nouveau>Fichier cliquez sur Icon , Vb ouvre une fenêtre Icon1 (dans l'éditeur d'images de Visual Studio.Net) Cela permet de créer ou modifier une icône (Fichier>Ouvrir>Fichier pour modifier).

Comment enregistrer? Click droit dans l'onglet 'Icon1' ouvre un menu contextuel permettant d'enregistrer votre Icône.

WindowState :

Donne l'état de la fenêtre : Plein écran (FormWindowState.Maximized), normale (FormWindowState.Normal), dans la barre de tache (FormWindowState.Minimized).

Exemple: mettre une fenêtre en plein écran avec du code.

Me.WindowState =FormWindowState.Maximized 
(Quand on tape Me.WindowsState= , Vb donne la liste, l'énumération)

Remarque: Me indique l'instance ou le code est en train de s'exécuter, dans ce cas Me indique le formulaire en cours.


ControlBox

Si cette propriété à comme valeur False, les boutons de contrôle situés à droite de la barre de la fenêtre n'apparaissent pas.


MaximizeBox

Si cette propriété à comme valeur False, le boutons de contrôle ‘Plein écran' situés à droite de la barre de la fenêtre n'apparaît pas.

MinimizeBox

Si cette propriété à comme valeur False, le boutons de contrôle ‘Minimize' situés à droite de la barre de la fenêtre n'apparaît pas.


En résumé:

FormBorderStyle

Permet de choisir le type des bords de la fenêtre : sans bord (None), bord simple (FixedSingle)ne permettant pas à l'utilisateur de modifier la taille de la fenêtre, bord permettant la modification de la taille de la fenêtre (Sizable)..

Si on a 'None', la barre de titre n'apparaît pas.

En VB 2005 il y a aussi Fixed3D qui ajoute un petit effet 3d de profondeur sur le tour , FixedDialog et aussi FixedToolWindows et SizableToolWindows (ces 2 dernières cachent les boutons Maximize et Minimize et l'icone).


Exemple de code:

Me.FormBorderStyle =FormBorderStyle.Sizable 
Cela donne:

None FixedSingle Sizable SizableToolWindows.

StartPosition :

Permet de choisir la position de la fenêtre lors de son ouverture.

Fenêtre au centre de l'écran ? à la position qui existait lors de la conception ...?

Me.StartPosition =FormStartPosition.CenterScreen 
Size, MinSize et MaxSize

Donne les dimensions de la Form (largeur, hauteur) ou les dimensions minimum et maximum que l'on peut utiliser pour redimensionner une fenêtre lorsqu'elle est redimensionnable.

Me.Size = New Size(100, 100) 'Les dimensions sont contenues dans un objet Size que l'on crée.

Width et Height: donne la largeur et hauteur.

On parle ici des dimensions extérieures du formulaire (Barre de titre et bordures comprises)

Pour avoir les dimensions internes utilisables (Sans barre de titre et bordures) il faut utiliser ClientSize.

On remarque que si on modifie ClientSize, cela modifie Size car la hauteur de la barre de titre n'est pas modifiable.


Opacity

Allant de 0% (0) à 100% (1), permet de créer un formulaire plus ou moins transparent.

Pour 0 il est transparent, pour 1 il est totalement opaque (normal)


Exemple complet:

Me.FormBorderStyle= Sizable

Me.ControlBox=False

Me.Size = New Size(100, 100)

Me.StartPosition = FormStartPosition.CenterScreen

Me.Opacity= 0.75
Me.Text = "Exemple" 
Donne au milieu de l'écran, la fenêtre:

(Dans notre exemple, on ne s'occupe pas pour le moment du bouton et du label "Bonjour")


VII-C-3. Ouvrir un formulaire

On vient de dessiner une Form1 et une Form2 c'est donc les Class 'Form1 et ''Form2' (les moules) que l'on a dessiné.

Si dans une routine de la Form1 on veut ouvrir une seconde fenêtre de type Form2, il faut:

Créer un Objet fenêtre (formulaire) avec le moule Form2:

            Dim f As New Form2()
La nouvelle instance f de la Class 'form2' est un objet formulaire.

Pour la faire apparaître j'utilise la méthode: .ShowDialog.

            f.ShowDialog()      
La fenêtre f est modale car on a utilisé ShowDialog : quand elle est ouverte, on ne peut pas aller dans une autre fenêtre de l'application avant de sortir de celle là. (A titre d'exemple les fenêtres MessageBox sont toujours Modales).

Utiliser .show pour ouvrir une feuille non modale.

f.Show()  
warning Attention: une fenêtre est un objet et est 'visible' suivant les règles habituelles des objets.
Si on instancie une fenêtre à partir d'une procédure, elle sera visible dans cette procédure. Si elle est 'Public' et instanciée dans un module standard, elle sera visible partout.

f.Activate donne le focus à un formulaire visible.


VII-C-4. Fermer un formulaire

On utilise Close.

Exemple:

Me.Close ferme le formulaire courant: le formulaire n'existe plus, il disparaît.

Par contre:

Me.Hide fait disparaître le formulaire, il n'est plus visible mais est toujours présent (Visible passe à False).


VII-C-5. Propriétés:

On a vu qu'un formulaire possédait de nombreuses propriétés:

Name contenant le nom du formulaire.

Text contenant ce qui est affiché dans la barre de titre.

Mais aussi

Left et Top qui donne les coordonnées x et y du coin supérieur gauche du formulaire.

Me.Left=100

Location: coordonnés du point supérieur gauche par rapport au conteneur.

    Me.Location = New Point(100, 100) 'c'est un objet 'point' (et non les coordonnés)
Size: taille du contrôle ; accepte un objet Size comportant: largeur, hauteur

Me.Size = New Size(100, 100)

(MaxSize donne la taille maximum possible).

Width et Height: donne la largeur et hauteur.

SetBounds permet de modifier x, y, width, heigth

Me.SetBounds(100, 100, 45, 45)
La collection Controls contient les contrôles qui sont dans le formulaire (boutons, listes..).

On peut parcourir la collection, pour voir de quel type est le contrôle:

Dim i As Integer
For i = 0 To Me.Controls.Count - 1

...Me.Controls.Item(i).GetType... 

Next i
Pour un bouton GetType retourne System.Windows.Forms.Button

Le nom du bouton est :

Me.Controls.Item(i).Name
 
On verra plus loin que pour ajouter, par code, un contrôle à une form, il faut l'ajouter à la collection Controls:

 Controls.Add(MyButton)

VII-C-6. Evènements:

Au cours de l'exécution:

Quand le formulaire est chargé la procédure Form1_Load() est exécutée.

On pourra donc y mettre le code initialisant la feuille.

(Form_Load se produit AVANT l'affichage du formulaire.)

Private Sub Form1_Load (..)

    ' Code initialisant les variables, chargeant les listbox..

End Sub
Le formulaire est affiché.

Form1_Activated() est exécuté ensuite car la feuille deviendra active.

Form1.GotFocus() est enfin exécuté puisque la fenêtre prend le focus (un contrôle qui a le focus est celui qui reçoit les évènements clavier, souris.. Sa barre de titre n'est plus grisée).

Form1.Enter () est exécuté lorsque l'utilisateur entre dans la fenêtre.

Dès qu'une propriété change de valeur un évènement 'PropriétéChanged' se déclenche:

Form1.BackColorChanged se déclenche par exemple quand la couleur du fond change.

Form1.Resized se déclenche quand on modifie la taille de la fenêtre.( c'est intéressant pour interdire certaines dimensions)


Form1.Leave survient quand il y a perte du focus.

Bien sur il existe aussi Form1_Desactivate quand la fenêtre perd le focus et n'est plus active.

Si l'utilisateur ferme la fenêtre:

Form1.Closing se produit avant la fermeture de la fenêtre (on peut annuler cette fermeture en donnant à la variable Cancel la valeur True)

Form1.Closed se produit lorsque la fenêtre est fermée.

Il y en a beaucoup d'autres comme par exemple les évènements qui surviennent quand on utilise la souris (MouveUp, MouseDown, MouseMove) ou le clavier (KeyUp, KeyDown, KeyPress) sur la fenêtre.


Exemple pratique:

-Comment voir 'bonjour' dans un textbox à l'ouverture du formulaire?

Private Sub Form1_Load()

TextBox1.Text= "bonjour"

End Sub
-Comment afficher le formulaire Form1 PUIS une message box affichant "Hello"?

Si on tape:

Private Sub Form1_Load(

MsgBox("hello")

End Sub
La message box est affichée Avant la fenêtre!! car le formulaire s'affiche après Form-Load!!

Il faut écrire:

Private Sub Form1_Load 
Me.Show() 'affiche la form1

MsgBox("hello")' affiche la messagebox

End Sub
Form1 est bien affichée avant la MessageBox.

Si on met le msgbox dans form_ gotfocus ou form_activated, cela boucle car à la sortie de la msgbox le gotfocus et le activated sont effectués de nouveau.


VII-C-7. Méthodes:

On a déjà vu que pour faire apparaître une fenêtre il faut utiliser .ShowDialog (pour qu'elle soit modale) ou .Show (pour non modale).

Sachant que Me indique l'instance ou le code est en train de s'exécuter:

Me.Close() ferme le formulaire.

Me.Activate() l'active s'il est visible

Me.Show() affiche un formulaire invisible

Me.Hide() rend la fenêtre invisible.


VII-C-8. System.Windows.Forms.Form

On se rend compte que quand on dessine une fenêtre Form1 par exemple, VB crée une nouvelle classe 'Class Form1' (Un 'moule' à formulaire!!)

Public Class Form1

End Class
Elle hérite de System.Windows.Forms.Form: on voit bien dans le code:

Inherits Systeme.Windows.Forms.Form

Quand on tape Dim f As New Form1(), on crée une instance de la Class Form1. (Un véritable Objet 'formulaire')


Pour les surdoués:

En VB 2003:

Quand on regarde le code, il y a:

-du code généré automatiquement par le concepteur Windows Forms et qui crée la fenêtre et ses contrôles.

(on peut le voir en cliquant sur le petit '+'; en ouvrant la région 'Code généré par le concepteur Windows Form')

Comme pour toute classe, il y a un constructeur (Sub New) un destructeur (Sub Dispose) et le code pour créer les contrôles contenus dans le formulaire.

-les procédures liées aux évènements.

En VB.Net 2005:

L'onglet Form1.vb contient:

Public Class Form1

Public Sub New()

' This call is required by the Windows Form Designer.

InitializeComponent()    '<=======Appel d'une routine qui 'initialise les composants de la form

' Add any initialization after the InitializeComponent() call.

End Sub
La classe contient un constructeur (Sub New) qui apelle une routine Ititialise Component:

Pour voir cette routine, il faut passer par le menu de droite:

Si on clique sur InitializeComponent, l'onglet Form1.Designer.vb apparaît.

On a ainsi accès à InitialiseComponent et à Dispose qui sont dans une classe Partielle de Form1.
(En VB 2005, une Classe peut être 'découpée' en Classes partielles)

C'est ici qu'il est indiqué que la Class hérite de System.Windows.Forms.Form


VII-C-9. Formulaire d'avant plan:

Un formulaire d'avant plan est un formulaire qui reste en avant plan, devant les autres formulaires, même si on ne l'utilise pas.

Pour définir au moment de la conception un formulaire en tant que formulaire d'avant-plan d'une application.

  • Dans la fenêtre Propriétés, attribuez à la propriété TopMost la valeur true.
Pour définir par code un formulaire en tant que formulaire d'avant-plan d'une application.

  • Dans une procédure, attribuez à la propriété TopMost la valeur true.

  Me.TopMost = True
Par contre, BringToFront ramène la fenêtre au premier plan temporairement: si l'utilisateur clique sur une autre fenêtre, elle passera au premier plan..


VII-D. Les 'Boutons'.

Ils sont omniprésent dans les 'formulaires'.


VII-D-1. Créer un bouton :

Cliquer sur ‘Boite à Outils' à gauche , bouton Windows Forms, puis bouton ‘Button',cliquer dans Form1, déplacer le curseur sans lâcher le bouton, puis lâcher le bouton : un bouton apparaît.


VII-D-2. Modifier ses propriétés:

On peut modifier les propriétés dans la fenêtre des propriétés en bas à droite:

On peut aussi modifier les propriétés par du code.


Name est utilisé pour lui donner un nom explicite (BoutonOk BoutonCancel)


FlatStyle donne un aspect au bouton (Flat, standard, System, pop Up)

En VB 2003

En vb2005:

Standard et System utilisent le thème d'affichage de Windows que vous avez choisi dans le panneau de configuration. (Thème Windows XP, personnel..)

Quand on utilise Flat on peut choisir dans FlatStyle l'épaisseur du bord et sa couleur (3 et rouge dans notre premier bouton).

Enfin on peut choisir la position du texte avec TextAlign. Il a la valeur TopLeft dans le dernier bouton.

Text contient le texte a afficher sur le bouton. ForeColor correspond à la couleur de ce texte (BackColor étant la couleur du fond)

Exemple:

button1.Text="Ok" affiche 'Ok' dans le bouton.

Si on y inclut un « & » la lettre qui suit sera soulignée et servira de raccourci clavier.

Button.Text= "&Ok" donne sur le bouton Ok et crée le raccourci clavier 'Ctrl O' qui est l'équivalent d'un click sur le bouton.


TextAlign permet de positionner le texte dans le bouton.


Image contient le nom de l'image à afficher sur le bouton (si on veut afficher une image, on le fait en mode Design; noter que quand on distribue l'application, il n'y a pas besoin de fournir le fichier contenant l'image avec l'application ). (AlignImage permet de positionner l'image sur le bouton.)

On peut aussi puiser une image dans une ImageList grâce à la propriété ImageList et ImageIndex, on peut ainsi changer d'image.

La propriété BackGroundImage permet de mettre une image de fond.


Font contient la police de caractère, sa taille, son enrichissement (gras, italique..)

Truc: quand vous travaillez sur de très petits boutons, changer la propriété Font et choisir une petite taille de caractère (8 par exemple)


VII-D-3. Utiliser les évènements:

L'évènement principalement utilisé est Click() : quand l'utilisateur clique sur le bouton la procédure

Private Sub Button_Click(..)

End Sub
est traitée.

Cette procédure contient le code qui doit être exécuté lorsque l'utilisateur clique sur le bouton.

Le bouton peut être sélectionné grâce à un clic de souris, à la touche ENTRÉE ou à la BARRE d'espacement si le bouton a le focus.


VII-D-4. Créer un bouton Ok ou Cancel:

Parfois il faut permettre aux utilisateurs de sélectionner un bouton en appuyant sur la touche ENTRÉE même si le bouton n'a pas le focus.

Exemple: Il y a sur la fenêtre un bouton "Ok" qui doit être enfoncé quand l'utilisateur tape 'Enter' au clavier, c'est le bouton qui 'valide' le questionnaire ( et qui le ferme souvent).

Comment faire?

Définissez la propriété AcceptButton de la Form en lui donnant le nom du bouton.

Cela permet au formulaire d'avoir le comportement d'une boîte de dialogue.

La propriété CancelButton de la Form permet de la même manière de créer un bouton 'Annuler'( qui répond à la touche 'Echap'(ESC).


VII-D-5. Couleur transparent dans les images des boutons:

On a vu qu'on pouvait mettre une image dans un bouton , il faut pour cela donner à la propriété Image le nom du fichier contenant l'image, ceci en mode Design.

Mais l'image est souvent dans un carré et on voudrait ne pas voir le fond (rendre la couleur du fond transparente)

Voici l'image , je voudrais ne pas afficher le 'jaune' afin de voir ce qu'il y a derrière et donner l'aspect suivant

Dans Visual Basic 6.0, la propriété MaskColor était utilisée pour définir une couleur qui devait devenir transparente, permettant ainsi l'affichage d'une image d'arrière plan.

Dans Visual Basic .NET 2003, il n'existe pas d'équivalent direct de la propriété MaskColor!! Cependant,

  1. Si au lieu de mettre du jaune , on met une image avec un fond blanc , Vb 2003 ou 2005 n'affichent pas le blanc autour.
  2. Si on a une image avec un fond jaune ou d'une autre couleur, on peut ruser et définir la transparence:
Dans le " Code généré par le Concepteur Windows Form " après la définition du bouton ou dans Form_Load ajouter:

Dim g As New System.Drawing.Bitmap(Button1.Image)

g.MakeTransparent(System.Drawing.Color.Yellow)

Button1.Image = g
On récupère le Bitmap de l'image du bouton , on indique que le jaune doit être transparent, on remet le BitMap.

Bien sur il y a intérêt à choisir une couleur (toujours la même) qui tranche pour les fonds de dessin et ne pas l'utiliser dans le dessin lui même.

info En VB 2005 le simple fait de mettre du blanc comme couleur de fond de l'image (à la place du jaune) permet la transparence.

VII-D-6. Utilisation avancée: Créer de magnifique bouton en VB2005:

On peut créer des boutons avec ses propres images:

Exemple donné par Microsoft:

Pour faire cela il faut créer le dessin, le mettre en fond et paramétrer correctement le bouton.

1-Mettre le dessin dans les ressources:

Aller dans les ressources (ensemble d'éléments,: images, textes, sons.. qui seront incorporés dans le programme.)

(Pour cela double cliquez sur MyProjet dans l'explorateur de solution ou menu 'Projet'=>'Propriétés de..', Onglet 'Ressources')

Dérouler la liste à gauche pour y mettre 'Images' puis cliquer sur 'ajouter une ressource'; on vous demande le nom de la ressource (tapez par exemple 'button_blue'), vous vous trouver dans Paint, dessinez (ou collez) l'image de votre bouton. Puis menu 'Fichier'=>'Enregistrer': le dessin apparaît dans les ressources. Fermez Paint.

2-Mettre ce dessin comme fond du bouton:

MyButton.BackGroundImage= MonProgramme.My.Ressources.Ressources.button_Blue
(ou modifier cette propriété BackGroundImage dans la fenêtre de propriétés à droite)

2-Modifier les propriétés du bouton dans la fenêtre de propriétés:

En effet l'image de la ressources n'a pas la même taille que le bouton, de plus le dessin du bouton standard apparaît!!

MyButton.BackGroundImageLayout= Stretch  'met le dessin à la taille du bouton.

MyButton.FlatStyle= Flat  'fait disparaître des éléments du bouton standard.

MyButton.BackColor= Transparent  'Efface le fond du bouton standard.

MyButton.Text= "Importer Image'  'met le texte.
Super, c'est beau!!

On peut aussi en VB 2003 ou VB2005 personnaliser ses boutons.

Un exemple:

Voir 5-3.htm c'est un peu complexe!!


VII-D-7. Utilisation avancée: Création d'un bouton par code:

L'exemple suivant crée un Button nommé Button1 sur lequel on voit "Ok", on modifie certaines de ses propriétés et on l'ajoute à Form.

Private Sub InitializeMonButton()
Dim button1 As New Button1()
button1.Text="Ok"
' Ajouter le bouton à la Form
Controls.Add(button1)
End Sub 
Il faut par code créer aussi les évènements liés à ce bouton: dans ce cas il faut déclarer le bouton plutôt avec la syntaxe contenant WithEvents et en haut du module.

Private WithEvents Button1 As New Button
(dans ce cas on ne remet pas la ligne Dim button1 dans la Sub InitializeMonButton)

Puis écrire la sub évènement.

Sub OnClique ( sender As Objet, EvArg As EventArgs) Handles Button1

End Sub  
Ainsi VB sait que pour un évènement sur le Button1 , il faut déclencher la Sub OnClique.

(On reviendra sur cela)


VII-E. Les 'TextBox'

Les contrôles permettant de saisir du texte sont:

Les TextBox

Les RichTextBox

Les MaskedTextBox (VB2005 Framework2)


VII-E-1. Les contrôles TextBox.

Contrôle qui contient du texte qui peut être modifié par l'utilisateur du programme.

C'est la propriété Text qui contient le texte qui a été tapé par l'utilisateur.

Exemple hyper simple: Comment demander son nom à l'utilisateur ?

Il faut créer un label dont la propriété Text contient "Tapez votre nom:", suivi d'un TextBox nommé txtNom avec une propriété Text="" (Ce qui fait que la TextBox est vide), enfin un bouton nommé btOk dont la propriété Text="Ok".Cela donne:

Tapez votre nom:

txtNom.Select() dans Form_Load donne le focus à la TextBox

Une fois que l'utilisateur a tapé son nom , il clique sur le bouton 'Ok':

Dans btOk_Click il y a:

Dim nom As String

nom= txtNom.Text
La variable Nom contient bien maintenant le nom de l'utilisateur.


Un TextBox correspond à un mini éditeur de texte.(Mais sans enrichissement: sans gras, ni italique… du moins pour être exact, l'enrichissement affecte la totalité du texte et pas seulement une partie) La police de caractères affectant la totalité du texte peut simplement être modifiée par la propriété Font. La couleur du texte peut être modifiée par ForeColor, mais la totalité du texte aura la même couleur.

La propriété .text permet aussi de modifier le texte visible dans le contrôle.

 TextBox1.text= "Bonjour" ‘Affiche ‘Bonjour' dans le contrôle.
Parmi les multiples propriétés de ce contrôle, signalons :

Multiline : autorise ou non l'écriture sur plusieurs lignes.
Scrollbars : fait figurer une barre de défilement horizontale ou verticale (ou les deux)
PaswordChar : crypte le texte entré sous forme d'étoiles.
MaxLength : limite le nombre de caractères qu'il est possible de saisir.

TextBox1.MaxLength= 3 'limite la saisie à 3 caractères.

TextBox1.MaxLength= 0 'ne limite pas la saisie et permet de taper un très long texte.

TextLength donne la longueur du texte


En mode MultiLine la collection Lines contient dans chacun de ses éléments une des lignes affichées dans le contrôle:

TexBox1.Lines(0) contient la première ligne

TexBox1.Lines(1) la seconde...


Les TextBox contiennent une méthode Undo:annulation de la dernière modification.

La propriété CanUndo du TextBox doit être à True.

Ensuite pour modifier:

If textBox1.CanUndo = True Then
textBox1.Undo()
' Vider le buffer Undo.
textBox1.ClearUndo()
End If
Il existe aussi Redo.


Ajouter au texte:

On peut ajouter du texte au texte déjà présent dans le TextBox

textBox2.AppendText(MonText)
C'est équivalent à textBox2.Text=textBox2.Text+MonText


Pour saisir un mot de passe:

TextBox1.PassWord = true
Ainsi il apparaît des *** au lieu des caractères tapés.


Evènements liés aux TextBox:

KeyDown survient quand on appuie sur le touche.

KeyPress quand la touche est enfoncée.

KeyUp quand on relâche la touche.

Ils surviennent dans cet ordre.

KeyPress permet de récupérer la touche tapée dans e.KeyChar (le code unicode mais pas les touches de fonction de direction comme CTRL,F1, F2, flèche haut...)


KeyDown et KeyUp permettent de voir ce qui a été tapé physiquement, le code clavier (dans e.KeyCode) et aussi si MAJ ALT CTRL ont été pressés (dans e.Shift e.Alt..)


On peut récupérer la touche pressée, mais impossible d'en modifier la valeur en VB 2003(e.KeyChar est en lecture seule), par contre en VB 2005 , on peut modifier e.KeyChar.

Voir exemple plus bas;

Comment récupérer la totalité du texte qui est dans le TextBox?

T= textBox1.Text

Comment mettre les lignes saisies par l'utilisateur dans un tableau ?

Dim tempArray() as String

tempArray = textBox1.Lines     'On utilise la collection Lines
Comment récupérer la première ligne ?

T= textBox1.Lines(0)

Si une partie du texte est sélectionnée par l'utilisateur, on peut la récupérer par:

T= TexBox1.SelectedText


Pour sélectionner une portion de texte on utilise:

TextBox1.SelectionStart=3 'position de départ

TextBox1.SelectionLength=4 'nombre de caractère sélectionné
On peut aussi écrire:

TextBox1.Select(3,4)

puis

TexBox1.SelectedText="toto" 'remplace la sélection par 'toto'


Comment positionner le curseur après le troisième caractère?

En donnant à la propriété SelectionStart la valeur 3

TextBox1.SelectionStart=3

SelectionLength doit avoir la valeur 0

Comment interdire la frappe de certains caractères dans une TextBox?

Exemple:

Ne permettre de saisir que des chiffres.

Pour cela il faut utiliser l'évènement KeyPress du textBox qui retourne un objet e de type KeyPressEventArgs. e.KeyChar contient le caractère pressé, mais il est en lecture seule!! on ne peut le modifier. Pour annuler la frappe (dans notre exemple si le caractère n'est pas un chiffre) il faut faire e.handled=True

IsNumeric permet de tester si le caractère est numérique.

Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress

If IsNumeric(e.KeyChar) Then 

    e.Handled = False

Else

    e.Handled = True

End If

End Sub
En VB 2005 TextBox1.CharacterCasing = CharacterCasing.Upper permet de saisir que des majuscules.

(Numeric qui ne permet de saisir que du numérique fonctionne uniquement en C#!!)

Compter combien de fois on a tapé certains caractères?

Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress

Select Case e.KeyChar
' Compte les  backspaces.
Case ControlChars.Back
    Nombrebackspace = Nombrebackspace + 1
' Compte les  'ENTER' .
Case ControlChars.Lf
    Nombrereturn = Nombrereturn + 1
' Compte les  ESC . 
Case Convert.ToChar(27)
    NombreEsc = NombreEsc + 1
' Compte les autres.
Case Else
    keyPressCount = keyPressCount + 1
End Select
End Sub
Petite parenthèse:

Pour comparer les caractères il y a 2 méthodes:

if e.KeyChar=Convert.ToChar(27) then

ou

if AscW(e.Keychar)=27 then

Différentes manières de récupérer ce qui a été tapé:

L'évènement TextBox1_TextChanged se produit dès qu'il y a une modification dans le textbox (frappe d'un caractère mais aussi modification de la propriété Text), dans la procédure TextBox1_TextChanged on peut utiliser TextBox.text qui contient la totalité du texte.


Quand on tape un caractère au clavier, les évènements suivant se déclenchent (dans l'ordre):

TextBox1_KeyDown() quand on appuie sur la touche.

TextBox1_KeyPress()

TextBox1_KeyUp() quand on relâche la touche.

TextBox1_KeyDown() et TextBox1_KeyUp() retourne le paramètre e.

e.KeyChar permet de récupérer le caractère qui à été tapé (le caractère UNICODE).

(on peut facilement le tester avec les fonctions traitant des caractères: IsDigit par exemple pour voir s'il est numérique, ou tester son code Ascii ou plutôt unicode)

if AscW(e.Keychar)=27 then

TextBox1_KeyPress()retourne le paramètre e.

e.KeyCode permet de récupérer le code clavier qui à été tapé. Pour tester une caractère on utilise l'énumération Keys:

If e.KeyCode = Keys.A Then (permet devoir si l'utilisateur a tapé sur la touche A.)

End If
Noter bien que c'est le code de la touche (et pas du caractère), on peut tester Keys.Escape Keys.Back..

Aussi on peut aussi tester:

e.Alt permet de savoir si la touche Alt est enfoncée.

e.Shift permet de savoir si la touche Shift est enfoncée.

e.Ctrl permet de savoir si la touche Contrôle est enfoncée.

KeyChar et KeyCode sont en lecture seule en 2003, on ne peut donc pas les modifier!! (en 2005 on le peut)

En VB 2003, y a t-il un moyen de modifier le caractère tapé? les propriétés de e comme e.KeyChar (dans KeyPress) ou e.KeyCode, e.KeyData e.KeyValue dans les évènements KeyPress et KeyDown sont en lecture seule!!! Une solution est de modifier directement le texte:

Exemple: Si l'utilisateur tape ',' afficher '.' à la place.

Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress

Dim pos As Integer

pos = TextBox1.SelectionStart 'on mémorise la position du curseur

If e.KeyChar = "," Then

e.Handled = True 'on ne valide pas le caractère ',' qui n'apparaîtra pas.

TextBox1.Text = TextBox1.Text.Insert(pos, ".")'on insère un '.'

TextBox1.SelectionStart = pos + 1 'on avance le curseur d'un caractère

End If

End Sub
En VB 2005 (Framework 2) y a t-il un moyen de modifier le caractère tapé?

e.KeyChar est enfin en lecture-écriture.
Pour transformer un caractère tapé au clavier, c'est simple:


Exemple:

Quand l'utilisateur tape ',' , afficher '.'.

Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox3.KeyPress

    If e.KeyChar = "," Then e.KeyChar = CType(".", Char)

End Sub
VB 2005 (le Framework 2) apporte de nouvelles facilités:
La propriété ShortCutsEnabled = True permet à l'utilisateur d'ouvrir un menu contextuel avec le click droit; ce menu permet les annuler, couper, copier, coller, supprimer, Sélectionner tout; ce qui peut aussi être fait avec les raccourcis clavier Shift/Inser Ctrl/Inser..

Il est aussi possible d'aider la saisie de mot.
Exemple: je tape 'tot' le textBox propose 'toto'

pour cela dans la fenêtre de propriétés:
AutoCompletedMode doit prendre la valeur Append ou Suggest à la place de None.
AutoCompletedSource indique ou chercher les lignes de 'suggestion'
AutoCompletedCustomSource est une liste de lignes utilisées.

Ci dessus, dans l'exemple:
AutoCompletedMode= Suggest affiche le mot dessous; Append l'aurait affiché dans le textBox.
AutoCompletedSource= CustomSource indique d'utiliser les mots de AutoCompletedCustomSource
AutoCompletedCustomSource contient la liste des mots (pour les rentrer cliquer sur les '..'.)


VII-E-2. Le contrôle RichTextBox :

Si vous êtes débutant passer à un rubrique suivante, vous reviendrez plus tard à la gestion du code RTF.


Rich Text veut dire 'Texte enrichi'

Le contrôle RichTextBox permet d'afficher, d'entrer et de manipuler du texte mis en forme. Il effectue les mêmes tâches que le contrôle TextBox, mais il peut également afficher des polices, des couleurs et des liens, charger du texte et des images incorporées à partir d'un fichier, ainsi que rechercher des caractères spécifiques.

info Le contrôle RichTextBox a les possibilités d'un traitement de texte comme Word.
Qu'est ce que RTF?

Le format du texte que l'on peut mettre dans une RichTextBox est le format RTF (Rich Text Format = Format de Texte Enrichi)

Voir Format RTF pour le détails


Pour utiliser les fonctionnalités du RichTextBox il faut utiliser la propriété .Rtf

Quand j'affecte un texte à la propriété .Text il est affiché tel quel, sans tenir compte de l'enrichissement.

Quand j'affecte un texte à la propriété .Rtf du contrôle pour l'afficher, s'il contient des enrichissement au format RTF , l'enrichissement est affiché :

Comment afficher un texte enrichi?

RichTextBox1.RTF= T        'T étant le texte enrichi
Exemple complet :

"{\rtf1\ansi 

 { \colortbl 

\red0\green0\blue0;

\red255\green0\blue0;

\red0\green255\blue0;}

{\fonttbl

{\fo\froman Symbol;}

{\f1\fswiss Arial;}

}

Ce qui suit est en \f1 \cf1 \i Arial Rouge Italique \f0 \cf0 \i0

} »
Cela donne:

Nb : Si vous voulez copier coller l'exemple pour l'essayer, enlever les sauts à la ligne.

Comment modifier l'aspect du texte qui a été sélectionné ?

On n'est plus dans le cas ou on affiche d'emblée la totalité du texte, mais dans le cas ou l'utilisateur veut modifier son texte qui est déjà dans le contrôle.

Exemple: L'utilisateur sélectionne une portion du texte dans le contrôle puis clique sur une bouton nommé 'Rouge' pour mettre la sélection en rouge.

Dans BoutonRouge_Click() écrire :

RichTextBox1.SelectionColor = System.Drawing.Color.Red
De même pour modifier la police, la hauteur de la police, l'aspect gras ou non :

RichTextBox1.SelectionFont = New Font("Tahoma", 12, FontStyle.Bold)

Enfin le texte peut être enregistré dans un fichier :

richTextBox1.SaveFile(FileName, RichTextBoxStreamType.RichText)
Si on remplace .RichText par .PlainText c'est le texte brut et non le texte enrichi qui est enregistré

Pour lire un fichier il faut employer .LoadFile avec la même syntaxe.

Comment faire une recherche dans le texte?

La fonction Find permet de rechercher une chaîne de caractères dans le texte :

richTextBox1.Find(searchText, searchStart, searchEnd, RichTextBoxFinds.MatchCase)

La méthode retourne l'emplacement d'index du premier caractère du texte recherché et met en surbrillance ce dernier ; sinon, elle retourne la valeur -1.


Il peut y avoir des liens hypertexte et on peut interdire la modification enfin il y a les méthodes Undo et Redo sur les dernières modifications. Comme pour les textbox il y a une collection Lines() qui contient chacune des lignes.

Si MaxLength=0 , la limite du texte est de 64k caractères.

Comment Imprimer ce que contient la RichTextBox?

Rien de simple...

Microsoft fourni le code d'un contrôle nommé ExtendedRichTextBox qui hérite de RichTextBox mais qui contient en plus une méthode Print.

Dur, dur pour le trouver sur le net!!

Il est sur le site CodeSource:

Exemple en anglais du code d'un traitement de texte (Word processor) utilisant un ExtendedRichTextBox qui permet l'impression.

Le code en VB du contrôle ExtendedRichTextBox est dans l'exemple.

Le Solution RichTextEditor contient le code du contrôle ExtendedRichTextBox et le code de l'application RichTextEditor qui utilise le contrôle.

Il faut charger le projet RichTextEditor , le générer (pour que le contrôle soit 'compilé' ), fermer puis rouvrir le projet.


VII-E-3. Le contrôle MaskedTextBox (VB Framework 2):

Permettant d'utiliser un masque pour la saisie de caractères. Le masque indique quels caractères interdire ou permettre.

La propriété Mask permet d'indiquer le masque de saisie.

On peut la modifier en mode 'Design' à partir de la fenêtre 'Propriétés' :

On voit bien dans la fenêtre ci dessus: le masque '00:00' permet de saisir 2 groupes de 2 chiffres. L'utilisateur ne voit que ce qu'il y a dans l'aperçu '__:__' et est obligé de taper 2 chiffres puis 2 chiffres.

On peut utiliser des masques de la liste (Heure, date, code postal..) ou créer un masque personnalisé.

On peut aussi modifier le masque par code:

maskedTextBox1.Mask = "LL"

Pour le masque personnalisé on utilise:

0 Chiffre requis (lettres refusés) 
9 Chiffre ou espace optionnel. (lettres refusés) 
# Chiffre ou espace optionnel. (+) (-) sont permis. 
L Lettre requise. (chiffres refusés) 
? Lettre requise optionnelle. (chiffres refusés) 
& Caractère requis.(Chiffres et lettres permises)   
C Caractère, requis optionnel.(Chiffres et lettres permises %*& permis)  
A Alphanumérique requis opt.(Chiffres et lettres permises %*& refusés)  
. Point Decimal; celui de la culture. 
, Séparateur de millier; celui de la culture. 
: Séparateur de temps; celui de la culture. 
/ Séparateur de date; celui de la culture. 
$ Symbole monétaire; celui de la culture. 
< Convertir les caractères qui suivent en minuscule.  
>  Convertir les caractères qui suivent en majuscule. 
| Stop la conversion minuscule ou majuscule. 
\ Escape. Le caractère qui suit devient un littéral.“\\” affichera '\'. 
Autres caractères Littéraux. Affichés tels quels  
Exemple:

"00/00/0000" permet de saisir une date.

"LLL" permet de saisir trois lettres (pas des chiffres)

/ $ , : sont dépendant de la culture en cours:

Si le Mask="0$" il apparaîtra "_€" en culture française.

On peut modifier cela par FormatProvider property.

MaskCompleted indique si la saisie est conforme.

Dim returnValue As Boolean
returnValue = maskedTextBox1.MaskCompleted
 
MaskedTextBox1.text permet de lire le contenu du texte.

L'évènement le plus souvent utilisé est TextChanged

Private Sub MaTextBox_TextChanged(sender As Object, _ 
  e As EventArgs) Handles MaTextBox.TextChanged
End Sub 

VII-F. Les 'Labels'

Ceci est un Label Rouge!!

Il y a 2 sortes de Label:

Les 'Label'

Les 'LinkLabel'


VII-F-1. Les labels.

On en a déjà utilisé pour afficher du texte non modifiable par l'utilisateur (ce n'est donc pas une zone de saisie pour l'utilisateur du logiciel).

Les contrôles Label sont généralement utilisés pour fournir un texte descriptif à un contrôle. Vous pouvez par exemple utiliser un contrôle Label pour ajouter un texte descriptif à un contrôle TextBox. Ceci a pour but d'informer l'utilisateur du type de donnée attendu dans le contrôle.


Exemple hyper simple: Comment indiquer à l'utilisateur qu'il faut saisir son nom?

Devant le TextBox permettant la saisie du nom, on ajoute un 'Label' qui affiche 'Donner votre nom:'.

Donner votre nom:

 
La légende qui s'affiche dans l'étiquette est contenue dans la propriété Text du label.

Après avoir déposé le 'Label' sur le formulaire, on peut modifier le texte affiché à partir de la fenêtre de propriétés, en passant par la propriété 'Text':

On peut aussi mettre la propriété ForeColor à Red pour que le texte du label soit en rouge.


Pour modifier le texte du label1 par du code:

Label1.Text="Donner votre Prénom"

La propriété Alignement vous permet de définir l'alignement du texte dans l'étiquette (centré, à droite, à gauche), BorderStyle permet de mettre une bordure (un tour) ou non..

Label1.Text="Label avec une bordure et un fond jaune"

Label1.BorderStyle=BorderStyle.FixedSingle

Label1.ForeColor=Color.Red

Label2.BackColor=Color.Yellow
donne:

Remarque: la plupart du temps les labels sont modifiés en mode design, directement dans la fenêtre des propriétés.

Il est également possible d'y afficher une image avec la propriété .Image

La propriété AutoSize autorise le label, si elle est égale à True,a se redimensionner pour afficher la totalité du texte.

Remarque sur la mise à jour de l'affichage:

La mise à jour de l'affichage du Label (comme les autres contrôles d'ailleurs) est effectuée en fin de Sub:

Si on écrit:

Dim i As Integer

For i = 0 To 100

    Label1.Text = i.ToString

Next i
La variable i prend les valeurs 1 à 100, mais à l'affichage rien ne se passe pendant la boucle, VB affiche uniquement 100 à la fin; si on désire voir les chiffres défiler avec affichage de 0 puis 1 puis 2... il faut rafraîchir l'affichage à chaque boucle avec la méthode Refresh():

Dim i As Integer

For i = 0 To 100

    Label1.Text = i.ToString: Label1.Refresh()

Next i
Une alternative est de mettre un Application.DoEvents() qui donne à Windows le temps de traiter les messages et de rafraîchir l'affichage.


VII-F-2. Les LinkLabel

Permettent de créer un lien sur un label


Text Indique le texte qui apparaît.

LinkArea défini la zone de texte qui agira comme un lien; dans la fenêtre de propriété taper 11 ;4 (on verra que c'est plus simple que de le faire par code)

Les 4 caractères à partir du 11ème seront le lien, ils seront soulignés. Ne pas oublier comme toujours que le premier caractère est le caractère 0.

L'événement LinkClicked est déclenché quand l'utilisateur clique sur le lien. Dans cette procédure on peut permettre le saut vers un site Internet par exemple ou toute autre action.

Exemple :

LinkLabel1.text= "Visitez le site LDF"

LinkLabel1.LinkArea = New System.Windows.Forms.LinkArea(11, 4)
‘Pourquoi faire simple !!

Cela affiche :

Si l'utilisateur clique sur le mot 'site', la procédure suivante est déclenchée :

Private Sub LinkLabel1.LinkClickedEnd Sub
Il est possible de modifier la couleur du lien pour indiquer qu'il a été utilisé:

Si VisitedLinkColor contient une couleur e.visited=True modifie la couleur.

(e est l'élément qui a envoyé l'évènement, j'en modifie la propriété Visited.)

On peut y inclure une action quelconque, en particulier un saut vers un site Web:

System.diagnostics.Process.Start(" http://plasserre.developpez.com/ ")

'correspond au code qui ouvre un browser Internet (Internet Explorer ou Netscape) et qui charge la page dont l'adresse est indiquée.

La collection Links permet d'afficher plusieurs liens dans un même texte, mais cela devient vite très compliqué.


VII-G. Les cases à cocher.

Il y a 2 sortes de case à cocher:

Les CheckBox.

Les RadioButton.

  • Les " cases à cocher " (CheckBox): Elles sont carrées, et indépendantes les unes des autres, si l'utilisateur coche une case , cela n'a pas d'influence sur les autres cases du formulaire, qu'elles soient regroupées dans un cadre pour faire plus joli ou non.
  • Les " boutons radio " (RadioButton): Ils sont ronds et font toujours partie d'un groupe (Ils sont dans une fenêtre ou dessinés dans un objet GroupBox ). Ce groupe est indispensable, car au sein d'un groupe de RadioButton, un seul bouton peut être coché à la fois : si l'utilisateur en coche un, les autres se décochent.
Il faut regrouper les radios boutons dans des 'GroupBox' par exemple pour rendre les groupes indépendants:

Ici si je clique sur le bouton 'OUI' à droite, cela décoche 'NON' mais n'a pas d'influence sur le cadre Format

La propriété Text, bien sur, permet d'afficher le libellé à coté du bouton, on peut aussi mettre une image avec la propriété Image. CheckAlign permet de mettre la case à cocher à droite ou à gauche du texte, TextAlign permet d'aligner le texte.

Exemple pour le bouton en haut à droite.

RadioButton3.Text="OUI"

RadioButton3.TextAlign= MiddleCenter 'Middle=hauteur, center = horizontale

RadioButton3.CheckAlign=MiddleRight

La propriété la plus intéressante de ces cases est celle qui nous permet de savoir si elle est cochée ou non et de modifier son état. Cette propriété s'appelle Checked. Sa valeur change de False à True si la case est cochée.

RadioButton.Checked=True 'Coche le bouton


If RadioButton.Checked=True  Then ' Teste si le bouton est coché. 

End If
La procédure RadioButton.CheckedChange() permet d'intercepter le changement d'état d'un bouton.

Voici la procédure:

Private Sub RadioButton1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioButton1.CheckedChanged

End Sub

Pour le CheckButton ThreeState=True permet de définir 3 états au lieu de 2 (coché, indéterminé=grisé, non coché)

CheckedState indique dans ce cas un des 3 états (Checked, Unchecked, Indeterminate) (alors que Checked n'en indique que deux.)


Appearance peut aussi donner une apparence de bouton à la case à cocher. Il est enfoncé ou pas en fonction de la valeur de Checked.

Ici les 2 boutons ont une Appearance=Button , celui du haut n'est pas coché, l'autre est coché (enfoncé).


VII-H. Les 'Listes'.

Il y a 6 sortes de contrôle affichant des listes:

Les ListBox.

Les CheckedListBox

Les Combos

Les ListView.

Les DomainUpDown et NumericUpDown

Les TreeView


VII-H-1. Les 'ListBox'

Le contrôle ListBox affiche une liste d'éléments (d'objets) dans laquelle l'utilisateur peut faire un ou plusieurs choix.

La liste contient "tarte", "poisson", "viande", "légumes", "sauces".

Ici l'élément "poisson" est sélectionné, la ligne correspondante est en bleu.


La listBox contient une collection d'"Item":

Elle est vide au départ.

Si j'ajoute un élément à la ListBox, cela ajoute un élément à la collection Items

ListBox1.Items est une collection contenant tous les éléments (les objets) chargés dans la liste.

La propriété Items.Count indique le nombre d'éléments contenus dans la liste . Attention le premier élément est toujours l'élément 0, aussi le nombre d'éléments est égal au numéro de l'élément le plus haut plus un.


VII-H-1-a. Pour ajouter ou supprimer des éléments dans un contrôle ListBox:

Utilisez la méthode Items.Add, Items.Insert, Items.Clear ou Items.Remove. En mode conception, vous pouvez également utiliser la propriété Items.


Exemples :


VII-H-1-b. Vider la ListBox:

ListBox1.Items.Clear()


VII-H-1-c. Ajouter l'élément "poisson"

ListBox1.Items.Add("poisson")

Ajouter '4'

ListBox1.Items.Add(4.Tostring)

ou

ListBox1.Items.Add(4) 'accepté car les items sont des objets.

Insérer 'lulu en 4éme position

ListBox1.Items.Insert(4, "lulu")

Les listBox acceptent des objets, elles affichent généralement ce qu'il y a dans la propriété 'Text' de l'objet.


VII-H-1-d. Charger dans une ListBox1 les nombres de 1 à 100 :


For i = 1 To 100

    ListBox1.Items.Add(i.ToString)

Next i

VII-H-1-e. Comment enlever des éléments?


' Enlever l'élément d'index 5:
ListBox1.Items.RemoveAt(5)
 

' Enlever l'élément sélectionné:
ListBox1.Items.Remove(ListBox1.SelectedItem)
 

' Enlever l'élément "Tokyo":
ListBox1.Items.Remove("Tokyo")
 

VII-H-1-f. Comment lire l'élément 3?


Dim t As String

t=ListBox1.Items(3).ToString
(En Option=Strict il est nécessaire de transformer l'objet Items(3) en String avec .ToString)


VII-H-1-g. Comment rechercher l'élément qui contient une chaîne de caractères?


Dim x As Integer

x=List1.FindString("pa")   retourne le numéro du premier élément commençant par 'pa'.

x=List1.FindString("pa",12)   retourne le numéro de l'élément commençant par 'pa' en cherchant à partir de l'élément numéro 12.

x=List1.FindStringExact("papier")    'permet de rechercher l'élément correspondant exactement à la chaîne. 

VII-H-1-h. Comment sélectionner un élément par code?


ListBox1.SetSelected(x, True) 'la ligne contenant x devient bleue

VII-H-1-i. L'utilisateur double-clique sur un des éléments, comment récupérer son numéro ?

Grâce à SelectedIndex.

Private Sub ListBox_DoubleClick.

    N=ListBox1.SelectedIndex

End If 
‘N contient le numéro de l'élément sélectionné. Attention comme d'habitude, si je sélectionne la troisième ligne c'est en faite l'élément numéro 2.

SelectedIndex retourne donc un entier correspondant à l'élément sélectionné dans la zone de liste. Si aucun élément n'est sélectionné, la valeur de la propriété SelectedIndex est égale à -1.

La propriété SelectedItem retourne l'élément sélectionné ("poisson" dans l'exemple si dessus).


VII-H-1-j. Et la multi sélection, quels éléments ont été sélectionnés?

La propriété SelectionMode indique le nombre d'éléments pouvant être sélectionnés en même temps.

Lorsque plusieurs éléments sont sélectionnés, la valeur de la propriété SelectedIndex correspond au rang du premier élément sélectionné dans la liste. Les collections SelectedItems et SelectedIndices contiennent les éléments et les numéros d'index sélectionnées.

info Si la propriété Sorted = True, la liste est triée automatiquement.

VII-H-1-k. On peut 'charger' une ListBox automatiquement avec un tableau en utilisant Datasource:


Dim LaList() As String = {"one", "two", "three"}
ListBox1.DataSource = LaList
On peut aussi utiliser AddRange:

Dim Ite(9) As System.Object
Dim i As Integer
For i = 0 To 9
Ite(i) = "Item" & i
Next i
 

ListBox1.Items.AddRange(Ite)

VII-H-1-l. Comment 'charger' une ListBox automatiquement à partir d'un fichier texte.


ListBox1.Items.AddRange(System.IO.File.ReadAllLines("c:\list.txt"))
(le fichier list.txt est un fichier .txt crée avec NotePad par exemple et contenant les items séparés par des retours à la ligne"

Exemple de fichier:

"philippe

paul

jean

luc"


VII-H-1-m. Comment connaître l'index de l'élément que l'on vient d'ajouter? (et le sélectionner)


Dim x As Integer
x = List1.Items.Add("Hello")
List1.SelectedIndex = x
 
On utilise la valeur retournée (x dans notre exemple) par la méthode Add.

(NewIndex n'existe plus en VB.NET)


VII-H-1-n. Comment affecter à chaque élément de la liste un numéro, une clé?

Exemple : Dans un programme, chaque utilisateur a un nom et un numéro; je charge dans une ListBox la liste du nom des utilisateurs; quand on clique sur la liste, je veux récupérer le numéro de l'utilisateur (pas l'index de l'élément).

Comment donc, à chaque élément de la Listbox, associer un numéro (différent de l'index).

- En VB6 on utilisait une propriété (ListBox.ItemData()) pour lier à chaque élément de la ListBox un nombre (une clé); cela n'existe plus en VB.Net!!

Il existe des fonctions de compatibilité VB6, mais il faut éviter de les utiliser:

VB6.SetItemData(ListBox1, 0, 123) 'pour lier à l'élément 0 la valeur 123.

- Une alternative, pas très élégante:

Ajouter l'élément "toto"+chr$(9)+chr$(9)+ clé (clé n'est pas visible car les caractères de tabulation l'ont affichée hors de la Listbox)

Quand l'utilisateur clique sur la ligne, on récupère la partie droite donc la clé.

On peut aussi utiliser un Listview avec 2 colonnes; la seconde colonne servant à stocker le numéro.

- Une solution plus élégante:

On utilise le Tag du ListBox (Le Tag est une propriété qui peut contenir un objet (un tableau par exemple; chaque élément de ce tableau va contenir le numéro de l'utilisateur.)

Dim pos As Integer

ReDim ListBox1.Tag(100)  'Création du tableau dans le Tag

 

pos = ListBox1.Items.Add("Utilisateur1") 'On ajoute le nom de l'utilisateur1, pos est l'index de l'élément ajouté

ListBox1.Tag(pos) = 1  'On ajoute dans le Tag  le numéro de l'utilisateur

pos = ListBox1.Items.Add("Utilisateur2")

ListBox1.Tag(pos) = 2

pos = ListBox1.Items.Add("Utilisateur3")

ListBox1.Tag(pos) = 3

 

'Quand l'utilisateur double-clique dans la liste, on récupère le numéro correspondant

Private Sub ListBox1_DoubleClick()

    MsgBox(ListBox1.Tag(ListBox1.SelectedIndex))

End Sub
La contrainte est qu'il faut connaître le nombre maximum d'élément à charger et charger la liste dans l'ordre; il faut être en Option Strict=Off (sinon il y a liaison tardive).

Quand on charge une ListBox directement avec une base de données, il y a une solution pour gérer une clé.

Remarque:

Lorsque la propriété MultiColumn a la valeur true, la liste s'affiche avec une barre de défilement horizontale. Lorsque la propriété ScrollAlwaysVisible a la valeur true, la barre de défilement s'affiche, quel que soit le nombre d'éléments.


VII-H-1-o. Comment à partir des coordonnées de la souris connaître l'élément de la liste qui est survolé?

Exemple: La souris survole ListBox2 , on a e.X et e.Y, coordonnées de l'écran, comment obtenir l'index.

On va d'abord transformer e.X et e.Y en coordonnées client (par rapport à la listBox)

ListBox2.PointToClient(New Point(e.X, e.Y)

Puis ListBox2.IndexFromPoint() va retourner l'index survolé.

Private Sub ListBox2_DragOver(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListBox2.DragOver

IndexdInsertion = ListBox2.IndexFromPoint(ListBox2.PointToClient(New Point(e.X, e.Y)))

End Sub

VII-H-2. Les CheckedListBox

C'est une Listbox mais avec une case à cocher sur chaque ligne.

Attention : SelectedItems et SelectedIndices ne déterminent pas les éléments qui sont cochés, mais ceux qui sont en surbrillance.

La collection CheckedItems vous donne par contre les éléments cochés. La méthode GetItemChecked (avec comme argument le numéro d'index) détermine si l'élément est coché.

Exemple :

Pour déterminer les éléments cochés dans un contrôle CheckedListBox :

Tester chaque élément de la collection CheckedItems, en commençant par 0. Notez que cette méthode fournit le numéro que porte l'élément dans la liste des éléments cochés, et non dans la liste globale. Par conséquent, si le premier élément de la liste n'est pas coché alors que le deuxième l'est, le code ci-dessous affiche une chaîne du type « Item coché 1 = Dans la liste : 2 ».

If CheckedListBox1.CheckedItems.Count <> 0 Then
   'S'il y a des éléments cochés une boucle balaye les éléments cochés 
   '(collection CheckedItems) et affiche le numéro de l'élément DANS LA LISTE toutes lignes.
   Dim x As Integer
   Dim s As String = ""
   For x = 0 To CheckedListBox1.CheckedItems.Count - 1
      s = s & "Item coché " & (x+1).ToString & " = " & « Dans la liste : »& CheckedListBox1.CheckedItems(x).ToString & ControlChars.CrLf
   Next x
   MessageBox.Show(s)
End If
On rappelle comme toujours que quand on parle du 3eme élément cela correspond à l'index 2.


VII-H-3. Les ComboBox

Les listes Combo (Liste combinée) possèdent deux caractéristiques essentielles par rapport aux ListBox.

Elles sont modifiables : c'est-à-dire que l'utilisateur a la possibilité d'entrer un élément qui ne figure pas au départ dans la liste. Cette caractéristique concerne donc les données proprement dites ; cela se traduit par la présence d'une zone de texte en haut de la liste.

Elles peuvent être déroulantes ou déjà déroulée: c'est-à-dire qu'on ne voit qu'un seul élément de la liste à la fois, et qu'il faut cliquer sur la flèche du côté pour " déplier " la liste, ou bien que la liste est déjà visible. C'est la propriété DropDownList qui gère cela.

La combos du bas a sa DropDownList=Simple

L'utilisateur peut donc cliquer dans la liste (ce qui met le texte cliqué dans la zone texte), ou taper un nouveau texte.

Items.Add (méthode) ajoute un élément à une liste.
Items.Clear (méthode) efface tous les éléments d'une liste
Items.Count (propriété) renvoie le nombre d'éléments d'une liste
Multiselect (propriété) permet la sélection multiple
Item.Remove (méthode) supprime un élément de la liste
Sorted (propriété) trie les éléments d'une liste

Comment récupérer la zone texte quand elle change ?

Elle est dans la propriété Text.

On utilise l'évènement TextChanged qui se déclenche quand le texte est modifié.

Private Sub ComboBox1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ComboBox1.TextChanged

        Label1.Text = ComboBox1.Text

End Sub

VII-H-4. Le Contrôle ListView :

De plus en plus puissant, le contrôle ListView permet d'afficher des listes multi colonnes, ou des listes avec icône ou case à cocher.


VII-H-4-a. A- Liste avec sous éléments.

Ajouter un ListView nommé ListBox.

En mode conception :

La propriété View permet de déterminer l'aspect général du contrôle, elle peut prendre les valeurs :

Details permet une liste avec sous éléments et titre de colonnes.

Liste utilise un ascenseur horizontal.

LargeIcon

SmallIcone

Par programmation cela donne :

ListBox.View= View.Details

Utilisons le mode détails (Appelé mode Rapport)

Exemple : Faire un tableau de 3 colonnes, mettre les nombres de 1 à 100 dans la première, leur carré dans la seconde, leur cube dans la troisième.

1-Comment remplir les en-têtes de colonnes?

En mode conception, dans la fenêtre propriété du ListView, il y a une propriété Columns, le fait de cliquer sur le bouton d'expansion (…) ouvre une fenêtre, cliquer sur ‘Ajouter' permet d'ajouter une colonne ; la propriété Text permet de donner un libellé qui apparaîtra en haut de la colonne. On peut ainsi nommer les 3 colonnes (« Nombre », « Carré », « Cube » dans notre exemple)

Par programmation on peut aussi créer des colonnes; cela donne:

ListBox.Columns.Add ("Nombre", 60, HorizontalAlignment.Left)

ListBox.Columns.Add ("Carré", 60, HorizontalAlignment.Left)

ListBox.Columns.Add ("Cube", 60, HorizontalAlignment.Left)
Une autre manière est de créer une colonne et de l'ajouter:

 Dim MyCol1 As ColumnHeader = New ColumnHeader 

 MyCol1.Text = "Nombre"

 MyCol1.Width = 60

 MyCol1.TextAlign = HorizontalAlignment.Center

 ListBox.Columns.Add(MyCol1)
Si on créer 3 columns (MyCol1 , MyCol2, MyCol3), on peut les ajouter en une fois avec AddRange.

 Dim cols() As ColumnHeader = {MyCol1, MyCol2, MyCol3}

 ListBox.Columns.AddRange(cols)

 
2-Comment remplir le tableau?

Pour remplir le tableau, on pourrait, sur la ligne Items de la fenêtre des propriétés, cliquer sur … et rentrer les valeurs ‘à la main'. On le fait le plus souvent par programmation:

Pour chaque ligne il faut créer un objet ListViewItem:

sa propriété Text contient le texte de la première cellule

j'ajoute à cet objet des SubItems qui correspondent aux cellules suivantes.

Enfin j'ajoute le ListViewItem au contrôle ListView.

Dim i As Integer

For i = 1 To 100

    Dim LVI As New ListViewItem

    LVI.Text = i.ToString                  'première cellule

    LVI.SubItems.Add((i * i).ToString)     'seconde cellule

    LVI.SubItems.Add((i * i * i).ToString) 'troisième cellule

    ListBox.Items.Add(LVI)                 'ajout de la ligne

 Next i
Autre manière: ajouter la ligne ' 2 4 8'

Dim MyLine As ListViewItem = New ListViewItem("2") 

Dim subLine As ListViewItem.ListViewSubItem = New ListViewItem.ListViewSubItem(MyLine, "4")

 MyLine.SubItems.Add(subLine) 

 subLine = New ListViewItem.ListViewSubItem(MyLine, "8")

 MyLine.SubItems.Add(subLine) 

 MyLine.SubItems.Add(subLine) 

 ListBox.Items.Add(MyLine)
3-Comment relire une cellule, récrire dans une cellule?

Voyons d'abord comment on peut localiser une cellule:

ListBox.Items(0).Subitems(0).text ListBox.Items(0).Subitems(1).text ListBox.Items(0).Subitems(2).text
ListBox.Items(1).Subitems(0).text ListBox.Items(1).Subitems(1).text ListBox.Items(1).Subitems(2).text
... ... ...
Les lignes sont contenues dans la collection Items.

La première ligne est ListBox.Items(0), la seconde ligne: ListBox.Items(1)...

Les cellules sont contenues dans la collection Items().SubItems.

La première cellule est ListBox.Items(0).SubItems(0) ou ListBox.Items(0).Text , la seconde ListBox.Items(0).SubItems(1).

Pour lire le texte de la seconde ligne seconde colonne:

Texte=ListBox.Items(1).SubItems(1).

Pour écrire dans une cellule:

listBox.Items(1).SubItems(1).Text = "88"

Comment intercepter le numéro de la ligne qui a été cliquée par l'utilisateur (et l'afficher)?

Private Sub Listview1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Listview1.Click

        Label1.Text = Listview1.SelectedIndices(0).ToString

End Sub
Si la propriété MultiSelect est à False il y a, bien sur, une seule ligne sélectionnée, sinon les lignes sélectionnées sont dans la collection SelectedIndices().

Si on veut récupérer le texte de la ligne sélectionnée, il faut utiliser :

ListBox.SelectedItems(0)
Si la propriété GridLine est à True, des lignes matérialisant les cases apparaissent.

Si la propriété CheckedBox est à True , des cases à cocher apparaissent.

listBox.LabelEdit = True autorise la modification d'une cellule de la première colonne (pour modifier, il faut cliquer une fois (sélection) puis une seconde fois (modification). Pour le colonnes suivantes, il n'y a pas d'édit.

Attention : si la somme des colonnes est plus large que le contrôle, un ascenseur horizontal apparaît !!

Pour ne pas voir cet ascenseur, ruser sur la largeur des colonnes (c'est le 2eme paramètre de la méthode .Columns.Add)

Afficher des images dans les SubItems en VB 2005: voir annexe en bas de page


VII-H-4-b. B- Liste d'icônes.

Permet de faire un menu d'icône à gauche d'un formulaire, du plus bel effet:

La propriété View permet de déterminer l'aspect général du contrôle, ici on la met à la valeur LargeIcon.

Voyons certaines propriétés du Listview (nommé menu_graphique):

Dock= Left    'cela le 'colle' sur le rebord gauche. 

MultiSelected= False    'on n'utilise qu'un bouton à la fois.

Activation= OnClick     'les icônes marchent comme des boutons   

LabelEdit= False        'impossible de modifier le texte sous les icônes

LargeIconeList= NOMdeIMAGELIST 
'En effet, il faut créer un contrôle ImageList y mettre les images du menu et indiquer au Listview le nom de l'ImageList dans la propriété LargeIconeList.

Dans la collection Items du Listview (fenêtre des propriétés), dans chaque élément, ImageIndex donne le numéro de l'image du imageList à mettre dans l'élément (ainsi que le texte qui est sous l'image).

Quand l'utilisateur clique sur une image, la procédure suivante se déclenche:

Private Sub menu_graphique_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles menu_graphique.Click

 

Select Case menu_graphique.SelectedItems(0).Text

    Case "Rendez-vous"

    ...

    Case "Quitter"

        Application.Exit()

End Select

End Sub
On voit que menu_graphique.SelectedItems(0).Text permet de savoir sur quel bouton l'utilisateur à cliqué et ainsi d'appeler la procédure correspondant au choix de l'utilisateur.


VII-H-5. Le Contrôle DomainUpDown :

Le contrôle DomainUpDown permet d'afficher une liste occupant peu de place: on ne voit qu'une ligne, on se déplace avec les boutons up et down:

On charge la liste avec:

MondomainUpDown.Items.Add("une ligne")

Quand l'utilisateur change de ligne cela déclenche SelectedItemChanged. Le texte sélectionné est dans SelectedItem.

La sub suivante affiche dans une messageBox l'index et le texte sélectionné.

Private Sub MondomainUpDown1_SelectedItemChanged _ (sender As System.Object, e As System.EventArgs)

MessageBox.Show(("Index sélectionné: " & MondomainUpDown1.SelectedIndex.ToString() & 
			_ ControlChars.Cr & "Item sélectionné: " & MondomainUpDown1.SelectedItem.ToString())) 

End Sub 
Attention la liste contient des objets, il peut être nécessaire lorsqu'on utilise un des items de caster l'objet en string grace à ToString.

Il existe aussi un contrôle NumericUpDown.


VII-H-6. Le Contrôle TreeView :

Le contrôle TreeView permet d'afficher des listes 'arborescentes' avec des noeuds.

Un arbre (Tree) est composé de noeuds (nodes) qui sont des objets.

Chaque noeud est composé d'une Image et d'un Text.

Les noeuds du premier niveau sont dans la collection Nodes du TreeView, ils sont repérés par un index unique.

MyTree.Nodes(0) est le premier noeud.

Avec l'image ci dessus:

MyTree.Nodes(0).Text = "Paul" 'collection dont le premier élément est zéro

MyTree.Nodes(1).Text = "Luc" 'c'est bien le second élément du premier niveau

MyTree.Nodes(2).Text retourne une erreur: la collection ne comporte que les noeuds du premier niveau.

Chaque noeud à un Parent (au dessus), des noeuds enfants (au dessous)

MyTree.Nodes(10).Children 'retourne le nombre d'enfant
Pour voir les enfants il y a plusieurs méthodes:

MyTree.Nodes(0).Nodes(0).Text = "Odile" ' on utilise la collection Nodes du noeud Nodes(0)	
MyTree.Nodes(0).FirstNode.Text = "Odile" ' on utilise FirstNode qui donne le premier enfant.
Il existe aussi LastNode.

NextNode, PrevNode Parent permettent, par rapport à un noeud (sur une instance de noeud et pas sur nodes()), de voir respectivement le noeud suivant, le précédent au même niveau ou le noeud parent.

MyTree.Nodes(0).FirstNode.NextNode permet dans les enfants de Nodes(0), de voir celui qui est après le premier.

On peut modifier l'image:

MyTree.Nodes(7).Image = "closed" 
 
Nombre de noeuds:

MyTree.GetNodeCount(True) donne le nombre de noeuds (noeuds enfants compris car l'argument est True).
MyTree.GetNodeCount(False) donne les noeuds de premier niveau
Pour ajouter des noeuds en mode Desig, utiliser la propriété Nodes dans la fenêtre de propriété. Cela donne accès à une fenêtre qui permet de rajouter des noeuds au même niveau ou des noeuds enfants.

On peut aussi ajouter un noeud par code (au niveau de 'Paul' et 'Luc')

A partir d'un noeud, on travaille sur la collection nodes et la méthode Add de cette collection.

MyTree.Nodes.Add("Lucienne")
On peut ajouter un noeud sous le noeud sélectionné.

MyTree.SelectedNode.Nodes.Add("toto")
ou en développant:

Dim node As System.Windows.Forms.TreeNode
node = MyTree.SelectedNode
node.Nodes.Add("Nouveau noeud sous la sélection")
 
On peut enlever un noeud:

MyTree.Nodes.RemoveAt(0)
Un noeud peut être expanded or collaped on peut modifier l'état de l'arbre par CollapsedAll ou ExpandedAll , on peut travailler sur les noeuds visibles, voir ou non les '+' et les '-' grâce à la propriété ShowPlusMinus.

Le noeud sélectionné par l'utilisateur est dans SelectedNode

Dim node As System.Windows.Forms.TreeNode
node = MyTree.SelectedNode
MyTree.SelectedNode.Text retourne 'Tree Node: Paul' si on a cliqué sur le premier noeud.

Quand on est perdu FullPath donne le chemin du noeud.

Comment savoir si l'utilisateur à sélectionné un noeud, ou double cliqué sur un noeud?

On utilise les procédures évènements suivantes:

Private Sub MyTreeAfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles MyTree.AfterSelect

End Sub

Private Sub MyTreeDoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyTree.DoubleClick

TextBox1.Text = TreeView1.SelectedNode.ToString

End Sub
Exemple complet: sur MyTree, rentrer les clients et leurs commandes .

(Exemple librement inspiré de Microsoft)

Dim node As TreeNode
node = MyTree.Nodes.Add("Noeud de niveau 1")
node.Nodes.Add("noeud de niveau 2")
 

' Créer une ArrayList pour Customer objects.
Private MyClientArray As New ArrayList()

Private Sub FillMyTreeView()
   ' On ajoute des éléments à l'ArrayList.
   Dim x As Integer
   For x = 0 To 999
      MyClientArray.Add(New MyClient("MyClient" + x.ToString()))
   Next x

   ' On ajoute des commandes (order) pour chaque client dans ArrayList.
   Dim MyClient1 As MyClient
   For Each MyClient1 In MyClientArray
      Dim y As Integer
      For y = 0 To 14
         MyClient1.MyClientOrders.Add(New Order("Order" + y.ToString()))
      Next y
   Next MyClient1

   ' on met d'un curseur d'attente.
   Cursor.Current = New Cursor("MyWait.cur")

   ' on gèle la mise à jour du contrôle.
   MyTree.BeginUpdate()

   ' on efface le précédent contenu.
   MyTree.Nodes.Clear()

   ' On ajoute des root TreeNode pour chaque MyClient object.
   Dim MyClient2 As MyClient
   For Each MyClient2 In MyClientArray
      MyTree.Nodes.Add(New TreeNode(MyClient2.MyClientName))

      ' on ajoute des TreeNode enfant pour chaque commande (Order) object .
      Dim order1 As Order
      For Each order1 In MyClient2.MyClientOrders
         MyTree.Nodes(MyClientArray.IndexOf(MyClient2)).Nodes.Add( _
    New TreeNode(MyClient2.MyClientName + "." + order1.OrderID))
      Next order1
   Next MyClient2

   ' On permet la mise à jour.
   MyTree.EndUpdate()

   ' On remet le curseur normal.
   Cursor.Current = System.Windows.Forms.Cursors.Default

End Sub 

VII-H-7. Annexe: Afficher des images dans un ListView

Débutant s'abstenir.

De plus en plus puissant: on a vu que dans le mode 'détails' d'un ListView, on avait des colonnes de SubItems. Comment afficher des images dans ces cellules?

Il faut mettre la propriété du ListView OwnerDraw à True, cela permet au programmeur d'utiliser la Sub DrawSubItem qui se déclenche quand le subitem doit être dessiné et de dessiner soi même dans la cellule en utilisant l'argument e qui correspond au bitmap de la cellule.

Dans cette sub DrawSubItem, par exemple, au lieu d'afficher un + dans la première colonne , j'affiche une image (avec e.Graphics.DrawImage). Si par contre je veux laisser s'afficher le texte normal, je dois écrire e.DrawDefault = True.

Private Sub ListView1_DrawSubItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawListViewSubItemEventArgs) Handles ListView1.DrawSubItem

If e.ColumnIndex = 1 Then

If e.SubItem.Text = "+" Then

    e.Graphics.DrawImage(Image.FromFile("c:\b.bmp"), New Point(e.Bounds.X, e.Bounds.Y))

Else

    e.DrawDefault = True

End If

else

e.DrawDefault = True

end if

End Sub
Ne pas oublier d'afficher normalement les têtes de colonnes.

Private Sub ListView1_DrawColumnHeader(ByVal sender As Object, ByVal e 
	_As System.Windows.Forms.DrawListViewColumnHeaderEventArgs) Handles ListView1.DrawColumnHeader

e.DrawDefault = True

End Sub

VII-I. Boites toutes faites (MessageBox..).

Il existe :

Les MessageBox et MsgBox.

Les InputBox

et les autres

...

Ces fenêtres toutes faites facilitent le travail :


VII-I-1. MessageBox du Framework 2 (VB 2005):

Ouvre une fenêtre qui présente un message.

C'est une fonction qui affiche un message dans une boîte de dialogue, attend que l'utilisateur clique sur un bouton (Ok ou Oui-Non..), puis retourne si on le désire, une information qui indique le bouton cliqué par l'utilisateur.

On utilise la méthode Show pour afficher la boite.

On doit fournir le texte à afficher, on peut aussi fournir le titre dans la barre, le type de bouton , le type d'icône et le bouton par défaut, une option , la présence d'un bouton d'aide.

Syntaxe:

MessageBox.show(TexteAAfficher) ' Affiche une box avec le message et un bouton 'Ok', pas de valeur de retour.
Reponse= MessageBox.show(TexteAAfficher,Titre, TypeBouton , Icone, BoutonParDéfaut, Option, Bouton d'aide)

Le bouton cliqué par l'utilisateur est retourné dans Reponse (de type DialogResult).

Exemple:

Paramètres

TexteAAfficher

Obligatoire. Expression String affichée comme message de la boîte de dialogue (longueur maximale 1 024 caractères). N'oubliez pas d'insérer un retour chariot si le texte est long, cela crée 2 lignes.

Titre

Expression String affichée dans la barre de titre de la boîte de dialogue. Si l'argument Titre est omis, le nom de l'application est placé dans la barre de titre.


TypeBouton

Expression numérique qui représente la somme des valeurs spécifiant

-le nombre et le type de boutons à afficher :

MessageBoxButtons.OKOnly Un seul bouton ‘Ok'

MessageBoxButtons.YesNo Deux boutons ‘Oui' ‘Non'

MessageBoxButtons.OkCancel ‘Ok' et ‘Annuler'

MessageBoxButtons.AbortRetryIgnore ‘Annule' ‘Recommence' ‘Ignore'

Icons

-le style d'icône à utiliser

MessageBoxIcon.Error

MessageBoxIcon.Exclamation

...

L'identité du bouton par défaut

MessageBoxDefaultButton.Button1

MessageBoxDefaultButton.Button2

Les options

MessageBoxOptions.RightAlign


L'affiche d'un bouton d'aide

True pour l'afficher.

Comme d'habitude, il suffit de taper MessageBox.Show( pour que VB proposer les paramètres.

Retour de la fonction :

Retourne une constante de type DialogResult qui indique quel bouton à été pressé.

DialogResult.Yes

DialogResult.No

DialogResult.Cancel

DialogResult.Retry

DialogResult.Ok
Exemple 1:

Afficher un simple message:

 MessageBox.Show("bonjour")
Affiche

Exemple 2:

Afficher les boutons Oui Non et un bouton d'aide, une icône d'erreur, tester si l'utilisateur a cliqué sur Oui:

Dim r As DialogResult  (cela marche aussi avec Integer)

r = MessageBox.Show("bonjour", "Programme", MessageBoxButtons.YesNo, MessageBoxIcon.Error,
_ MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign, True) 

If r = Windows.Forms.DialogResult.Yes Then

..

End If
Affiche:

Ecriture plus compact:

If MessageBox.Show("bonjour", "Programme", MessageBoxButtons.YesNo) = Windows.Forms.DialogResult.Yes then 

.....

End If

VII-I-2. MsgBox du Visual Basic

L'ancienne syntaxe Visual Basic avec MsgBox est conservée :(A éviter? on l'utilise tous!!)

MessageBox.Show est VB.NET, MsgBox qui est de la compatibilité avec VB.

Reponse= MsgBox(TexteAAfficher, Style, Titre)
 
Dans ce cas il faut utiliser MsgBoxStyle et MsgBoxResult pour le retour. De plus les arguments ne sont pas dans le même ordre!!

-Pour le choix des boutons MsgBoxStyle peut prendre les valeurs:

YesNo (cela affiche 2 boutons "Oui" et "Non"), OkCancel, AbortRetryIgnore...

Pour le choix du bouton par défaut MsgBoxStyle peut prendre les valeurs:

DefaultButton1, DefaultButton2..

Pour les icônes MsgBoxStyle peut prendre les valeurs:

Il faut ajouter les styles les uns aux autres avec 'Or'.

Au retour au a les valeurs:

MsgBoxResult.Yes, MsgBoxResult.No, MsgBoxResult.Cancel...

Exemple simple fournissant un simple message à l'utilisateur:

MsgBox ("Bonjour") affiche une message box avec le message 'Bonjour', un bouton 'Ok' et dans la barre de titre, le nom de l'application. Il n'y a pas de valeur de retour.

Exemple courant posant une question, l'utilisateur doit cliquer sur 'oui' ou 'non', on teste si c'est 'oui':

If MsgBox("D'accord?", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then

End If
Exemple complet :

Dim msg As String

Dim title As String

Dim style As MsgBoxStyle

Dim response As MsgBoxResult

msg = "Voulez vous continuer?"               ' Définition du message à afficher.

style = MsgBoxStyle.DefaultButton2 Or _

   MsgBoxStyle.Critical Or MsgBoxStyle.YesNo 'On affiche Oui Non

title = "MsgBox Démonstration"               ' Définition du  titre.

' Affiche la boite MsgBox.

 

response = MsgBox(msg, style, title)

 

If response = MsgBoxResult.Yes Then   

   ' code si l'utilisateur a cliqué sur Oui

Else

   ' code si l'utilisateur a cliqué sur Non.

End If
Voila ce que cela donne:

‘On remarque que dans l'exemple, on crée des variables dans lesquelles on met le texte ou les constantes adéquates, avant d'appeler la fonction MsgBox. En condensé cela donne:

If MsgBox("Voulez vous continuer?", MsgBoxStyle.DefaultButton2 Or MsgBoxStyle.Critical Or MsgBoxStyle.YesNo, 
	_"MsgBox Démonstration")= MsgBoxResult.Yes Then  

End If

VII-I-3. InputBox

C'est une fonction qui permet d'ouvrir une fenêtre qui pose une question :

Elle retourne la réponse tapée par l'utilisateur.

Le retour est effectué dans une variable String.

Dim Nom As String

Nom = InputBox("Bonjour","Tapez votre nom ?")
Cela donne :

On pourrait rajouter un 3eme argument=la réponse par défaut.

Si l'utilisateur clique sur le bouton 'Annuler', une chaîne vide est retournée.

On a souvent besoin de contrôler si l'utilisateur à tapé quelque chose puis d'enlever les espaces:

Dim reponse As String 'on crée une variable qui contiendra la chaîne tapée par l'utilisateur.

Do

    reponse= InputBox("Tapez un nom") 'saisir une chaîne de caractères dans une InputBox

Loop Until String.IsNullOrEmpty(reponse)'si l'utilisateur n'a rien tapé, on boucle et on réaffiche l'inputbox

 

reponse=reponse.Trim(" ")    'enlève les espaces avant et après

VII-I-4. OpenFileDialog

Comment afficher une boite de dialogue permettant de sélectionner un fichier (ou des fichiers) à ouvrir par exemple ?

Dans la boite à Outils, cliquez sur OpenFileDialog puis cliquez sur la fenêtre en cours : un contrôle OpenFileDialog1 apparaît sous le fenêtre.

Ouvre une boite de dialogue permettant de choisir un nom et un chemin de fichier, au programmeur d'écrire le code lisant les fichiers.

Dans le code, à l'endroit ou doit s'ouvrir la fenêtre,(Dans l'évènement Click d'un bouton nommé 'Ouvrir' par exemple) tapez :

Private Sub ButtonOuvrir_Click()

    OpenFileDialog1.ShowDialog()

End Sub
C'est suffisant pour créer une fenêtre montrant l'arborescence des fichiers et répertoires et pour que l'utilisateur choisisse un fichier:

Mais le plus souvent on a besoin que la boite de dialogue propose un type de fichier et un répertoire précis.

Par exemple je veux ouvrir un fichier .TXT dans le répertoire c:\MesTextes

Il faut dans ce cas, AVANT le ShowDialog renseigner certaines propriétés du contrôle OpenFileDialog1 :

 With OpenFileDialog1

      .Title= "Ouvrir"        'Titre de la barre de titre

    .InitialDirectory = "c:\"   'répertoire de départ        

    .Filter="Fichiers txt|*.txt" ' on travaille uniquement sur les .txt

                              's'il y a plusieurs filtres les séparer par ;  

                                FilterIndex  indique le filtre en cours

    .Multiselect=False        'sélectionner 1 seul fichier

    .CheckFileExists=True     'Message  si nom de fichier qui n'existe pas.

                              'Permet d'ouvrir uniquement un fichier qui existe; CheckPathExists peut aussi être utilisé. 

      .ValidateNames=True        'n'accepte que les noms valides (win 32)

     .AddExtension=True        'ajoute une extension au nom s'il n'y en a pas

End With
Comment afficher la boite et vérifier si l'utilisateur à cliqué sur 'Ouvrir'?

La méthode .ShowDialog peut retourner un élément de l'énumération DialogResult pour indiquer l'action de l'utilisateur sur la boite de dialog:

DialogResult.Ok    'si l'utilisateur a cliqué sur 'Ouvrir'

DialogResult.Cancel   'si l'utilisateur a cliqué sur 'Annuler'
Comment utiliser cela?

If OpenFileDialog1.ShowDialog= DialogResult.Ok Then  'L'utilisateur a bien cliqué sur ok

End if  
Maintenant, OpenFileDialog1.FileName contient le nom du fichier sélectionné (avec extension et chemin)

Path.GetFileName(OpenFileDialog1.FileName) donne le nom du fichier sans chemin.

VII-I-5. SaveFileDialog

Boite de dialogue fonctionnant de la même manière que OpenFileDialog mais avec quelques propriétés spécifiques.

Ouvre une boite de dialogue permettant à l'utilisateur de choisir un nom et un chemin de fichier, au programmeur d'écrire le code enregistrant les fichiers.

SaveFileDialo1.CreatePrompt= True    ' Message de confirmation si

                                     'création d'un nouveau fichier

SaveFileDialo1.OverwritePrompt=True  'Message si le fichier existe déjà

                                     'évite l'effacement d'anciennes données

SaveFileDialo1.DefaultExt="txt"      'extension par défaut
On récupère aussi dans .FileName le nom du fichier si la propriété .ShowDialog à retourné DialogResult.Ok.


VII-J. Regroupement de contrôles 'Groupe de contrôles'.

On peut regrouper des contrôles dans :

Les GroupBox.

Les Panels.

Les PictureBox.

Les TabControl.

Les SplitContainer.(Framework 2 Vb2005)

Les LayoutPanel.(Framework 2 Vb2005)

Comment se passer des groupes de contrôles de VB6 qui n'existent plus en VB.Net?

Comment plusieurs contrôles peuvent-ils déclencher un même évènement?

Comment travailler sur plusieurs contrôles identiques?


VII-J-1. GroupBox et Panel

Il est possible de regrouper des contrôles dans un container, on peut par exemple regrouper plusieurs RadioButton. Le container peut être un GroupBox ou un Panel.

GroupBox Panel avec AutoScroll =True et BorderStyle=Single

Pour l'utilisateur, le fait que toutes les options soient regroupées dans un panneau est un indice visuel logique (Tous les RadioButton permettrons un choix dans une même catégorie de données). Au moment de la conception, tous les contrôles peuvent être déplacés facilement ; si vous déplacez le contrôle GroupBox ou Panel, tous les contrôles qu'il contient sont également déplacés. Les contrôles regroupés dans un panneau ou un GroupBox sont accessibles au moyen de la propriété Controls du panneau.

Le contrôle Panel est similaire au contrôle GroupBox ; mais, seul le contrôle Panel peut disposer de barres de défilement et seul le contrôle GroupBox peut afficher une légende.

La légende de la GroupBox est définie par la propriété Text.

Pour faire apparaître les barres de défilement dans le Pannel mettre AutoScroll =True et AutoScrollMinSize =100;100

Dans un Panel, pour afficher des barres de défilement, attribuez à la propriété AutoScroll la valeur true.. La propriété BorderStyle détermine si la zone est entourée d'une bordure invisible (None), d'une simple ligne (FixedSingle) ou d'une ligne ombrée (Fixed3D).

Comment créer un contrôle Panel ?

Faites glisser un contrôle Panel de l'onglet Windows Forms de la boîte à outils jusqu'à un formulaire.

Ajoutez des contrôles au panneau en les déposant dans le panneau.

Si vous voulez mettre dans le panneau des contrôles existants, sélectionnez-les tous, coupez-les dans le Presse-papiers, sélectionnez le contrôle Panel et collez-les.


VII-J-2. PictureBox

Le contrôle PictureBox peut afficher une image mais peut aussi servir de conteneur à d'autres contrôles.

Retenons la notion de conteneur qui est le contrôle parent.


VII-J-3. TabControl

Ce contrôle permet de créer des onglets comme dans un classeur, onglets entièrement gérés par VB. Chaque page peut contenir d'autres contrôles.

En mode conception, en passant par la propriété TabPages, on ajoute des onglets dont la propriété Text contient le texte à afficher en haut (Ici: Page 1..). il suffit ensuite de cliquer sur chaque onglet et d'y ajouter les contrôles.

En mode run les onglets fonctionnent automatiquement: cliquez sur Page 2 affiche la page correspondante (et déclenche l'événement Click de cet objet TabPage)..

La propriété Alignment permet de mettre les onglets en haut, en bas, à droite, à gauche.


VII-J-4. SplitContainer:

VB 2005 Framework 2.

Permettant de créer facilement une séparation déplaçable entre 2 zones.

On met le SplitContainer, dans les 2 zones on met par exemple 2 textbox. Il faut mettre la propriété Dock de ces 2 textbox à Fill.

En mode Run, cela marche : si je déplace la zone de séparation centrale, cela agrandit un textbox et diminue le second.

Margin indique la largeur de la séparation.

Orientation permet une séparation horizontale ou verticale.


VII-J-5. LayoutPanel

VB Framework 2.

Permettent de positionner les contrôles dans une Form en mode conception. On ne les voit pas en mode Run.

FlowLayoutPanel: Place les contrôles à droite du précédent, passe 'à la ligne' si nécessaire, c'est génial pour créer plusieurs lignes de label, TextBox, Bouton:

TableLayoutPanel:On crée un tableau de panel, puis on met les contrôles dans les cellules:


VII-J-6. Comment se passer des groupes de contrôles de VB6 qui n'existent plus en VB.Net?

En VB6 on pouvait créer un groupe de plusieurs contrôles identiques et les repérer par un Index.

Texte(0), Texte(1), Texte(2)..

Pour parcourir le groupe, on avait une boucle For Next sur l'index:

For i=1 To 10

Texte(i).text...

Next
de plus il n'y avait qu'une routine évènement pour l'ensemble du groupe.

Sub Texte_Click (Index)
Cela n'existe plus en VB.Net!!!!!

Comment donc utiliser un groupe de contrôle en VB.Net?


VII-J-7. 1 - Evènement commun.(Comment pallier à la disparition des groupes de contrôles?)

Exemple: 3 cases à cocher permettent de colorer un label en vert rouge ou bleu.

Comment gérer les évènements?

On peut écrire 3 routines complètes pour chaque case à cocher.

Il est aussi toujours possible dans chacune des 3 procédures CouleurX.checkedChanged de vérifier si la case est cochée et de modifier la couleur.

C'est plus élégant d'avoir une procédure unique qui, en fonction de la case à cocher qui a déclenché l'évènement, change la couleur.

On désire donc parfois que l'évènement de plusieurs contrôles différents soit dirigé sur une seule et même procédure.

Mais, la notion de groupe de contrôle comme en VB6 n'existe plus!!!

Par contre par l'intermédiaire du Handles, il est possible d'associer plusieurs évènements à une seule procédure:

Private Sub CouleurCheckedChanges (ByVal sender As System.Object, ByVal e As System.EventArgs) 

Handles CouleurVert.CheckedChanged, CouleurRouge.CheckedChanged, CouleurBleu.CheckedChanged

   

End Sub
Cette procédure est activée quand les cases à cocher CouleurVert CouleurBleu, CouleurRouge changent d'état.

A noter que Sender est le contrôle ayant déclenché l'évènement et e l'évènement correspondant.

Pour modifier la couleur il faut ajouter dans la procédure:

Select Case sender

    Case CouleurRouge

..
ou

Select Case True
   Case sender Is CouleurRouge
.
End Select
Enfin la ligne suivante marche !

If sender Is CouleurRouge Then...


VII-J-8. 2 - Comment travaillez sur plusieurs contrôles.(Comment pallier à la disparition des groupes de contrôles?)

Si j'ai une interface utilisateur avec 20 Textbox, comment modifier la couleur de fond des 20 Textbox?

(En VB6 on créait un groupe de contrôle, cela n'existe plus en VB.net!!)

Solution 1

TextBox1.BackColor= Color.Red

TextBox2.BackColor= Color.Red

TextBox3.BackColor= Color.Red

.....  !!!!!!Bof

 
Solution 2

Mettre les 20 TextBox dans un Panel (invisible); la collection Controls du Panel contient tous les contrôles contenus dans le panel, on utilise cette collection pour atteindre tous les textbox:

Dim i As Integer

For i=0 to Panel1.Controls.Count

    Panel1.Controls(i).BackColor=Color.Red

Next
ou

For Each TB As TextBox in Panel1.Controls

    TB.BackColor= Color.Red

Next
S'il n'y a pas que des TextBox dans le Panel et qu'on ne veut modifier que les TextBox:

For Each TB As Control in Panel1.Controls

    If TypeOf (TB)= TextBox then    

        TB.BackColor= Color.Red

    End if

Next
Solution 3

Mettre les 20 TextBox dans un tableau:

Dim Textes(8) As TextBox           
  
'puis dans le form_load
Textes(0) = TextBox0
Textes(1) = TextBox1
Textes(2) = TextBox2
... 
'ensuite, on peut bien utiliser la syntaxe de VB 6.0

Dim i As integer
For i = 0 To 19
 Dim MyTexte As Integer= Textes(i).Text
..
Next
Noter qu'on a créer un tableau de TexBox, si on utilise un tableau d'objet, il faut caster l'objet en textbox pour utiliser sa propriété text:

Dim Textes(8) As Object

Textes(1) = TextBox1

Textes(2) = TextBox2

Dim i As Integer

For i = 1 To 2

Dim MyTexte As String = CType(Textes(i), TextBox).Text

Next

VII-K. Dimensions, position des contrôles.

On peut dimensionner et positionner les contrôles et formulaires:

En mode conception.

Mais aussi avec du code.

Tous les contrôles héritent donc tous de la classe Windows Forms.

Les contrôles et formulaires ont tous des propriétés communes.


VII-K-1. Unité de mesure :

Pixel:

L'unité de mesure est le 'Pixel' (Picture Elément).(plus de twips)

Les coordonnées d'un contrôle se définissent à partir du coin supérieur gauche du conteneur (coin situé sous la barre de tache dans le cas du formulaire).

Noter qu'à partir du coin supérieur gauche, l'axe des X va de gauche à droite, l'axe des Y de haut en bas.

Le Point:

Pour définir une paire de coordonnées on utilise un objet Point ( ou System.Drawing.Point)contenant les coordonnées x et y du point:

Dim P As New Point(12,45)    'Ici 12 et 45 sont les coordonnées X et Y du point.
On peut utiliser P.x et P.y pour modifier une coordonnée.

La taille:

Pour définir la taille d'un contrôle on utilise un objet Size ( ou System.Drawing.Size)contenant 2 integers indiquant habituellement largeur et hauteur:

Dim S As New Size(12,45) .

VII-K-2. Position initiale dans l'écran d'un formulaire:

On peut définir la position initiale, sur l'écran, d'un formulaire grâce à la propriété 'StartPosition':

Le formulaire peut apparaître au centre de l'écran (CenterScreen)ou à des coordonnées précises.

De plus la propriété WindowState permet de définir la taille du formulaire: normal, plein écran (Maximized) ou réduit dans la barre de tache (Minimized).


VII-K-3. Taille et position d'un formulaire ou d'un contrôle:

On peut utiliser simplement:

Left, Top coordonnées du coin supérieur gauche et Bottom, Right inférieur droit.

Height, Width pour la hauteur et la largeur du contrôle en pixels.

On peut utiliser aussi:

Size : hauteur, largeur peuvent aussi être utilisées.

Location : coordonnées X,Y du coin supérieur droit du contrôle en pixels.

SetBounds : coordonnées X,Y , largeur, hauteur.

Exemple :

Button.left=188

Button.Top =300
Ou

Button.Location= New System.Drawing.Point(188,300)
Point() positionne un point dans l'espace.

On remarque qu'il faut donner à la propriété Location un objet Point et non les coordonnées brutes.(En effet, Form1.Location =100, 100 n'est pas accepté)

Form1.Location = New Point(100, 100) est équivalent à:

Form1.left=100: Form1.Top=100
Pour définir la taille:

Dim Me.Size= New Size(150,150)
On créer un objet Size que l'on affecte à la propriété size du contrôle.

On peut aussi donner la position et les dimensions du contrôle en une fois:

Exemple pour le formulaire courant:

Me.SetBounds (12, 15, 100, 100)    'X,Y, Width, Height.

Form1.DesktopLocation = new Point(100,100) 'Ici on donne les coordonnées par rapport à la barre de tache.
info En mode conception il est bien plus simple de dimensionner les contrôles à la main dans la fenêtre Design.

VII-K-4. Pour le re-dimensionnement de fenêtre par l'utilisateur:

Pour que l'utilisateur puisse redimensionner la fenêtre(en cliquant sur les bords) il faut que la propriété FormBorderStyle de la fenêtre soit Sizable. (FixedSingle interdit le re-dimensionnement)

ControlBox permet d'afficher la boite de contrôles( bouton d'agrandissement, réduction, fermeture du formulaire) en haut à droite de la barre de tache.

MaximizedBox et MinimizedBox permettent d'utiliser les boutons d'agrandissement ou de réduction du formulaire.

Exemple d'un formulaire ayant ControlBox =True, MinimizedBox =True, MaximizedBox =True et FormBorderStyle= Sizable (les bords de la fenêtre on 2 traits, ce qui permet le redimentionnement).

Après que l'utilisateur ai modifié les dimensions du formulaire, on peut intervenir sur les dimensions du formulaire, pour cela on utilise l'évènement Form.Resize qui est déclenché quand les dimensions du formulaire sont modifiées par l'utilisateur: dans Form.Resize on peut intervenir sur les dimensions du formulaire ou des contrôles:

Exemple: permettre à l'utilisateur de modifier la hauteur mais imposer une largeur de formulaire de 200 pixels.

Private Sub Form1_Resize()

Me.Width = 200

End Sub
Noter que dans Form.Resize on peut récupérer les dimensions du formulaire avec Me.

Les propriétés MaximmunSize et MinimunSize imposent les dimensions maximales et minimales d'un formulaire, ce qui permet de se passer du code qui précède.

Mais si l'utilisateur modifie la taille du formulaire qui contient les contrôles, la taille des contrôles ne suit pas.

Avant cette version VB.net, il fallait dans l'événement Form_Resize, déclenché par la modification des dimensions de la fenêtre, écrire du code modifiant les dimensions et positions des contrôles afin qu'ils s'adaptent à la nouvelle fenêtre:

Exemple: La largeur d'une TextBox se modifie en fonction de la dimension du formulaire.

Private Sub Form1_Resize()

TextBox.Width = Me.Width-50

End Sub
En VB.Net c'est plus facile avec Dock et Anchor (voir plus bas).


VII-K-5. Déplacement.


Form1.Left += 200    'déplace le formulaire de 200 pixels

 

'déplacement progressif d'un bouton de gauche à droite:

For i As Integer =0 to 100

    Button1.Left= i

Next i

VII-K-6. Coordonnées souris:

Certains évènements relatif à la souris comme MouseDown (appuyer sur le bouton) MouveUp (relâcher le bouton), MouseMove (déplacer le bouton) ont comme paramètre e qui contient les coordonnées souris, elles sont dans e.X et e.Y, ce sont bien les coordonnées DANS le contrôle (coordonnées 'client').

Private Sub ListBox2_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListBox2.MouseDown

End Sub
Mais attention, dans les évènement relatifs au Drag and Drop (DragOver par exemple) ce sont les coordonnées écran. Si je veux avoir des coordonnées relatives à l'objet graphique en cours, il faut les transformer à l'aide de PointToClient qui transforme un point écran en point client:

Exemple: La souris survole ListBox2 , on a e.X et e.Y, coordonnées de l'écran, comment obtenir le Point par rapport à la listbox?

On transforme e.X et e.Y en coordonnées client (par rapport à la listBox)

Private Sub ListBox2_DragOver(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListBox2.DragOver

MonImage.Location=ListBox2.PointToClient(New Point(e.X, e.Y)
En plus ListBox2.IndexFromPoint(ListBox2.PointToClient(New Point(e.X, e.Y)) retourne l'index survolé.

PointToScreen fait l'inverse (coordonnées listbox=> coordonnés écran).


VII-K-7. Anchor :

Permet d'ancrer les bords. Un bord ancré reste à égale distance du bord du conteneur quand le conteneur (la fenêtre) est redimensionné.

En mode conception il suffit de cliquer sur '. . .' en face de Anchor pour voir s'ouvrir une fenêtre, cliquer sur les bords que vous voulez ancrer.

Par défaut les bords Top (haut) et left(gauche) sont ancrés.

Expliquons !!

Left est ancré, si je déplace le bord droit de la fenêtre, le contrôle n'est pas déplacé car la distance bord gauche de la fenêtre et bord gauche du contrôle est fixe. Par contre si je déplace le bord gauche de la fenêtre, le contrôle suit.

Exemple :

Prenons 2 contrôles dans une fenêtre, celui de gauche a Anchor =left et celui de droite à Anchor =left et right.

Si je déplace le bord droit (ou le gauche d'ailleurs) : le contrôle droit est redimensionné car la distance 'bord gauche du conteneur-bord gauche du contrôle droit' est fixe., les 2 contrôles restent cote à cote.


VII-K-8. Dock

Amarre aux bords. La bordure spécifiée est ancrée directement au conteneur.

Exemple: le contrôle de droite est Dock=Right (Anchor=None)

Le bord droit du contrôle est accroché au bord droit du conteneur. Le contrôle droit est déplacé sans être redimensionné..

Il y a même possibilité d'amarrer aux 4 bords (Dock=Fill) pour remplir le conteneur, et de modifier la propriété DockPaddind du formulaire afin se s'éloigner légèrement des bords pour faire joli.


VII-K-9. Spliter

Le contrôle Splitter sert à redimensionner des contrôles au moment de l'exécution par l'utilisateur.

Le contrôle Splitter est utilisé dans les applications dont les contrôles présentent des données de longueurs variables, comme l'Explorateur Windows.

Pour permettre à un utilisateur de redimensionner un contrôle ancré au moment de l'exécution, ancrer le contrôle à redimensionner au bord d'un conteneur, puis ancrez un contrôle Splitter sur le même côté de ce conteneur.

En VB.Net 2005 il existe aussi SplitContainer qui est plus pratique que Spliter et LayoutPanel voir 3-9


VII-L. Main Menu, ContextMenu

Comment créer un menu principal en haut d'un formulaire ou un ContextMenu?

Avec MainMenu et ContextMenu en VB 2003.

Avec MenuTrip et ContextMenuStrip en VB 2005.


VII-L-1. MainMenu en Vb 2003

On peut ajouter un menu dans une fenêtre.

Beaucoup d'applications contiennent un menu.

Exemple de menu :

On remarque que le contenu des menus est standardisé afin que l'utilisateur s'y retrouve sans aide (L'utilisateur lit, à mon avis, rarement les aides !!)

Comment créer un menu ?

En allant dans la boite à outils, chercher un main menu et en le déposant sur la fenêtre : il apparaît en dessous de la fenêtre.

Pour ‘dessiner' le menu, il suffit de mettre le curseur sur le menu en haut de la fenêtre, ou est écrit ‘Taper ici' : tapez le texte du menu, (‘Fichier' par exemple).

Il apparaît automatiquement un ‘Tapez Ici‘ pour les lignes dessous ou le menu suivant.

Les lignes du menu sont nommées automatiquement MenuItem1, MenuItem2..

Quand le curseur est sur une ligne du menu,la fenêtre de propriété donne les propriétés de la ligne :

La propriété ShortKey permet de créer un raccourci.

La propriété Checked permet de cochez la ligne

La propriété Visible permet de faire apparaître ou non une ligne.

Si vous double-cliquez sur la ligne du menu vous voyez apparaître :

Private Sub MenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem1.Click

End Sub     
C'est la procédure événement liée à la ligne du menu.

Quand l'utilisateur clique sur une ligne du menu c'est le code contenu dans cette procédure qui est effectué.


VII-L-2. Menu Contextuel Vb 2003

C'est un menu qui s'ouvre quand, le curseur de l'utilisateur est sur un objet, et qu'on clique sur le bouton droit de la souris.

En allant dans la boite à outils, chercher un Context menu, on le dépose sur la fenêtre : il apparaît en dessous de la fenêtre.

Si on le sélectionne avec la souris, il apparaît en haut et comme pour le menu principal, on peut ajouter des lignes.

Il faut ensuite affecter ce Context Menu à un contrôle; pour cela donner à la propriété ContextMenu du contrôle le nom du ContextMenu.

TextBox1.ContextMenu= ContextMenu1
Si vous double-cliquez sur une ligne du menu vous voyez apparaître les procédures évènement correspondantes.


VII-L-3. MenuStrip de Vb 2005:

Remplace le MainMenu en VB 2005.

En allant dans la boite à outils, chercher un MenuStrip et en le déposant sur la fenêtre : il apparaît en dessous de la fenêtre et la barre apparaît en haut du formulaire.

On peur ajouter des menus, combobox et zone texte.

Pour remplir rapidement les menus , c'est comme en vb2003

On peut mettre des images dans les menus.

Dans les propriétés Items permet d'avoir accès aux menus ou lignes et à toutes les propriétés des éléments (image..).

Chaque élément de la barre a sa procédure évènement: Pour le premier bouton par exemple:

Private Sub MenuStrip1_ItemClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripButton1.Click

End Sub

VII-L-4. ContextMenuStrip de Vb 2005:

Remplace le ContextMenu de Vb2003


VII-M. Avoir le Focus

Nous allons étudier comment un objet de l'interface devient 'actif'.

Lorsqu'une fenêtre ou un contrôle est actif on dit qu'il a le focus.

Un contrôle qui a le focus est celui qui reçoit les évènements clavier, souris..

Si une fenêtre prend le focus, sa barre de titre en haut prend la couleur active, si c'est un contrôle texte, le curseur apparaît


VII-M-1. Comment donner le focus à une fenêtre ?

Si une fenêtre est visible la méthode Activate lui donne le focus.

Form1.Activate()
Dans ce cas l'évènement Form1_Activated survient.

La méthode Desactivate est déclenché quand la fenêtre perd le focus.


VII-M-2. Comment donner le focus à un contrôle ?

Avec la méthode Focus

TxtNom.Focus()
Avec la méthode Select:

TxtNom.Select()     'donne le focus à la zone de texte Txnom et met le curseur dedans.
On peut la surcharger et en plus sélectionner une portion du texte:

TxtNom.Select(2,3)    'donne le focus et sélectionne 3 caractères à partir du second.  
ou forcer à ne rien sélectionner (second argument à 0).

On peut interdire a un contrôle le focus en donnant la valeur False à sa propriété CanFocus.

Aussi avant de donner le focus il est préférable de vérifier s'il peut le prendre:

If TxtNom.CanFocus then

    TxtNom.Focus()

End If
L'évènement GotFocus se produit quand le contrôle prend le focus.

Private Sub TxtNom_GotFocus..

End Sub

VII-M-3. Cascade d'évènement quand on prend ou on perd le focus:

Il se déclenche dans l'ordre:


Enter

Se produit quand l'utilisateur entre dans le contrôle.

GotFocus

Se produit quand le contrôle prend le focus.

Leave

Se produit quand le focus quitte le contrôle.

Validating

Se produit lorsque le contrôle est en cours de validation.

On va quitter le contrôle, il faut vérifier la validité avant. La validation c'est vous qui devez la faire!!!

Pour un bouton, par exemple, se produit lorsque l'on quitte le bouton, cela permet de contrôler la validité de certaines données et si nécessaire d'interdire de quitter le contrôle si certaines conditions ne sont pas remplies:

Exemple: ne pas quitter une textbox si l'utilisateur n'a rien tapé:

Private Sub TextBox1_Validating ((ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating

If   TextBox1.Text=""  then

    e.Cancel = True    'Annuler la perte du focus: le focus reste sur TextBox11

End If

End Sub
Validated

Se produit lorsque le contrôle à terminé sa validation

LostFocus

L'évènement LostFocus se produit quand le contrôle perd le focus, mais attention:

Lorsque vous changez le focus à l'aide du clavier (TAB, MAJ+TAB, etc.), en appelant les méthodes Select ou SelectNextControl, ou en définissant la propriété ContainerControl.ActiveControl au formulaire actuel, les événements Focus se produisent dans l'ordre suivant :

  1. Enter
  2. GotFocus
  3. Leave
  4. Validating
  5. Validated
  6. LostFocus
Lorsque vous changez le focus avec la souris ou par l'appel à la méthode Focus, des événements Focus se produisent dans l'ordre suivant :

  1. Enter
  2. GotFocus
  3. LostFocus
  4. Leave
  5. Validating
  6. Validated
Dans Validating, si la propriété Cancel du CancelEventArgs prend la valeur true , tous les événements qui se produiraient normalement après l'événement Validating sont supprimés.


Si la propriété CauseValidating du contrôle a la valeur false, les événements Validating et Validated sont supprimés.

Les événements Enter et Leave sont supprimés dans les formulaire (fenêtres) Les événements équivalents dans la classe Form sont les événements Activated et Desactivate.

info Certains contrôles ne peuvent pas avoir le focus, comme les labels par exemple.

VII-M-4. Usage du clavier pour passer d'un contrôle à l'autre. la touche 'TAB'

Dans une application où un utilisateur tape beaucoup de données dans de multiples contrôles, il passe souvent d'un contrôle (TextBox par exemple) au suivant avec la touche TAB.

Comment permettre cela? Chaque contrôle à une propriété TabIndex qui s'incrémente automatiquement de 0 à 1, 2, 3...quand en cours de conception on ajoute des contrôles sur une fenêtre.

Lorsque l'utilisateur appuie sur TAB, le focus passe au contrôle qui a le TabIndex immédiatement supérieur.

On peut modifier le TabIndex des contrôles pour modifier l'ordre de tabulation.

Quand TabStop a la propriété False (au niveau d'un contrôle) celui ci est exclu de l'ordre de tabulation et le focus ne s'arrête pas.

En VB 2005 on peut très rapidement modifier l'ordre de tabulation:

Passer par le menu Affichage-> Ordre de tabulation.

En mode design apparaît sur chaque contrôle un carré avec le numéro du TabIndex; il suffit de cliquer successivement sur chaque carré dans l'ordre des tabulations croissantes pour mettre les tabulations dans le bon ordre.

Il faut pour finir repasser par le menu Affichage-> Ordre de tabulation.


VII-M-5. Raccourcis clavier.

Dans beaucoup d'applications certains contrôles ont un raccourci clavier:

Exemple: Nouveau est une ligne de menu. N étant souligné, ALT-N déclenche la ligne de menu, donne le focus au contrôle.

Comment faire cela: Dans la propriété Text du contrôle, quand on tape le texte en mode conception, il faut mettre un '&' avant la lettre qui servira de raccourci clavier.

'&Nouveau' dans notre exemple affichera bien Nouveau et ALT N fonctionnera.

Pour une TextBox, la propriété text ne peut pas être utilisée, aussi il faut mettre devant la textBox un contrôle label (qui lui ne peut pas avoir le focus), si les TabIndex du label et du TextBox se suivent, le fait de faire le raccourci clavier du label donne le focus au TextBox.

Exemple quand l'utilisateur tape Alt-N, le focus va dans le TextBox dessous.


VII-N. Barre de bouton , barre de status. MAJ 2005

Comment mettre une barre de bouton en haut et une barre d'état en bas?


VII-N-1. La barre de bouton: ToolBar en VB 2003

Voici un exemple classique, sous le menu il y a une barre de bouton: Nouveau, Ouvrir, Enregistrer, Chercher, Imprimer...

Allez chercher dans la boite à outils un contrôle ToolBar, il se place en haut, sous le menu. Mettre aussi un ImageList.(Un contrôle ImageList est un contrôle qui stocke des images, chaque image étant chargée en mode conception et repérée par un numéro (0,1,2,3..)

Dans le ToolBar mettre dans la propriété ImageList le nom du contrôle ImageList qui contient les images des boutons.


Ouvrir la collection Buttons dans la fenêtre des propriétés de le ToolBar pour pouvoir ajouter ou modifier les boutons:

Vous pouvez ajouter ou enlever des boutons.

Chaque bouton a ses propriétés affichées à droite:

Name Nom du Bouton Exemple NewButton.

ImageIndex donne le numéro de l'image (contenue dans l'Imagelist) qui doit s'afficher dans le bouton.

ToolTipText donne le texte du ToolTip (Carré d'aide qui apparaît quand on est sur le bouton) Il faut aussi que la propriété ShowToolTip de la ToolBar soit à True


L'évènement déclenché par le click de l'utilisateur sur un bouton est: ToolBar1_ButtonClick

L'argument e contient les arguments de l'évènement click de la ToolBar. e.Button contient le nom du bouton qui a déclenché l'évènement. Pour chaque nom de bouton on appellera la procédure correspondante: NewDoc(), Open()...

Comme d'habitude il suffit de double-cliquer sur la ToolBar pour faire apparaître ToolBar1_ButtonClick

Voici le code complet:

Private Sub ToolBar1_ButtonClick(ByVal Sender As System.Object, ByVal e As System.Windows.Forms.ToolBarButtonClickEventArgs) 
					_Handles toolBar1.ButtonClick

If e.Button Is NewButton Then

        NewDoc()

ElseIf e.Button Is OpenButton Then

        Open()

ElseIf e.Button Is SaveButton Then

        Save()

ElseIf e.Button Is PreviewButton Then

        PrintPreview()

...

End If

End Sub
info Le ToolBar a donc une collection de Buttons, de plus il n'y a qu'une procédure évènement 'Click' unique propre à la ToolBar et pour tous les boutons.

VII-N-2. Contrôle StatusBar en VB 2003.

La barre d'état se trouve en bas de la fenêtre et affiche des informations relatives aux opérations en cours.

Ajouter un StatusBar au formulaire. Dans la fenêtre des propriétés du StatusBar, la collection Panels contient les zones d'affichage du StatusBar.

Dans le code, pour modifier le texte d'une zone faire:

StatusBar1.Panels(0).Text="1715.2F"
On remarque (c'est du Net) que le premier panel est panels(0).


VII-N-3. ToolStrip en VB 2005:

On peut créer une barre n'importe ou dans le formulaire.

Exemple de barre de menu comprenant:

Un bouton.

Un label

Un bouton déroulant un menu.

Un comboBox

Une zone texte

Une barre de progression.

Images possible dans les menus, il peut y avoir des séparateurs.


Pour créer la barre ToolStrip, allez la chercher dans la boite à outils.

A la droite de la barre, en mode design, se trouve un menu déroulant qui permet de choisir l'élément à ajouter à la barre:

Cela ajoute des ToolStripLabel, ToolStripButton.... (noter que ce sont des objets spécifiques aux ToolStrip). Chaque élément ajouté est un objet

Ensuite, en cliquant sur chaque élément de la barre, on peut changer ses propriétés (qui apparaissent en bas à droite)

Ici le premier élément à gauche est un label; j'en ai modifié la propriétés (text='Groupe') et j'ai mis une image (il a accepté une icône) dans la propriété 'Image'. Le second élément est un bouton avec une image de stop.

Dans le code, on a accès aux propriétés de l'élément directement à partir de son nom:

    ToolStripButton1.Text="Ok"
Ou par l'intermédiaire de la barre ToolStrip qui a une collection d'items contenant tous les objets de la barre:

    ToolStrip1.Items.Item (2).Text
A la place de l'index de l'élément dans la barre (ici 2), on peut mettre le nom d'élément.

Evènement déclenché par un click:

1- Comme d'habitude, en double-cliquant sur un élément (le second par exemple qui correspond à un bouton), on se retrouve dans la procédure exécutée quand l'utilisateur clique sur le bouton.

Private Sub ToolStripButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripButton1.Click

End Sub
warning Attention: chaque élément à sa propre procédure évènement.
Ainsi s'il y a un second bouton, il y aura une autre procédure Click:

Private Sub ToolStripButton2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripButton2.Click

End Sub
2- On a aussi une procédure unique pour le click sur la barre.

Private Sub ToolStrip1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ToolStrip1.Click

End Sub
Mais le sender est le ToolStrip; pour savoir dans la routine quel bouton a été cliqué, il faut modifier la sub en indiquant comme Handles le nom de tous les boutons de la barre, ainsi par exemple, on peut savoir quel bouton à été cliqué.

Private Sub ToolStrip1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ToolStripButton1.Click, 
								_ToolStripButton2.Click, ToolStripButton3.Click

  Dim Button As System.Windows.Forms.ToolStripItem = CType(sender, System.Windows.Forms.ToolStripItem)

  MsgBox(Button.Name) '

End Sub
La barre de bouton peut être mise horizontalement (grâce à la propriété LayoutStyle ).

Avec l'aide du petit bouton permettant les taches courantes sur le ToolStrip, on peut comme ici, incorporer instantanément tous les boutons standards ( nouveau, ouvrir, enregistrer, imprimer, couper, copier, coller. magique!!)

Avec l'aide du petit bouton permettant les taches courantes sur le ToolStrip, on peut aussi mettre le ToolStrip dans un conteneur (ToolStripContaineur), en mode design , on voit apparaître dessous des outils permettant de modifier le conteneur; si on clique sur un des coté (dessous) on a accès aux propriétés du bord. (mais la mise en oeuvre n'est pas facile!!)

Il n'y a plus de 'groupe de bouton' avec un seul bouton enfoncé, ou du moins j'ai pas trouvé.(On ne peut pas tout avoir!!) par contre, on peut 'enfoncer' ou non un bouton:

.ToolStripButton2.Checked = True
On n'a pas accès à cette propriété (et d'autres) en utilisant les Items du ToolSTrip.

Comment créer un bouton à bascule:

Lorsqu'un utilisateur clique sur un bouton bascule, ce bouton apparaît enfoncé et conserve cet aspect jusqu'à ce que l'utilisateur clique une nouvelle fois sur le bouton.

toolStripButton.CheckOnClick = True
toolStripButton.CheckedChanged AddressOf EventHandler(toolStripButton_CheckedChanged)
Merci Microsoft (Non testé)

Le ToolStrip contient des objets (button, label..) qui ont chacun leur procédure évènement.


VII-N-4. StatuStrip en VB 2005:

Pour créer une barre d'état en bas d'un formulaire; remplace les StatusBar.

Peut contenir des ToolStripStatusLabel (Texte ou icone), des ToolStripProgressBar, ToolStripDropDownButton et ToolsStripSplitButton (combinaison d'un bouton standard et d'un bouton déroulant). Il n'y a plus de Panel.


VII-O. Les images

Comment afficher des images ?


VII-O-1. Le contrôle 'PictureBox':

Le contrôle PictureBox sert à afficher des graphismes au format bitmap, GIF, JPEG, métafichier ou icône (Extension .BMP .GIF .JPG .WMF .ICO)

L'image à affichée est déterminée par la propriété Image, laquelle peut être définie au moment de l'exécution ou du design. La propriété SizeMode détermine la façon dont l'image et le contrôle se dimensionnent l'un par rapport à l'autre.

On peut charger une image en mode conception par le fenêtre 'propriétés' et la propriété 'Image' ou dans le code:

PictureBox1.Image = Image.FromFile("vimage.gif")
(la Classe Image (Shared) possède une fonction qui retourne une image à partir d'un fichier. On l'affecte ensuite à la propriété Image du PictureBox1.)

Ho! merveille, les GIF animés sont acceptés et s'animent sous VB.

Comment effacer une image?

If Not (PictureBox1.Image Is Nothing) Then
    PictureBox1.Image.Dispose()
    PictureBox1.Image = Nothing
End If
Les objets de la Classe Image ont comme d'habitude des propriétés et des méthodes.

La méthode RotateFlip permet par exemple d'effectuer une rotation de l'image; quand on tape le code, VB donne automatiquement la liste des paramètres possible.

PictureBox1.Image.RotateFlip(RotateFlipType.Rotate90FlipX)
La méthode Save sauvegarde l'image dans un fichier.

PictureBox1.Image.Save("c:\image.bmp")
Bien Noter que le nom de l'extension suffit à imposer le format de l'image sur le disque.

On peut charger une image .GIF puis la sauvegarder en .BMP

Il y a bien d'autres propriétés gérant les dimensions, la palette de l'image.

Il est possible de définir une couleur comme 'transparente': voir le page sur les boutons.

Charger une image à partir d'un fichier, mais sans 'bloquer' ce fichier.

On a vu qu'on peut 'charger' une image par PictureBox1.Image = Image.FromFile("vimage.gif")

L'inconvénient de cette méthode est que tant que le programme est ouvert, le fichier correspondant sur le disque est utilisé et par conséquence il est impossible de travailler dessus. (Impossible d'effacer le fichier par exemple!!)

Une méthode pour libérer le fichier est d'utiliser un Stream (Merci la Faq de Developpez.com)

'En haut du module

Imports System.IO

' Créer le FileStream sur le fichier vimage.gif

Dim MyStream As FileStream = New FileStream("C:\vimage.gif”, FileMode.Open)

 ' affecter l'image à pictureBox1 

pictureBox1.Image = Image.FromStream(MyStream) 

' libérer les ressources 

MyStream.Close 

' supprimer le fichier vimage.gif

 File.Delete("C:\vimage.gif”)
Comment placer l'image dans le PictureBox?

La propriété SizeMode impose comment l'image sera placée dans le contrôle PictureBox:
  • aucun : L'image est alignée en haut à gauche du contrôle. Elle peut être trop grande ou trop petite, mais rien ne change de taille.
  • stretch : l'image est automatiquement étirée afin que sa taille s'adapte à celle du contrôle qui la contient.
  • autosize : la taille du contrôle est modifiée pour faire la taille de l'image.
  • centerImage : l'image est centrée par rapport au contrôle.

VII-O-2. La propriété 'Image' des contrôles:

De nombreux contrôles Windows Forms peuvent afficher des images. L'image affichée peut être une icône symbolisant la fonction du contrôle ou une image ; par exemple, l'image d'une disquette sur un bouton indique généralement une commande d'enregistrement. L'icône peut également être une image d'arrière-plan conférant au contrôle une certaine apparence.

Pour tous les contrôles affichant des images:
  • l'image peut être définie à l'aide des propriétés Image ou BackgroundImage directement en mode Design par la fenêtre des propriétés. Il faut sélectionner Image puis cliquez sur "..." et choisir une fichier contenant une image. Dans ce cas, une fois chargée, l'image fait partie intégrante du programme. (Il n'est pas utile de fournir le fichier .BMP ou .GIF avec l'application)
  • Lorsque le programme 'tourne' on peut aussi charger une Image. Le code affecte à la propriété Image ou BackgroundImage un objet de type System.Drawing.Image, en général, vous utiliserez la méthode FromFile de la classe Image pour charger une Image à partir d'un fichier.(Dans ce cas le fichier contenant l'image doit être fourni)
Exemple pour un bouton:

button1.Image = Image.FromFile("C:\Graphics\MyBitmap.bmp")
' Aligne l'image.
button1.ImageAlign = ContentAlignment.MiddleRight
 
Exemple pour un label:

Dim Label1 As New Label()
Dim Image1 As Image

Image1 = Image.FromFile("c:\\MyImage.bmp")

' modifier la taille du label pour qu'il affiche l'image.

Label1.Size = Image1.Size 

' Mettre l'image dans le label.

Label1.Image = Image1
Si on renseigne la propriété Image, on ne peut pas utiliser en même temps la propriété ImageList décrite ci-dessous.


VII-O-3. Le contrôle ImageList:

Il sert de containeur à images, c'est une collection d'images. les images qu'il contient seront utilisées par d'autres contrôles (PictureBox, Listview, TreeView, Button....)

Il n'est pas visible en exécution.

En conception il apparaît en bas sous la fenêtre. A droite figurent ses propriétés, en particulier, la collection Images qui contient les images et la propriété TransparentColor qui indique la couleur qui doit être transparent, c'est à dire non visible.

Il faut l'ajouter au formulaire, il apparaît en dessous.

Si je clique sur le bouton '...' en face de Images, l'éditeur de collections d'image s'ouvre.

On peut ajouter des images avec le bouton 'Ajouter'.

L'ImageList est ainsi chargé.


Ensuite pour utiliser une image de l'ImageList dans un autre contrôle, il faut modifier les propriétés de cet autre contrôle( un bouton par exemple):

La propriété ImageList du bouton doit contenir le nom du contrôle imageList et ImageIndex du bouton doit contenir l'index de l'image dans l'ImageList.

btOk.ImageList = imagelist1

btOk.ImageIndex = 2
Un ImageList peut aussi être chargé par code:

imageList1.Images.Add(Image.FromFile(NomImage))
On ajoute à la collection Images une image venant d'un fichier nommé NomImage.

On peut surcharger la méthode Add en fournissant en plus la couleur transparente.

imageList1.Images.Add(Image.FromFile(imageToLoad), CouleurTransparente)
 
La taille des images peut aussi être modifiée par code:

imageList1.ImageSize = New Size(255, 255)
imageList1.TransparentColor = Color.White
 

VII-P. Couleurs et Font


VII-P-1. Les couleurs:


VII-P-1-a. A- Généralités:

Une couleur est représentée par 3 octets correspondent aux composants de couleur rouge, vert et bleu. Chaque octet peut prendre la valeur 0 à 255 (ou 0 à FF en hexadécimal).

Si on utilise la notation hexadécimale, il faut mettre &H avant: &HFF correspond à 255.

Exemple : valeur des 3 composantes couleurs et couleurs correspondantes:

En plus, dans certains cas, il y a une composante alpha qui indique la transparence. 255 indique que la couleur est opaque, 1 à 254 indique que la couleur est transparente.

Il y a une Classe Color dans SystemDrawing. On peut instancier un Objet Color:

Dim myColor As Color
On peut voir ou modifier les composants de cette couleur avec:

myColor.A composante alpha

myColor.B composante bleue

myColor.R composante rouge

myColor.G composante verte


VII-P-1-b. B- Constantes:

Le plus simple est, pour modifier la couleur d'un objet par du code, d'utiliser les constantes VB qui contiennent le code d'une couleur toute faite (en RGB sans composante Alpha):

Color.Back,

Color.Fuchsia

Color.Chocolate

Color.Red ...

Voici toutes les couleurs à votre disposition:

Elles font partie de System.Drawing

Comme d'habitude il suffit de taper Color. et la liste très longue des couleurs s'ouvre.

Bouton.BackColor=Color.Red     'modifie la couleur de fond du bouton

VII-P-1-c. C- Rouge,vert, bleu

Plus puissant:

 Color.FromArgb
Crée une couleur à partir des valeurs des quatre composants ARVB (argb en anglais) 8 bits (alpha, rouge, vert et bleu).

alpha indique la transparence. 255 indique que la couleur est opaque, 1 à 254 indique que la couleur est transparente.

L'octet le plus significatif, représenté par AA, correspond à la valeur du composant alpha. Les second, troisième et quatrième octets, représentés par RR, VV et BB, correspondent aux composants de couleur rouge, vert et bleu, respectivement. Chaque octet prend la valeur 0 à 255 ou 0 à FF en hexadécimal.

Le paramètre correspond à 4 X 8bits=32 bits= un Integer. Pour plus de clarté on rentre généralement les données en hexadécimal:

Me.BackColor= Color.FromArgb(&H780000FF)    'correspond à un bleu transparent.
 

Il y a des surcharges:

On peut passer chaque paramètre séparément:

Me.BackColor=Color.FromArgb(120, 0, 0, 255)
 
On peut aussi passer l'alpha et la couleur en second paramètre.

Plus simple:

On peut définir une couleur avec la fonction RGB (red, green, blue) , pas de composantes alpha ici.

Dim red As Color = RGB(255, 0, 0) ' fait partie de Microsoft.VisualBasic

VII-P-1-d. D-Couleurs 'system'

Ce sont les couleurs utilisées par Windows pour afficher la barre de titre, les fonds, couleurs d'éléments actifs ou non. On peut modifier ces couleurs en passant par le panneau de configuration (option 'Affichage'). Toutes les applications les utilisent. On peut aussi les utiliser.

L'énumération KnownColor contient les couleurs système (couleur des barres, texte, fenêtre active..)

mais pour utiliser une couleur system, il faut employer SystemColors.

Me.BackColor = SystemColors.ActiveBorder 'modifie la couleur de fond du formulaire en cours

VII-P-1-e. E- Couleur dans les objets:

Pour changer la couleur d'arrière-plan du contrôle, utilisez la propriété BackColor, la propriété d'avant plan est Forcolor.

Ici pour ce bouton, BackColor est égal à Color.Red et ForColor est à Color.Black

Dans le code MyButton.BackColor = Color.Red

En mode Design (conception), on peut modifier la couleur directement en cliquant sur le bouton '...' en face de BackColor par exemple: la fenêtre de choix des couleurs apparaît:

On a le choix entre les couleurs habituelles (custom), les couleurs Web (couleurs standard web visibles sur tous les environnements) et couleurs system (Windows).


VII-P-1-f. F- Choix d'une couleur par l'utilisateur.

Pour permettre à l'utilisateur de choisir une couleur, il faut mettre dans le formulaire une ColorDialog à partir de la boite à outils; elle vient se placer sous le formulaire:

Il faut ensuite, par code, ouvrir cette ColorDialog.

La classe ColorDialog a une méthode ShowDialog, analogue à la méthode ShowDialog des classes OpenFileDialog et

SaveFileDialog, qui permet d'afficher la boite de dialogue.

Si l'utilisateur quitte la boîte de dialogue en cliquant sur le bouton 'OK', la méthode ShowDialog retourne DialogResult.OK et la couleur choisie est dans la propriété Color de l'objet ColorDialog .

Exemple:

L'utilisateur clique sur un bouton nommé 'CouleurButton' cela ouvre la ColorDialog, l'utilisateur clique sur une couleur puis sur 'Ok', cela donne aux caractères de la TextBox 'Texte' la couleur choisie.

Private Sub CouleurButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) _

Handles CouleurButton.Click

' Ouverture de la dialogBox colordialog1

If colorDialog1.ShowDialog() = DialogResult.OK Then

' on met la couleur dans la propriété forecolor du TextBox

Texte.ForeColor = colorDialog1.Color

End If

End Sub

VII-P-2. Police de caractères (ou Font)

Pour modifier la police de caractère utilisée dans un contrôle, il faut lui assigner un objet 'Font'

label1.Font = New System.Drawing.Font("Arial", 10) 'on indique le nom de la font et la taille, on aurait pu ajouter un troisième argument: le style (gras, italique, souligné).

label1.Font = New System.Drawing.Font(label1.Font, FontStyle.Bold Or FontStyle.Italic)

Ici c'est une autre signature Font, Style

Visual Basic .NET ne prend plus en charge que les polices TrueType et OpenType.

Les propriétés de police sont automatiquement héritées du parent, sauf lorsqu'elles sont explicitement définies pour l'objet enfant. Par exemple, si vous avez deux contrôles d'étiquette dans un formulaire et que vous changiez les propriétés de police du formulaire en Arial, les polices du contrôle d'étiquette sont également changées en Arial. Si par la suite vous changez la police d'une étiquette en Times Roman, les modifications qui pourront être apportées à la police du formulaire ne remplaceront pas la police de l'étiquette.

Pour lire les fonts installées utiliser l'espace de noms System.Drawing.FontFamily.

Dim ff As FontFamily
For Each ff In System.Drawing.FontFamily.Families
listBox1.Items.Add(ff.Name)
Next
Pour que l'utilisateur modifie la police du contrôle List1.

Dim myFontDialog As FontDialog
   myFontDialog = New FontDialog()
   
   If myFontDialog.ShowDialog() = DialogResult.OK Then
      
      List1.Font = myFontDialog.Font
   End If
On ouvre une fenêtre de choix de police, si une police est sélectionnée par l'utilisateur, on l'applique à List1.

Pour mettre la font de la form en gras:

If Not (Me.Font.Bold) Then
        Me.Font = New Font(Me.Font, FontStyle.Bold)
End If
Pour qu'un TextBox utilise la font "Courier New" de taille 12 en italique:

TextBox1.Font = New Font("Courier New", 12, FontStyle.Italic)


VII-Q. Grille ou Grid

Qu'utiliser pour afficher dans une 'Grille'(Grid), un tableau (type tableur avec des lignes et des colonnes)?

Ici on affiche du texte directement dans les cellules SANS utiliser de liaison avec une base de données. On parle de grille 'indépendante'

MsFlexGrid de VB6

LameGrid et SourceGrid Shareware VB.Net

DataGrid VB.Net 2003

DataGridView VB.Net 2005


VII-Q-1. A - Contrôle 'MsFlexGrid' de VB6

Microsoft fournissait avec VB6 l'activeX 'Microsoft Flexgrid 6' qui permettait de satisfaire à la plupart des demandes . Il est toujours possible d'utiliser cet activeX dans vos programmes mais ce n'est plus du .net (c'est du non managé).

Il faut l'ajouter dans la boite à outils: Bouton droit puis dans le menu 'Ajouter/Supprimer un composant' puis 'Parcourir' , on ajoute MSFLXGRD.OCX qui est dans Windows/System32 ( si vb6 installé, ou sinon le demander à quelqu'un qui a VB6).

Voila ce qu'il permet de faire en VB6: (Logiciel LDF de l'auteur)

Les propriétés Cols et Rows permettent de définir le nombre de colonne et de ligne.

FixedCols et FixedRows permettent de déterminer les colonnes et lignes qui ne bougent pas (titres); BackColorFixed donne une couleur à ces lignes fixes.

Modifier la largeur d'une colonne:

Grid.ColWidth(i) =150

Pour modifier une cellule:

Grid.Row = 2        'Coordonnées de la cellule
Grid.Col = 3
Grid.CellFontBold = True    'Texte en gras
Grid.CellForeColor = Color.Red 'Couleur du texte

Grid.Text= Texte  
ou

Grid.TextMatrix(2, 3) = Texte
.TextMatrix est beaucoup plus rapide que .Text mais on n'a accès qu'au texte et pas à l'enrichissement.

Modifier la couleur de fond d'une cellule:

Grid.CellBackColor = Color.Red
Mettre une image dans une cellule

Grid.CellPictureAlignment = flexAlignCenterCenter '4= gère l'alignement
Set Grid.CellPicture = ImageCoche.Picture    'Syntaxe VB6, le Set doit disparaître en .Net
On peut gérer l'évènement Grid_RrowColChanged quand l'utilisateur change de cellule. Il existe bien sur Grid_Click...

Il n'y a pas de gestion de saisie dans les cellules, il faut le faire 'à la main', Grid_KeyPress appelle une routine qui simule une saisie dans la grille avec un textbox qui prend les dimensions de la cellule. ( Voir le code en annexe en bas de page )

Pour accélérer l'affichage et éviter le scintillement , surtout si il faut réafficher la totalité du tableau avec des couleurs et des images, il faut désactiver la mise à jour de l'affichage, afficher la page, réactiver. L'affichage devient instantané.

L'exemple suivant colore une ligne sur deux, c'est instantané.

Dim i As Integer

Dim j As Integer

Grid.Redraw = False
Grid.Clear

For i = 0 To NbMaxLigne Step 2
Grid.Row = i
For j = 0 To MaxColonne - 1
Grid.Col = j
Grid.CellBackColor = VERTCLAIR
Next j
Next i

Grid.Redraw = True

VII-Q-2. B - Contrôles Freeware à télécharger, c'est du '.Net':


VII-Q-2-a. 'lameGrid'en français +++++

Il existe un contrôle gratuit nommé lameGrid qui est du pur .Net et qui permet simplement d'afficher dans une grid.

On le trouve ici avec son mode d'emploi:


C'est simple rapide, efficace. On le conseille.

Son usage est simple:

Grille(1.2).Forecolor= MyColor

Grille(1.2).Font= MyFont

Grille(1.2).Texte="Lulu"

VII-Q-2-b. Autre:

SourceGrid en Anglais.



VII-Q-3. C - Contrôle 'DataGrid ' de VB 2003

C'est un des contrôles fournit avec VB.Net 2003 les plus puissant. Il est très adapté pour faire une liaison avec une base de données, mais pour l'utiliser simplement, dur, dur!!

Il est composé de lignes et de colonnes:


VII-Q-3-a. Aspect du contrôle 'DataGrid'

Mettre un 'DataGrid' dans le formulaire en cours en allant le chercher dans la boite à outils.

On peut modifier l'aspect du DataGrid1
  • en dans la fenêtre de propriété les propriétés
  • en utilisant la mise en forme automatique (lien en bas de la fenêtre de propriétés.)
Pour travailler avec un DataGrid, on peut:
  • écrire directement dedans
  • créer un DataSet (un DataSet c'est un objet qui a la structure d'une base de données mais en local, il comporte des lignes , des colonnes.. voir la chapitre 6-5).Ce DataSet sera ensuite lié au DataGrid par DataGrid1.DataSource= MonDataSet. Toute modification du Dataset sera ensuite répercutée automatiquement sur le DataGrid. Et toute modification du DataGrid sera répercutée sur le DataSet.
Comment modifier le texte d'une cellule?

Pour modifier une cellule du Datagrid, il faut modifier le DataSet (pas le DataGrd)

MonDataSet.Tables(0).Rows (0) (1)= "Montexte" '0 et 1 sont respectivement le numéro de ligne et de colonne. 
Comment lire le texte d'une cellule?

Lire ligne 1, colonne 1, l'afficher dans une TextBox.

TextBox1.Text = CType(DataGrid1(1, 1), String)

DataGrid1(1, 1) = TextBox1.Text
Comment sélectionner une ligne?

Il faut taper

DataGrid1.Select(1)
Comment cacher une colonne?

MonDataSet.Tables["Employees"].Columns["LastName"].ColumnMapping = MappingType.Hidden
 

VII-Q-3-b. Comment améliorer la rapidité de l'affichage:

Si on fait un grand nombre de modifications dans un DataGrid, le DataGrid est remis à jour à chaque modification, c'est long et souvent l'affichage clignote.

Pour éviter cela, il faut désactiver l'affichage par BeginUpdate, afficher toutes les modifications puis réactiver l'affichage par EndUpdate: la mise à jour se fait en une fois très rapidement.

Private Sub BeginEndUpdate()
' MyDataGridColumnStyle is a class derived from DataGridColumnStyle.
Dim dgc As MyDataGridColumnStyle
Dim dgCols As GridColumnStylesCollection
dgCols = DataGrid1.TableStyles(0).GridColumnStyles
For Each dgc In dgCols
dgc.BeginUpdate
Next 

' Code to update not shown here.

For Each dgc In dgCols
dgc.EndUpdate
Next

End Sub
 

VII-Q-4. D - Contrôle 'DataGridView ' de VB 2005

C'est celui qu'il faut utiliser.

Il remplace le DataGrid dans VB.Net 2005 Il est bien plus simple à utiliser surtout pour modifier directement la grille sans passer par un DataSet.(Contrôle indépendant)

Exemple 1: On crée la Grid puis des colonnes de la grid; on crée les lignes que l'on ajoute à la grille.

MyDataGridView.ColumnCount = 5 indique le nombre de colonne.

MyDataGridView.Columns(0).Name = "Date" met un texte dans le haut de la colonne.

MyDataGridView.Rows.Add(t) 'Ajout de ligne; t est un tableau de 5 strings.

MyDataGridView.CurrentCell est la cellule courante (CurrentCellAdress contient les numéro de ligne et colonne)

MyDataGridView.EditMode = DataGridViewEditMode.EditOnEnter autorise de modifier les cellules.

Exemple de Microsoft: afficher dans le contrôle MyDataGridView 5 colonnes( nommées date, piste, titre, artiste, album) et 6 lignes de chanson.(exemple à partir d'un exemple de Microsoft)

'création de la grille

Private WithEvents MyDataGridView As New DataGridView

Me.Controls.Add(MyDataGridView)

 

'On met 5 colonnes

MyDataGridView.ColumnCount = 5

 

'On colore les en-têtes, on met les fonts

With MyDataGridView.ColumnHeadersDefaultCellStyle

.BackColor = Color.Navy

.ForeColor = Color.White

.Font = New Font(MyDataGridView.Font, FontStyle.Bold)

End With

 

'on positionne la grille

With MyDataGridView

.Name = "MyDataGridView"

.Location = New Point(8, 8)

.Size = New Size(500, 250)

.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCellsExceptHeaders

.ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single

.CellBorderStyle = DataGridViewCellBorderStyle.Single

.GridColor = Color.Black

.RowHeadersVisible = False

 

'On donne le nom des colonnes

.Columns(0).Name = "Date"

.Columns(1).Name = "Piste"

.Columns(2).Name = "Titre"

.Columns(3).Name = "Artiste"

.Columns(4).Name = "Album"

.Columns(4).DefaultCellStyle.Font = New Font(Me.MyDataGridView.DefaultCellStyle.Font, FontStyle.Italic)

.SelectionMode = DataGridViewSelectionMode.FullRowSelect

.MultiSelect = False

.Dock = DockStyle.Fill

End With

 

 

'Création d'un tableau de 5 strings pour chaque ligne

Dim row0 As String() = {"11/22/1968", "29", "Revolution 9", _

"Beatles", "The Beatles [White Album]"}

Dim row1 As String() = {"1960", "6", "Fools Rush In", _

"Frank Sinatra", "Nice 'N' Easy"}

Dim row2 As String() = {"11/11/1971", "1", "One of These Days", _

"Pink Floyd", "Meddle"}

Dim row3 As String() = {"1988", "7", "Where Is My Mind?", _

"Pixies", "Surfer Rosa"}

Dim row4 As String() = {"5/1981", "9", "Can't Find My Mind", _

"Cramps", "Psychedelic Jungle"}

Dim row5 As String() = {"6/10/2003", "13", _

"Scatterbrain. (As Dead As Leaves.)", _

"Radiohead", "Hail to the Thief"}

Dim row6 As String() = {"6/30/1992", "3", "Dress", "P J Harvey", "Dry"}

With Me.MyDataGridView.Rows

'Ajout de ligne

.Add(row0)    

.Add(row1)

.Add(row2)

.Add(row3)

.Add(row4)

.Add(row5)

.Add(row6)

End With

With Me.MyDataGridView

'Ordre des colonnes

.Columns(0).DisplayIndex = 3

.Columns(1).DisplayIndex = 4

.Columns(2).DisplayIndex = 0

.Columns(3).DisplayIndex = 1

.Columns(4).DisplayIndex = 2

End With

 

 

 

'Ajouter une ligne

Me.MyDataGridView.Rows.Add()

 

'Enlever la ligne pointée

If Me.MyDataGridView.SelectedRows.Count > 0 AndAlso _

Not Me.MyDataGridView.SelectedRows(0).Index = _

Me.MyDataGridView.Rows.Count - 1 Then

Me.MyDataGridView.Rows.RemoveAt( _

Me.MyDataGridView.SelectedRows(0).Index)

End If

 

'Faire disparaître toutes es lignes

Me.MyDataGridView.Rows.Clear()  'il ne reste plus que les en-têtes de colonnes

 
Exemple 2: On crée la grid avec des lignes et des colonnes puis on modifie les cellules.



'Mettre 5 colonnes et 50 lignes dans la grid

Grid.RowCount = 50

Grid.ColumnCount = 5

 

With Me.Grid


 


'Une ligne sur 2 en bleue

.RowsDefaultCellStyle.BackColor = Color.White

.AlternatingRowsDefaultCellStyle.BackColor = Color.AliceBlue


'Interdir la selection de plusieurs cellules

.MultiSelect = False



'Empeche la saisie dans les cellules (en faite, le permet par programmation)

.EditMode = DataGridViewEditMode.EditProgrammatically

End With


 


'Gestion des en-têtes de colonne

With Grid.ColumnHeadersDefaultCellStyle '

.BackColor = Color.Blue  'ça marche pas!!??

.ForeColor = Color.Blue

.Font = New Font(Grid.Font, FontStyle.Bold)' en gras

End With

 

With Grid


 


'Empêche les modifications de lignes, colonnes, l'ajout, la suppression

.AllowUserToAddRows = False

.AllowUserToDeleteRows = False

.AllowUserToOrderColumns = False

.AllowUserToResizeColumns = False

.AllowUserToResizeRows = False


 


'Nomme les colonnes (en têtes)

.Columns(0).Name = "Date"

.Columns(1).Name = "Libellé"

.Columns(2).Name = "Montant"

.Columns(3).Name = "Origine"

.Columns(4).Name = "Cochée"

.RowHeadersVisible = False 'pas de première colonne d'en tête

.Columns(2).Width = 30 'modifie la largeur de la colonne 2

End With
Pour avoir une 2 lignes d'en-tête:

.Columns(2).Name = "Montant" & ControlChars.CrLf & "en euros"

(ColumnsHeaderHeightSizeMode est par défaut à AutoSize)


 


'On modifie la couleur de fond d'une cellule, on aligne au milieu, impose un format et affiche "12"

Grid.Item(3, 3).Style.BackColor = Color.Coral

Grid.Item(3, 3).Style.Alignment = DataGridViewContentAlignment.MiddleRight

Grid.Item(3, 3).Style.Format = "#####"

Grid.Item(3, 3).Value = 12


 


'On modifie la couleur de fond d'une cellule, on aligne au milieu, on met en italique et affiche "Toro"

Grid.Item(3, 4).Style.BackColor = Color.Chartreuse

Grid.Item(3, 4).Style.Alignment = DataGridViewContentAlignment.MiddleRight

Grid.Item(3, 4).Style.Font = New Font(Grid.Font, FontStyle.Italic)

Grid.Item(3, 4).Value = "Toro"



If Not Button1.Font.Style = FontStyle.Bold Then 

Button1.Font = New Font(FontFamily.GenericSansSerif, _ 12.0F, FontStyle.Bold) 

End If 




'On force la cellule à accepter une image, on aligne au milieu, donne une couleur de fond 
et affiche une image à partir d'un fichier.

Grid.Item(2, 2) = New DataGridViewImageCell

Grid.Item(2, 2).Style.Alignment = DataGridViewContentAlignment.MiddleCenter

Grid.Item(2, 2).Style.BackColor = Color.Wheat

Grid.Item(2, 2).Value = New Bitmap("viconote.gif")


 


'On  autorise le redimensionnement  auto, marche pas?

Grid.AutoResizeColumns()


 

'Positionner la cellule courante, le curseur sur la cellule 1,1

Grid.Rows(1).Cells(1).Selected = True

 

'Connaître la ligne et la colonne de la cellule  courante

Dim x As Integer = Grid.CurrentCellAddress.X

Dim y As Integer = Grid.CurrentCellAddress.Y


 

 


'Effacer le contenu de toutes les cellules de la grid

Grid.Rows.Clear()

Grid.RowCount = 50

Grid.ColumnCount = 5



'Modifier le ToolTipText (Petit rectangle jaune contenant un test qui apparait quand le curseur de 
					_la souris reste un moment sur une cellule)

Private Sub Grid_CellFormatting(ByVal sender As Object, ByVal e 
					_As System.Windows.Forms.DataGridViewCellFormattingEventArgs) Handles Grid.CellFormatting

Dim cell As DataGridViewCell = Grid(e.ColumnIndex, e.RowIndex)

cell.ToolTipText = "oui"

End Sub
On rappelle que la première cellule en haut à gauche est la cellule '0,0'; on ne compte pas les en-têtes.


VII-Q-5. Annexe: code permettant de simuler la saisie dans un MsFlexGrid:

Mettre dans un formulaire une grille MSFLEXGRID nommée Grid, une TextBox (avec borderSTyle =None) nommée TxtEdit.

Grid_KeyPress appelle une routine qui affiche le textbox (qui prend les dimensions de la cellule), l'utilisateur tape son texte dans le textbox, quand il sort, le textbox est effacé et le texte affiché dans la cellule de la grid.

AJOUTER DANS LES PROCEDURES:

Private Sub Grid_DblClick()
If Txtedit.Visible = True Then Exit Sub 'evite une boucle
'edite
MSHFlexGridEdit Grid, Txtedit, 32 ' Simule un espace.
End Sub


Private Sub Grid_GotFocus()
If Txtedit.Visible = True Then
Grid = Txtedit
Txtedit.Visible = False
End If
End Sub


Private Sub Grid_KeyPress(KeyAscii As Integer)
MSHFlexGridEdit Grid, Txtedit, KeyAscii
End Sub



Private Sub Grid_RowColChange()
EditKeyCode Grid, Txtedit, 27, 0
End Sub


Private Sub Txtedit_KeyDown(KeyCode As Integer, Shift As Integer)
EditKeyCode Grid, Txtedit, KeyCode, Shift
End Sub
AJOUTER LES 3 routines:

Sub EditKeyCode(MSHFlexGrid As Control, Edt As Control, KeyCode As Integer, Shift As Integer)
' Traitement de contrôle d'édition standard.
Select Case KeyCode
Case 27 ' ÉCHAP : masque, renvoie le focus à MSHFlexGrid.
Edt.Visible = False
MSHFlexGrid.SetFocus
Case 13 ' ENTRÉE renvoie le focus à MSHFlexGrid.
Edt.Visible = False
MSHFlexGrid.SetFocus
MiseaJourLigne
Case 38 ' Haut.
MSHFlexGrid.SetFocus: DoEvents
Edt.Visible = False
MiseaJourLigne
If MSHFlexGrid.Row > MSHFlexGrid.FixedRows Then
MSHFlexGrid.Row = MSHFlexGrid.Row - 1
End If
Case 40 ' Bas.
MSHFlexGrid.SetFocus: DoEvents
Edt.Visible = False
MiseaJourLigne
If MSHFlexGrid.Row < MSHFlexGrid.Rows - 1 Then
MSHFlexGrid.Row = MSHFlexGrid.Row + 1
End If
Case 39 ' droit.
' MSHFlexGrid.SetFocus: DoEvents
' If MSHFlexGrid.Col < MSHFlexGrid.Cols Then
' MSHFlexGrid.Col = MSHFlexGrid.Col + 1
' End If
' Edt.Visible = False
' MiseAJourLigne
' Case 37 ' Gauche.
' MiseAJourLigne
' MSHFlexGrid.SetFocus: DoEvents
' If MSHFlexGrid.col > MSHFlexGrid.FixedCols - 1 Then
' MSHFlexGrid.col = MSHFlexGrid.col - 1
' End If
End Select
End Sub

Sub MSHFlexGridEdit(MSHFlexGrid As Control, Edt As Control, KeyAscii As Integer)
' Utilise le caractère qui a été tapé.
Select Case KeyAscii
' Un espace signifie "modifier le texte en cours".
Case 0 To 32
Edt = Trim(MSHFlexGrid)
If Len(Edt) < 1 Then

Edt = Grid.Text
End If

Edt.SelStart = 1000
' Tout autre élément signifie "remplacer le ' texte en cours".
Case Else
Edt = Chr(KeyAscii)
Edt.SelStart = 1
End Select
' Affiche Edt au bon endroit.
Edt.Move MSHFlexGrid.Left + MSHFlexGrid.CellLeft, MSHFlexGrid.Top + MSHFlexGrid.CellTop, 
					_MSHFlexGrid.CellWidth - 8, MSHFlexGrid.CellHeight - 8
Edt.ForeColor = ROUGE
Edt.Visible = True
' Et laisse l'opération s'effectuer.
Edt.SetFocus
End Sub

Public Sub MiseaJourLigne()
'Met à jour la grid

Grid.text=Txtedit.text
End sub

VII-R. ProgressBar


VII-R-1. ProgressBar de VB 2003

Une progressBar permet de voir la progression d'une opération.

On donne une valeur aux propriétés Minimum et Maximum, la propriété Value permet de positionner la barre.

Souvent on utilise la ProgressBar différemment:

On donne une valeur aux propriétés Minimum et Maximum, on donne un pas (Step); la méthode PerformStep()augmente d'un pas.

Exemple de Microsoft:

filenames() contient une liste de fichier à copier, à chaque fois qu'un fichier est copié, on avance la barre (qui se nomme MyBarre):

Private Sub CopyAvecProgressBar(ByVal ParamArray filenames As String())

' Minimum à 1 
MyBarre.Minimum = 1
' Maximum= nombre total de fichier à copier.
MyBarre.Maximum = filenames.Length
' On initialise la ProgressBar.
MyBarre.Value = 1
' On indique le pas.
MyBarre.Step = 1

' Boucle de copie.
Dim x As Integer
for x = 1 To filenames.Length - 1
' Copier un fichier.
If CopyFile(filenames(x - 1)) = True Then
' Si la copie est OK incrémenter la ProgressBar.
      MyBarre.PerformStep()
End If
Next x
End Sub

VII-R-2. ProgressBar de VB 2005

Fonctionne de la même manière.

MyBarre.Style = ProgressBarStyle.blocks   'indique d'avancer par block

MyBarre.Style = ProgressBarStyle.continuous 'indique d'avancer progressivement
On peut aussi, quand on ne connaît pas la durée du processus, indiquer à la ProgressBar d'avancer de gauche à droite (comme lors de l'ouverture de Windows XP)

MyBarre.Style = ProgressBarStyle.Marquee 

VIII. Programmation fonctionnelle (procédurale).


VIII-A. La programmation fonctionnelle.

En programmation 'Fonctionnelle' ou 'procédurale':

Chaque problème complexe est décomposé en 'Fonctions'(Les Subs et Fonctions) plus simples.

Ces fonctions sont stockées dans des modules standards (ou dans les modules de formulaire).

Dans une application en programmation 'fonctionnelle' il y a habituellement:

Des modules de formulaires

Des modules standard contenant des Sub et Function.

Chaque fonction peut être appelée d'une autre fonction.

Exemple:

Créons une Function nommée CalculCarré.

Public Function CalculCarré ( c As Single) As Single

    Return c*c

End Function 
Cette fonction est Public (elle peut être appelée de n'importe où dans le programme).

Elle accepte un paramètre qui doit être un Single.

Comme c'est une fonction, elle retourne une valeur qui est aussi un Single.

Comment l'appeler?

Dim carré As Single

carré= CalculCarré (12)  

Une Sub par contre ne retourne pas de valeur.

Public Sub Affiche Carré ( c As Single)

..

End Sub
Comment l'appeler?

AfficheCarré (12) ou Call AfficheCarré (12)  

 

L'autre manière de programmer en VisualBasic est la programmation 'Objet'


VIII-A-1. Comment créer un module standard? une Sub?

Faire Menu Projet>Ajouter un module. Donner un nom au module. C'est Module1.vb par défaut.

Module Module1        'Nom du Module

...

End Module
On remarque que le module est bien enregistré dans un fichier .vb

Un module standard ne contient que du code.

Comment ajouter une Sub dans un module Standard?

Taper Sub Calcul puis valider, cela donne:

Sub Calcul()

End Sub

VIII-A-2. Exemple d'utilisation de procédures et de modules:

Exemple simple de programmation fonctionnelle.


L'utilisateur saisit un nombre puis il clique sur un bouton; cela affiche le carré de ce nombre:


Il faut créer l'interface utilisateur: créer une fenêtre (Form1), y mettre un bouton (nommé Button1), une zone de texte (Text1) permettant de saisir un nombre, un label (label1) permettant l'affichage du résultat.

Créer un module standard (Module1) pour y mettre les procédures communes.

On observera uniquement l'agencement des procédures et non leur contenu. Pour un programme d'une telle complexité , la structure aurait pu être plus simple, mais l'intérêt de ce qui suit est didactique.


On décompose le programme en taches plus simples: En particulier une procédure sert au calcul, une sert à l'affichage.

La procédure CalculCarré calcule le carré.

La procédure AfficheCarre affiche le résultat dans le label.

La procédure Button1_Click (qui est déclenchée par le Click de l'utilisateur):

Lit le chiffre tapé par l'utilisateur dans la zone texte.

Appelle la procédure CalculCarré pour calculer le carré.

Appelle la procédure AfficheCarré pour afficher le résultat.


Ou sont placées les procédures?

La procédure Button1_Click est automatiquement dans le module du formulaire, Form1 (elle est liée au contrôle Bouton1) elle est créée automatiquement quand on crée le bouton.

La procédure AfficheCarré est créée dans le module du formulaire (Form1) car elle agit sur le contrôle Label1 de ce formulaire.

La procédure CalculCarré est créée dans le module Standard (Module1) car elle doit être appelable de n'importe où; elle est d'ailleurs 'Public' pour cette raison. Elle n'agit sur aucune fenêtre, aucun contrôle, elle est 'd'intérêt général', c'est pour cela qu'on la met dans un module standard.

Voyons le cheminement du programme:

Quand l'utilisateur clique sur le bouton la Sub Button1_Click démarre.

Elle appelle CalculCarre avec comme paramètre le nombre qui a été tapé dans le textbox (nommé Text1).

Val(Text1.Text) permet de transformer la String Text1.Text en numérique.

CalculCarre calcule le carré et renvoie la valeur de ce carré.

La Sub Button1_Click appelle ensuite AfficheCarre (en envoyant le paramètre Carré) qui affiche le résultat.


On remarque:

On appelle la Function CalculCarre par

Carre= CalculCarre(Valeur)
On envoie un paramètre Single , la fonction retourne dans la variable Carre, la valeur du carré.

Par contre la Sub AfficheCarre reçoit un paramètre, et ne retourne rien puisque c'est une Sub!!


VIII-B. Programmation fonctionnelle: l'IMC.

Ce chapitre permet de 'réviser' pas mal de notion


VIII-B-1. Qu'est ce que l'IMC?

L'index de masse corporelle est très utilisé par les médecins. Il est calculé à partir du poids et de la taille:

IMC=Poids/(Taille*Taille) (avec Poids en Kg, Taille en mètres)

Cela permet de savoir si le sujet est

maigre (IMC<18.5)

normal (IMC idéale=22)

en surpoids (IMC>25)

obèse (IMC>30).

On peut calculer le poids idéal par exemple PI= 22* T*T

Nous allons détailler ce petit programme:


VIII-B-2. Quel est le cahier des charges du programme?

L'utilisateur doit pouvoir:

Saisir un poids, une taille, cliquer sur un bouton 'Calculer'

Les routines doivent:

Vérifier que l'utilisateur ne fait pas n'importe quoi.

Calculer et afficher les résultats: l'IMC mais aussi, en fonction de la taille, le poids idéal, les poids limites de maigreur, surpoids, obésité.


VIII-B-3. Création de l'interface

Il faut 2 zones de saisie pour saisir le poids et la taille:

On crée 2 'TextBox' que l'on nomme

TexBoxPoids

TextBoxTaille.

On laisse la propriété Multiline à False pour n'avoir qu'une ligne de saisie.

Pour afficher les résultats , on crée 5 'label' les uns sous les autres. (Pour aller plus vite et que les labels soient de la même taille, on en crée un puis par un copier et des coller, on crée les autres)

labelImc    'pour afficher l'Imc

labelPi     'pour afficher le poids idéal

labelM      'pour afficher le poids limite de la maigreur.

labelS      'pour afficher le poids limite du surpoids

labelO      'pour afficher le poids limite de l'obésité.
Ensuite on ajoute des labels devant et derrière chaque TextBox pour indiquer devant, ce qu'ils contiennent et derrière, l'unité.

On ajoute 2 boutons:

ButtonCalcul ayant pour propriété Text= "&Calculer"

ButtonQuitter ayant pour propriété Text= "&Quitter"

Cela donne:

Pour faire beau:

La propriété Text de la fenêtre contient "Calcul IMC", pour afficher cela dans la barre de titre.

La propriété ForeColor de labelImc est en rouge.

La propriété BorderStyle des labels a la valeur 'Fixed3d' ce qui rend les bords visibles.

Ajout du Code

La procédure évènement Form1_Load qui se déclenche lorsque la fenêtre se charge initialise les zones d'affichage en les vidant:

Private Sub Form1_Load(..)

TextBoxTaille.Text = ""

TextBoxPoids.Text = ""

LabelImc.Text = ""

LabelPi.Text = ""

LabelM.Text = ""

LabelS.Text = ""

LabelO.Text = ""

End Sub
La procédure ButtonCalcul_Click qui se déclenche lorsque l'utilisateur clique sur le bouton 'Calculer' contient le code principal.

Voici la totalité du code, on le détaillera dessous.

Private Sub ButtonCalcul_Click(..)

 

Dim sPoids As Single  'Variable Single contenant le poids

Dim sTaille As Single 'Variable Single contenant la taille


'******Controle de validité des entrées************

'Les valeurs saisies sont-elles numérique?

If Not (IsNumeric(TextBoxTaille.Text)) Then

    MsgBox("Entrez une valeur numérique pour la taille")

    Exit Sub

End If

If Not (IsNumeric(TextBoxPoids.Text)) Then

    MsgBox("Entrez une valeur numérique pour le poids")

    Exit Sub

End If


'Convertir les textes saisis en single 

' et les mettre dans les variables

sTaille = CType(TextBoxTaille.Text, Single) / 100

sPoids = CType(TextBoxPoids.Text, Single)


'Les valeurs saisies sont-elles cohérentes?

If sTaille < 0.50 Or sTaille > 2.50 Then

    MsgBox("Entrez une taille valide")

    Exit Sub

End If

    If sPoids < 20 Or sPoids > 200 Then

    MsgBox("Entrez un poids valide")

Exit Sub

End If


'Effectuer les calculs et afficher les résultats.

LabelImc.Text = (Math.Round(sPoids / (sTaille * sTaille), 2)).ToString

LabelPi.Text = (Math.Round(22 * (sTaille * sTaille), 2)).ToString

LabelM.Text = (Math.Round(18.5 * (sTaille * sTaille), 2)).ToString

LabelS.Text = (Math.Round(25 * (sTaille * sTaille), 2)).ToString

LabelO.Text = (Math.Round(30 * (sTaille * sTaille), 2)).ToString

End Sub
Détaillons:

Quelles sont les différentes étapes?
  • On déclare les variables.
  • On vérifie que ce qui a été tapé est numérique.
  • On convertit le texte qui est dans la TextBox en Single
  • On teste si les valeurs de poids et taille sont cohérentes.
  • On fait le calcul et on affiche.
Déclaration de variables.

Dim sPoids As Single  'Variable Single contenant le poids

Dim sTaille As Single 'Variable Single contenant la taille
Ce sont des variables 'privées' propre à la procédure (utilisation de Dim ou Private).


Contrôle de validité:

L'utilisateur est sensé taper un poids et une taille puis cliquer sur le bouton 'Calculer'. Mais il ne faut absolument pas lui faire confiance: il a peut-être oublié de taper le poids ou a donner une taille=0 (l'ordinateur n'aime pas diviser par 0!!), il a peut-être fait une faute de frappe et tapé du texte!!..

Donc il faut tester ce qui a été tapé, s'il y a erreur, on prévient l'utilisateur avec une 'MessageBox' puis on sort de la routine par (Exit Sub )sans effectuer de calcul.


Ici par exemple, on teste si le texte saisi dans la zone taille n'est pas numérique:

If Not (IsNumeric(TextBoxTaille.Text)) Then

    MsgBox("Entrez une valeur numérique pour la taille")

    Exit Sub

End If
Amélioration: On aurait pu automatiquement effacer la valeur erronée et placer le curseur dans la zone à ressaisir:

If Not (IsNumeric(TextBoxTaille.Text)) Then

    MsgBox("Entrez une valeur numérique pour la taille")

    TextBoxTaille.Text=""

    TextBoxTaille.Select()

    Exit Sub

End If
Conversion:

Si le texte est bien 'Numéric', on fait la conversion en réel simple précision (Single)

sTaille = CType(TextBoxTaille.Text, Single) / 100
On utilise CType pour convertir une String en Single.

On divise taille par 100 car l'utilisateur à saisi la taille en centimètre et les formules nécessitent une taille en mètre.


Problème du séparateur décimal dans les saisies.

Pourquoi saisir la taille en Cm? c'est pour éviter d'avoir à gérer le problème du séparateur décimal.


Si la taille était saisie en mètre, l'utilisateur aurait-il tapé "1.75" ou "1,75"?

On rappelle que pour convertir un texte en Single VB accepte le point et pas la virgule.

Pour ma part, si j'avais demandé de saisir des mètres, voici ma solution: j'ajouterais en début de routine une instruction transformant les ',' en '.':

TextBoxTaille.Text = Replace(TextBoxTaille.Text, ",", ".")

Faire les calculs et afficher les résultats.


Je fais le calcul:

sPoids / (sTaille * sTaille)
J'arrondis à 2 décimales après la virgule grâce à Math.Round( ,2):

Math.Round(sPoids / (sTaille * sTaille), 2)
Je convertis en String:

(Math.Round(sPoids / (sTaille * sTaille), 2)).ToString
J'affiche dans le label 'labelImc':

LabelImc.Text = (Math.Round(sPoids / (sTaille * sTaille), 2)).ToString
(J'aurais pu aussi ne pas arrondir le calcul mais formater l'affichage pour que 2 décimales soient affichées)

La procédure ButtonQuitter_Click déclenchée quand l'utilisateur clique sur le bouton 'Quitter' ferme la seule fenêtre du projet (c'est Me , celle où on se trouve), ce qui arrête le programme.

Private Sub ButtonQuitter_Click()

    Me.Close()

End Sub

VIII-B-4. Structuration:

Ici on a fait simple: une procédure évènement calcule et affiche les résultats.

On pourrait, dans un but didactique 'structurer' le programme.


On pourrait découper le programme en procédure.
Une procédure (une fonction) faisant le calcul.
Une procédure (une fonction) affichant les résultats.

Si plusieurs procédures utilisent les mêmes variables il y a dans ce cas 2 possibilités:
Mettre les variables en 'Public' dans un module Standard.
Utiliser des variables privées et les passer en paramètres.

Première solution: Variables 'Public'
Créer dans un module standard des variables 'Public' pour stocker les variables Poids et Taille, résultats (Public sIMC A Single par exemple),créer dans ce même module standard une procédure Public nommée 'Calculer' qui fait les calculs et met les résultats dans les variables 'Public'; enfin dans le module de formulaire créer une procédure 'AfficheResultat' affichant les résultats.

Module standard:

'Déclaration de variables Public 

Public sPoids As Single

Public sTaille As Single

Public sIMC A Single

..

'Procedure Public de calcul

Public Sub Calculer

    sIMC=Math.Round(sPoids / (sTaille * sTaille), 2)

    ...

End Sub
Module de formulaire Form1:

'Procédure évènement qui appelle les divers routines

Private Sub ButtonCalculer_Click

    ...

    sTaille = CType(TextBoxTaille.Text, Single) / 100

    Calculer()    'Appelle la routine de calcul

    AfficheResultat() 'Appelle la routine d'affichage

End Sub

 

'routine d'affichage toujours dans le formulaire

Private Sub AfficheResultat()

    

    LabelImc.Text = sIMC.ToString

    ...

End Sub
On voit bien que la routine de Calcul est générale et donc mise dans un module standard et d'accès 'Public', alors que la routine d'affichage affichant sur Form1 est privée et dans le module du formulaire.

Seconde solution: Variables 'Privées' et passage de paramètres

On peut ne pas créer de variables 'public' mais créer des fonctions (CalculIMC par exemple) à qui on passe en paramètre le poids et la taille et qui retourne le résultat du calcul. Une procédure AfficheResultatIMC récupère en paramètre la valeur de l'IMC à afficher.

Module standard:

'Pas de déclaration de variables Public 

..

'Function Public de calcul: reçoit en paramètre le poids et la taille

'retourne l'Imc

Public Function CalculerIMC (T as Single, P As Single) As Single

    Return Math.Round(P / (T*T), 2)

End Sub
Module de formulaire Form1:

'Procédure évènement qui appelle les divers routines

Private Sub ButtonCalculer_Click

    ...

    sTaille = CType(TextBoxTaille.Text, Single) / 100

    

    'Appelle de la routine calcul avec l'envoie de paramètres sPoids et sTaille

    'Au retour on a la valeur de L'imc que l'on envoie à la routine d'affichage.

    AfficheResultatIMC(CalculerIMC(sTaille, sPoids)) 'Appelle la routine d'affichage

End Sub

 

'routine d'affichage 

Private Sub AfficheResultatIMC(I As Single)

    LabelImc.Text = i.ToString

End Sub
Remarque:

La ligne AfficheResultatIMC(CalculerIMC(sTaille, sPoids))

est équivalente à:

Dim s As single

s=(CalculerIMC(sTaille, sPoids)

AfficheResultatIMC(s))
mais on se passe d'une variable temporaire.

Conclusion:

Faut-il travailler avec des variables Public ou passer des paramètres?

Réponses:

Les savants disent qu'il faut éviter les variables Publics. Toutes les routines ayant accès à ces variables, il est toujours possible qu'une routine modifie une valeur sans qu'on le sache!!

info Utiliser donc des variables le plus privées possible.
(on y reviendra)

VIII-C. Ordre des instructions dans un module: résumé.


VIII-C-1. Contenu des modules.

Dans quel ordre écrire dans un module?

Le code Visual Basic est stocké dans des modules (modules de formulaire,modules standard, modules de classe ..), chaque module est dans un fichier ayant l'extension '.vb". Les projets sont composés de plusieurs fichiers '.vb', lesquels sont compilés pour créer des applications.

Respecter l'ordre suivant :
  1. Instructions Option toujours en premier.(force des contraintes de déclaration de variables, de conversion de variables, de comparaison)
  2. Instructions Imports (charge des espaces de nom)
  3. Les énumérations, les structures 'générales'.
  4. Instructions Class, Module et Namespace, le cas échéant
  5. En haut de la classe du module les énumérations et structures 'locales'.
  6. Les Subs et Functions.
Exemple1: Un Formulaire.

Option Explicit On     'Toujours en premier.

 

Imports System.AppDomain

Imports Microsoft.VisualBasic.Conversion

 

Enum Fichier           'Ici une énumération utilisable dans la totalité du programme

    Doc

    Rtf

End Enum    

    

Public Class Form1                                   'la classe, le moule du formulaire

Inherits System.Windows.Forms.Form                    

    Dim WithEvents m As PrintDocument1                

#Region " Code généré par le Concepteur Windows Form"

                                                      

Public Sructure MaStructure                          'Structure utilisable dans la Classe uniquement.

    i As Integer                                      

    J As Integer                                      

End Structure                                         

Public d As Integer                                   

                                                      

Private Sub Form1_Load(...) Handles Form.load        'Ici une Sub

    Dim A As integer                                  

    ...                                               

End Sub                                               

End Class    
On remarque de nouveau l'importance de l'endroit où les variables sont déclarées: Dans notre exemple A est accessible uniquement dans Form_Load, alors que d est public.

Exemple2: Un module standard Module2.

Imports System.Activator

Enum MyEnum  'Ici une énumération utilisable dans la totalité du programme

    Toto

    titi

End Enum

Structure MyStructure  'Ici une structure utilisable dans la totalité du programme

    Dim i As Integer

End Structure

 

Module Module2

Sub Main()    

End Sub       

End Module    
On remarque donc que Option et Imports sous toujours avant Class et Module.

La position de Enum et Structure (avant ou après les mots Class et module) gère leur visibilité.

info Si vous entrez les instructions dans un ordre différent, vous risquez de créer des erreurs de compilation.

VIII-C-2. Composant visuel et Classe.

Nous avons vu que pour utiliser un composant visuel, un bouton par exemple, il faut aller le chercher dans la boite à outils et le poser sur le formulaire (VB créera du code automatiquement pour cela).

Une autre manière de procéder est d'utiliser la Classe 'Button' et d'instancier un bouton, puis de l'ajouter aux contrôles du formulaire.

Créons le bouton.

Dim Button1 As New Button

 

 

Modifions ses propriétés

Me.Button1.Location = New System.Drawing.Point(56, 144)

Me.Button1.Name = "Button1"

Me.Button1.Size = New System.Drawing.Size(104, 24)

Me.Button1.TabIndex = 0

Me.Button1.Text = "Button1"
Le bouton existe mais il faut l'ajouter à la collection Controls de la fenêtre (Cette collection contient tous les contrôles contenus dans la fenêtre):

Me.Controls.Add(Button1)
Il faudra gérer soi même les évènements mais on verra cela plus loin.


VIIII-E. Exemple de petits programmes.


VIII-F-1. Conversion F/€ (Une fenêtre)

Comment créer un programme de conversion Francs=>Euros et Euros=> Francs ?

Voici l'interface utilisateur:

Euros

2
Francs:

13.12
Il y a une zone de saisie Euros, une zone Francs, si je tape dans la zone Euros '2' il s'affiche '13.12' dans la zone Francs; cela fonctionne aussi dans le sens Francs=>Euros.

Conseils:

Un formulaire affichera les zones de saisie, un module standard contiendra les procédures de conversion.

On crée un formulaire Form1 contenant :

2 TextBox BoiteF et BoiteE, leurs propriétés Text=""

2 labels dont la propriété Text sera ="Euros" et "Francs", on les positionnera comme ci-dessus.

Un module Module1 contiendra 2 routines ConversionFE ConversionEF

Réponse en bas:



Dans le formulaire, je dimensionne un flag (ou drapeau): flagAffiche, il sera donc visible dans la totalité du formulaire. Je l'initialise à True.

Public Class Form1

Inherits System.Windows.Forms.Form

Dim flagAffiche As Boolean = True
Comme la conversion doit se déclencher automatiquement lorsque le texte de BoiteF ou BoiteE change, j'utilise les évènements 'TextChanged' de ces TextBox:

Pour la conversion Euros=>Francs, dans la procédure TextChanged de BoiteE, je récupère le texte tapé (BoiteE.Text), j'appelle la fonction ConversionEF en lui envoyant comme paramètre ce texte. La fonction me retourne un double que je transforme en string et que j'affiche dans l'autre TextBox(BoiteF).

Private Sub BoiteE_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BoiteE.TextChanged

If flagAffiche = True Then

flagAffiche = False

BoiteF.Text = (ConversionEF(BoiteE.Text)).ToString

flagAffiche = True

End If

End Sub
Idem pour l'autre TextBox:

Private Sub BoiteF_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles BoiteF.TextChanged

If flagAffiche = True Then

flagAffiche = False

BoiteE.Text = (ConversionFE(BoiteF.Text)).ToString

flagAffiche = True

End If

End Sub

End Class
A quoi sert le flag : flagAffiche?

A éviter une boucle sans fin: sans flag, BoiteF_TextChanged modifie BoiteE_Text qui déclenche BoiteE_TextChanged qui modifie BoiteF_Text qui déclenche BoiteF_TextChanged.....

Avec le flag, quand je vais modifier la propriété Text d'une TextBox, le met le flag à False, cela indique à l'autre évènement TextChanged de ne pas lui aussi convertir et afficher.


Enfin il faut écrire les procédures qui font la conversion: ConversionEF et ConversionFE dans un module standard. Ces procédures 'Function' appellent elles mêmes une autre fonction qui arrondi les résultats à 2 décimales.

Pour transformer des Euros en Francs, je les multiplie par 6.55957 puis j'arrondis .

On remarque que ces procédures reçoivent une string en paramètres et retourne un double.

Module Module1

Public Function ConversionEF(ByVal e As String) As Double

Dim somme As Double

Dim resultat As Double

somme = Val(e)

resultat = Arrondir(somme * 6.55957)

Return resultat

End Function

 

Public Function ConversionFE(ByVal e As String) As Double

Dim somme As Double

Dim resultat As Double

somme = Val(e)

resultat = Arrondir(somme / 6.55957)

Return resultat

End Function
Enfin la Function Arrondir arrondit à 2 décimales: pour cela on multiplie par 100, on arrondit à l'entier avec Round puis on divise par 100.

Public Function Arrondir(ByVal Valeur As Double) As Double

'arrondi a 2 chiffres après la virgule

Return (Math.Round(Valeur * 100)) / 100

End Function

End Module
A noter que l'on aurait pu utiliser une surcharge de Round qui arrondit directement à 2 décimales:

Return (Math.Round(Valeur, 2))
Exercice:

Quel code mettre dans la procédure Button_Click d'un bouton nommé 'Remise à zéro' qui met les 2 zones de saisie à zéro?

(Penser au flag)

Amélioration:

Si l'utilisateur tape une virgule il y a problème car la fonction Val utilisée pour convertir le nombre saisi en numérique reconnaît uniquement le point, il faut donc transformer les virgules en points avec

e = Replace(e, ",", ".")
On peut tester si l'utilisateur a bien tapé un nombre, avec la fonction IsNumeric.


VIII-F-2. Calcul mensualités d'un prêt.(les fonctions financières de VB)

Comment créer un programme qui calcul les mensualités d'un prêt ?

Dans l'espace Microsoft.VisualBasic il existe des fonctions financières. (VB 2003 et VB 2005)

Pmt calcul les mensualités d'un prêt.

Remboursement mensuel= Pmt( Rate, NPer, PV, FV, Due)

Rate  
  Obligatoire. Donnée de type Double indiquant le taux d'intérêt par période. Si taux d'intérêt annuel de 10 pour cent et si vous effectuez des remboursements mensuels, le taux par échéance est de 0,1/12, soit 0,0083.
NPer  
  Obligatoire. Donnée de type Double indiquant le nombre total d'échéances. Par exemple, si vous effectuez des remboursements mensuels dans le cadre d'un emprunt de quatre ans,il y a 4 * 12 (soit 48) échéances.
PV  
  Obligatoire. Double indiquant la valeur actuelle . Par exemple, lorsque vous empruntez de l'argent pour acheter une voiture, le montant du prêt correspond à la valeur actuelle (pour un emprunts il est négatif).
FV  
  Facultatif. Double indiquant la valeur future ou le solde en liquide souhaité au terme du dernier remboursement. Par exemple, la valeur future d'un emprunt est de 0 F car il s'agit de sa valeur après le dernier remboursement. Par contre, si vous souhaitez économiser 70 000 F sur 15 ans, ce montant constitue la valeur future. Si cet argument est omis, 0 est utilisée par défaut.
Due  
  Facultatif. Objet de type Microsoft.VisualBasic.DueDate indiquant la date d'échéance des paiements. Cet argument doit être DueDate.EndOfPeriod si les paiements sont dus à terme échu ou DueDate.BegOfPeriod si les paiements sont dus à terme à échoir (remboursement en début de mois). Si cet argument est omis, DueDate.EndOfPeriod est utilisé par défaut.
   
Noter que si Rate est par mois NPer doit être en mois; si Rate est en année NPer doit être en année.

Sub CalculPret()
Dim PVal, Taux, FVal, Mensualite, NPerVal As Double
Dim PayType As DueDate

Dim Response As MsgBoxResult
Dim Fmt As String

Fmt = "###,###,##0.00" ' format d'affichage.
FVal = 0  '0 pour un prêt.
 

PVal = CDbl(InputBox("Combien voulez-vous emprunter?"))
Taux = CDbl(InputBox("Quel est le taux d'intérêt annuel?"))
If Taux > 1 Then Taux = Taux / 100 ' Si l'utilisateur à tapé 4 transformer en 0.04.
NPerVal =12* CDbl(InputBox("Durée du prêt (en années)?"))
Response = MsgBox("Echéance en fin de mois?", MsgBoxStyle.YesNo)
If Response = MsgBoxResult.No Then
  PayType = DueDate.BegOfPeriod
Else
  PayType = DueDate.EndOfPeriod
End If
Mensualite = Pmt(Taux / 12, NPerVal, -PVal, FVal, PayType)
MsgBox("Vos mensualités seront de " & Format(Mensualite, Fmt) & " par mois")
End Sub

 

IPmt calcul les intérêts pour une période.

 

Calculons le total des intérêts:

Dim IntPmt, Total, P As Double

For P = 1 To TotPmts ' Total all interest.
IntPmt = IPmt(APR / 12, P, NPerVal, -PVal, Fval, PayType)
Total = Total + IntPmt
Next Period
Autres mots clés :

Calculer l'amortissement. DDB, SLN, SYD
Calculer la valeur future. FV
Calculer le taux d'intérêt. Rate
Calculer le taux de rendement interne. IRR, MIRR
Calculer le nombre de périodes. NPer
Calculer les paiements. IPmt, Pmt, PPmt
Calculer la valeur actuelle. NPV, PV
Par exemple:
Rate Permet de calculer le taux d'un prêt en connaissant la somme prêtée, le nombre de mois et la mensualité.


IX. Faire un vrai programme: il faut savoir:


IX-A. Démarrer, arrêter un programme. - Sub Main(), fenêtre Splash.

Quand vous démarrez votre programme, quelle partie du code va être exécutée en premier?

En Vb 2003

Vous pouvez le déterminer en cliquant sur le menu Projet puis Propriétés de NomduProjet, une fenêtre Page de propriétés du projet s'ouvre.

Sous la rubrique Objet du démarrage, il y a une zone de saisie avec liste déroulante permettant de choisir:

-Le nom d'un formulaire du projet

ou

-Sub Main()


En Vb 2005 (Framework 2) :

Ouvrir le 'Projet Designer', il est directement accessible dans l'explorateur de solution (Double cliquer sur 'My Projet')ou par le menu Projet-> Propriétés de ..:

On définit:

Le Formulaire de démarrage (startUp Form).

Si 'Activer l'infrastructure de l'application' est coché, l'élément de démarrage ne peut être qu'un formulaire; s'il est décoché, on peut lancer le programme par la Sub Main().


IX-A-1. Démarrer par un formulaire.

Si vous tapez le nom d'un formulaire du projet, c'est celui-ci qui démarre : cette fenêtre est chargée au lancement du programme et la procédure Form_Load de cette fenêtre est effectuée.

En théorie, si vous avez une application avec un formulaire, le fait de dessiner ce formulaire crée une Classe Form1; il faudrait donc théoriquement créer une instance de ce formulaire (par un Dim MyForm As New Form1) pour lancer l'application.

En pratique, dessinez un formulaire, lancez l'exécution, ça marche car le runtime crée une instance du formulaire automatiquement à l'aide de sa méthode New et l'affiche (sans que l'on ai besoin de l'intancier soit même).


IX-A-2. Démarrer par Sub Main()

C'est cette procédure Sub Main qui s'exécute en premier lorsque le programme est lancé.

Elle peut servir à ouvrir le formulaire de démarrage:

Exemple 1:

En mode design Form1 a été dessinée, C'est un modèle 'une Classe'.

Dans un module standard, dans une Sub Main(), on instancie initForm à partir la Class Form1. Puis on affiche ce formulaire (cette fenêtre) avec .ShowDialog

Sub Main()

        Dim initForm As New Form1

        initForm.ShowDialog()

End Sub
Exemple 2:

Sub Main() 
' Démarre l' application et affiche une instance de Form1
Application.Run(New Form1())
End Sub
S'il y a plusieurs threads, Application.Run commence à exécuter une boucle de messages d'application standard sur le thread en cours et affiche le formulaire spécifié. Peut être utilisé aussi s'il y a un seul thread.


warning Attention Sub Main() peut se trouver dans une Classe (Y compris une classe de formulaire) ou dans un module:
Si vous déclarez la procédure Main dans une classe, vous devez utiliser le mot clé Shared.

Class Form1

Public Shared Sub Main()

    .....

End Sub

..

End Classe
Dans un module, la procédure Main n'a pas besoin d'être partagée (Shared).

Module1

Sub Main()

...

End Sub

End Module
Fonction Main():

On peut utiliser 'Function Main' (au lieu de 'Sub Main') qui retourne un Integer, que le système d'exploitation utilise comme code de sortie du programme. D'autres programmes peuvent tester ce code en examinant la valeur ERRORLEVEL Windows.

Function Main() As Integer
...
Return 0 ' Zéro signifie : tout est Ok.
End Function
Récupération de la ligne de commande:

Main peut également avoir comme argument un tableau de String. Chaque élément du tableau contient un des arguments de ligne de commande utilisée pour appeler le programme. Vous pouvez réaliser diverses actions en fonction de leurs valeurs.

Function Main(ByVal CmdArgs() As String) As Integer
...

Return 0 
End Function

On rappelle qu'en VB2005, si 'Activer l'infrastructure de l'application' est coché dans les propriétés du programme, le formulaire de démarrage ne peut être qu'un formulaire; s'il est décoché, on peut lancer le programme par la Sub Main().


IX-A-3. Autre méthode de récupération de la ligne de commande en VB 2005:

On trouve les arguments de la ligne de commande dans My.Application.CommandLineArgs (VB 2005)

Exemple:

Cliquez sur un fichier de données, l'exécutable lié s'exécute et ouvre le fichier de données.

(Exemple: Quand on clique sur un fichier .bmp on lance automatiquement Paint qui charge l'image .bmp)

Il faut que l'extension du fichier soit liée avec le programme exécutable, si vous cliquez sur le fichier de données, cela lance l'exécutable.

Modifier l'extension liée Explorer->Outils-> Option des dossiers-> Type de fichiers

Dans Form_Load mettre:

If My.Application.CommandLineArgs.ToString <> "" Then

Dim i

For i = 0 To My.Application.CommandLineArgs.Count - 1

If mid(My.Application.CommandLineArgs(i).ToString,1,2)  "-o" Then ' dans le cas ou la ligne de commande contient le nom du fichier à lancer et '-o'

FileName = Mid(My.Application.CommandLineArgs(i).ToString, 3)

OpenFile() ' charger les données

Exit For

End If

Next

End If

IX-A-4. Fenêtre Splash

C'est une fenêtre qui s'ouvre au démarrage d'un programme, qui montre simplement une belle image, (pendant ce temps le programme peut éventuellement initialiser des données, ouvrir des fichiers...) ensuite la fenêtre 'Splash' disparaît et la fenêtre principale apparaît.

Exemple de formulaire splash de VisualStudio 2003:

En Vb 2003 (Framework 1) il faut tout écrire:

Dans la Sub Main il est possible de gérer une fenêtre Splash.

Exemple:

Je dessine Form1 qui est la fenêtre Spash.

Dans Form2 qui est la fenêtre principale, j'ajoute:

Public Shared Sub Main()

Dim FrmSplash As New Form1    'instance la fenêtre Splash 

Dim FrmPrincipal As New Form2 'instance la feuille principale

FrmSplash.ShowDialog()        'affiche la fenêtre Splash en Modale


FrmPrincipal.ShowDialog()     'a la fermeture de Splash,  affiche la fenêtre principale

End Sub
Dans Form1 (la fenêtre Splash)

Private Sub Form1_Activated

Me.Refresh() 'pour afficher totalement la fenêtre.

'ici ou on fait plein de choses on ouvre des fichiers ou on perd du temps.

' s'il n'y a rien a faire on met un Timer pour que l'utilisateur admire la belle image.

Me.Close()

End Sub
On affiche FrmSplash un moment (Ho! la belle image) puis on l'efface et on affiche la fenêtre principale. Word, Excel.. font comme cela.

Autre méthode:

Public Sub main() 

 

'création des formulaires frmmain and frmsplash 

Dim frmsplash As New frmsplash 

Dim frmmain As New frmmain 

 

'on affiche la Splash

frmsplash.Show() 

Application.DoEvents() 

 

'On attend (3000 milliseconds) 

System.Threading.Thread.Sleep(3000) 

 

'On efface la Splash

frmsplash.Close() 

 

'On affiche le formulaire principal

Application.Run(frmmain)  

 

End Sub 
En Vb 2005 (Framework 2) c'est très simple:

Ouvrir le 'Projet Designer', il est directement accessible dans l'explorateur de solution (My Projet)ou par le menu Projet-> Propriétés de..:

Il faut que 'Activer l'infrastructure de l'application' soit coché:

On définit

Le formulaire de démarrage (startUp Form),

L'écran de démarrage (Splash Screen), il suffit d'indiquer son nom (En mode Run, VB l'affiche et le fait disparaître quand le formulaire de démarrage s'ouvre).

On peut aussi ajouter un écran splash tout fait:

Menu Projet, Ajouter un formulaire Windows, double cliquer sur 'formulaire de démarrage'.

On obtient:

Le nom de l'application, la version, le nom de la société sont automatiquement mis à jour en utilisant les 'Informations de l'assembly' accessible par un bouton situé dans le projet designer, en face du nom du formulaire de démarrage.

L'inconvénient de cet écran Splash automatique est qu'il s'affiche et s'efface très rapidement, avant de charger le formulaire de démarrage!! Pour le voir une seconde, j'ai ajouté à la fin de la procédure Form_Load de cet écran:

Me.Show()

Application.DoEvents()

System.Threading.Thread.Sleep(1000)

IX-A-5. Comment arrêter le programme?


Me.Close()    'Ferme la fenêtre en cours
Noter bien Me désigne le formulaire, la fenêtre en cours.

Application.Exit()    'Ferme l'application
Vide la 'pompe à messages', ferme les formulaires. Si des fichiers sont encore ouvert, cela les ferme. (Il vaut mieux les fermer avant, intentionnellement.)


IX-A-6. Fin de programme :Attention!

Outre l'usage de Application.Exit(), on peut terminer une application en fermant les formulaires, mais:

Dans Visual Basic 6.0, une application ne se terminait que lorsque tous les objets créés étaient détruits.

Dans Visual Basic .NET 2003, l'application se termine lorsque l'objet de démarrage est détruit. Si le formulaire que vous fermez est le formulaire de démarrage de votre application, votre application se termine. Si la procédure Sub_Main est définie comme objet de démarrage l'application se termine dès que le code de Sub_Main a fini de s'exécuter.

Dans Visual Basic .NET 2003, l'application se termine automatiquement lorsque l'objet de démarrage est détruit.

En VB 2005 vous avez le choix entre les 2 solutions: terminer l'application quand le formulaire de démarrage est fermé ou quand tous les formulaires sont fermés.(dans l'application Designer voir 'Mode d'arrêt')


IX-B. Ouvrir plusieurs formulaires

Comment à partir d'un formulaire 'Form1' ouvrir un second formulaire à partir de la Classe 'Form2' ?

En VB2003

En VB 2005

Formulaire modal et non modale.

Comment se nomment les formulaires?

Autres

Un formulaire est un objet

Exemple

DialogResult

Bouton par défaut


IX-B-1. Créer un formulaire en VB 2003:

A- Il faut d'abord créer la Classe Form2

Ajoutez un formulaire (Menu Projet, Ajouter un formulaire au projet), nommez le 'Form2' .

On se rend compte que quand on ajoute un formulaire (Form2 par exemple), on crée une nouvelle 'classe':

'Class Form2' qui hérite de System.Windows.Forms.Form , elle hérite donc de toutes les propriétés et méthodes de la Classe Form qui est la classe 'formulaire'.

Public Class Form2

Inherits System.Windows.Forms.Form 

End Class
Elle contient du code généré automatiquement par le concepteur Windows Forms et les procédures liées aux évènements.

Dessinez dans Form2 les contrôles nécessaires.

B- Il faut créer ensuite le nouvel Objet formulaire, une instance de Form2:

Pour créer un nouveau formulaire dans le programme, il faut:
  • Instancier un formulaire à partir du moule, de la Classe Form2 avec le mot New.
  • Ouvrir ce formulaire, le faire apparaître, (avec ShowDialog, c'est un formulaire modal)

Dim formSecondaire As New Form2()

formSecondaire.ShowDialog()  
En résumé: on a Form1, on dessine Form2:

Pour que le bouton nommé "Créer Form secondaire" ouvre le second formulaire, il faut y mettre le code:

Private ButtonCreerFormSecondaire_Click()

  Dim formSecondaire As New Form2()

  formSecondaire.ShowDialog()  

End Sub
info En conclusion:
Le fait d'ajouter un formulaire à un projet crée une Class, (un 'type' de formulaire, un moule) ce qui permet ensuite d'instancier (de créer) un objet formulaire.
VB 2003 est tolérant pour le premier formulaire: si on dessine un formulaire et ses contrôles et qu'on lance le programme, il accepte de fonctionner bien qu'on ait pas instancié le formulaire. Par contre, si on crée une seconde classe formulaire, il faut créer une instance de ce formulaire.

Dim formSecondaire As New Form2()
formSecondaire.ShowDialog()  

IX-B-2. Créer un formulaire en VB 2005:

Pas besoin d'instancier systématiquement un formulaire:

On peut utiliser la Class Form2 sans instancier, en utilisant directement le nom de la Classe:

On dessine Form2 (la classe) puis on peut écrire directement:

Private ButtonCreerFormSecondaire_Click()
    Form2.ShowDialog()
End sub
On peut même utiliser les propriétés directement:

 Form2.ForeColor = System.Drawing.Color.Coral
 Form2.BackColor = System.Drawing.Color.Cyan
En fait, comme il n'y a pas d'instance de Form2, VB en crée une.

(Vb 2005, C'est comme en VB6)

On peut aussi faire comme en VB 2003 en instancier le formulaire, mais c'est plus complexe.


IX-B-3. Formulaire modale ou non modale:

Un formulaire modal est un formulaire qui, une fois ouvert, prend la main, interdit l'usage des autres fenêtres. Pour poursuivre, on ne peut que sortir de ce formulaire.

Exemple typique: une MessageBox est un formulaire modal, les fenêtres d'avertissement dans Windows sont aussi modales.

Pour ouvrir un formulaire modal, il faut utiliser la méthode .ShowDialog

Dim f As New Form2           

f.ShowDialog()
ou en VB 2005

form2.ShowDialog()
Noter, et c'est très important, que le code qui suit .showDialog est exécuté après la fermeture de la fenêtre modale.

Pour avoir un formulaire non modal faire

Dim f As New Form2      

f.Show() 
ou en VB 2005

form2.Show()
Dans ce cas le formulaire f s'ouvre, le code qui suit .Show est exécuté immédiatement, et il est possible de passer dans une autre fenêtre de l'application sans fermer f.

Instance multiple: si un bouton1 contient le code:

Private Button1_Click

Dim f As New Form2      

f.Show()      

End Sub
A chaque fois que l'on clique sur le bouton cela ouvre un formulaire: on peut en ouvrir plusieurs. On se retrouve avec X instances de Form2!!

Pour éviter cela:
  • Utiliser ShowDialog
  • Mettre Dim f As New Form2 dans la partie déclaration, ainsi il n'y aura qu'une instance de Form2. Le second click déclenche une erreur.

Class Form1

Dim f As New Form2   

 

Private Button1_Click   

    f.Show()      

End Sub

End Class

IX-B-4. Dénomination des formulaires après leur création:

En VB 2003 et 2005 (avec instanciation d'un formulaire)

Une procédure qui est dans Form1 crée un formulaire par

Private Buttonformsecondaire_Click ()    

    Dim formSecondaire As New Form2

End Sub
  • Dans le formulaire formSecondaire créé:
    Utiliser Me pour désigner le formulaire où on se trouve. (Form2 ou formSecondaire ne sont pas acceptés)

    Exemple:

    Me.Text= "Second formulaire" modifie le texte de la barre supérieure du formulaire

    Le formulaire formSecondaire pourra être fermé par Me.close() dans le code du bouton Quitter par exemple.

  • Hors du formulaire formSecondaire, dans la procédure où a été instancié le formulaire:
    Utiliser formSecondaire pour désigner le formulaire.

    Exemple:

    Si la fenêtre appelante veut récupérer des informations dans le formulaire formSecondaire (un texte dans txtMessage par exemple), il faudra écrire.

    Text=formSecondaire.txtMessage.Text

  • Par contre, hors de la procédure qui a créée le formulaire, formSecondaire n'est pas accessible car on a crée le formulaire dans une procédure: cette instance du formulaire n'est visible que dans cette procédure. Pour rendre un formulaire accessible partout on peut écrire Public formSecondaire As New Form2 dans la zone générale avant les procédures.
Exemple:

Class Form1

 

Sub MaRoutine()

    Dim formSecondaire As New Form2

    Text=formSecondaire.TextBox.Text

End Sub

 

Sub AutreRoutine()

..

End Sub

 

End Class
Dans la procédure MaRoutine() le formulaire formSecondaire est visible et formSecondaire.TextBox est utilisable, pas dans la procédure AutreRoutine(). En résumé: Attention donc, si vous instanciez un formulaire dans une procédure, elle sera visible et accessible uniquement dans cette procédure .

Cela parait évident car un formulaire est un objet comme un autre et sa visibilité obéit aux règles habituelles ( J'ai mis malgré tout un certains temps à le comprendre!!).

info Un formulaire est un objet et sa visibilité obéit aux règles habituelles: Il peut être instancié dans une procédure, un module, précédé de 'Public' ,'Private'.. ce qui permet de gérer son accessibilité.
En VB 2005, sans instanciation des formulaires:

Par contre en VB 2005, si vous dessinez Form2 et que vous tapez:

Private ButtonCreerFormSecondaire_Click()
    Form2.Show()
End sub
Vous pouvez utiliser dans Form1 les propriétés et contrôles de Form2 directement:

 Form2.ForeColor = System.Drawing.Color.Coral
 
La Classe Form2 étant public , on a toujours accès au formulaire et aux contrôles.

(Par contre, on n'a pas accès aux procédures évènements qui sont 'Private')

Un exemple:

Dans Form1 Button1 affiche le formulaire Form2 (directement sans instanciation).

Dans la procédure Button2_Click de Form1 on a accès au TextBox qui est dans Form2:


IX-B-5. Autres remarques sur les formulaires:


IX-B-5-a. Un formulaire est un objet:On peut ajouter à un formulaire des méthodes et des membres:

On a vu que, en fait, il y a création d'une Classe quand on dessine un formulaire, et bien comme dans un module de Classe (on verra cela plus loin), on peut ajouter des propriétés et des méthodes.

Pour ajouter une méthode à un formulaire, il faut créer une Sub Public dans le corps de la fenêtre:

Class Form1

Public Sub Imprime()

    Code d'impression

End Sub

End Class
Si une instance de la fenêtre se nomme F, F.Imprime() exécute la méthode Imprime (donc la sub Imprime())

De même, pour définir un membre d'un formulaire, il faut ajouter une variable 'public'.

Public Utilisateur As String
Permet d'utiliser en dehors du formulaire F.Utilisateur


IX-B-5-b. Exemple plus complet: Afficher un formulaire.

Autre problème : comment savoir si un formulaire existe, s'il n'existe pas le créer, s'il existe le rendre visible et lui donner la main :

        If f Is Nothing Then    'Si f=rien 

            f = New Form2

            f.ShowDialog()

        Else

            If f.Visible = False Then

                f.Visible = True

            End If

            f.Activate()

        End If
Autre solution plus complète gérant aussi la taille du formulaire:

Si le formulaire existe et n'a pas été 'disposed'(détruit), le mettre à la taille normale et en avant.

        If Not IsNothing(F) Then
            'Si on en a pas déjà disposé
            If Not F.IsDisposed Then
                F.WindowState = FormWindowState.Normal  ' Optional
                F.BringToFront()  '  Optional
            Else
                F = New Form3
                F.Show()
            End If
        Else
            F = New Form3
            F.Show()
        End If
(Merci Michel de Montréal)


IX-B-5-c. Récupération d'information par DialogResult.

On ouvre un formulaire modal, comment, après sa fermeture, récupérer des informations sur ce qui s'est passé dans ce formulaire modale?

Par exemple, l'utilisateur a t-il cliqué sur le bouton Ok ou le bouton Cancel pour fermer le formulaire modale?

Pour cela on va utiliser une propriété DialogResult des boutons, y mettre une valeur correspondant au bouton, quand l'utilisateur clique sur un bouton, la valeur de la propriété DialogResult du bouton est assignée à la propriété DialogResult du formulaire, on récupère cette valeur à la fermeture du formulaire modal.

Dans le formulaire modal Form2 on met

 ButtonOk.DialogResult= DialogResult.ok

 

 ButtonCancel.DialogResult= DialogResult.Cancel
Dans le formulaire qui appelle:

Form2.ShowDialog()

If form2.DialogResult= DialogResult.ok then

    'l'utilisateur a cliqué sur le bouton ok

End if
Remarque:
  1. On utilise comme valeur de DialogResult les constantes de l'énumération DialogResult:DialogResult.ok .Cancel .No .Yes .Retry .None
  2. Si l'utilisateur clique sur la fermeture du formulaire modal (bouton avec X) cela retourne DialogResult.cancel
  3. on peut aussi utiliser la syntaxe: If form2.ShowDialog(Me) = System.Windows.Forms.DialogResult.OK Then qui permet en une seule ligne d'ouvrir form2 et de tester si l'utilisateur a cliqué sur le bouton ok de form2.
  4. La fermeture du formulaire modal par le bouton de fermeture ou l'appel de la méthode Close ne détruit pas toujours le formulaire modal, il faut dans ce cas utiliser la méthode Dispose pour le détruire.

IX-B-5-d. Bouton par défaut.

Parfois dans un formulaire, l'utilisateur doit pouvoir, valider (taper sur la touche 'Entrée') pour accepter et quitter rapidement le formulaire (c'est l'équivalent du bouton 'Ok') ou taper 'Echap' pour sortir du formulaire sans accepter (c'est l'équivalent du bouton 'Cancel').

Il suffit pour cela de donner aux propriétés AcceptButton et CancelButton du formulaire,le nom des boutons ok et cancel qui sont sur la feuille.

form1.AcceptButton = buttonOk
form1.CancelButton = buttonCancel
Si l'utilisateur tape la touche 'Echap' la procédure buttonCancel_Click est exécutée.


IX-C. bis Faire communiquer les formulaires.

Rappel:Formulaire=fenêtre
Rappel:Formulaire=fenêtre
Comment faire communiquer 2 formulaires?+++
  1. Comment à partir d'un formulaire consulter un objet d'un autre formulaire?
  2. Comment à partir du second formulaire connaître le formulaire propriétaire?
  3. Les formulaires ouverts en VB 2005
Cette question est fréquemment posée et créée beaucoup de problèmes!!

Soit Form1 et Form2.


IX-C-1. A- Comment à partir du premier formulaire consulter un objet du second formulaire?


IX-C-1-a. 1-En VB 2003 (en VB 2005) si on instancie le formulaire

Reprenons toujours le même exemple: le premier formulaire (Class Form1) crée une instance de Form2 (L'utilisateur du programme clique sur ButtonCreerformsecondaire de Form1) cela crée formSecondaire. formSecondaire contient un textbox nommé TextBox2. L'utilisateur saisi un texte dans le textbox2 et quitte formsecondaire. Comment Form1 peut-il récupérer TextBox2.text et l'afficher dans un label1

 Class Form1
Contient Button1 "Créer Form2"

Contient Label1

 Class Form2  instance: formsecondaire
Contient TextBox2

Contient Button2 "Quitter"

IX-C-1-b. 1-Première solution:

Pour qu'un formulaire puisse utiliser les objets d'un autre formulaire, il faut que le second formulaire soit visible.

Créer un formulaire formSecondaire en utilisant la Classe Form2.

Class Form1

Sub buttonCreerformsecondaire_Click

Dim formSecondaire As New form2 ()    'On crée formSecondaire

formSecondaire.ShowDialog()           'On ouvre formSecondaire

label1.Text=formSecondaire.TextBox2.Text 'On récupère le texte de TextBox1

End Sub

 

End Class
formSecondaire n'est visible QUE dans button1_Click+++

Les contrôles de Form2 sont Public ce qui permet d'y avoir accès.

On peut se poser la question de savoir si après ShowDialog le formulaire modal formSecondaire existe encore?

La ruse c'est de mettre dans le code du bouton Quitter de Form2 Me.Hide() pour rendre la fenêtre Form2 invisible mais accessible (et pas Me.Close() qui détruirait la fenêtre, le contrôle txtMessage et son contenu).

Dim formSecondaireAs New Form2()

formSecondaire.ShowDialog()

label1.Text=formSecondaire.TextBox2.Text

formSecondaire.Close()

Une fois que le texte à été récupéré, on faire disparaître le formulaire formSecondaire.

En réalité, curieusement, il semble que les propriétés de formSecondaire soient accessibles même après un Close!! Cela vient du fait que, bien que le formulaire soit fermé, il n'est pas encore détruit.


Si vous voulez créer un formulaire Form2 qui soit visible dans la totalité d'un formulaire Form1, il faut l'instancier dans la partie déclaration du formulaire Form1:

Class Form1

    Public formSecondaire As New Form2()

    

    Sub buttoncreerformsecondaire_Click

formSecondaire.ShowDialog()           'On ouvre formSecondaire

label1.Text=formSecondaire.TextBox2.Text 'On récupère le texte de TextBox1

    End Sub
    

End Class
On peut ainsi l'ouvrir par formSecondaire.ShowDialog() dans une procédure et lire une zone texte dans une autre procédure.


IX-C-1-c. 2 - Seconde solution.

Si vous voulez créer un formulaire qui soit visible dans la totalité du programme et dont les contrôles ou propriétés soient accessibles par l'ensemble du programme, il faut l'instancier dans un module standard (Les puristes vont pas aimer!!):

Module MonModule

    Public formSecondaire As New Form2().

End Module

On peut l'ouvrir  n'importe ou!!

Class Form3

Sub Buttoncreerformsecondaire_Click

    formSecondaire.ShowDialog()

End Sub

 

Sub Button2_Click

    label1.Text= formSecondaire.TextBox2.Text

End Sub

 


End Class
On peut avoir accès au TextBox2 n'importe ou!!

C'est un objet 'Public' et on n'aime pas bien!!!


IX-C-1-d. 3 -Troisième solution:

On peut créer dans le second formulaire un objet Public Shared:

Class Form2

Public Shared MonTextBox As TextBox

Private Sub Button2_Click 'Bouton quitter

MonTextBox = TextBox1    'On affecte à l'objet MonTexBox le TextBox1

Me.Close()

End Sub

End Class
Dans Form1

Class Form1

Sub buttoncreerformsecondaire_Click

Dim formSecondaire As New form2 ()    'On crée formSecondaire

formsecondaire.ShowDialog()

Label1.Text = formsecondaire.MonTextBox.Text()

End Sub

End Class
Noter que contrairement aux exemples donnés par certains sites, il faut bien écrire: formsecondaire.MonTextBox.Text() et pas Form2.MonTextBox.Text() du moins en VS 2003.

Cette troisième solution a le même principe que la première, en plus compliqué!!

On peut simplement retenir que si formsecondaire est visible, seuls ses membres publiques sont visibles bien entendu: par exemple ses propriétés, ses contrôles, les procédures publiques, PAS les procédures événementielles qui sont privées.

Dans le même ordre d'idée, on peut créer une Property Public:

Class Form2

Public ReadOnly Property LeText() As String
    Get
        Return TextBox2.Text
    End Get
End Property
End Class

Class Form1

Sub button1_Click

Dim formSecondaire As New form2 ()    'On crée formSecondaire

formsecondaire.ShowDialog()

Label1.Text = formsecondaire.LeText   'On utilise la property

End Sub

End Class
Même conclusion, mais il faut toujours utiliser formsecondaire qui doit être visible , c'est ça l'important!!


IX-C-1-e. 4 -Quatrième solution:

Créer une variable ou une Classe 'Public' (dite 'Globale') et y faire transiter les données :

Module MonModule

    Public BAL As String     'Variable Public Boite aux lettres

End Module

Class Form2

Private Sub Button2_Click 'Bouton quitter

BAL = TextBox2.Text    'On met TextBox1.Text dans BAL

Me.Close()

End Sub

End Class

 

Class Form1

Sub Button1_Click

    formSecondaire.ShowDialog()

    label1.Text= BAL    'On récupère ce qui est dans BAL

End Sub

 

End Class
Cela a tous les inconvénients: c'est une variable globale, source d'erreur, n'importe quel formulaire peut écrire dans BAL...
Mais c'est simple et cela marche bien.


IX-C-1-e-i. 2-En VB 2005, sans instanciation de formulaire:
Par contre en VB 2005, si vous dessinez Form2 et que vous tapez:

Private ButtonCreerFormSecondaire_Click()
    Form2.Show()
End sub
Vous pouvez utiliser dans Form1 les propriétés et contrôles de Form2 directement:

 Label1.Text = Form2.TextBox2.Text
La Classe Form2 étant public , on a toujours accès au formulaire et aux contrôles.

(Par contre, on n'a pas accès aux procédures évènements qui sont 'Private'; on peut d'ailleurs les mettre 'Public' pour y avoir accès)


IX-C-2. B- Comment à partir du formulaire 'secondaire' connaître le formulaire 'propriétaire'?

Exemple: Comment savoir quel formulaire a ouvert le formulaire en cours?

ShowDialog possède un argument facultatif, owner, qu'on peut utiliser afin de spécifier une relation 'propriétaire'-'formulaire en cours'. Par exemple, lorsque le code de votre formulaire principal ouvre un formulaire, vous pouvez passer Me comme propriétaire de la boîte de dialogue, afin de désigner votre formulaire principal comme propriétaire, comme le montre le code de l'exemple suivant :

Dans Form1

Dim formSecondaire As New Form2 

f.ShowDialog(Me)
Dans Form2
On peut récupérer le nom du 'propriétaire', qui a ouvert la fenêtre.
Il est dans Owner,et on peut par exemple afficher son nom.

Par exemple:

    Label1.text=Me.Owner.ToString
Cela affiche: NomApplication.NomFormulaire,Texte de la barre de titre.

Owner a toutes les propriétés (Name, Location, Controls..) d'un formulaire car il hérite de Form. , mais on ne peut pas consulter les contrôles de Owner directement. Il faut d'abord caster owner qui est une Form en Form1, ensuite on peut avoir accès aux contrôles de Form1.

Dim f As Form1 = CType(Me.Owner, Form1)

Label1.Text() = f.Button1.Text
Comment obtenir le nom du formulaire propriétaire? Autre méthode.

Une autre méthode consiste à surcharger le constructeur de la Form2 afin qu'il accepte un paramètre qui indique le propriétaire ( nom de l'instance de Form1):

Dans Form1: Lors de l'instanciation de la form2 il faut écrire:

Dim FormSecondaire As New Form2(Me) 
FormSecondaire .ShowDialog(Me) 'affichage modal de la form2
Dans Form2:

 Private FormProp As Form1
    Public Sub New(ByVal NomForm As Form1) 
        MyBase.New() 
        FormProp = NomForm 
        'This call is required by the Windows Form Designer. 
        InitializeComponent() 

        'Add any initialization after the InitializeComponent() call 

    End Sub
On crée donc dans Form2 une variable FormProp qui indique la form propriétaire.

Pour appeler une méthode de form1 à partir de FormSecondaire (Form2):

FormProp.MaRoutine()

L'inconvénient de toutes ces méthodes est qu'il faut connaître la classe du formulaire propriétaire (Form1 ici).


IX-C-3. C- Les formulaires ouverts en VB 2005

- My.Application.OpenForms contient les formulaires ouverts.

Afficher le texte contenu dans la barre de titre du formulaire nommé 'Form3'.

MyTextBox.Text= My.Application.OpenForms("Form3")
Afficher le texte contenu dans la barre de titre du premier formulaire ouvert.

MyTextBox.Text= My.Application.OpenForms(0)
Exemple: rajouter le texte 'ouvert' à la barre de tache des formulaires ouverts:

For Each F As System.Windows.Forms.Form In My.Application.OpenForms
F.Text += "[ouvert]"
Next

- My.Forms contient tous les formulaires.

Afficher le texte contenu dans la barre de titre du formulaire Form1.

MyTextBox.Text= My.Forms.Form1.Text
Remarquons qu'il est interdit d'utiliser My.Forms.Form1 si on est dans Form1 .(il faut utiliser Me)


-Différence?

Dim f As New Form1

f.Text = "hello"

f.Show()

TextBox1.Text = My.Forms.Form1.Text 

'Affiche 'Form1' qui est le texte de la barre par défaut en design (celui de la Classe Form1)

 

TextBox2.Text = My.Application.OpenForms("Form1").Text    

'Affiche 'hello' qui est le texte de l'instance f

IX-D. Traiter les erreurs.

Il y a plusieurs types d'erreurs.

Les erreurs de syntaxe.

Les erreurs d'exécution.

Les erreurs de logique.

Voir la vidéo au format 'Flash': ou au format AVI en Visual Basic 2005


IX-D-1. Les erreurs de syntaxe:

Elle surviennent en mode conception quand on tape le code:

Exemples:

A+1=B            'Erreur dans l'affectation

f.ShowDialogue   'Faute de frappe, il fallait taper ShowDialog

2 For... et un seul Next

Dim i As Integer: Label.Text= i  'Affectation d'un Integer à une propriété text qui attend une String.

....
Dans ces cas VB souligne en ondulé bleue le code. Il faut mettre le curseur sur le mot souligné, l'explication de l'erreur apparaît.

Exemple: Propriété Text d'un label mal orthographiée:

Il faut les corriger immédiatement en tapant le bon code (ici 'Text').


En bas il y a aussi une fenêtre; "liste des erreurs":

Elle affiche tous les problèmes; pour atteindre le code correspondant à une de ces erreurs, double-cliquez sur une des lignes de la liste.

En VB 2005 un panneau d'exclamation permet d'ouvrir une fenêtre proposant le moyen de corriger l'erreur:

Ici on met dans la propriété text d'un label un Integer, alors qu'il faut mettre une String (Option Strict est probablement égal à On); Vb montre la correction : CStr(i) converti i en String.


Si vous exécuter le programme dans l'IDE alors qu' il y a un problème , VB demande si on veut exécuter la dernière génération réussie:

Si vous tapez 'oui' VB exécute la dernière version qui a été générée correctement, mais PAS de code source actuel qui contient des erreurs!!


IX-D-2. Les erreurs d'exécution:

Elle surviennent en mode Run ou lors de l'utilisation de l'exécutable:
une instruction ne peut pas être effectuée.

Quand on utilise l'exécutable:Le logiciel s'arrête brutalement, c'est très gênant!!

Pour l'utilisateur c'est un 'BUG'

Il y a levée d'une exception, voila ce que cela donne dans l'IDE:

Exemple: je tente d'accéder à un élément d'un tableau qui n'existe pas (l'indice est trop grand cela entraîne une exception 'OutOfRange').

Le logiciel s'arrête, l'instruction qui a planté apparaît en jaune et VB donne une explication.

L'erreur est:
  • Soit une erreur de conception.
    Exemple:

    Ouvrir un fichier qui n'existe pas (On aurait du vérifier qu'il existe avant de l'ouvrir!).

    Division par zéro.

    Utiliser un index d'élément de tableau supérieur au nombre d'élément:

    Envoyer un mauvais paramètre à une fonction.

  • Soit une erreur de l'utilisateur.
    Exemple: On lui demande de taper un chiffre, il tape une lettre ou rien puis valide.

    Il faut toujours vérifier ce que fait l'utilisateur et prévoir toutes les possibilités.

    Exemple: si je demande à l'utilisateur de tapez un nombre entre 1 et 10, il faut:

    Vérifier qu'il a tapé quelque chose.

    Que c'est bien un chiffre (pas des lettres).

    Que le chiffre est bien entre 1 et 10.

    Sinon il faudra reposer la question.

A-Capter les erreurs avec Try Catch Finally:

Avant l'instruction supposée provoquer une erreur indiquez: Essayer (Try), si une erreur se produit Intercepter l'erreur (Catch) puis poursuivre (après Finally)

Try

    Instruction susceptible de provoquer une erreur.

Catch

    Traitement de l'erreur

Finally

    Code toujours exécuté    

End Try
Il faut pour que cela fonctionne avoir tapé au préalable Imports System.IO

Il est possible d'utiliser Catch pour récupérer l'objet 'Exception' qui est généré par l'erreur.

Catch ex As Exception
Cet objet Exception à des propriétés:

Message qui contient le descriptif de l'erreur.

Source qui contient l'objet qui a provoqué l'erreur....

ex.Message contient donc le message de l'erreur.

Cet objet Exception ( de l'espace IO) à aussi des classes dérivées: StackOverFlowException; FileNotFoundExeption; EndOfStreamExeption; FileLoadExeption; PathTooLongExeption. Enfin une exception peut provenir de l'espace System: ArgumentExceptions; ArithmeticException; DivideByZeroExeception.....

Il est possible d'écrire plusieurs instructions Catch avec pour chacune le type de l'erreur à intercepter. (Faisant partie de la classe Exceptions)

Exemple:

On ouvre un fichier par StreamReader , comment intercepter les exceptions suivantes?

Répertoire non valide

Fichier non valide

Autre.

Try

    sr= New StreamerReader (NomFichier)

Catch ex As DirectoryNotFoundException

    MsgBox("Répertoire invalide")

Catch ex As FileNotFoundException

    MsgBox("Fichier invalide")

Catch ex As Exception

    MsgBox(ex.Message)

End Try
Noter que le dernier Catch intercepte toutes les autres exceptions.

On peut encore affiner la gestion par le mot clé When qui permet une condition.

Catch ex As FileNotFoundException

             When ex.Message.IndexOf ("Mon Fichier.txt") >0

                MsgBox ("Impossible d'ouvrir Mon Fichier.txt")
Si le texte "Mon Fichier.txt" est dans le message, affichez que c'est lui qui ne peut pas être ouvert.

Exit Try permet de sortir prématurément.


B-Capter les erreurs avec On error :

On peut aussi utiliser la méthode Visual Basic:

On Error Goto permet en cas d'erreur de sauter à une portion de code traitant l'erreur.

On peut lire le numéro de l'erreur qui s'est produite, ce numéro est dans Err.Number.

Err.Description contient le texte décrivant l'erreur. Err.Source donne le nom de l'objet ou de l'application qui a crée l'erreur.

Quand l'erreur est corrigée, on peut revenir de nouveau à la ligne qui a provoqué l'erreur grâce à Resume ou poursuivre à la ligne suivante grâce à Resume Next

Exemple:

On Error GoTo RoutinedErreur 'Si une erreur se produit se rendre à 'RoutineErreur'
Dim x As Integer = 33
Dim y As Integer = 0
Dim z As Integer
z = x / y ' Crée une division par 0 !!

RoutinedErreur: ' La Routine d'erreur est ici (remarquer  ':').
Select Case Err.Number ' On regarde le numéro de l'erreur.
Case 6 ' Cas : Division par zéro interdite
    y = 1 ' corrige l'erreur.
Case Else
    ' autres erreurs....
End Select
Resume ' Retour à la ligne qui a provoqué l'erreur.
Pour arrêter la gestion des erreurs il faut utiliser:

On Error Goto 0
Parfois on utilise une gestion hyper simplifiée des erreurs:

Si une instruction 'plante', la sauter et passez à l'instruction suivante, pour cela on utilise:

On Error Resume Next

Exemple: On veut effacer un fichier

On Error Resume Next

Kill (MonFichier)

On Error goto 0
Ainsi , si le fichier n'existe pas , cela ne plante pas (on aurait pu aussi vérifier qu'il existe avant de l'effacer).

On Error Gosub n'existe plus.

info On Error est moins performant que Try Catch et surtout il ralentit le code+++: si nécessaire utiliser Try Catch.
En résumé: pour éviter les erreurs d'exécution il est donc possible:

- D'écrire du code gérant le problème, contrôlant les actions de l'utilisateur..

Exemple: on demande à l'utilisateur de saisir un nombre dans TextBox1 puis de cliquez sur Button3

Si l'utilisateur a tapé une lettre au lieu d'un chiffre, le prévenir

Private Sub Button3_Click 

If String.IsNullOrEmpty(TextBox1.Text) Then 'on teste si l'utilisateur a tapé quelque chose

 MsgBox("Tapez quelque chose")

Else

 If Not IsNumeric(TextBox1.Text) Then 'on teste si l'utilisateur a tapé du numérique

    MsgBox("Tapez un chiffre")

 End If

End If

End Sub

- Une autre alternative est de capter l'erreur.

Exemple: on demande à l'utilisateur de saisir un nombre dans TextBox1 puis de cliquez sur Button3

On converti le texte tapé en Integer, on sait que si la conversion est impossible (pas de texte tapé ou texte non numérique) une exception invalidCastException sera levée et le programme 'plantera'. On écrit donc avant l'instruction Ctype un Try pour capter l'erreur:

Tester s'il y a une erreur, s'il y a erreur, la capter.

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

Dim i As Integer

Try

    i = CType(TextBox1.Text, Integer)

Catch

    MsgBox("saisir un nombre")

End Try

End Sub

IX-D-3. Les erreurs de logique:

Le programme fonctionne, pas d'erreurs apparentes, mais les résultats sont erronés, faux.

Il faut faire des tests dans les conditions réelles avec des données courantes, mais aussi avec des données remarquables (limites supérieures, inférieures, cas particuliers..) pour voir si les résultats sont cohérents et exacts.

Une fois l'erreur trouvée, il faut en déterminer la cause et la corriger.

Ou bien elle est évidente à la lecture du code ou bien elle n'est pas évidente et c'est l'horreur.

Dans ce dernier cas il faut analyser le fonctionnement du programme pas à pas, instruction par instruction en surveillant la valeur des variables.(voir la rubrique déboguage )

Les erreurs les plus communes sont:

Utilisation d'un mauvais nom de variable (La déclaration obligatoire des variables évite cela)
Erreur dans la portée d'une variable.
Erreur dans le passage de paramètres (Attention au By Val et By Ref)
Erreur dans la conception de l'algorithme.
...

Quelques règles permettent de les éviter: voir Règles de bonne programmation.


IX-D-4. Les Tests:

Il faut donc toujours tester le fonctionnement du programme de multiples fois:

On fera des:
  • Tests unitaires: qui testerons les procédures, les classes une à une sans tester la totalité du programme.
  • Tests de composants et d'intégration: qui testeront plusieurs procédures ou classes fonctionnant ensemble.
  • Tests de régression: c'est la répétition des test précédents afin de voir si une modification ou un ajout n'entraîne pas de nouvelles erreurs qui n'existaient pas.
  • Tests système: test sur le logiciel dans sa version finale.
Les tests détecterons les erreurs, le déboguage permettra de trouver la cause et de corriger l'erreur.

info Il faut avoir une armée de Bêta-testeurs.

IX-E. Créer une fenêtre 'multi document'.

Comment créer un programme MDI (Multi Document Interface) en VB 2003 puis en VB 2005 ?


IX-E-1. Comprendre les programmes MDI :

L'exemple de Word : la fenêtre principale (fenêtre MDI) contient les menus en haut, on peut ouvrir plusieurs documents dans des fenêtres filles.

Ci dessous l'exemple de LDF (Programme de comptabilité écrit par l'auteur):

On a une fenêtre MDI (conteneur) contenant 2 fenêtres filles affichant chacune une année de comptabilité.
Dans VB.NET, un MDIForm (fenêtre principale MDI) est une fenêtre quelconque dont la propriété :

IsMDIContainer = True.

Dans la fenêtre fille, la propriété MDIParent indique le conteneur (C'est à dire le nom de la fenêtre MDI) .


Les applications MDI peuvent avoir plusieurs conteneurs MDI.

Une fenêtre principale MDI peut contenir plusieurs fenêtres filles de même type ou de type différente.


IX-E-2. A - En VB 2003


IX-E-2-a. Création de la fenêtre conteneur parent :

Exemple d'un programme MDI.

On va créer une Form1 qui est le conteneur.

Une Form2 qui est la fenêtre fille.

Dans Form1 le menu principal contient la ligne '&Nouvelle' qui crée une nouvelle instance de la fenêtre fille.

Créer la fenêtre Form1 :

Dans la fenêtre Propriétés, affectez la valeur True à la propriété IsMDIContainer. Ce faisant, vous désignez la fenêtre comme le conteneur MDI des fenêtres enfants.

Remarque Affecter la valeur Maximized à la propriété WindowState, car il est plus facile de manipuler des fenêtres MDI enfants lorsque le formulaire parent est grand. Sachez par ailleurs que le formulaire MDI parent prend la couleur système (définie dans le Panneau de configuration Windows).

Ajouter les menus du conteneur :

A partir de la boîte à outils, faire glisser un contrôle MainMenu sur le formulaire. Créer un élément de menu de niveau supérieur en définissant la propriété Text avec la valeur &File et des éléments de sous-menu appelés &Nouvelle et &Close. Créer également un élément de menu de niveau supérieur appelé &Fenêtre.

Dans la liste déroulante située en haut de la fenêtre Propriétés, sélectionnez l'élément de menu correspondant à l'élément &Fenêtre et affectez la valeur true à la propriété MdiList. Vous activez ainsi le menu Fenêtre qui permet de tenir à jour une liste des fenêtres MDI enfants ouvertes et indique à l'utilisateur par une coche la fenêtre enfant active.

Il est conseillé de créer un module standard qui contient une procédure Main qui affiche la fenêtre principale:

Module StandartGénéral

Public FrmMDI as Form1

Sub Main()

    FrmMDI.ShowDialog()

End sub

End Module
Noter bien que FrmMDI est donc la fenêtre conteneur et est Public donc accessible à tous.


IX-E-2-b. Création des fenêtres filles :

Pour créer une fenêtre fille, il suffit de donner à la propriété MDIParent d'une fenêtre le nom de la fenêtre conteneur.

Dessiner dans Form2 les objets nécessaire dans la fenêtre fille.

Comment créer une instance de la fenêtre fille à chaque fois que l'utilisateur clique sur le menu '&Nouvelle'?

En premier lieu, déclarez dans le haut du formulaire Form1 une variable nommée MDIFilleActive qui contient la fenêtre fille active.

Dim MDIFilleActive As Form2
La routine correspondant au MenuItem &Nouvelle (dans la fenêtre MDI) doit créer une instance de la fenêtre fille :

Protected Sub MDIChildNouvelle_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem2.Click

   MDIFilleActive = New Form2()

   'Indique à la fenêtre fille son ‘parent'.

   MDIFilleActive.MdiParent = Me

   'Affiche la fenêtre fille

   MDIFilleActive.Show()

End Sub

IX-E-2-c. Comment connaître la fenêtre fille active?

Quand on en a ouvert plusieurs?

La fenêtre fille active est dans Me.ActiveMdiChild du conteneur

Comment voir s'il existe une fenêtre active?

If Not Me.ActiveMdiChild Is Nothing then    'elle existe
En mettant dans la variable MDIFilleActive la fenêtre active, on est sûr de l'avoir toujours à disposition: pour cela dans la procédure Form1_MdiActivate de la fenêtre MDI (qui se produit à chaque fois que l'on change de fenêtre fille) je récupère Me.ActiveMdiChild qui retourne la fenêtre fille active.

Dans Form1

Private Sub Form1_MdiChildActivate..

    MDIFilleActive=Me.ActiveMdiChild

End Sub
warning Il faut comprendre que peut importe le nom de la fenêtre fille active, on sait simplement que la fenêtre fille active est dans MIDFilleActive, variable que l'on utilise pour travailler sur cette fenêtre fille.

IX-E-2-d. Comment avoir accès aux objets de la fenêtre fille à partir du conteneur?

De la fenêtre conteneur j'ai accès aux objets de la fenêtre fille par l'intermédiaire de la variable MDIFilleActive précédemment mise à jour; par exemple le texte d'un label:

 MDIFilleActive.label1.text
Comment avoir accès à des éléments de cette fenêtre fille, une sub Affichetotaux par exemple à partir de ActiveMdiChild:

Si me tape Me.ActiveMdiChild.AfficheTotaux cela plante!! (car ActiveMdiChild est une instance de la classe Form)

Il faut écrire: CType(ActiveMdiChild, Form2).Affichetotaux() (car il faut convertir ActiveMdiChild en classe Form2)


IX-E-2-e. Comment parcourir toutes les fenêtres filles?

La collection MdiChildren contient toutes les fenêtres filles, on peut les parcourir:

Dim ff As Form2

For Each ff In Me.MdiChildren

...

Next
Cela est valable s'il n'y a qu'un type de formulaire permettant de créer des formulaires fils (Form2 par exemple)

Mais si on a 2 formulaires Form1 et Form2 cela se complique.

dim i_form as Form ' on utilise une variable Form :formulaire 

dim i_form1 as form1
dim i_form2 as form2

For Each i_form  In Me.mdichildren
    if typeof  i_form is form2 then
        i_form2 = ctype(i_form,form2)
        msgbox i_form2.property_du_form2
    end if

if typeof  i_form is form1 then
        i_form1 = ctype(i_form,form1)
        msgbox i_form2.property_du_form1
    end if
next
Merci Gaël.


IX-E-2-f. Comment fermer toutes le fenêtres filles?


Dim form As Form

For Each form In Me.MdiChildren

form.Close()

Next

IX-E-2-g. Comment avoir accès aux objets du conteneur à partir de la fenêtre fille?

En utilisant Me.MdiParent qui contient le nom du conteneur.

Dans la fenêtre fille le code Me.MdiParent.text ="Document 1" affichera 'Document 1' dans la barre de titre du conteneur.


IX-E-2-h. Comment une routine du module conteneur appelle une routine dans la fenêtre fille active?

Si une routine public de la fenêtre fille se nomme Affiche, on peut l'appeler par:

MDIFilleActive.Affiche()
Il n'est pas possible d'appeler les évènements liés aux objets.


IX-E-2-i. Agencement des fenêtres filles :

La propriété LayoutMdi de la fenêtre conteneur modifie l'agencement des fenêtres filles.

0 - MdiLayout.Cascade
1 - MdiLayout.TileHorizontal
2 - MdiLayout.TileVertical
3 - MdiLayout.ArrangeIcons

Exemple:

Le menu Item Cascade met les fenêtres filles en cascade.

Protected Sub CascadeWindows_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)

   Me.LayoutMdi(System.Windows.Forms.MdiLayout.Cascade)

End Sub

IX-E-3. A - En VB 2005

90% du travail est fait automatiquement: c'est merveilleux!!

Dans l'explorateur de solution: Click droit sur le nom du programme ('mdi' ici):

Dans le menu, passer par 'Ajouter' puis 'Formulaire Windows':

Cliquer sur 'MDI Parent Form' ('Formulaire Parent MDI')

On obtient un formulaire MDI parent avec les menus, la barre d'icône, d'état, les menus déroutants avec image:

(Le logiciel a rajouté les 4 outils en bas, nécessaire pour réaliser l'interface.)

Le code qui génère les formulaires enfants est automatiquement crée:

Public Class MDIParent1

Private Sub ShowNewForm(ByVal sender As Object, ByVal e As EventArgs) Handles NewToolStripMenuItem.Click, 
	_NewToolStripButton.Click, NewWindowToolStripMenuItem.Click

' Créer une nouvelle instance du formulaire enfant.

Dim ChildForm As New System.Windows.Forms.Form

' Make it a child of this MDI form before showing it.

ChildForm.MdiParent = Me

m_ChildFormNumber += 1

ChildForm.Text = "Window " & m_ChildFormNumber

ChildForm.Show()

End Sub

Private Sub ExitToolsStripMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles ExitToolStripMenuItem.Click

'Quitter l'application

Global.System.Windows.Forms.Application.Exit()

End Sub

Private Sub CascadeToolStripMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles CascadeToolStripMenuItem.Click

'Positionnement des formulaires enfant

Me.LayoutMdi(MdiLayout.Cascade)

End Sub

Private Sub TileVerticleToolStripMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles TileVerticalToolStripMenuItem.Click

Me.LayoutMdi(MdiLayout.TileVertical)

End Sub

Private Sub TileHorizontalToolStripMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles TileHorizontalToolStripMenuItem.Click

Me.LayoutMdi(MdiLayout.TileHorizontal)

End Sub

Private Sub ArrangeIconsToolStripMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles ArrangeIconsToolStripMenuItem.Click

Me.LayoutMdi(MdiLayout.ArrangeIcons)

End Sub

Private Sub CloseAllToolStripMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles CloseAllToolStripMenuItem.Click

' Ferme tous les formulaires enfant

For Each ChildForm As Form In Me.MdiChildren

ChildForm.Close()

Next

End Sub

Private m_ChildFormNumber As Integer = 0

End Class

IX-F. Travailler sur les dates, les heures, sur le temps.

On a vu qu'il existe un type de variable 'DateTime' pour gérer les dates et heures, comment l'utiliser ?

Nous verrons aussi comment utiliser les Timers pour déclencher des évènements à intervalle régulier,

Enfin comment perdre du temps?

Une variable DateTime Contient une date plus l'heure.

Elle occupe 8 octets.(64 bits)

Elle peut contenir une date comprise entre le 1er janvier de l'année 1 et le 31 décembre 9999 et une heure comprise entre 0:00:00 (minuit) et 23:59:59.

En fait ce qui est codé dans la variable DateTime est le nombre de graduations ( Une graduation= 100 nanosecondes.) écoulées à compter de minuit, le 1er janvier de l'année 1 jusqu'a la date codée.

Nb: DateTime fait partie d'une Classe .Net , il existe aussi un type nommé Date qui fait partie de Visual Basic, qui n'est pas une classe donc, mais qui est équivalent à DateTime.

Donc DateTime est équivalent à Date.


IX-F-1. Définir une date, une heure

A - Pour définir une valeur DateTime en utilisant un littéral: elle doit être placée entre des signes (#) et son format doit être de type d/m/yyyy, par exemple #31/5/1998#.

Dim  dateNaissance As DateTime

dateNaissance= #02/12/1951#
B - Autre manière de saisir une date, une heure:

Dim dateNaissance As New System.DateTime(1996, 6, 3, 22, 15, 0)    

'Année, mois, jour, heure, minute, seconde, et éventuellement millisecondes)
Ici on a utilisé le constructeur.

C -Troisième méthode:

On peut saisir une date dans une string puis convertir:

DateNaissance = CDate("02/12/1951")
CDate converti donc une chaîne en dateTime. On peut aussi utiliser Ctype:

Dim dateNaissance As Date = Ctype("01/12/2005", Date)
IsDate (objet) permet de vérifier si objet est convertible en date.

IsDate retourne True si l'expression est de type Date ou est une chaîne convertible en type Date ; sinon, elle retourne False.

Cela permet de vérifier, après une saisie d'une string par exemple, si l'utilisateur a bien tapé des chiffres valides et même si la date est valide ("31/02/1945" n'est pas valide).

Bizarrerie= "12/2005" est considéré comme une date valide et équivalente à "01/12/2005"!! Pas de vérification des 2 '/'.

If IsDate( MyString) Then..
Exemple de Microsoft:

Dim MyDate, YourDate As DateTime
Dim NoDate As String
Dim D As Boolean
MyDate = CDate("12 Février, 1969")
YourDate = #2/12/1969#
NoDate = "Hello"
D = IsDate(MyDate) ' Retourne True.
D = IsDate(YourDate) ' Retourne True.
D = IsDate(NoDate) ' Retourne False.

IX-F-2. Afficher une date, une heure.

Pour afficher les dates et heures simplement, il suffit d'utiliser .ToString

MsgBox(DateNaissance.ToString)    'Affichera  02/12/1951 11:00:00
C'est le format utilisé par l'ordinateur (en fonction du pays)

ToString peut comporter des arguments qui formatent l'affichage:

Voici quelques codes de formatage:

d        affiche le jour                           2

dd       affiche le jour sur 2 chiffres            02

ddd      affiche le jour abrégé                    Dim.

dddd     affiche le jour complet                   Dimanche

M        affiche le mois                           12

MM       affiche le mois sur 2 chiffres            12

MMM      affiche le mois abrégé                    déc

MMMM     affiche le mois complet                   décembre

y, yy, yyyy affiche 1 à 2 chiffres, deux chiffres ou quatre chiffre     51, 51, 1951

H      affiche l'heure  sur un ou deux chiffres (format 24h)

HH     affiche l'heure sur 2 chiffres

h et hh font de même mais avec un format 12 h.

t, tt  affiche l'heure en format 12h  plus A ou P (pour matin, après midi)

m, mm, s, ss, f, ff font de même pour les minutes, secondes et millisecondes.

: et / sont les séparateurs heure et date.
Exemple:

MsgBox(DateNaissance.ToString("dddd d MMMM yyyy"))    'Affichera  Dimanche 2 décembre 1951

MsgBox(DateNaissance.ToString("hh:mm")    'Affichera  11:00

MsgBox(DateNaissance.ToString("d/MM/yy")    'Affichera  02/12/51 

MsgBox(DateNaissance.ToString("%h)    'Affichera  11   le caractère % est utilisé quand on affiche une seule donnée.
On peut enfin utiliser les méthodes de la classe DateTime!!

DateNaissance.ToLongDateString        'dimanche 02 décembre 1951

DateNaissance.ToShortDateString       '02/12/1951

DateNaissance.ToLongTimeString        '11:00:00

DateNaissance.ToShortTimeString       '11:00

IX-F-3. Variable "temps"

Un TimeSpan est une unité de temps (un intervalle de temps) exprimée en jours, heures, minutes, secondes;

Un TimeSpan initialisé avec 1.0e+13 graduations représente "11.13:46:40", ce qui correspond à 11 jours, 13 heures, 46 minutes et 40 secondes.

L'espace de nom System.DateTime. contient une multitude de membre:


IX-F-4. Add, Substrat

On peut ajouter ou soustraire un TimeSpan à un DateTime, on obtient un DateTime.

En clair on peut ajouter à une date une durée, on obtient une date.

' Quel sera la date  dans 36 jours?.
Dim today As System.DateTime
Dim duration As System.TimeSpan
Dim answer As System.DateTime

today = System.DateTime.Now
duration = New System.TimeSpan(36, 0, 0, 0)
answer = today.Add(duration)
On peut ajouter ou soustraire 2 dates, on obtient une TimeSpan

Dim diff1 As System.TimeSpan
diff1 = date2.Subtract(date1)

IX-F-5. AddDay, AddMouths, AddHours, AddSeconds, AddMiliseconds

Permet d'ajouter des jours, des mois, des heures, des secondes, ou des millisecondes à une date, on obtient une date.

Answer=today.AddDay(36)

IX-F-6. Year, Mouth, Day, Hour, Minute, Seconde, Millisecond

Permettent d'extraire l'année, le mois, le jour, l'heure, les minutes, les secondes, les millisecondes d'une date:

I=DateNaissance.Year    ' => I=1951

I=System.DateTime.Now.Day    'donne le jour d'aujourd'hui (1 à 31)
(DatePart permet aussi d'extraire plein d'infirmations d'une date: jour , mois, année, jour de la semaine..)


IX-F-7. DayOfWeek

Retourne le jour de la semaine (0 pour dimanche à 6 pour samedi)

I=DateNaissance.DayOfWeek    'I=0  car le 02/12/1951 est un dimanche.
DayForYear existe aussi.


IX-F-8. Now, ToDay, TimeOfDay

Now est la date et l'heure du système.(Là, maintenant)

ToDay est la date du système avec l'heure à 0.

TimeOfDay est l'heure actuelle.

En Clock permet de récupérer l'heure courante ainsi que le nombre de millisecondes écoulées depuis le démarrage.

MsgBox(My.Computer.Clock.LocalTime.ToString) 'Affiche date et heure

IX-F-9. Ticks

Donne le nombre de graduations d'un DateTime.

AddTicks peut être utilisé.


IX-F-10. Année bissextile?

Pour cela utiliser IsLeapYear:

MsgBox(DateTime.IsLeapYear(2005)) 'Affiche False

IX-F-11. Comparaison de DateTime

On utilise Compare: DateTime.Compare(t1, t2) retourne 0 si t1=t2, une valeur positive si t1>t2 négative si t1<t2.

Dim t1 As New DateTime(100)
Dim t2 As New DateTime(20)

If DateTime.Compare(t1, t2) > 0 Then
    Console.WriteLine("t1 > t2")
End If
If DateTime.Compare(t1, t2) = 0 Then
    Console.WriteLine("t1 = t2")
End If
If DateTime.Compare(t1, t2) < 0 Then
    Console.WriteLine("t1 < t2")
End If
On peut aussi utiliser la méthode op_Equality de l'espace de nom pour voir si 2 dates sont égales:

areEqual = System.DateTime.op_Equality(april19, otherDate)
 
Il existe aussi op_GreaterThan et beaucoup d'autres.


IX-F-12. Calcul de la différence entre 2 dates

On utilise DateDiff, il faut fournir en paramètre:

  • L'intervalle de temps à utiliser comme unité de la différence entre Date1 et Date2.
    DateInterval.Day pour obtenir le nombre de jours entre les 2 dates.

    DateInterval.Year pour obtenir le nombre d'années entre les 2 dates.

    ..

  • Date1
  • Date2
Exemple:

Afficher le nombre de jours entre une date donnée et la date du jour.

Dim DateS, Msg As String ' Declare les  variables.
Dim DateD As DateTime
DateS = InputBox("Entrer une date") 'Saisir une date : on récupère une string
DateD = CDate(DateS)                'Conversion de la string en DateTime
Msg = "Nombre de jour:"& DateDiff(DateInterval.Day, Now, DateD) 'différence en jours
MsgBox (Msg)

IX-F-13. Comment saisir rapidement une date dans un programme?

En ajoutant à une fenêtre un contrôle DateTimePicker

En mode Run , il apparaît une zone rectangulaire avec la date système dedans:

Si l'utilisateur clique sur la flèche déroulante, il apparaît une fenêtre calendrier.

Il suffit pour l'utilisateur de cliquer sur la bonne date.

Le programmeur récupère la date dans DateTimePicker1.value

Il existe, bien sur, de multiples propriétés et plusieurs évènements, le plus remarquable étant: ValueChanged.


MonthCalendar est un contrôle similaire mais qui reste toujours ouvert.

De plus grâce à CalendarDimension on peut afficher plusieurs mois.


IX-F-14. Les Timers.

Pour déclencher un évènement à intervalle régulier, il faut utiliser les minuteries ou 'Timer'.

Prendre le contrôle Timer dans la Boite à outils, l'ajouter à la fenêtre. Il apparaît en bas sous la fenêtre dans la barre d'état des composants.

Il n'apparaît pas à l'utilisateur dans la fenêtre en mode Run.

Il est très simple à utiliser.

La propriété Interval contient la périodicité de l'événement Ticks , évènement qui se déclenche régulièrement.

Interval est en millisecondes. Pour Interval=500 l'évènement Ticks se déclenche toutes les 1/2 secondes.

Start et Stop déclenche et arrête la minuterie. (De même Enabled active ou non )

Exemple:

Faire clignoter un label toutes les 1/2 secondes.

Créer le label1

Ajouter un Timer1 (qui se place en bas sous la fenêtre)

Private Sub Form3_Load(...)

    Timer1.Interval = 500

    Timer1.Start()

End Sub
 

Private Sub Timer1_Tick(..)

    Label1.Visible = Not (Label1.Visible)

End Sub
Un évènement Timer_Tick se produit toutes les 1/2 secondes et inverse la valeur de la propriété visible du label. (Si elle était égale à True, elle devient égale à False et vice versa.)

Mais attention: Timer à des restrictions de taille:
  • Si votre application ou une autre demande beaucoup au système (boucles longues, calculs complexes, accès intensifs à un périphérique, un réseau ou un port, par exemple), les événements de minuterie peuvent être moins fréquent que spécifié dans la propriété Interval. Il n'est pas garanti que l'intervalle s'écoule dans le temps exact!!
  • L'intervalle peut être compris entre 1 et 64 767 millisecondes: l'intervalle le plus long ne dépasse pas de beaucoup la minute (64,8 secondes).
  • Le système génère 18 graduations à la seconde (même si la valeur de la propriété Interval est mesurée en millisecondes, la véritable précision d'un intervalle ne dépassera pas un dix-huitième de seconde).
Donc pour faire clignoter un label :OUI

Pour compter précisément un intervalle de temps:NON

Mais il y a d'autres méthodes.


IX-F-15. Perdre du temps:

Parfois on a besoin de perdre du temps:

Exemple ne rien faire pendant 3 secondes puis poursuivre..

  • Il est exclu de faire des boucles vides:
    
    For i=0 to 100000    ' le temps écoulé est variable en fonction des machines..
    
    Next i
    
  • Autre méthode : on boucle tant que l'heure courante est inférieure à l'heure du départ+3s
    
    Dim t As DateTime=DateTime.Now
    
    Do While DateTime.Now <t.AddSeconds(3)
    
    Loop
    
    Mais cela accapare le processeur.

  • On peut utiliser un Timer et vérifier dans la procédure Tick si le temps est écoulé (avec les restrictions que l'on connait).
  • On peut utiliser Thread.Sleep (qui met le processus en cours en sommeil).
    
    System.Threading.Thread.Sleep(3000) 
    
    Le temps de sommeil du thread est en millisecondes: 3000 correspond à 3 secondes.


IX-F-16. Chronométrer:

Parfois on a besoin de chronométrer un évènement:

Voir la rubrique Chronométrer 7-4

L'exemple sur l'horloge est aussi didactique.


IX-G. Lire et écrire dans les fichiers (séquentiels ou aléatoires)

Comment lire et écrire dans des fichiers du texte, des octets, du XML du Rtf ?

Les Classes du Framework

FileOpen

Les objets

Les nouveautés de VS 2005


IX-G-1. Généralités et rappels:

Le mot 'fichier' est a prendre au sens informatique: ce n'est pas un ensemble de fiches mais plutôt un ensemble d'octets. Un fichier peut être un programme (Extension .EXE), du texte (Extension .TXT ou .DOC....), une image (Extension .BMP .GIF .JPG...), une base de données (.MDB..) du son, de la vidéo....

Pour travailler avec du texte, des octets, des données très simple (sans nécessité d'index, de classement..), on utilise les méthodes décrites dans cette page: travail direct dans les fichiers séquentiels, aléatoires, binaires. Mais dès que les informations sont plus structurées, il faut utiliser les bases de données (Il y a plusieurs chapitre plus loin traitant des bases de données).

Un fichier a un nom: 'Image.GIF' , une extension: '.GIF' qui en indique généralement le type de contenu , des attributs (Longueur, Date de création, de modification, Fichier en lecture seule ou non..).

On voit cela dans l'explorer Windows:

Un fichier est composé d'enregistrements qui sont des 'paquets' de données; suivant le type de fichier un enregistrement peut correspondre à une ligne, un octet, un groupe d'octets..

Un fichier peut être vu comme contenant du texte, de l'XML, des octets.

Comment utiliser les fichiers? Voici le plan de cet article:

A- Il est conseillé de travailler avec les Classes du Frameworks

Avec la Classe FileInfo, on obtient des renseignements sur le fichier.

Pour lire écrire dans un fichier (en dehors des bases de données), il y a plusieurs méthodes:

Avec la Classe System.Io on a a notre disposition StreamReader StreamWriter BinaryReader BinaryWriter FileStream:

Pour lire ou écrire dans un fichier, il faut l'ouvrir (Open), lire ou écrire en utilisant un flux de données (Stream) puis le refermer (Close).

Le Stream (flux, torrent, courant) est une notion générale, c'est donc un flux de données provenant ou allant vers un fichier, un port, une connexion TCP/IP...

L'accès est séquentiel: les données sont traitées du début à la fin du fichier.


B- Il existe toujours la méthode classique du FileOpen:

On ouvre le fichier en mode séquentiel, aléatoire, binaire, on lit X enregistrements, on referme le fichier.

C- Avec certains objets, on gèrent automatiquement les lectures écritures sur disque.

Comme avec le RichTextBox par exemple.

En résumé, pour travailler sur les fichiers, on dispose:
  • de l'espace de nom System.IO avec les Classes et objets .NET
  • des instructions VisualBasic runtime traditionnelles: FileOpen WriteLine..
  • des instructions du FSO (FileObjetSystem) pour la compatibilité avec les langages de script.
Les 2 derniers font appel au premier; donc pourquoi ne pas utiliser directement les Classe .NET?


IX-G-2. A- Classe FileInfo et File, Stream.

Pour travailler sur les fichiers, il faut au préalable taper:

Imports System.IO

La classe File est utilisée pour travailler sur un ensemble de fichier ou un fichier (sans instanciation préalable: ce sont des méthodes statiques), la Classe FileInfo donne des renseignements sur un fichier particulier (Il faut instancier au préalable un objet FileInfo).

La Classe File possède les méthodes suivantes.

Exists            Teste si le fichier existe.

Create            Crée le fichier

Copy              Copie le fichier

Delete            Efface le fichier

GetAttributes , SetAttributes     Lire ou écrire les attributs.

GetCreationTime , GetLastAccessTime , GetLastWriteTime et les Set.. correspondant.

Move              Déplacement de fichier

Replace           Framework 2

ReadAllText, WriteAllText   Framework 2 lire ou écrire un texte dans un fichier

ReadAllLines, WriteAllLines   Framework 2 lire ou écrire des lignes dans un fichier

ReadAllBytes, WriteAllBytes   Framework 2 lire ou écrire des octets dans un fichier
Toutes les méthodes Open (pour un FileStream) OpenRead, OpenWrite, OpenText.

Exemple:

Un fichier existe-t-il? Afficher True s'il existe:

Label1.Text = File.Exists("vessaggi.gif").ToString

Exists est bien une 'méthode de Classe': pas besoin d'instancier quoi que ce soit.


Déplacer un fichier de c: vers d:?

File.Move("c:\monText.txt", "d:\monText.txt")

Copier un fichier de c: vers d:?

File.Copy("c:\monText.txt", "d:\monText.txt", True)

Le dernier argument facultatif (framework 2) permet de remplacer cible s'il existe.

Sauvegarde un fichier et le remplace? (Framework 2)

File.Copy("c:\monText.txt", "c:\newText.txt",, "c:\newText.bak " True)

Sauvegarde monText.tx sans un .bak , puis copie NewText.txt dans monText.tx ; True permet de remplacer cible s'il existe.

Efface un fichier:

File.Delete("d:\monText.txt")

Lire la totalité d'un fichier texte? (Framework 2)

Dim myText As String =File.ReadAllText("c:\monText.txt")

File.WriteAllText("c:\monText.txt", myText) 'pour réecrire le texte dans un autre fichier.

La méthode AppendAllText existe aussi.

Lire et mettre dans un tableau les lignes d'un fichier texte? (Framework 2)

Dim myLines() As String =File.ReadAllLines("c:\monText.txt")

Lire et mettre dans un tableau les octets d'un fichier? (Framework 2)

Dim myBytes() As Byte =File.ReadAllBytes("c:\monText.txt")

Un fichier est-il en lecture seule?

If File.GetAttributes("c:\monText.txt") And FileAttributes.ReadOnly Then..

La Classe FileInfo possède les propriétés suivantes.

Name            Nom du fichier (sans chemin)

FullName        Nom complet avec chemin

Extension       Extension   (.txt par exemple)

Length          Longueur du  fichier.

Directory       Répertoire parent

DirectoryName   Répertoire ou se trouve le fichier

Exists          Existe?

LastAccessTime  Date du dernier accès, LastWriteTime existe aussi.

Attributes      Attributs
Il faut faire un AND entre Attributes et une valeur de l'énumération FileAttributes ( Archive, Compressed, Directory, Encrypted, Hidden, Normal, ReadOnly, System, Temporaly).

Pour tester ReadOnly par exemple:

Dim sNom As String = "c:\monfichier.txt"

Dim Fi As FileInfo      'On déclare un FileInfo

Fi=New FileInfo( sNom)  'On instancie ce FileInfo avec comme paramètre le nom du fichier
Fi.Attributes And FileAttributes.ReadOnly Retourne True si le fichier est ReadOnly


Et aussi:

Fi.Name retourne "monfichier.txt"

Fi.FullName retourne "c:\monfichier.txt"

Fi.Name.Substring(0, Fi.Name.LastIndexOf(".")) retourne "monfichier" : pas de chemin ni d'extension.


Et les méthodes suivantes:

Create, Delete, MoveTo

AppendTex, CopyTo Open, OpenRead, OpenWrite, OpenText..

On voit que toutes les informations sont accessibles.

Exemple:

Pour un fichier, afficher successivement le nom, le nom avec répertoire, le répertoire, la longueur, la date de dernière écriture et si le fichier est en ReadOnly.

Dim sNom As String = "c:\monfichier.txt"

Dim Fi As FileInfo  'On déclare un FileInfo

Fi=New FileInfo( sNom)  'on instance ce FileInfo avec comme paramètre le nom du fichier

    MsgBox("Nom="& Fi.Name)

    MsgBox("Nom complet ="& Fi.FullName)

    MsgBox("Répertoire="& Fi.DirectoryName)

    MsgBox("Longueur="& Fi.Length.ToString)

    MsgBox("Date der modification="& Fi.LastWriteTime.ToShortDateString)

    MsgBox("ReadOnly="& (Fi.Attributes And FileAttributes.ReadOnly).ToString)

				

IX-G-3. Classe My.Computer.FileSystem en VS 2005.

En VS 2005 il y a en plus la classe My.Computer.FileSystem qui simplifie énormément les choses:

les méthodes CopyFile, DeleteFile, FileExits permettent de copier, effacer un fichier ou de voir s'il existe. Il existe aussi RenameFile et MoveFile.

Exemple :

Afficher dans une MsgBox True si 'c:\config.sys' existe.

MsgBox(My.Computer.FileSystem.FileExists("c:\config.sys").ToString)
Exemple :

Afficher la liste des fichiers qui sont sous c:\; ici on utilise GetFiles qui retourne une collection des fichiers.(count contient le nombre de fichiers, item () les noms.

Dim i As Integer

For i = 0 To My.Computer.FileSystem.Getfiles("c:\").Count - 1

ListBox1.Items.Add(My.Computer.FileSystem.GetFiles("c:\").Item(i))

Next i
Un fichier existe t-il et est-il ouvert et utilisé par une autre application?

If My.Computer.FileSystem.FileExists("c:\monText.txt") Then

Try

   'on tente d'ouvrir un stream sur le fichier, s'il est déjà utilisé, cela déclenche une erreur.

   Dim fs As IO.FileStream = My.Computer.FileSystem.GetFileInfo("c:\monText.txt").Open(IO.FileMode.Open, IO.FileAccess.Read)

   fs.Close()

Catch ex As Exception

  MsgBox("Le fichier  est déjà ouvert")

End Try

End If

IX-G-3-a. Utiliser les "Stream".

Le Stream (flux, torrent, courant) est une notion générale, c'est donc un flux de données provenant ou allant vers un fichier, un port, une connexion TCP/IP...

Ici on utilise un Stream pour lire ou écrire dans un fichier.

L'accès est séquentiel: les données sont traitées du début à la fin du fichier.

Pour écrire dans un fichier texte:

Il faut instancer un objet de la classe StreamWriter . On écrit avec Write ou WriteLine.(ajoute un saut de ligne) Enfin on ferme avec Close.

On peut instancier avec le constructeur de la classe StreamWriter et avec New, ou par la Classe File.

Dim SW As New StreamWriter ("MonFichier.txt") ' crée ou si existe écrase
Il existe une surcharge permettant de ne pas écraser mais d'ajouter à la fin du fichier:

Dim SW As New StreamWriter ("MonFichier.txt", True) ' crée ou si existe ajoute
Avec la classe File:

Dim SW As  StreamWriter=File.CreateText ("MonFichier.txt") ' crée ou si existe écrase

Dim SW As StreamWriter = File.AppendText("MonFichier.txt") ' crée ou si existe ajoute
Ensuite pour écrire 2 lignes:

SW.WriteLine ("Bonjour")

SW.WriteLine ("Monsieur")
Enfin on ferme:

SW.Close()
Pour lire dans un fichier Texte:

Il faut instancier un objet de la classe StreamReader. On lit avec Read (un nombre d'octet) ReadLine (une ligne) ReadToEnd (de la position courante jusqu'à la fin). Enfin on ferme avec Close.

Avec le constructeur de la Classe Stream Reader:

Dim SR As New StreamReader ("MonFichier.txt")
Avec la Classe File:

Dim SR As  StreamReader=File.OpenText ("MonFichier.txt") '
Comment lire chaque ligne du fichier et s'arrêter à la fin?

En effet on ne sait pas habituellement combien le fichier contient de ligne, si le fichier contient 2 lignes il faut en lire 2 et s'arrêter sinon on tente de lire après la fin du fichier et cela déclenche une erreur.

3 solutions:
  1. Utiliser ReadToEnd qui lit en bloc jusqu'à la fin.
  2. Avant ReadLine mettre un Try: quand l'erreur 'fin de fichier' survient elle est interceptée par Catch qui sort du cycle de lecture et ferme le fichier.
  3. Utiliser Peek qui lit dans le fichier un caractère mais sans modifier la position courante de lecture.
La particularité de Peek est de retourner -1 s'il n'y a plus de caractère à lire sans déclencher d'erreur, d'exception.

La troisième solution est la plus générale et la plus élégante:

Do Until SR.Peek=-1

     Ligne=SR.ReadLine()

Loop

Enfin on ferme:

SR.Close()
Notion de 'Buffer', utilisation de Flush.

En fait quand on écrit des informations sur le disque, le logiciel travaille sur un buffer ou mémoire tampon qui est en mémoire vive. Si on écrit des lignes dans le fichier, elles sont 'écrites' dans le buffer en mémoire vive. Quand le buffer est plein,(ou que l'on ferme le fichier) l'enregistrement du contenu du buffer est effectué effectivement sur le disque.

Ce procédé est général à l'écriture et à la lecture de fichier mais totalement transparent car le programmeur ne se préoccupe pas des buffers.

Parfois, par contre, même si on a enregistré peu d'information, on veut être sûr qu'elle est sur le disque, il faut donc forcer l'enregistrement sur disque même si le buffer n'est pas plein, on utilise alors la méthode Flush.

  SW.Flush()
Le fait de fermer un fichier par Close, appelle automatiquement Flush() ce qui enregistre des données du buffer.


IX-G-4. B- Utiliser "FileOpen".

Visual Basic fournit trois types d'accès au fichier :

  • l'accès séquentiel, pour lire et écrire des fichiers 'texte' de manière continue, chaque donnée est enregistrée successivement du début à la fin ; les enregistrements n'ont pas la même longueur, ils sont séparés par un séparateur (des virgules ou des retours à la ligne).
On ne peut qu'écrire le premier enregistrement puis le second, le troisième, le quatrième...

Pour lire c'est pareil: on ouvre , on lit le premier, le second, le troisième, le quatrième....

Pour lire le troisième enregistrement , il faut lire avant les 2 premiers.

  • l'accès aléatoire (Random), (on le nomme parfois accès direct) pour lire et écrire des fichiers texte ou binaire constitués d'enregistrements de longueur fixe ; on peut avoir directement accès à un enregistrement à partir de son numéro.
Les enregistrements ont une longueur fixe: il faut prévoir!! si on décide de 20 caractères pour le prénom, on ne pourra pas en mettre 21, le 21ème sera tronqué, à l'inverse l'enregistrement de 15 caractères sera complété par des blancs.

Il n'y a pas de séparateur entre les enregistrements.

Les enregistrements peuvent être constitués d'un ensemble de variables: une structure, ici prénom et adresse.

Ensuite on peut lire directement n'importe quel enregistrement,le second enregistrement par exemple, ou écrire sur le 3éme.(on comprend que, connaissant la longueur d'un enregistrement qui est fixe, l'ordinateur peut calculer la position d'un enregistrement quelconque.)

  • l'accès binaire, pour lire et écrire dans tous les fichiers , on lit ou écrit un nombre d'octet désiré à une position désirée..C'est comme l'accès direct, on peut lire le 36ème octet..
En pratique:

Les fichiers séquentiels sont bien pratique pour charger une série de ligne, (toujours la même) dans une ListBox par exemple.

Faut-il utiliser les fichiers séquentiels ou random (à accès aléatoire, à accès direct) pour créer par exemple un petit carnet d'adresse?

Il y a 2 manières de faire:
  • Créer un fichier random et lire ou écrire dans un enregistrement pour lire ou modifier une adresse.
  • Créer un fichier séquentiel. A l'ouverture du logiciel lire séquentiellement toutes les adresses et les mettre dans un tableau (de structure). Pour lire ou modifier une adresse: lire ou modifier un élément du tableau. En sortant du programme enregistrer tous les éléments du tableau séquentiellement.(Enregistrer dans un nouveau fichier, effacer l'ancien, renommer le nouveau avec le nom de l'ancien).
Bien sur s'il y a de nombreux éléments dans une adresse, un grand nombre d'adresse, il faut utiliser une base de données.

info Si on ouvre un fichier en écriture et qu'il n'existe pas sur le disque, il est crée.

Si on ouvre un fichier en lecture et qu'il n'existe pas, une exception est déclenchée (une erreur). On utilisait cela pour voir si un fichier existait: on l'ouvrait, s'il n'y avait pas d'erreur c'est qu'il existait. Mais maintenant il y a plus simple pour voir si un fichier existe (File.Exists).

Si on ouvre un fichier et que celui-ci est déjà ouvert par un autre programme, il se déclenche généralement une erreur (sauf si on l'ouvre en Binaire, c'était le cas en VB6, c'est à vérifier en VB.NET).
Pour ouvrir un fichier on utilise FileOpen

FileOpen (FileNumber, FileName, Mode, Access, Share, RecordLength)

Paramètres de FileOpen

FileNumber
A tous fichier est affecté un numéro unique, c'est ce numéro que l'on utilisera pour indiquer sur quel fichier pratiquer une opération.. Utilisez la fonction FreeFile pour obtenir le prochain numéro de fichier disponible. FileName
Obligatoire. Expression de type String spécifiant un nom de fichier. Peut comprendre un nom de répertoire ou de dossier, et un nom de lecteur. Mode
Obligatoire. Énumération OpenMode spécifiant le mode d'accès au fichier : Append, Binary, Input (séquentiel en lecture), Output (séquentiel en écriture) ou Random (accès aléatoire). Access
Facultatif. Mot clé spécifiant les opérations autorisées sur le fichier ouvert : Read, Write ou ReadWrite. Par défaut, la valeur est OpenAccess.ReadWrite. Share
Facultatif. Spécifiant si un autre programme peut avoir en même temps accès au même fichier : Shared (permet l'accès aux autres programmes), Lock Read (interdit l'accès en lecture), Lock Write (interdit l'accès en écriture) et Lock Read Write (interdit totalement l'accès). Le processus OpenShare.Lock Read Write est paramétré par défaut. RecordLength
Facultatif. Nombre inférieur ou égal à 32 767 (octets). Pour les fichiers ouverts en mode Random, cette valeur représente la longueur de l'enregistrement. Pour les fichiers séquentiels, elle représente le nombre de caractères contenus dans la mémoire tampon.

Pour écrire dans un fichier on utilise

Print , Write, WriteLine. dans les fichiers séquentiels

FilePut dans les fichiers aléatoires

Pour lire dans un fichier on utilise:

Input, LineInput dans les fichiers séquentiels

FileGet dans les fichiers aléatoires.

Pour fermer le fichier on utilise FileClose()


Numéro de fichier:

Pour repérer chaque fichier, on lui donne un numéro unique (de type Integer).

La fonction FreeFile retourne le premier numéro libre.

Dim No as Integer

No= Freefile()
Ensuite on peut utiliser No pour repérer le fichier sur lequel on travaille.

FileOpen( No, "MonFichier", OpenMode.Output)

Print(No,"toto")

FileClose (No)

Fichier séquentiel:

Vous devez spécifier si vous voulez lire (entrer) des caractères issus du fichier (mode Input), écrire (sortir) des caractères vers le fichier (mode Output) ou ajouter des caractères au fichier (mode Append).

Ouvrir le fichier 'MonFichier' en mode séquentiel pour y écrire:

Dim No as integer

No= Freefile

FileOpen( No, "MonFichier", OpenMode.Output)
Pour écrire dans le fichier séquentiel: on utilise Write ou WriteLine Print ou PrintLine:

  • La fonction Print écrit dans le fichier sans aucun caractère de séparation.
    
    Print(1,"toto")
    
    Print(1,"tata")
    
    Print(1, 1.2)
    
    Donne le fichier 'tototata1.2'

  • La fonction Write insère des points-virgules entre les éléments et des guillemets de part et d'autre des chaînes au moment de leur écriture dans le fichier, les valeurs booléens et les variables DateTime sont écrites sans problèmes.
    
    Write(1,"toto")
    
    Write(1,"tata")
    
    Write(1, 1.2)
    
    Donne le fichier '"toto";"tata";1.2"

    warning Attention s'il y a des points-virgules dans les chaînes , elles seront considérées comme séparateurs!! ce qui entraîne des erreurs à la lecture; il faut mettre la chaîne entre "" ou bien remplacer le point-virgule par un caractère non utilisé (# par exemple) avant de l'enregistrer puis après la lecture remplacer '#' par ';'
    Il faut utiliser Input pour relire ces données (Input utilise aussi le point-virgule comme séparateur.

  • La fonction WriteLine insère un caractère de passage à la ligne, c'est-à-dire un retour chariot+ saut de ligne (Chr(13) + Chr(10)),On lira les données par LineInput.
    
    WriteLine(1,"toto")
    
    WriteLine(1,"tata")
    
    WriteLine(1, 1.2)
    
    Donne le fichier

    "toto"

    "tata"

    1.2

    Il faut utiliser LineInput pour relire ces données car il lit jusqu'au retour Chariot, saut de ligne.


Toutes les données écrites dans le fichier à l'aide de la fonction Print respectent les conventions internationales ; autrement dit, les données sont mises en forme à l'aide du séparateur décimal approprié. Si l'utilisateur souhaite produire des données en vue d'une utilisation par plusieurs paramètres régionaux, il convient d'utiliser la fonction Write

EOF (NuméroFichier) veut dire 'End Of File', (Fin de Fichier) il prend la valeur True si on est à la fin du fichier et qu'il n'y a plus rien à lire.

LOF (NuméroFichier) veut dire 'Lenght Of File', il retourne la longueur du fichier.

Exemple: Lire chaque ligne d'un fichier texte.

Dim Line As String
FileOpen(1, "MonFichier.txt", OpenMode.Input) ' Ouvre en lecture.
While Not EOF(1) ' Boucler jusqu'à la fin du fichier

Line = LineInput(1) ' Lire chaque ligne
Debug.WriteLine(Line) ' Afficher chaque ligne sur la console.
 

End While
FileClose(1) ' Fermer.
Ici on a utilisé une boucle While.. End While qui tourne tant que EOF est Faux. Quand on est à la fin du fichier EOF (End of File)devient égal à True et on sort de la boucle.


IX-G-4-a. Fichier à accès aléatoire:

On ouvre le fichier avec FileOpen et le mode OpenMode.Random, ensuite on peut écrire un enregistrement grâce à FilePut() ou en lire un grâce à FileGet(). On peut se positionner sur un enregistrement précis (le 2eme, le 15ème) avec Seek.

Le premier enregistrement est l'enregistrement numéro 1

Exemple:

Fichier des adresses

Créer une structure Adresse, on utilise <VBFixedString( )> pour fixer la longueur.

Public Structure Adresse

   <VBFixedString(20)>Dim Nom        As String

   <VBFixedString(20)>Dim Rue        As String

   <VBFixedString(20)>Dim Ville      As String

End Structure


 

'Ouvrir le fichier, comme il n'existe pas, cela entraîne sa création
Dim FileNum As Integer, RecLength As Long,  UneAdresse As Adresse
' Calcul de la longueur de l'enregistrement 
RecLength = Len(UneAdresse)
' Récupérer le premier numéro de fichier libre.
FileNum = FreeFile
' Ouvrir le fichier.
FileOpen(FileNum, "MONFICHIER.DAT", OpenMode.Random, , , RecLength)
 
Pour écrire des données sur le second enregistrement par exemple:

UneAdresse.Nom = "Philippe"

UneAdresse.Rue = "Grande rue"

UneAdresse.Ville = "Lyon"

FilePut(FileNum, UneAdresse,2 )
Dans cette ligne de code, FileNum contient le numéro utilisé par la fonction FileOpen pour ouvrir le fichier, 2 est le numéro de l'enregistrement ou sera copié la variable 'UneAdresse' (c'est un long si on utilise une variable) et UneAdresse, déclaré en tant que type Adresse défini par l'utilisateur, reçoit le contenu de l'enregistrement. Cela écrase l'enregistrement 2 s'il contenait quelque chose.

Pour écrire à la fin du fichier, ajouter un enregistrement il faut connaître le nombre d'enregistrement et écrire l'enregistrement suivant.

Dim last as long  'noter que le numéro d'enregistrement est un long
Pour connaître le nombre d'enregistrement, il faut diviser la longueur du fichier par la longueur d'un enregistrement.

last = FileLen("MONFICHIER.DAT") / RecLength
On ajoute 1 pour créer un nouvel enregistrement.

FilePut(FileNum, UneAdresse,last+1 )
Pour lire un enregistrement (le premier par exemple):

FileGet(FileNum, UneAdresse, 1)

Attention Option Strict doit être à false .

Si option Strict est à True, la ligne qui précède génère une erreur car le second argument attendu ne peut pas être une variable 'structure'. Pour que le second argument de FileGet (Une adresse) soit converti dans une variable Structure automatiquement Option Strict doit donc être à false. (Il doit bien y avoir un moyen de travailler avec Option Strict On et de convertir explicitement mais je ne l'ai pas trouvé)

Remarque: si le fichier contient 4 enregistrements, on peut écrire le 10ème enregistrement, VB ajoute entre le 4ème et le 10ème, 5 enregistrements vides. On peut lire un enregistrement qui n'existe pas, cela ne déclenche pas d'erreur.

Le numéro d'enregistrement peut être omis dans ce cas c'est l'enregistrement courant qui est utilisé.

On positionne l'enregistrement courant avec Seek:

Exemple: Lire le 8ème enregistrement:

Seek(FileNum,8)

FileGet(FileNum,Une Adresse)

Suppression d'enregistrements

Vous pouvez supprimer le contenu d'un enregistrement en effaçant ses champs (enregistrer à la même position des variables vides), mais l'enregistrement existe toujours dans le fichier.

Pour enlever un enregistrement supprimé
  • Créez un nouveau fichier.
  • Copiez tous les enregistrements valides du fichier d'origine dans le nouveau fichier (pas ceux qui sont vides).
  • Fermez le fichier d'origine et utilisez la fonction Kill pour le supprimer.
  • Utilisez la fonction Rename pour renommer le nouveau fichier en lui attribuant le nom du fichier d'origine.

IX-G-4-b. Fichier binaire:

Dans les fichiers binaires on travaille sur les octets.

La syntaxe est la même que pour les fichiers Random, sauf qu'on travaille sur la position d'un octet et non sur un numéro d'enregistrement.

Pour ouvrir un fichier binaire:

FileOpen(FileNumber, FileName, OpenMode.Binary)


FileGet et FilePut permettent de lire ou d'écrire des octets .

FileOpen(iFr, ReadString, OpenMode.Binary)
MyString = New String(" "c, 15)        'Créer une chaîne de 15 espaces
FileGet(iFr, MyString)                 ' Lire 15 caractères dans MyString
FileClose(iFr)
MsgBox(MyString)
Le fait de créer une variable de 15 caractères et de l'utiliser dans FileGet permet de lire 15 caractères.


IX-G-5. C-Utilisation du Contrôle RichTextBox.

On rappelle que du texte présent dans un contrôle RichTextBox peut être enregistré ou lu très simplement avec les méthodes .SaveFile et .LoadFile.

Le texte peut être du texte brut ou du RTF.

richTextBox1.SaveFile(FileName, RichTextBoxStreamType.PlainText)
Si on remplace .PlainText par .RichText c'est le texte enrichi et non le texte brut qui est enregistré

Pour lire un fichier il faut employer .LoadFile avec la même syntaxe.

Simple, non!!!


IX-G-6. Lire ou écrire des octets ou du XML:

BinaryWriter et BinaryReader permettent d'écrire ou de lire des données binaires.

XMLTextWriter et XMLTextReader écrit et lit du Xml.


Pour enregistrer un tableau, un objet, Vb.Net propose aussi la Sérialization (voir ce chapitre)


IX-H. Travailler sur les répertoires

Comment créer, copier effacer des répertoires (ou dossiers)?

Avec les classes DirectoryInfo et Directory.

Avec la classe Path.

Avec la classe Environment.

Avec My.Computer.FileSystem en VS 2005.

Avec les Classes de VisualBasic.

Comment créer une boite de dialogue 'choix de répertoire' en VB2005?


IX-H-1. Classe DirectoryInfo et la Classe Directory du Framework:

Pour travailler sur les dossiers (ou répertoires), il faut au préalable taper:

Imports System.IO

La classe Directory est utilisée pour travailler sur un ensemble de dossier, la Classe directoryInfo donne des renseignements sur un dossier particulier (Après instanciation ).

La Classe Directory possède les méthodes suivantes.

Exists Teste si le dossier existe.
CreateDirectory Crée le dossier
Delete Efface le dossier
Move Déplacement de dossier
GetCurrentDirectory Retourne le dossier de travail de l'application en cours
SetCurrentDirectory Définit le dossier de travail de l'application.
GetDirectoryRoot Retourne le dossier racine du chemin spécifié.
GetDirectories Retourne le tableau des sous dossiers du dossier spécifié.
GetFiles Retourne les fichiers du dossier spécifié.
GetFilesSystemEntries Retourne fichier et sous dossier avec possibilité d'un filtre.
GetLogicalDrives Retourne les disques
GetParent Retourne le dossier parent du dossier spécifié
La Classe Directory est statique : on l'utilise directement.

Exemple:

Afficher dans une ListeBox les sous dossiers (répertoires) du répertoire de l'application:

Dim SousDos() As String= Directory.GetDirectories(Directory.GetCurrentDirectory)

Dim Dossier As String

For Each Dossier In SousDos

    List1.Items.Add(Dossier)

Next
Afficher dans une ListeBox les sous dossiers et fichiers.

On utilise ici la récursivité. Pour chaque sous-répertoire, on appelle la routine elle même.

Imports System.IO

 

Sub  AfficheTree ( ByVal myDir As String, ByVal Optional Niveau As Integer =0)

 

'Affiche le répertoire myDir

List1.Items.Add(New String (" ", niveau *2) & myDir)

 

'Affiche les fichiers

For Each fichier As String  In Directory.GetFiles( myDir)

    List1.Items.Add(New String (" ", niveau *2+2) & fichier)

Next

 

'Parcourt les sous-répertoires

For each sousRepertoire As String In Directory.GetDirectories( myDir)

    'Appel de manière récursive 'AfficheTree pour afficher le contenu des sous répertoires.

    AfficheTree (sousRepertoire, niveau+1)

Next

 

End Sub
La variable niveau permet de pratiquer une indentation :New String (" ", niveau*2) produit une chaîne d'espace de longueur niveau *2.

On appelle cette routine avec AfficheTree (c:\myprogramme", 0) 'éviter "c:\" car c'est très très long!!! on le fait tous pour tester!!

Directory.GetFiles et Directory.GetDirectories acceptent un argument supplémentaire qui fait office de filtre.

Directory.GetFiles( myDir, "*.txt") 'pour ne voir que les fichiers .txt.

Afficher dans une ListeBox les exécutables d'un répertoire et de ses sous-répertoires.

Ici on utilise un argument supplémentaire qui permet de rechercher dans les sous répertoires.

Imports System.IO

For Each file As String In Directory.GetFiles("c:\windows", "*.exe", System.IO.SearchOption.AllDirectries ))

    List1.Items.Add (file)

Nex
Génial , non? quelle économie de code!!

Afficher dans une ListeBox les disques.

Imports System.IO

 

For Each disque As String In Directory.GetLogicalDrives()

    List1.Items.Add (Disque)

Next  
Afficher dans une ListeBox les fichiers .jpg d'un répertoire.

Dim dirInfo As New System.IO.DirectoryInfo ("C:\Nos Images\sicile")

Dim file As System.IO.FileInfo

Dim files() As System.IO.FileInfo = dirInfo.GetFiles("*.jpg")

If (files IsNot Nothing) Then

For Each file In files

    ListBox1.Items.Add(file.FullName) 

Next

End If

Changer de répertoire courant, effacer un sous-répertoire.

Directory.SetCurrentDirectry (c:\mydirectory")

Directory.Delete (c:\otherdirectory") 'efface ce répertoire s'il est vide

Directory.Delete (c:\otherdirectory", True) 'efface ce répertoire ses fichiers et sous-répertoires.

Ah!! nostalgique du DEL *.*

La Classe DirectoryInfo possède les propriétés suivantes.

Name            Nom du dossier (sans extension)

Full Name       Chemin et nom du dossier

Exists

Parent         Dossier parent

Root            Racine du dossier
La Classe DirectoryInfo n'est pas statique : il faut instancier un dossier avant de l'utiliser.

Il y a aussi les méthodes suivantes:

Create, Delete, MoveTo

CreateSubdirectory

GetDirectories    Retourne les sous-dossiers

GetFiles          Retourne des fichiers

GetFileSystemInfos
Exemple:

Afficher le répertoire parent d'un dossier:

Dim D As DirectoryInfo

D= New DirectoryInfo( MonDossier)

MsgBox(D.Parent.ToString)
Créer un répertoire:

Dim D As DirectoryInfo

D= New DirectoryInfo( MonDossier)

D.CreateSubdirectory("monsousdossier")
Effacer un répertoire et ses sous-répertoires:

Dim D As DirectoryInfo

D= New DirectoryInfo( MonDossier)

D.Delete(True)

IX-H-2. Classe Path

La Classe statique Path a des méthodes simplifiant la manipulation des répertoires:

Exemple:

Si  C= "C:\Windows\MonFichier.txt"

Path.GetDirectoryName(C)  retourne "C:\Windows

Path.GetFileName(C) retourne "Monfichier.txt"

Path.GetExtension(C) retourne ".txt"

Path.GetFileNameWithoutExtension(C) retourne "MonFichier"

Path.PathRoot(C) retourne "c:\"
Il y a aussi les méthodes GetFulPath ChangeExtension, Combine, HasExtension...

GetFulPath: Transforme un chemin relatif en chemin absolu à l'aide du répertoire courant.

Path.GetFullPath("monAppli.exe")) retourne "C:\MonRep\monAppli.exe" si le répertoire courant est "C:\MonRep"

Combine: combine bout à bout un chemin et un nom de fichier

Path.Combine("C:\MonRep", "monAppli.exe")) retourne "C:\MonRep\monAppli.exe"


IX-H-3. Classe DriveInfo

Nouveauté en VB 2005, la Classe DriveInfo :

Pour un disque particulier, il faut instancier un DriveInfo avec la lettre du drive, ensuite, on a accès à toutes les propriétés du lecteur.

Dim di As New DriveInfo ("c:")

di.Name retourne le nom  du lecteur ( "c:" ici)

VolumeLabel  Nom (label) du lecteur (en lecture écriture)

DriveType ( Fixed, Removal, CDRom, Ram, Networl, Unknown)

DriveFormat (NTFS, Fat32)

TotalSize, TotalFreeSpace, AvailableFreeSpace
DriveInfo.GetDrives retourne tous les disques installées

For Each di As DriveInfo in DriveInfo.GetDrives()

 If di.IsReady Then 'il parait qu'il faut bien tester s'il est ready!!

    MsgBox (di.VolumeLabel)

 End if


Next

IX-H-4. Classe Environment

Donne des informations concernant l'environnement et la plate-forme en cours ainsi que des moyens pour les manipuler. Par exemple: les arguments de la ligne de commande, le code de sortie, les paramètres des variables d'environnement, le contenu de la pile des appels, le temps écoulé depuis le dernier démarrage du système ou le numéro de version du Common Language Runtime mais aussi certains répertoires .

Environment.CurrentDirectory  'donne le répertoire courant : ou le processus en cours démarre.

Environment.MachineName       'Obtient le nom NetBIOS de l'ordinateur local.

Environment.OsVersion         'Obtient un objet contenant l'identificateur et le numéro de version de la plate-forme en cours.

Environment.SystemDirectory   'Obtient le chemin qualifié complet du répertoire du système

Environment.UserName          'Obtient le nom d'utilisateur de la personne qui a lancé le thread en cours.
La fonction GetFolderPath avec un argument faisant partie de l'énumération SpecialFolder retourne le répertoire d'un tas de choses:

Exemple: Quel est le répertoire Système?

Environment.GetFolderPath(Environment.SpecialFolder.System)

Comment récupérer le nom des disques?

Dim drives As String() = Environment.GetLogicalDrives()
 
Comment récupérer la ligne de commande?

Dim arguments As String() = Environment.GetCommandLineArgs()

IX-H-5. Classe My.Computer.FileSystem en VS 2005.

En VS 2005 la classe My.Computer.FileSystem simplifie énormément les choses:

les méthodes CopyDirectory, CreateDirectory, DeleteDirectory, DirectoryExits permettent de copier, créer, effacer un répertoire ou de voir s'il existe. Il existe aussi RenameDirectory et MoveDirectory.

Exemple :

Afficher dans une MsgBox True si le répertoire 'c:\MyApplication\' existe.

MsgBox(My.Computer.FileSystem.FileExists("c:\MyApllication\").ToString)
Copier un répertoire dans un autre:

My.Computer.FileSystem.CopyDirectory("c:\a\", "c:\b\")

Exemple :

Afficher la liste des répertoires qui sont sous c:\; ici on utilise GetDirectories qui retourne une collection des répertoires.(count contient le nombre des répertoires, item () les noms.

Dim i As Integer

For i = 0 To My.Computer.FileSystem.GetDirectories("c:\").Count - 1

ListBox1.Items.Add(My.Computer.FileSystem.GetDirectories("c:\").Item(i))

Next i
SpecialDirectories permet de connaître certains répertoires spéciaux comme Programs, My Documents, My Music..

Exemple:

MsgBox(My.Computer.FileSystem.SpecialDirectories.CurrentUserApplicationData)

My.Computer.FileSystem.Drives est une collection contenant les disques présents.

On peut rechercher les fichiers qui contiennent un certain texte et afficher leurs noms dans une listBox.

Grâce à My.Computer.FileSystem.FindInFiles (Répertoire, texteàchercher, respectdelacasse, tyderecherche)

Dim value As System.Collections.ObjectModel.ReadOnlyCollection(Of String) = My.Computer.FileSystem.FindInFiles
		_("c:\", "Open", False, FileIO.SearchOption.SearchTopLevelOnly)

For Each name As String In value

ListBox1.Items.Add(name)

Next

IX-H-6. On peut aussi utiliser les anciennes méthodes de l'espace Visual Basic:

CurDir() retourne le chemin d'accès en cours.

MyPath = CurDir() 
MyPath = CurDir("C"c) 
Dir()

Retourne une chaîne représentant le nom d'un fichier, d'un répertoire ou d'un dossier qui correspond à un modèle ou un attribut de fichier spécifié ou à l'étiquette de volume d'un lecteur.

'vérifier si un fichier existe:

' Retourne "WIN.INI" si il existe.
MyFile = Dir("C:\WINDOWS\WIN.INI")

' Retourne le fichier spécifié par l'extension .
MyFile = Dir("C:\WINDOWS\*.INI")

'Un nouveau Dir retourne le fichier suivant
MyFile = Dir()

' On peut surcharger avec un attribut qui sert de filtre .
MyFile = Dir("*.TXT", vbHidden) ' affiche les fichiers cachés

' Recherche les sous répertoires.
MyPath = "c:\" ' Set the path.
MyName = Dir(MyPath, vbDirectory) 
ChDrive change le lecteur actif. La fonction lève une exception si le lecteur n'existe pas.

ChDrive("D")   
MkDir crée un répertoire ou un dossier. Si aucun lecteur n'est spécifié, le nouveau répertoire ou dossier est créé sur le lecteur actif.

MkDir("C:\MYDIR") 
RmDir enlève un répertoire ou un dossier existant.

' Vérifier que le répertoire est vide sinon effacer les fichier avec Kill.
RmDir ("MYDIR") 
ChDir change le répertoire par défaut mais pas le lecteur par défaut.

ChDir("D:\TMP")
L'exécution de changements relatifs de répertoire s'effectue à l'aide de "..", comme suit :
ChDir("..") ' Remonte au répertoire parent.

FileCopy
Copier un fichier.

FileCopy(SourceFile, DestinationFile)
Rename
Renommer un fichier, un répertoire ou un dossier.

Rename (OldName, NewName)
FileLen donne la longueur du fichier, SetAttr et GetAttr modifie ou lit les attributs du fichier

Result = GetAttr(FName)
Result est une combinaison des attributs. Pour déterminer les attributs définis, utilisez l'opérateur And pour effectuer une comparaison d'opérations de bits entre la valeur retournée par la fonction GetAttr et la valeur de l'attribut. Si le résultat est différent de zéro, cet attribut est défini pour le fichier désigné. Par exemple, la valeur de retour de l'expression And suivante est zéro si l'attribut Archive n'est pas défini :

Result = GetAttr(FName) And vbArchive

IX-H-7. Comment créer une boite de dialogue 'Choix de répertoire' en VB2005?

Il faut instancier un FolderBrowserDialog, indiquer le répertoire de départ (RootFolder), le texte de la barre (Description) et l'ouvrir avec ShowDialog.

Le répertoire sélectionné par l'utilisateur se trouve dans SelectedPath .


Dim fB As New FolderBrowserDialog

fB.RootFolder = Environment.SpecialFolder.Desktop

fB.Description = "Sélectionnez un répertoire"

fB.ShowDialog()

If fB.SelectedPath = String.Empty Then

  MsgBox("Pas de sélection")

Else

  MsgBox(fB.SelectedPath)

End If

fB.Dispose()

IX-I. Afficher correctement du texte

  1. Remarque sur le rafraîchissement de l'affichage.
  2. Comment afficher du texte , du numérique suivant le format désiré ?
  3. Comment utiliser les 'CultureInfo'

IX-I-1. A - Remarque sur la mise à jour de l'affichage:

La mise à jour de l'affichage d'un Label (comme les autres contrôles d'ailleurs) est effectuée en fin de Sub:

Si on écrit:

Dim i As Integer

For i = 0 To 100

    Label1.Text = i.ToString

Next i
La variable i prend les valeurs 1 à 100, mais à l'affichage rien ne se passe pendant la boucle, VB affiche uniquement 100 à la fin; si on désire voir les chiffres défiler avec affichage de 0 puis 1 puis 2... il faut rafraîchir l'affichage à chaque boucle avec la méthode Refresh():

Dim i As Integer

For i = 0 To 100

    Label1.Text = i.ToString: Label1.Refresh()

Next i
Une alternative est de mettre un Application.DoEvents() qui donne à Windows le temps de traiter les messages et de rafraîchir l'affichage.


IX-I-2. B - Afficher du text:

On a vu que pour afficher du texte il fallait l'affecter à la propriété 'Text' d'un label ou d'un textBox (ou pour des tests l'afficher sur la fenêtre 'console').

Pas de problème pour afficher des chaînes de caractères, par contre, pour les valeurs numériques, il faut d'abord les transformer en 'String' et les formater (définir les séparateurs, le nombre de décimales...) .


IX-I-2-a. ToString

On a déjà vu que pour afficher une variable numérique, il fallait la transformer en 'string' de la manière suivant:

MyDouble.ToString

Mais ToString peut être surchargé par un paramètre appelé chaîne de format. Cette chaîne de format peut être standard ou personnalisée.

Chaîne de format standard:

Cette chaîne est de la forme 'Axx' ou A donne le type de format et xx le nombre de chiffre après la virgule. Le format est défini par la 'culture' en cours sur le thread courant.

Imports System
Imports System.Globalization
Imports System.Threading

Module Module1
Sub Main()

Thread.CurrentThread.CurrentCulture = New CultureInfo("en-us")'changement de culture
Dim UnDouble As Double = 123456789

Console.WriteLine("Cet exemple est  en-US culture:")
Console.WriteLine(UnDouble.ToString("C"))    'format monétaire (C) affiche $123,456,789.00
Console.WriteLine(UnDouble.ToString("E"))    'format scientifique (E) affiche     1.234568E+008
Console.WriteLine(UnDouble.ToString("P"))    'format %   (P)            affiche      12,345,678,900.00%
Console.WriteLine(UnDouble.ToString("N"))    'format nombre (N)    affiche      123,456,789.00
Console.WriteLine(UnDouble.ToString("F"))    'format virgule fixe (F) affiche       123456789.00

End Sub
End Module
Autre exemple:

S=(1.2).ToString("C") retourne en CurrentCulture Français (par défaut sur mon ordinateur):1,2€

Il existe aussi D pour décimal, G pour général X pour hexadécimal.

  • Chaîne de format personnalisé:
On peut créer de toute pièce un format, on utilise pour cela les caractères suivants:

0 indique une espace réservé de 0

Chaque '0' est réservé à un chiffre. Affiche un chiffre ou un zéro. Si le nombre contient moins de chiffres que de zéros, affiche des zéros non significatifs. Si le nombre contient davantage de chiffres à droite du séparateur décimal qu'il n'y a de zéros à droite du séparateur décimal dans l'expression de format, arrondit le nombre à autant de positions décimales qu'il y a de zéros. Si le nombre contient davantage de chiffres à gauche du séparateur décimal qu'il n'y a de zéros à gauche du séparateur décimal dans l'expression de format, affiche les chiffres supplémentaires sans modification.

# indique un espace réservé de chiffre.

Chaque '#' est réservé à un chiffre. Affiche un chiffre ou rien. Affiche un chiffre si l'expression a un chiffre dans la position où le caractère # apparaît dans la chaîne de format ; sinon, n'affiche rien dans cette position.

Ce symbole fonctionne comme l'espace réservé au 0, sauf que les zéros non significatifs et à droite ne s'affichent pas si le nombre contient moins de chiffres qu'il n'y a de caractères # de part et d'autre du séparateur décimal dans l'expression de format.

. (point) indique l'emplacement du séparateur décimal (celui affiché sera celui du pays )

Vous devriez donc utiliser le point comme espace réservé à la décimale, même si vos paramètres régionaux utilisent la virgule à cette fin. La chaîne mise en forme apparaîtra dans le format correct pour les paramètres régionaux.

, (virgule) indique l'emplacement du séparateur de millier.

Séparateur de milliers. Il sépare les milliers des centaines dans un nombre de quatre chiffres ou plus à gauche du séparateur décimal.

"Littéral" la chaîne sera affichée telle quelle.

% affichera en pour cent.

Multiplie l'expression par 100. Le caractère du pourcentage (%) est inséré

E0 affiche en notation scientifique.

: et / sont séparateur d'heure et de date.

; est le séparateur de section : on peut donner 3 formats (un pour les positifs, un pour les négatifs, un pour zéro) séparés par ;

Exemple:

Chaîne de format '0000', le chiffre 145 cela affiche '0145'

Chaîne de format '####', le chiffre 145 cela affiche '145'

Chaîne de format '000.00', le chiffre 45.2 cela affiche '045.20'

Chaîne de format '#,#', le chiffre 12345678 cela affiche '12,345,678'

Chaîne de format '#,,' le chiffre 12345678 cela affiche '12'

La chaîne de formatage' #,##0.00 ' veut dire obligatoirement 2 chiffres après le séparateur décimal et un avant:

Si on affiche avec ce format

1.1 cela donne 1,10

.5 cela donne 0,50

4563 cela donne 4 563,00

Exemple:

Dim N As Double = 19.95

Dim MyString As String = N.ToString("$#,##0.00;($#,##0.00);Zero")

' En page  U.S. English culture, MyString ="$19.95".
' En page  Française , MyString ="19,95€".
Exemple 2:

Dim UnEntier As Integer = 42
MyString = UnEntier.ToString( "Mon nombre " + ControlChars.Lf + "= #" )
Affiche:
Mon nombre
= 42


IX-I-2-b. Str() de Microsoft.VisualBasic est toujours accepté

Il permet de transformer une variable numérique et String, qui peut ensuite être affichée.

MyString=Str( LeNombre)
Label1.Text=MyString
Pas de formatage..


IX-I-2-c. String.Format du Framework

Permet de combiner des informations littérales à afficher sans modification et des zones formatées.

Les arguments de String.Format se décomposent en 2 parties séparées d'une virgule.
  • Chaîne de formatage entre guillemets: Exemple "{0} + {1} = {2}": les numéros indiquent l'ordre des valeurs.
  • Valeurs à afficher dans l'ordre, la première étant d'indice zéro. Exemple= A, B, A+B
Exemple:

Si A=3 et B=5
MsgBox(String.Format("{0} + {1} = {2}",A, B, A+B)) affiche  3+5=8
Autre exemple:

Dim MonNom As String = "Phil"
String.Format("Nom = {0}, heure = {hh}", MonNom, DateTime.Now)
Le texte fixe est "Nom =" et ", heure = ", les éléments de format sont « {0} » et « {hh} » et la liste de valeurs est MonNom et DateTime.Now.

Cela affiche: Nom = Phil Heure= 10

Là aussi on peut utiliser les formats:
  • Prédéfinis: Ils utilisent là aussi les paramètres régionaux, . Ils utilisent C, D, E, F,G,N,P,R,X comme ToString.
    
       MsgBox(String.Format("{0:C}",-456.45))    Affiche -456,45€
    
       MsgBox(String.Format("{0:D8}", 456))    Affiche 00000456    Décimal 8 chiffres
    
       MsgBox(String.Format("{0:P}", 0.14))    Affiche   14%    Pourcent
    
       MsgBox(String.Format("{0:X}", 65535))    Affiche  FFFF    Hexadécimal
    
  • Personnalisés: avec des # et des 0
    
    	MsgBox(String.Format("{0:##,##0.00}", 6553.23))
    

La fonction Format de Microsoft.VisualBasic (pas la classe String.Format) fournit des fonctions similaires mais les arguments sont dans l'ordre inverse (valeur, chaîne de formatage) et il n'y a pas de numéro d'ordre et de{}!! C'est pratique pour afficher une seule valeur.

MyStr = Format(5459.4, "##,##0.00") ' Returns "5,459.40".
MyStr = Format(334.9, "###0.00") ' Returns "334.90".
MyStr = Format(5, "0.00%") ' Returns "500.00%"

IX-I-3. C - CultureInfo

On se rend compte que l'affichage est dépendant de la CurrentCulture du Thread en cours.

Exemple:

Si la CurrentCulture est la 'CultureInfo Us' et que j'affiche avec le format 'C' (monétaire) cela affiche un $ avant, si je suis en 'CurrentCulture Français' cela affiche un € après.

Par défaut la CultureInfo est celle définie dans Windows, probablement 'fr-FR' sur votre ordinateur .

On peut modifier la CurrentCulture par code (voir exemple plus haut).

Imports System.Threading

Thread.CurrentThread.CurrentCulture = New Globalization.CultureInfo("en-us")'passage en culture US culture
En VB , on peut utiliser l'objet My.

MsgBox(My.Application.Culture.ToString) 'affiche 'fr-FR'

(My.Application.ChangeCulture 'permettra de changer la culture )
En français par défaut:

Le séparateur de décimal numérique est le '.'

Exemple : 1.20

Le séparateur décimal monétaire est la ','

Exemple : 1,20€


IX-J. Modifier le curseur, gérer la souris

Comment modifier l'apparence du curseur?

Un curseur est une petite image dont l'emplacement à l'écran est contrôlé par la souris, un stylet ou un trackball. Quand l'utilisateur déplace la souris, le système d'exploitation déplace le curseur.

Différentes formes de curseur sont utilisées pour informer l'utilisateur de l'action que va avoir la souris.


IX-J-1. Apparence du curseur

Pour modifier l'aspect du curseur il faut modifier l'objet Cursor.Current; l'énumération Cursors contient les différents curseurs disponibles:

System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.WaitCursor
ou plus simplement pour afficher le sablier:

Cursor.Current = Cursors.WaitCursor
Pour revenir au curseur normal:

Cursor.Current = Cursors.Default
Comme d'habitude il suffit de taper Cursors. pour voir la liste des curseurs.

Le curseur peut disparaître et être de nouveau affiché par Hide et Show.

Les fichiers curseur sont des .Cur ou des .Ico ; pour 'charger' le curseur personnalisé:

Button1.Cursor = New Cursor("MyCurseur.cur")

IX-J-2. Curseur sur un contrôle:

Un contrôle dans une fenêtre possède une propriété Cursor; en mode design, si je donne une valeur autre que celle par défaut, CursorWait par exemple, cela modifie le curseur quand la souris passe au dessus de l'objet (cela met un sablier dans notre exemple).


IX-J-3. La souris:

Chaque contrôle ou formulaire possède des procédures évènements déclenchées par la souris.

MouseEnter : s'exécute lors de l'arrivée de la souris sur un contrôle

MouseLeave :s'exécute lors de la sortie de la souris d'un contrôle


Plus important:

MouseUp se produit lorsque l'utilisateur appuie sur le bouton de la souris

MouseDown se produit lorsque l'utilisateur lâche sur le bouton de la souris


le déplacement de la souris exécute:

MouseMove se produit lorsque l'utilisateur déplace le pointeur de la souris


Un paramètre e de type MouseEventsArgs est alors disponible pour les 3 évènements.


Exemple:

La procédure évènement se produit quand l'utilisateur appuie sur le bouton de la souris.

Private Sub Form1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown

..

End Sub
Le paramètre e de type MouseEventsArgs permet de connaître la position de la souris et l'état des boutons:

e.X et e.Y contiennent les coordonnées de la souris dans le contrôle en cours.

warning Attention ce sont bien les coordonnées du control alors que dans les opérations de drag and drop ce sont par contre les coordonnées 'écran' qui sont utilisées, il faudra les transformer en coordonnées 'contrôl' avec PointToClient : voir le chapitre sur les coordonnées.
e.Button() retourne le bouton qui a été enfoncé.

if e.Button()=MouseButtons.Left Then..

e.Click() retourne le nombre de Click

e.Delta() retourne le nombre de cran de la molette souris.


Si la souris n'est pas sur le contrôle et que l'on veut quand même récupérer les évènements de la souris sur ce contrôle, il faut mettre la propriété Capture de ce contrôle à True.


IX-J-4. Exemples:

Dans un programme de dessin, quand l'utilisateur enfonce le bouton gauche de la souris, on peut récupérer les coordonnées du point ou se trouve la souris.

Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown

Dim NewPoint As New Point(e.X, e.Y)

End Sub
Pour voir un exemple complet de dessin, regarder Programme simple de Dessin


Exemple affichant dans une 'bulle' le numéro d'index de l'élément survolé dans une listbox:

Dans MouseMove les coordonnées de la souris permettent de déterminer l'index survolé grâce à IndexFromPoint. L'index est affiché dans un ToolTip.

Private Sub ListBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListBox1.MouseMove

ToolTip1.SetToolTip(ListBox1, "Index:"& CType(ListBox1.IndexFromPoint(e.X, e.Y), String))

End Sub
la propriété IndexFromPoint n'existe pas pour les combos.

Voir aussi la page sur le Drag and Drop.


IX-K. Lancer une autre application, afficher une page Web

Comment lancer une autre application, un autre programme ?


IX-K-1. L'ancienne méthode VisualBasic toujours valable: Shell

Shell lance un programme exécutable.

Id=Shell (NomdeProgramme)    'lance l'application NomdeProgramme
on peut utiliser aussi:

Id=Shell( NomdeProgramme, TypedeFenetre, Wait, TimeOut)
TypedeFenêtre utilise l'énumération AppWinStyle pour définir le type de fenêtre de l'application lancée: AppWinStyle.MaximizedFocus ouvre par exemple l'application en plein écran.

Si vous souhaitez attendre la fin du programme avant de continuer, vous devez définir Wait à True.

TimeOut est le nombre de millisecondes à attendre pour la fin du programme si Wait est True.

Exemple:

ID = Shell("""C:\Program Files\MonFichier.exe"" -a -q", , True, 100000)
Dans une chaîne une paire de guillemets doubles adjacents ("") est interprétée comme un caractère de guillemet double dans la chaîne. Ainsi, l'exemple précédent présente la chaîne suivante à la fonction Shell :
"C:\Program Files\MonFichier.exe" -a -q

La fonction AppActivate rend active l'application ou la fenêtre définie par son nom ou son Id (Numéro indentificateur).

Dim ID As Integer
On peut utiliser:

AppActivate("Untitled - Notepad") 
 
ou

ID = Shell(NOTEPAD.EXE", AppWinStyle.MinimizedNoFocus)
AppActivate(ID)

IX-K-2. On peut utiliser la Classe 'Process' du Framework.

La Classe Process fournit l'accès à des processus locaux ainsi que distants, et vous permet de démarrer et d'arrêter des processus système locaux.

Classe de nom à importer :Imports System.Diagnostics

  • On peut instancier un Process

Dim monProcess As New Process()
Ensuite il faut fournir à la classe fille StartInfo les informations nécessaires au démarrage.

monProcess.StartInfo.FileName = "MyFile.doc"
monProcess.StartInfo.Verb = "Print"
monProcess.StartInfo.CreateNoWindow = True
Enfin on lance le process

monProcess.Start()
 
Noter la puissance de cette classe: on donne le nom du document et VB lance l'exécutable correspondant, charge le document, effectue certaines actions.

Dans l'exemple du dessus on ouvre Word on y charge MyFile , on l'imprime, cela sans ouvrir de fenêtre.

  • On peut utiliser la classe Process en statique (sans instanciation)

Process.Start("IExplore.exe")

Process.Start(MonPathFavori)
ou en une ligne:

Process.Start("IExplore.exe", "http//:developpez.com")
En local on peut afficher un fichier html ou asp

Process.Start("IExplore.exe", "C:\monPath\Fichier.htm")
Process.Start("IExplore.exe", "C:\monPath\Fichier.asp")
 
  • On peut enfin utiliser un objet StartInfo

Dim startInfo As New ProcessStartInfo("IExplore.exe")
startInfo.WindowStyle = ProcessWindowStyle.Minimized

Process.Start(startInfo)

startInfo.Arguments = "hrrp//:developpez.com"

Process.Start(startInfo)
Des propriétés du processus en cours permettent de connaître l'Id du processus (Id) les threads, les modules, les Dll ,la mémoire , de connaître le texte de la barre de titre (MainWindowsTitle)..

On peut fermer le processus par Close ou CloseMainWindows


On peut instancier un 'Process' sur une application déjà en cours d'exécution avec GetProcessByName et GetProcessById:

Dim P As Process() = Process.GetProcessesByName("notepad")
 

 ' On peut récupérer le processus courant.
Dim ProcessusCourant As Process = Process.GetCurrentProcess()


' Récupérer toutes les instances de  Notepad qui tournent en local.
Dim localByName As Process() = Process.GetProcessesByName("notepad")
 

' Récupérer tous les processus en cours d'exécution grâce à GetProcesses:
Dim localAll As Process() = Process.GetProcesses()
Processus sur ordinateur distant.

Vous pouvez afficher des données statistiques et des informations sur les processus en cours d'exécution sur des ordinateurs distants, mais vous ne pouvez pas appeler Kill, Start, CloseMainWindows sur ceux-ci.


IX-L. Imprimer

Comment Imprimer ?

Prévoir une longue soirée, au calme, un bon siège, 1 g de paracétamol et un gros thermos de café!!

On verra que l'on peut utiliser pour imprimer:

A- La méthode .Net

Soit avec un composant 'PrintDocument'.

Soit avec une instance de 'la Class PrintDocument'.

B- On peut, en ajoutant une référence, imprimer comme en VB6 et c'est plus simple!!


IX-L-1. A- Avec PrintDocument


IX-L-1-a. 1 Imprimer 'Hello' avec le composant 'PrintDocument'

L'utilisateur clique sur un bouton, cela imprime 'Hello'

Cet exemple utilise un 'composant PrintDocument'

Comment faire en théorie?

C'est le composant PrintDocument qui imprime.

En prendre un dans la boite à outils, le mettre dans un formulaire. Il apparaît sous le formulaire et se nomme PrintDocument1.

Pour imprimer il faut utiliser la méthode Print de ce composant PrintDocument; Il faut donc écrire l'instruction suivante:

PrintDocument1.Print
Cette instruction appelle la procédure évènement PrintDocument1_PrintPage du composant PrintDocument et qui contient la logique d'impression. Un paramètre de cet évènement PrintPage est l'objet graphique envoyé à l'imprimante (nommé e). C'est à vous de dessiner dans l'objet graphique (e) ce que vous voulez imprimer . En fin de routine, l'objet graphique sera imprimé (automatiquement).

En pratique:
  • Je prends un PrintDocument dans la boite à outils, je le met dans un formulaire. Il apparaît sous le formulaire et se nomme PrintDocument1.
  • Si je double-clique sur PrintDocument1 je vois apparaître la procédure PrintDocument1_PrintPage (qui a été générée automatiquement):
    
    Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) 
    	_Handles PrintDocument1.PrintPage
    
    End Sub
    
    C'est cette procédure qui est fondamentale et qui contient les routines d'impression écrites par le programmeur. Les routines d'impression agissent sur l'objet graphique qui sera utilisé pour imprimer , cet objet graphique est fourni dans les paramètres de la procédure(ici c'est e qui est de type PrintPageEventArgs)

  • Dans cette routine PrintPage, j'ajoute donc le code dessinant une texte (DrawString) sur l'objet graphique 'e':
    
    e.Graphics.DrawString("Hello", New Font("Arial", 80, FontStyle.Bold), Brushes.Black, 150, 125)
    
  • Enfin je dessine un bouton nommé 'ButtonPrint' avec une propriété Text contenant "Imprimer Hello" et dans la procédure ButtonPrint_Click j'appelle la méthode Print
    
    PrintDocument1.Print()
    
Voici le code complet:

Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, 
	_ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage

e.Graphics.DrawString("Hello", New Font("Arial", 80, FontStyle.Bold), Brushes.Black, 150, 125)

End Sub

Private Sub ButtonPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonPrint.Click

PrintDocument1.Print()

End Sub
Si je clique sur le bouton 'ImprimerHello' cela imprime un gros 'Hello'.

info La méthode Print d'un PrintDocument déclenche l'évènement PrintPage de ce PrintDocument qui contient le code dessinant sur le graphique de la page à imprimer. En fin de routine PrintPage le graphique est imprimer sur la feuille de l'imprimante.
Toutes les méthodes graphiques écrivant, dessinant, traçant des lignes... sur un graphique permettent donc d'imprimer.


IX-L-1-a-i. Imprimer un dessin:
Créons une ellipse bleue à l'intérieur d'un rectangle avec la position et les dimensions suivantes : début à 100, 150 avec une largeur de 250 et une hauteur de 250.

Private Sub PrintDocument1_PrintPage(ByVal sender As Object, 
	_ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
   e.Graphics.FillEllipse(Brushes.Blue, New Rectangle(100, 150, 250, 250))
End Sub
		

IX-L-1-a-ii. Afficher un Message Box indiquant 'Fin d'impression'
On a étudié l'évènement PrintPage, mais il existe aussi les évènements:

BeginPrint et EndPrint respectivement déclenchés en début et fin d'impression

Il suffit d'utiliser l'évènement EndPrint pour prévenir que l'impression est terminée:

Private Sub PrintDocument1_EndPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles PrintDocument1.EndPrint
   MessageBox.Show("Fin d'impression")
End Sub
On peut même fignoler et afficher "Fin d'impression de Nom du document"

Il faut avoir renseigné le DocumentName:

PrintDocument1.DocumentName = "MyTextFile"

Puis écrire:

Private Sub PrintDocument1_EndPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles PrintDocument1.EndPrint
   MessageBox.Show( "Fin d'impression de "+PrintDocument1.DocumentName)
End Sub

IX-L-1-b. 2-Même programme: Imprimer 'Hello' mais avec la Classe PrintDocument

L'utilisateur clique sur un bouton, cela imprime 'Hello'

Cet exemple utilise 'une instance de la Classe PrintDocument'. On ne met pas de composant 'PrintDocument' dans le formulaire.

Comment faire en théorie?

Il faut importer l'espace de nom 'Printing' par :

Imports System.Drawing.Printing
Il faut créez une instance de la Classe PrintDocument dans le module.

 Dim pd As new PrintDocument()
Il faut créer soi même, une routine pd_PrintPage .

Private Sub pd_PrintPage(sender As object, ev As System.Drawing.Printing.PrintPageEventArgs)
End sub
Il faut indiquer le "lien" entre l'objet pd et la routine évènement PrintPage

AddHandler pd.PrintPage, AddressOf Me.pd_PrintPage
Dans la procédure Button_Click d'un bouton "Imprimer" il faut appeler la méthode Print du PrintDocument pour effectuer l'impression du document .

pd.Print

Cela déclenche la procédure Private Sub pd_PrintPage précédemment écrite, dans laquelle on a ajouté:

ev.Graphics.DrawString ("Hello", printFont, Brushes.Black, leftMargin, yPos, new StringFormat()).
Cela donne le code complet:

Imports System.Drawing.Printing

 

Public Class Form1

Inherits System.Windows.Forms.Form

 

Dim pd As  New PrintDocument 'Assumes the default printer


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    AddHandler pd.PrintPage, AddressOf Me.Pd_PrintPage

End Sub


Private Sub Pd_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)

e.Graphics.DrawString("Hello", New Font("Arial", 80, FontStyle.Bold),   Brushes.Black, 150, 125)

End Sub


Private Sub ButtonPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonPrint.Click

    pd.Print()

End Sub

 

End Class

IX-L-1-b-i. Comment choisir l'imprimante?
Le composant PrintDialog permet le choix de l'imprimante, de la zone à imprimer (tout, la sélection..) et donne accès aux caractéristiques de l'imprimante.

Comment l'utiliser?

Il faut créer une instance de PrintDialog:

    Dim dlg As New PrintDialog
Il faut indiquer au PrintDialog sur quel PrintDocument travailler:

    dlg.Document = pd
Puis ouvrir la fenêtre PrintDialog avec la méthode ShowDialog.

L'utilisateur choisit son imprimante puis clique sur 'Ok'.

Si elle retourne Ok, on imprime.

Quand l'utilisateur clique sur le bouton ButtonPrint ('Imprimer') la fenêtre PrintDialog s'ouvre:

Voici le code complet:

Private Sub ButtonPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonPrint.Click

Dim dlg As New PrintDialog

dlg.Document = pd

Dim result As DialogResult = dlg.ShowDialog()

If (result = System.Windows.Forms.DialogResult.OK) Then

    pd.Print()

End If

 

End Sub

IX-L-1-b-ii. Comment modifier la page à imprimer?
Comment choisir d'imprimer en portrait ou paysage? modifier les marges..

Il faut utiliser un composant PageSetUpDialog.

Pour stocker les informations sur la page (marges...) il faut un PageSetting

Je lie le PageSetting au PageSetUpDialog en donnant à la propriété PageSettings du PageSetUpDialog le nom du PageSetting.

puis j'ouvre le PageSetUpDialog.

Au retour le PageSetting contient les modifications, je les 'passe' au PrintDocument avant d'imprimer.

Cela donne:

Dim psDlg As New PageSetupDialog

Dim LePageSettings As New PageSettings

psDlg. PageSettings = LePageSettings

psDlg.ShowDialog()

pd.DefaultPageSettings = LePageSettings

IX-L-1-c. Prévisualisation de la page à imprimer?

On utilise pour cela un PrintPreviewDialog, on lui indique quel PrintDocument pré visualiser en l'assignant à sa méthode document puis on l'affiche par ShowDialog().

Dim dllg As New PrintPreviewDialog

dllg.Document = pd

dllg.ShowDialog()

IX-L-1-d. Construction d'une application d'impression complexe:

Comment imprimer le contenu d'un fichier texte?

Tous les didacticiels (Microsoft compris) donnent cet exemple.

La première chose que vous devez faire est d'écrire votre logique d'impression. Pour cela, quand la méthode PrintDocument.Print() est appelée, les événements suivants sont déclenchés.

  • BeginPrint
  • PagePrint (un ou plusieurs s'il y a plusieurs pages à imprimer)
  • EndPrint
L'argument d'événement de PagePrint (PagePrintEventArgs) comprend une propriété HasMorePages. Si celle-ci a la valeur True lors du retour de votre gestionnaire d'événements, PrintDocument définit une nouvelle page et déclenche de nouveau l'événement PagePrint.

Voyons la logique dans votre gestionnaire d'événements PagePrint :

  • Imprimez le contenu de la page en utilisant les informations des arguments d'événement. Les arguments d'événement contiennent l'objet Graphics pour l'imprimante, le PageSettings pour cette page, les limites de la page, et la taille des marges.
    Il faut dans la procédure PagePrint imprimer ligne par ligne en se déplaçant à chaque fois vers le bas d'une hauteur de ligne.

    Pour 'simplifier', on considère que chaque ligne ne déborde pas à droite!!

  • Déterminer s'il reste des pages à imprimer.
  • Si c'est le cas, HasMorePages doit être égal à True.
  • S'il n'y a pas d'autres pages, HasMorePages doit être égal à False.

Public Class ExampleImpression
    Inherits System.Windows.Forms.Form

    ....

    private printFont As Font
    private streamToPrint As StreamReader

    Public Sub New ()
        MyBase.New
        InitializeComponent()
    End Sub

    'Evénement survenant lorsque l'utilisateur clique sur le bouton 'Imprimer'
    Private Sub printButton_Click(sender As object, e As System.EventArgs)

        Try
            streamToPrint = new StreamReader ("PrintMe.Txt")
            Try
                printFont = new Font("Arial", 10)
                Dim pd as PrintDocument = new PrintDocument() 'déclaration du PrintDocument
                AddHandler pd.PrintPage, AddressOf Me.pd_PrintPage
                pd.Print()
            Finally
                streamToPrint.Close()
            End Try

        Catch ex As Exception
            MessageBox.Show("Une erreur est survenue: - " + ex.Message)
        End Try

    End Sub

    'Evènement survenant pour chaque page imprimer
    Private Sub pd_PrintPage(sender As object, ev As System.Drawing.Printing.PrintPageEventArgs)

        Dim lpp As Single = 0    'nombre de ligne par page
        Dim yPos As Single =  0  'ordonnée   
        Dim count As Integer = 0 'numéro de ligne
        Dim leftMargin As Single = ev.MarginBounds.Left
        Dim topMargin As Single = ev.MarginBounds.Top
        Dim line as String

        'calcul le nombre de ligne par page
        ' hauteur de la page/hauteur de la police de caractère
        lpp = ev.MarginBounds.Height  / printFont.GetHeight(ev.Graphics)

       
        'lit une ligne dans le fichier
        line=streamToPrint.ReadLine()
        

        'Boucle affichant chaque ligne    

        while (count < lpp AND line <> Nothing)

            yPos = topMargin + (count * printFont.GetHeight(ev.Graphics))

            'Ecrit le texte dans l'objet graphique
            ev.Graphics.DrawString (line, printFont, Brushes.Black, leftMargin, _
                                    yPos, new StringFormat())

            count = count + 1

            if (count < lpp) then
                line=streamToPrint.ReadLine()
            end if

        End While

        'S'il y a encore des lignes, on réimprime une page
        If (line <> Nothing) Then
            ev.HasMorePages = True
        Else
            ev.HasMorePages = False
        End If

    End Sub

    ....

End Class
On a vu que pour 'simplifier', on considère que chaque ligne ne déborde pas à droite.

Dans la pratique, pour gérer les retours à la ligne automatiques on peut dessiner dans un rectangle en utilisant une surcharge de DrawString.

Dim rectangle As New RectangleF (100, 100, 150, 150 )

Dim T as String= "Chaîne de caractères très longue"

g.DrawString (T, Me.Font, New SolidBrush (ColorBlack), Rectangle)
On peut mesurer la longueur (ou le nombre de lignes) d'une chaîne:

Avec MeasureString

(Voir la page sur les graphiques.)


IX-L-1-e. Propriétés du 'PrintDocumet':

On peut sans passer par une 'boite de dialog' gérer directement l'imprimante, les marges, le nombre de copies..

Si pd est le PrintDocument:

pd.PrinterSetting désigne l'imprimante en cours

pd.PrinterSetting.PrinterName retourne ou définit le nom de cet imprimante

pd.PrinterSetting.Printerresolution donne la résolution de cette imprimante.

pd.PrinterSetting.installedPrinted donne toutes les imprimantes installées.

La propriété DefaultPageSetting est en rapport avec les caractéristiques de la page.

pd.PrinterSetting.DefaultPageSetting.Margins donne les marges

pd.PrinterSetting.PrinttoFile permettrait d'imprimer dans un fichier (non testé)


IX-L-1-f. Imprime le formulaire en cours.

Exemple fournit par Microsoft.

La routine CaptureScreen capture l'image du formulaire en cours et la met dans memoryImage. puis memoryImage est passé dans l'objet graphique e qui est imprimé.

Private Declare Function BitBlt Lib "gdi32.dll" Alias "BitBlt" (ByVal _
   hdcDest As IntPtr, ByVal nXDest As Integer, ByVal nYDest As _
   Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal _
   hdcSrc As IntPtr, ByVal nXSrc As Integer, ByVal nYSrc As Integer, _
   ByVal dwRop As System.Int32) As Long
Dim memoryImage As Bitmap
Private Sub CaptureScreen()
   Dim mygraphics As Graphics = Me.CreateGraphics()
   Dim s As Size = Me.Size
   memoryImage = New Bitmap(s.Width, s.Height, mygraphics)
   Dim memoryGraphics As Graphics = Graphics.FromImage(memoryImage)
   Dim dc1 As IntPtr = mygraphics.GetHdc
   Dim dc2 As IntPtr = memoryGraphics.GetHdc
   BitBlt(dc2, 0, 0, Me.ClientRectangle.Width, _
      Me.ClientRectangle.Height, dc1, 0, 0, 13369376)
   mygraphics.ReleaseHdc(dc1)
   memoryGraphics.ReleaseHdc(dc2)
End Sub
Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, _
   ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles _
   PrintDocument1.PrintPage
   e.Graphics.DrawImage(memoryImage, 0, 0)
End Sub
Private Sub PrintButton_Click(ByVal sender As System.Object, ByVal e As _
   System.EventArgs) Handles PrintButton.Click
   CaptureScreen()
   PrintDocument1.Print()
End Sub

IX-L-1-g. Imprime un contrôle DataGrid.

Exemple fournit par Microsoft.

Cet exemple nécessite :
  • un contrôle Button, nommé ImprimerGrid, dans le formulaire ;
  • un contrôle DataGrid nommé DataGrid1 ;
  • un composant PrintDocument nommé PrintDocument1.
Comme d'habitude PrintPage imprime e.Graphics.

D'après ce que j'ai compris, l'évènement Paint redessine un contrôle

mais on peut choisir le contrôle et l'endroit ou le redessiner,

Je redessine donc grâce à Paint,le DataGrid dans e.graphics.

PaintEventArgs Fournit les données pour l'événement Paint:

PaintEventArgs spécifie l'objet graphics à utiliser pour peindre le contrôle, ainsi que le ClipRectangle dans lequel le peindre.

InvokePaint déclenche l'évènement Paint

Private Sub ImprimerGrid_Click(ByVal sender As System.Object, ByVal e As _
   System.EventArgs) Handles PrintGrid.Click
   PrintDocument1.Print()
End Sub

Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, _
   ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles _
   PrintDocument1.PrintPage
   Dim myPaintArgs As New PaintEventArgs(e.Graphics, New Rectangle(New _
      Point(0, 0), Me.Size))
   Me.InvokePaint(DataGrid1, myPaintArgs)
End Sub
Imprime le texte d'un RichTextBox

Voir Imprimer le contenu d'une RichtextBox

Simple, non!! Je plaisante!!


IX-L-2. B- Imprimer comme en VB6 avec un objet 'Printer'

Microsoft propose un PowerPack de compatibilité vb6 le 'Microsoft.VisualBasic.PowerPacks.Printing.Printer' qui ajoute à VB 2005 une Classe permettant d'imprimer 'comme en VB6'; cela permet d'utiliser votre code de routine d'impression VB6 ou de créer des routines d'impression beaucoup plus simple!!

Télécharger le PowerPack Printercompatibility 1

Voir la Documentation complète

Après avoir installé le Pack, aller dans le menu Project cliquer sur 'Ajouter une référence'.

Sur l'onglet NET , cliquez sur Microsoft.VisualBasic.PowerPacks.Printing.Printer, puis sur OK.

Dans le Code, ajouter en haut du module:

Imports Microsoft.VisualBasic.PowerPacks.Printing.Compatibility.VB6

Maintenant on peut utiliser du code VB6 pour imprimer:

Dim pr As New Printer        'Instanciation de l'imprimante par défaut

Dim pFont As New Font("Arial", 14)    'Une nouvelle font

pr.Font = pFont

pr.Print("This text will print in 14 point ")  'Texte à imprimer

pr.EndDoc()    'fin, on lance l'impression
Simple, non!! Je plaisante pas!!

DrawMode, DriverName, hDC, Port, TrackDefault, et Zoom n'existent plus.

Par contre il y a en plus: PrintAction property qui permet un print preview ou permet d'imprimer dans un fichier.

Il y a aussi la PrinterCollection class qui contient les imprimantes . La global Printers collection permet de sélectionner une imprimante.


IX-M. Dessiner

Avec GDI+ utilisé par VB.NET, on utilise des Graphics.

Un Graphics est une simple référence à

une Image ( un BitMap ou un MetaFile).

la surface de dessin d'un contrôle.

Le Graphics n'est pas le dessin lui même, il "pointe" simplement sur le dessin.

Il faut utiliser le Graphics pour dessiner (des points, lignes, rectangles, ellipses, couleur..) ou y écrire.

Rectangle permet de définir une zone.

Pen correspond à un Stylet.

Font correspond à une police de caractères

Brush est une brosse.


IX-M-1. A- Sur quoi dessiner?

Il faut définir une référence, un objet Graphics. On peut y associer des objets Image (des BitMap ou des MetaFile)

Pour obtenir un objet Graphics, il y a plusieurs façons:

  • Soit on instance un objet Graphics.

Dim g as Graphics     'Graphics contient Nothing, je ne peux rien en faire.
Il faut donc y associer un objet Image (un BitMap ou un MetaFile)pour pouvoir travailler dessus.

Pour obtenir un BitMap par exemple, on peut:

Soit créer un objet BitMap vide:

Dim newBitmap As Bitmap = New Bitmap(600, 400) 

Dim g as Graphics = Graphics.FromImage(newBitmap)   
Paramètres= taille du BitMap mais il y a plein de surcharges

Soit créer un BitMap à partir d'un fichier sur disque

C'est pratique si on veut modifier une image qui est dans un fichier: on la lit dans un BitMap puis on passe la référence dans l'objet Graphics.

Dim myBitmap as New Bitmap("maPhoto.bmp")    'Charge maPhoto dans le BitMap
Dim g as Graphics = Graphics.FromImage(myBitmap)    'Crée un Graphics et y associe le BitMap
 
g est un Graphics "pointant" sur l'image 'maPhoto.bmp' et je peux la modifier.

warning Attention: le Graphics n'est pas 'visible', pour le voir il faut le mettre dans un composant (un PictureBox par exemple) qui lui sera visible. On verra cela plus bas.
  • Soit on appelle la méthode CreateGraphics d'un contrôle ou d'un formulaire
On appelle la méthode CreateGraphics d'un contrôle ou d'un formulaire afin d'obtenir une référence à un objet Graphics représentant la surface de dessin de ce contrôle ou formulaire.

Cette méthode est utilisée si vous voulez dessiner sur un formulaire ou un contrôle existant ;

Dim g as Graphics
g = Me.CreateGraphics    'Pour un formulaire

Dim g as Graphics
g = Panel1.CreateGraphics    'Pour un contrôle Panel
On peut ensuite dessiner sur g, cela sera immédiatement visible sur le contrôle ou le formulaire (car g n'est pas un nouvel objet, il contient seulement la référence, le handles, de l'image du contrôle; quand on dessine sur g, en fait, on dessine sur l'image du contrôle).

Il faut quand on n'utilise plus l'objet graphics, utiliser la méthode Dispose pour le libérer.

  • Soit on récupère la référence de l'objet Graphics argument de l'évènement Paint d'un contrôle.
L'événements Paint des contrôles se déclenche lorsque le contrôle est redessiné, un objet Graphics est fourni comme une valeur de PaintEventArgs.

Pour obtenir une référence à un objet Graphics à partir des PaintEventArgs de l'événement Paint et dessiner:
  • Déclarez l'objet Graphics
  • Assignez la variable pour qu'elle référence l'objet Graphics passé dans les PaintEventArgs.
  • Dessinez dans l'objet Graphics.

Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles _
   MyBase.Paint    'appelle la méthode Paint 'normale'
   
   Dim g As Graphics = e.Graphics 
   ' Dessiner avec g , cela affichera dans la Form1
End Sub
Là aussi e est la référence à l'objet qui a déclenché Paint (Form1 ici), si je dessine sur e, en fait je dessine sur Form1.

Noter bien que e est visible uniquement dans Form1_Paint

Pour forcer le déclenchement de l'évènement Paint et dessiner, on utilise la méthode OnPaint


IX-M-2. B-Comment dessiner?

La classe Graphics fournit des méthodes permettant de dessiner

DrawImage     'Ajoute une image (BitMap ou MetaFile) à un gr^phics déjà crée.

DrawLine      'Trace une ligne

DrawString    'Ecrit un texte

DrawPolygon   'Dessine un polygone

...
En GDI+ on envoie des paramètres à la méthode pour dessiner:

Exemple:

MonGraphique.DrawEllipse( New Pen(Couleur),r)    'cela dessine une ellipse
Les 2 paramètres sont: la couleur et le rectangle dans lequel on dessine l'ellipse.

Pour travailler on utilise les objets:

Brush (Brosse) Utilisé pour remplir des surfaces fermées avec des motifs, des couleurs ou des bitmaps.
Il y a plusieurs types de brush:
La brosse peut être pleine et ne contenir qu'une couleur.
Dim SB= New SolidBrush(Color.Red) TextureBrush utilise une image pour remplir.
Dim SB= New TextureBrush(MonImage) LinéarGradientBrush permet des dégradés (passage progressive d'une couleur à une autre).
Dim SB= New LinearGradientBrush(PointDébut, PointFin,Color1, Color2) Les HatchBrush sont des brosse hachurées
Dim HatchBrush hb = new HatchBrush(HatchStyle.ForwardDiagonal, Color.Green,Color.FromArgb(100, Color.Yellow)) Les PathGradient sont des brosses plus complexes.
Pen (Stylet) Utilisé pour dessiner des lignes et des polygones, tels que des rectangles, des arcs et des secteurs.
Comment créer un Stylet?
Dim blackPen As New Pen(Color.Black) on donne la couleur Dim blackPen As New Pen(Color.Black, 3)on donne couleur et l'épaisseur Dim blackPen As New Pen(MyBrush) on peut même créer un stylet avec une brosse Propriétés de ce Stylet:
DashStyle permet de faire des pointillés.
StartCap et EndCap définissent la forme du début et de la fin du dessin (rond, carré, flèche..)
Font (Police) Utilisé pour décrire la police utilisée pour afficher le texte.
Dim Ft= New Font("Lucida sans unicode",60) 'paramètres=nom de la font et taille Il y a de nombreuses surcharges.
Dim Ft= New Font("Lucida sans unicode",60, FontStyle.Bold)'pour écrire en gras
Color (Couleur) Utilisé pour décrire la couleur utilisée pour afficher un objet particulier. Dans GDI+, la couleur peut être à contrôle alpha. System.Drawing.Color.Red pour le rouge
Point Ils ont des cordonnées x, y Dim point1 As New Point(120, 120) ' Point avec des Integer ou des PointF 'avec des Singles
Rectangle Permet de définir un rectangle. Dim r As New RectangleF(0, 0, 100, 100) On remarque que le F après Point ou Rectangle veut dire 'Float', et nécessite l'usage de Single.
Comment faire?

Dessiner une ligne sur le graphique:

Pour dessiner une ligne, on utilise DrawLine.

Dim blackPen As New Pen(Color.Black, 3)    'créer un stylet noir d'épaisseur 3
' Créer des points
Dim point1 As New Point(120, 120)    'créer des points
Dim point2 As New Point(600, 100)
' Dessine la ligne
e.Graphics.DrawLine(blackPen, point1, point2)
On aurait pu utiliser une surcharge de Drawline en spécifiant directement les coordonnées des points.

Dim x1 As Integer = 120
Dim y1 As Integer = 120
Dim x2 As Integer = 600
Dim y2 As Integer = 100
e.Graphics.DrawLine(blackPen, x1, y1, x2, y2)

Dessiner une ellipse:

Définir un rectangle dans lequel sera dessiné l'ellipse.

Dim r As New RectangleF(0, 0, 100, 100)

g.DrawEllipse(New Pen(Color.Red), r)' Dessinons l' ellipse

Dessiner une rectangle:

myGraphics.DrawRectangle(myPen, 100, 50, 80, 40)
Comme d'habitude on peut fournir après le stylet des coordonnées(4), des points (2) ou un rectangle.


Dessiner un polygone:

Dim MyPen As New Pen(Color.Black, 3)
' Créons les points qui définissent le polygone
Dim point1 As New Point(150, 150)
Dim point2 As New Point(100, 25)
Dim point3 As New Point(200, 5)
Dim point4 As New Point(250, 50)
Dim point5 As New Point(300, 100)
Dim point6 As New Point(350, 200)
Dim point7 As New Point(250, 250)
Dim curvePoints As Point() = {point1, point2, point3, point4, _
point5, point6, point7}
' Dessinons le Polygone.
e.Graphics.DrawPolygon(MyPen, curvePoints

Dessiner un rectangle plein:

e.FillRectangle(new SolidBrush(Color.red), 300,15,50,50)
Il existe aussi DrawArc, DrawCurve, DrawBezier DrawPie..


Ecrire du texte sur le graphique:

Pour cela on utilise la méthode DrawString de l'objet graphique:

g.DrawString ("Salut", Me.Font, New SolidBrush (ColorBlack), 10, 10)
Paramètres:

Texte à afficher.

Police de caractères

Brosse , cela permet d'écrire avec des textures.

Coordonnées.

Si on spécifie un rectangle à la place des 2 derniers paramètres, le texte sera affiché dans le rectangle avec passage à la ligne si nécessaire:

Dim rectangle As New RectangleF (100, 100, 150, 150 )

Dim T as String= "Chaîne de caractères très longue"

g.DrawString (T, Me.Font, New SolidBrush (ColorBlack), Rectangle)
On peut même imposer un format au texte:

Exemple: centrer le texte.

Dim Format As New StringFormat()

Format.Aligment=StringAlignment.Center

g.DrawString (T, Me.Font, New SolidBrush (ColorBlack), Rectangle, Format)
On peut mesurer la longueur (ou le nombre de lignes) d'une chaîne:

Avec MeasureString

Exemple 1: centrer le texte: pour cela, calculer la longueur de la chaîne, puis calculer le milieu de l'écran moins la 1/2 longueur de la chaîne:

Dim W As Double= Me.DisplayRectangle.Width/2

Dim L As SizeF= e.Graphics.MeasurString (Texte, TextFont)

Dim StartPos As Double = W - (L.Width/2)

g.Graphics.MeasureString (T, Me.Font, New SolidBrush (ColorBlack), Rectangle, StartPos, 10)
Exemple 2:Calculer le nombre de ligne et le nombre de caractères d'une chaîne:

g.Graphics.MeasureString (T, Me.Font, New SolidBrush (ColorBlack), Rectangle,New StringFormat() NombredeCaractères, NombredeLignes)

Ajouter une image sur le graphique:

Pour cela on utilise la méthode DrawImage de l'objet graphique:

g.Graphics.DrawImage(New Bitmap("sample.jpg"), 29, 20, 283, 212)
On peut travailler avec des images .jpeg .png .bmp .Gif .icon .tiff .exif


IX-M-3. C- Travailler sur un Objet Image

Charger une image:

Si on veut afficher une image bitmap ou vectoriel, il faut que Graphics référence un objet bitmap ou vectoriel. C'est la méthode DrawImage qui reçoit l'objet Metafile ou Bitmap comme argument. L'objet BitMap, si on le désire peut charger un fichier qui sera affiché.

Dim myBMP As New BitMap ("MonImage.bmp")

myGraphics.DrawImage(myBMP, 10, 10)
Le point de destination du coin supérieur gauche de l'image, (10, 10), est spécifié par les deuxième et troisième paramètres.

myGraphics.FromImage(myBMP) est aussi possible

On peut utiliser plusieurs formats de fichier graphique : BMP, GIF, JPEG, EXIF, PNG, TIFF et ICON.


Cloner une image:

La classe Bitmap fournit une méthode Clone qui permet de créer une copie d'un objet existant. La méthode Clone admet comme paramètre un rectangle source qui vous permet de spécifier la portion de la Bitmap d'origine à copier. L'exemple suivant crée un objet Bitmap en clonant la moitié supérieure d'un objet Bitmap existant. Il dessine ensuite les deux images.

Dim originalBitmap As New Bitmap("Spiral.png")'on charge un fichier png dans un BitMap
Dim sourceRectangle As New Rectangle(0, 0, originalBitmap.Width, _
originalBitmap.Height / 2) 'on définit un rectangle

Dim secondBitmap As Bitmap = originalBitmap.Clone(sourceRectangle, _
PixelFormat.DontCare)'on définit un second BitMap Clonant une partie du 1ere BitMap avec le rectangle

'On met les 2 BitMap dans un  Graphics

myGraphics.DrawImage(originalBitmap, 10, 10)
myGraphics.DrawImage(secondBitmap, 150, 10)

Enregistrer une image sur disque:

On utilise pour cela la méthode Save.

Exemple: enregistrer le BitMap newBitMap dans 'Image1.jpg'

newBitmap.Save("Image1.jpg", ImageFormat.Jpeg)

IX-M-4. D- Comment voir un Graphics?

Si on a instancé un objet Graphics, on ne le voit pas. Pour le voir il faut le mettre dans un PictureBox par exemple:

Exemple:

Dim newBitmap As Bitmap = New Bitmap(200, 200) 'créons un BitMap

Dim g As Graphics = Graphics.FromImage(newBitmap)'créons un Graphics et y mettre le BitMap

Dim r As New RectangleF(0, 0, 100, 100)' Dessinons une ellipse

g.DrawEllipse(New Pen(Color.Red), r)
Comment voir l'ellipse?

Ajoutons un PictureBox au projet, et donnons à la propriété Image de ce PictureBox le nom du BitMap du Graphics:

PictureBox1.Image = newBitmap
L'ellipse rouge apparaît!! Si ,Si!!

Si on utilise un objet Graphics représentant la surface de dessin d'un contrôle:

Le fait de dessiner sur le graphics affiche automatiquement le dessin sur le contrôle.


Pour que le dessin soit 'persistant' voir l'exemple e4-3 (logiciel de dessin)


IX-M-4-a. Paint déclenché par Resize.

Par défaut Paint n'est pas déclenché quand un contrôle ou formulaire est redimensionné, pour forcer à redessiner en cas de redimensionnement, il faut mettre le style Style.Resizedraw du formulaire ou du contrôle à true.

SetStyle (Style.Resizedraw, true)
Cette syntaxe marche, la suivante aussi (pour le formulaire)

Me.SetStyle (Style.Resizedraw, true) 'pour tous les objets du formulaire?
Mais PictureBox1.SetStyle (Style.Resizedraw, true) n'est pas accepté!!


IX-M-5. E- Un exemple: Afficher un texte en 3D

Afficher un texte en 3d.

PrivateSub TextEn3D(ByVal g As Graphics, ByVal position As PointF, ByVal text AsString, ByVal ft As Font, ByVal c1 As Color, ByVal c2 As Color)

    Dim rect AsNew RectangleF(position, g.MeasureString(text, ft))

    Dim bOmbre AsNew LinearGradientBrush(rect, Color.Black, Color.Gray, 90.0F)

 

    g.DrawString(text, ft, bOmbre, position)

 

    position.X -= 2.0F

    position.Y -= 6.0F

 

    rect = New RectangleF(position, g.MeasureString(text, ft))

    Dim bDegrade AsNew LinearGradientBrush(rect, c1, c2, 90.0F)

 

    g.DrawString(text, ft, bDegrade, position)

EndSub

IX-M-6. Espace de nom

Pour utiliser les graphiques il faut que System.Drawing soit importé (ce qui est fait par défaut).

(Systém.Drawing.DLL comme références de l'assembly)


IX-N. Faire une aide pour l'utilisateur

Quand un utilisateur utilise votre logiciel, il se pose parfois des questions, comment l'aider?

Avec des aides que le programmeur doit créer et ajouter au programme.


IX-N-1. Généralisées sur les 4 sortes d'aide.

  1. La Class Help permet d'ouvrir un fichier d'aide.
  2. Le composant HelpProvider offre 2 types d'aide.
    • Le premier consiste à ouvrir un fichier d'aide grâce à F1.
    • Quant au second, il peut afficher une aide brève pour chacun des contrôles en utilisant le bouton d'aide (?). Il s'avère particulièrement utile dans les boîtes de dialogue modale.
  3. Le composant ToolTip offre lui:
    • une aide propre à chaque contrôle des Windows Forms.
  4. Le composant ErrorProvider est un moyen de signaler une erreur dans un contrôle

IX-N-2. Les fichiers d'aide:

On peut utiliser les formats:

HTML Fichier .htm

HTMLHelp 1.x ou version ultérieure) Fichier .chm

HLP Fichier .hlp les plus anciens.

Comment créer ces fichiers:

Pour les fichiers HTM:

Utiliser Word, ou FrontPage, ou Netscape Composeur...

Pour les fichiers HLP:

Utiliser Microsoft HelpWorkshop livré avec VB6 (les fichiers .HLP fonctionnent nativement sous Windows 98 et XP mais ne fonctionne plus sous Windows Vista; si on veut quand même les utiliser, il faut télécharger puis installer WinHelp32.exe pour Vista (Télécharger Ici).

Pour les fichiers CHM:

Thierry AIM fournit sur le site developpez.com un excellent:

Cours pour créer un fichier CHM

On conseille d'utiliser les fichiers chm.


IX-N-3. Utilisation des fichiers d'aide:


IX-N-3-a. Appel direct:

La classe Help permet d'ouvrir directement par code un fichier d'aide.

C'est ce qu'on utilise dans le menu '?' d'un programme (sous menu 'Aide'); dans la procédure correspondante (Sub Aide_Click) on écrit:

Help.ShowHelp (Me, "MonAide.html")
MonAide.html doit être dans le répertoire de l'application (répertoire Bin)

Cela peut être un URL , l'adresse d'une page sur Internet!!

Il peut y avoir un 3ème paramètre: on verra cela plus bas (C'est le même paramètre que la propriété HelpNagigator de HelpProvider).

Help.ShowHelp(Me, "file://C:\Windows\Help\calc.chm", HelpNavigator.TableOfContents)

IX-N-3-b. Appel par F1:

Vous pouvez utiliser le composant HelpProvider pour attacher des rubriques d'aide figurant dans un fichier d'aide (au format HTML, HTMLHelp 1.x ou ultérieur) à des contrôles de l'interface utilisateur.

Quand on met un composant dans un formulaire (avec dans la propriété HelpNamespace, le nom de fichier d'aide), cela ajoute aux contrôles de ce formulaire les propriétés:

  • HelpNavigator qui déterminent le type d'appel (par numéro de rubrique, mot clé..)
  • HelpKeyword qui contient le paramètre de recherche (le numéro de rubrique, le mot clé..)
Quand l'utilisateur est sur le contrôle et qu'il clique sur F1 la rubrique d'aide s'ouvre.

Pour créer cette aide:

Faites glisser un composant HelpProvider de la boîte à outils vers votre formulaire.

Le composant se place dans la barre d'état située au bas de la fenêtre.

Dans la fenêtre Propriétés du HelpProvider , donner à la propriété HelpNamespace, un nom de fichier d'aide .chm, ou .htm.

Dans la fenêtre Propriétés du contrôle de l'interface qui doit déclencher l'aide, donner à la propriété HelpNavigator une valeur de l'énumération HelpNavigator.

Cette valeur détermine la façon dont la propriété HelpKeyword est passée au système d'aide. HelpNagigator peut prendre la valeur:

AssociateIndex Indique que l'index d'une rubrique spécifiée est exécuté dans l'URL spécifiée.
Find Indique que la page de recherche d'une URL spécifiée est affichée.
Index Indique que l'index d'une URL spécifiée est affiché.
KeywordIndex Spécifie un mot clé à rechercher et l'action à effectuer dans l'URL spécifiée.
TableOfContents Indique que le sommaire du fichier d'aide HTML 1.0 est affiché.
Topic Indique que la rubrique à laquelle l'URL spécifiée fait référence est affichée.
Définisser la propriété HelpKeyword dans la fenêtre Propriétés. (la valeur de cette propriété sera passé au fichier d'aide afin de déterminer la rubrique d'aide à afficher)

Au moment de l'exécution, le fait d'appuyer sur F1 lorsque le contrôle (dont vous avez défini les propriétés HelpKeyword et HelpNavigator) a le focus ouvre le fichier d'aide associé à ce composant HelpProvider.

Remarque Vous pouvez définir, pour la propriété HelpNamespace, une adresse http:// (telle qu'une page Web). Cela permet d'ouvrir le navigateur par défaut sur la page Web avec la chaîne indiquée dans la propriété HelpKeyword utilisée comme ancre (pour accéder à une section spécifique d'une page HTML).

Dans le code il faut utiliser la syntaxe HelpProvider.SetHelpKeyword=".."

Exemple:

Pour afficher la page d'aide sur les formes ovales, sélectionnez la valeur HelpNavigator.KeyWordIndex dans la liste déroulante Help Navigator ; dans la zone de texte HelpKeyword, 'tapez « ovales » (sans chevrons).


IX-N-3-c. Utilisation du bouton d'aide

Vous pouvez afficher l'aide pour un contrôle via le bouton Aide (?) situé dans la partie droite de la barre de titre .

Il faut que l'utilisateur clique sur le bouton d'aide (?) puis sur le contrôle qui nécessite une aide, ce qui entraîne l'ouverture d'un carré blanc contenant un message d'aide.

L'affichage de l'aide de cette façon convient particulièrement aux boîtes de dialogue. En effet, avec un affichage modal des boîtes de dialogue, il n'est pas facile d'ouvrir des systèmes d'aide externe, dans la mesure où les boîtes de dialogue modales doivent être fermées avant que le focus puisse passer à une autre fenêtre. Le bouton Réduire ou Agrandir ne doit pas être affiché dans la barre de titre. Il s'agit d'une convention pour les boîtes de dialogue alors que les formulaires disposent généralement de boutons Réduire et Agrandir.

Pour afficher l'aide contextuelle

Faites glisser un composant HelpProvider de la boîte à outils vers votre formulaire.

Le contrôle est placé dans la barre d'état des composants située au bas de la fenêtre.

Attribuer aux propriétés Minimize et Maximize de la fenêtre la valeur false.

Puis,

Dans la fenêtre Propriétés de la fenêtre, donner à la propriété HelpButton la valeur true. Cette configuration permet d'afficher dans la partie droite de la barre de titre du formulaire un bouton contenant un point d'interrogation.

Sélectionnez le contrôle pour lequel vous souhaitez afficher l'aide dans votre formulaire et mettre dans la propriété HelpString la chaîne de texte qui sera affichée dans une fenêtre de type ToolTip.

Test:

Appuyez sur F5.

Appuyez sur le bouton Aide (?) de la barre de titre et cliquez sur le contrôle dont vous avez défini la propriété HelpString. Le toolTip apparaît.


IX-N-3-d. Utilisation des info bulles.

Le composant ToolTip peut servir à afficher des messages d'aide courts et spécialisés relatifs à des contrôles individuels.

Cela ouvre une petite fenêtre indépendante rectangulaire dans laquelle s'affiche une brève description de la raison d'être d'un contrôle lorsque le curseur de la souris pointe sur celui-ci.

Il fournit une propriété qui précise le texte affiché pour chaque contrôle du formulaire.

En outre, il est possible de configurer, pour le composant ToolTip, le délai qui doit s'écouler avant qu'il ne s'affiche.

Comment faire:

Ajoutez le contrôle ToolTip au formulaire.

Chaque contrôle à maintenant une propriété ToolTip ou on peut mettre le texte a afficher dans l'info bulle

Utilisez la méthode SetToolTip du composant ToolTip.

On peut aussi le faire par code:

ToolTip1.SetToolTip(Button1, "Save changes")
Par code créons de toute pièce un ToolTip.

Dim toolTip1 As New ToolTip()

' modifions les délais du ToolTip.
toolTip1.AutoPopDelay = 6000
toolTip1.InitialDelay = 2000
toolTip1.ReshowDelay = 500
' Force le ToolTip a être visible que la fenêtre soit active ou non .
toolTip1.ShowAlways = True

' donne le texte de l'info bulle à 2 contrôles.
toolTip1.SetToolTip(Me.button1, "My button1")
toolTip1.SetToolTip(Me.checkBox1, "My checkBox1")

IX-N-3-e. Utilisation de ErrorProvider.

Le composant ErrorProvider peut servir à afficher un panneau d'erreur et un message d'aide court.

Exemple: une zone TextBox doit permettre de saisir une valeur numérique. si cela n'est pas le cas et qu'on tente de sortir du textbox ou de fermer la fenêtre, le panneau (!) s'affiche , et on ne peut pas sortir le focus du textbox.

Si on survole le panneau(!) cela affiche le message.

Pour cela on utilise l'évènement Validating du textBox qui est déclenché quand on tente de sortir, si le texte n'est par numérique, on donne le message au ErrorProvider et on annule la sortie (e.Cancel=True)

Private Sub MyBox_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBox.Validating

If Not IsNumeric(Me.MyBox.Text) Then

    Me.ErrorProvider1.SetError(Me.MyBox, "L'entrée doit être numérique")

    e.Cancel = True

Else

    Me.ErrorProvider1.SetError(Me.MyBox, "")

End If

End Sub

IX-O. Appeler un API

Les Api (Application Programming Interface) sont des bibliothèques de liaisons dynamiques (DLL, Dynamic-Link Libraries), se sont des fonctions (généralement écrites en C) et qui sont compilées dans une DLL.

Elles font :

soit partie intégrante du système d'exploitation Windows.(API Windows)

Ce sont ces Api (Kernel32.Dll=coeur du système, User32Dll= fonctionnement des applications, gdi32..dll=interface graphique) que Windows utilise pour fonctionner.

Les fonctions sont donc écrites pour Windows; parfois on n'a pas d'équivalent VB, aussi, plutôt que de les réécrire quand on en a besoin, on appelle celles de Windows.

Elles permettent d'effectuer des tâches lorsqu'il s'avère difficile d'écrire des procédures équivalentes. Par exemple, Windows propose une fonction nommée FlashWindowEx qui vous permet de varier l'aspect de la barre de titre d'une application entre des tons clairs et foncés.

Il faut avouer que, le Framework fournissant des milliers de classes permettant de faire pratiquement tout ce que font les Api Windows, on a rarement besoin d'utiliser les Api Windows. Chaque fois que cela est possible, vous devez utiliser du code managé à partir du .NET Framework plutôt que les appels API Windows pour effectuer des tâches.

soit partie de dll spécifiques fournies par des tiers pour permettre d'appeler des fonctions n'existant pas dans VB ni Windows.

Par exemple , il existe des Api MySql qui donnent accès aux divers fonctions permettant d'utiliser une base de données MySql. (Ces Api contiennent 'le moteur' de la base de données.)

Les Api Windows sont en code non managé. De plus elles n'utilisent souvent pas les mêmes types de données que VB . L'appel des Api se faisant avec des passages de paramètres, il y a des précautions à prendre!! Sinon cela plante!!!cela plante vraiment.

Il y a des API .Net en code managé.


IX-O-1. Appel d'une fonction dans une Api

Il faut déclarer la fonction en haut du module:

Declare  Function  MyFonction Lib "MyLibary.dll" () as Integer
On indique ici qu'on veut utiliser la fonction MyFonction situé dans la dll MyLibrary.dll; cette fonction retourne un Integer.

Ensuite on peut utiliser MyFonction dans le code:

Dim a = MyFonction()
Exemple:

On va récupérer le nom de l'utilisateur en appelant la fonction GetUserNameA de la dll "advapi32.dll"

Declare Function getUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, ByRef nSize As Integer) As Integer

Dim buffer As String = New String(CChar(" "), 25)

 Dim retVal As Integer = getUserName(buffer, 25) 

Dim userName As String = Strings.Left(buffer, InStr(buffer, Chr(0)) - 1)
Le terme Alias permet de donner un nom a la fonction (getusername) dans le module alors que le vrai nom dans la dll est différent (GetUserNameA).


IX-O-2. Les Api Windows

L'avantage de l'utilisation d'API Windows dans votre code réside dans le gain de temps de développement, car elles contiennent des centaines de fonctions utiles déjà écrites et prêtes à être utilisées. L'inconvénient des API Windows est qu'elles peuvent être complexes à utiliser et implacables lorsqu'une opération se déroule mal.

Pour plus d'informations sur les API Windows, consultez la documentation du kit de développement Win32 SDK dans les API Windows du kit de développement Platform SDK. Pour plus d'informations sur les constantes utilisées par les API Windows, examinez les fichiers d'en-tête, tels que Windows.h, fournis avec le kit de développement Platform SDK. MSDN donne aussi une description des Api


Appels API avec Declare

La façon la plus courante d'appeler les API Windows consiste à utiliser l'instruction Declare.

Exemple ( repris de chez Microsoft): appel de la fonction Windows 'MessageBox' qui est dans user32.dll et qui affiche une MessageBox.

  • Rechercher de la documentation de la fonction: MSDN et les Api donne la définition de la fonction MesssageBox:
    
    int MessageBox(      
        HWND hWnd,
        LPCTSTR lpText,
        LPCTSTR lpCaption,
        UINT uType
    );
    
    Parameters

    hWnd
    [in] Handle to the owner window of the message box to be created. If this parameter is NULL, the message box has no owner window.
    lpText
    [in] Pointer to a null-terminated string that contains the message to be displayed.
    lpCaption
    [in] Pointer to a null-terminated string that contains the dialog box title. If this parameter is NULL, the default title Error is used.
    uType
    [in] Specifies the contents and behavior of the dialog box. This parameter can be a combination of flags from the following groups of flags.

    Constantes API Windows : Vous pouvez déterminer la valeur numérique de des constantes utiliser dans les Api par l'examen des instructions #define dans le fichier WinUser.h. Les valeurs numériques sont généralement affichées au format hexadécimal. Par conséquent, vous pouvez les convertir au format décimal. Par exemple, si vous voulez combiner les constantes pour le style exclamation MB_ICONEXCLAMATION 0x00000030 et le style Oui/Non MB_YESNO 0x00000004, vous pouvez ajouter les nombres et obtenir un résultat de 0x00000034, ou 52 décimales.

    Return Value

    IDABORT Abort button was selected
    IDCANCEL Cancel button was selected.
    IDCONTINUE Continue button was selected.
    IDIGNORE Ignore button was selected.
    IDNO No button was selected
    IDOK OK button was selected.
    IDRETRY Retry button was selected.
    IDTRYAGAIN Try Again button was selected
    IDYES Yes button was selected
  • Il faut déclarer la procédure DLL
    Ajoutez la fonction Declare suivante à la section de déclaration du formulaire de départ de votre projet ou à celle de la classe ou du module où vous voulez utiliser la DLL :
    
    Declare Auto Function MBox Lib "user32.dll" _
    Alias "MessageBox" (ByVal hWnd As Integer, _
       ByVal txt As String, ByVal caption As String, _
       ByVal Typ As Integer) As Integer
    
    Declare comprend les éléments suivants.

    Le modificateur Auto indique de suivre les règles du Common Language Runtime.

    Le nom qui suit Function est celui que votre programme utilise pour accéder à la fonction importée.

    Le mot clé Alias indique le nom réel de cette fonction.

    Lib suivi du nom et de l'emplacement de la DLL qui contient la fonction que vous appelez. Vous n'avez pas besoin d'indiquer le chemin d'accès des fichiers situés dans les répertoires système Windows.

    Utilisez le mot clé Alias si le nom de la fonction que vous appelez n'est pas un nom de procédure Visual Basic valide ou est en conflit avec le nom d'autres éléments de votre application. Alias indique le nom réel de la fonction appelée.

    Les types de données que Windows utilise ne correspondent pas à ceux de Visual Studio. Visual Basic effectue la plupart des tâches à votre place en convertissant les arguments en types de données compatibles, processus appelé marshaling. Vous pouvez contrôler de manière explicite la façon dont les arguments sont marshalés en utilisant l'attribut MarshalAs défini dans l'espace de noms System.Runtime.InteropServices.

    info Remarque Les versions antérieures de Visual Basic vous autorisaient à déclarer des paramètres As Any (tout type). Visual Basic .NET ne le permet pas.
Ajoutez des instructions Const à la section des déclarations de votre classe ou module pour rendre ces constantes disponibles pour l'application. Par exemple :

Const MB_ICONQUESTION = &H20L
Const MB_YESNO = &H4
Const IDYES = 6
Const IDNO = 7
Pour appeler la procédure DLL


   Dim RetVal As Integer ' Valeur de retour.
   
   RetVal = MBox(0, "Test DLL", "Windows API MessageBox", _
                 MB_ICONQUESTION Or MB_YESNO)
   If RetVal = IDYES Then
      MsgBox("Vous avez cliqué sur OUI")
   Else
      MsgBox("Vous avez cliqué sur NON")
   End If
Visual Basic .NET convertit automatiquement les types de données des paramètres et valeurs de retour pour les appels API Windows, mais vous pouvez utiliser l'attribut MarshalAs pour indiquer de façon explicite les types de données non managés attendus par une API.

On peut aussi appeler une API Windows à l'aide de l'attribut DllImport mais c'est compliqué.


IX-O-3. Autre exemple classique.

Utilisation de la routine BitBlt qui déplace des octets.

La documentation donne les renseignements suivants:

     Declare Function BitBlt Lib "gdi32" ( _
        ByVal hDestDC As Long, _
        ByVal x As Long, _
        ByVal y As Long, _
        ByVal nWidth As Long, _
        ByVal nHeight As Long, _
        ByVal hSrcDC As Long, _
        ByVal xSrc As Long, _
        ByVal ySrc As Long, _
        ByVal dwRop As RasterOps _
        ) As Long
Parameter Information

· hdcDest
Identifies the destination device context.

· nXDest
Specifies the logical x-coordinate of the upper-left corner of the destination rectangle.

· nYDest
Specifies the logical y-coordinate of the upper-left corner of the destination rectangle.

· nWidth
Specifies the logical width of the source and destination rectangles.

· nHeight
Specifies the logical height of the source and the destination rectangles.

· hdcSrc
Identifies the source device context.

· nXSrc
Specifies the logical x-coordinate of the upper-left corner of the source rectangle.

· nYSrc
Specifies the logical y-coordinate of the upper-left corner of the source rectangle.

· dwRop
Specifies a raster-operation code.

Les Constantes dwRop

        ' Copies the source bitmap to destination bitmap
         SRCCOPY = &HCC0020
        '
        ' Combines pixels of the destination with source bitmap using the Boolean AND operator.
         SRCAND = &H8800C6
        '                                
        ' Combines pixels of the destination with source bitmap using the Boolean XOR operator.
         SRCINVERT = &H660046   
        ' 
        ' Combines pixels of the destination with source bitmap using the Boolean OR operator.
         SRCPAINT = &HEE0086    
        '
        ' Inverts the destination bitmap and then combines the results with the source bitmap 
        ' using the Boolean AND operator.
         SRCERASE = &H4400328   
        '
        ' Turns all output white.
         WHITENESS = &HFF0062
        '
        ' Turn output black.
         BLACKNESS = &H42 
Return Values

If the function succeeds, the return value is nonzero.

Ici on va utiliser cette routine pour copier l'image de l'écran dans un graphics.

Private Declare Function BitBlt Lib "gdi32.dll" Alias "BitBlt" (ByVal _
   hdcDest As IntPtr, ByVal nXDest As Integer, ByVal nYDest As _
   Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal _
   hdcSrc As IntPtr, ByVal nXSrc As Integer, ByVal nYSrc As Integer, _
   ByVal dwRop As System.Int32) As Long
Dim memoryImage As Bitmap

Private Sub CaptureScreen()
   Dim mygraphics As Graphics = Me.CreateGraphics()
   Dim s As Size = Me.Size
   memoryImage = New Bitmap(s.Width, s.Height, mygraphics)
   Dim memoryGraphics As Graphics = Graphics.FromImage(memoryImage)
   Dim dc1 As IntPtr = mygraphics.GetHdc
   Dim dc2 As IntPtr = memoryGraphics.GetHdc
   
   BitBlt(dc2, 0, 0, Me.ClientRectangle.Width, Me.ClientRectangle.Height, dc1, 0, 0, 13369376)
   
   mygraphics.ReleaseHdc(dc1)
   memoryGraphics.ReleaseHdc(dc2)
End Sub
Le dernier paramètre a pour valeur= 13369376= SRCCOPY = &HCC0020 et correspond à 'Copies the source bitmap to destination bitmap'.

Annexe: Conversions de type

Au cours du regroupement, l'une des principales étapes consiste à convertir les types non gérés en types gérés, et inversement. Le service de regroupement du CLR sait comment effectuer nombre de ces conversions, mais vous devez quand même connaître les correspondances entre les différents types lors de la conversion de la signature non gérée vers la fonction gérée. Vous pouvez utiliser le tableau de conversion suivant pour mettre en correspondance les différents types.

Type de données Windows Type de données .NET
BOOL, BOOLEAN Boolean ou Int32
BSTR String
BYTE Byte
CHAR Char
DOUBLE Double
DWORD/LPDWORD Int32 or UInt32
FLOAT Single
HANDLE (et tous les autres types de pointeur,
tels que HFONT et HMENU)
IntPtr, UintPtr ou HandleRef
HRESULT Int32 or UInt32
INT Int32
LANGID Int16 ou UInt16
LCID Int32 or UInt32
LONG Int32
LPARAM IntPtr, UintPtr ou Object
LPCSTR String
LPCTSTR String
LPCWSTR String
LPSTR String ou StringBuilder*
LPTSTR String ou StringBuilder
LPWSTR String ou StringBuilder
LPVOID IntPtr, UintPtr ou Object
LRESULT IntPtr
SAFEARRAY type de tableau .NET
SHORT Int16
TCHAR Char
UCHAR SByte
UINT Int32 or UInt32
ULONG Int32 or UInt32
VARIANT Object
VARIANT_BOOL Boolean
WCHAR Char
WORD Int16 ou UInt16
WPARAM IntPtr, UintPtr ou Object

IX-P. Faire du glisser déplacer (Drag&Drop)

L'exécution d'opérations glisser-déplacer (Drag ans Drop) peut être ajoutée dans un programme.

La méthode DoDragDrop du contrôle de départ autorise la collecte des données au début de l'opération.

Les évènement DragEnter, DragLeave et DragDrop. permettent de 'poser' les données dans le contrôle d'arrivée.


IX-P-1. Exemple No 1 (simple)

Exemple: Le contrôle de départ est un contrôle Button, les données à faire glisser sont la chaîne représentant la propriété Text du contrôle Button, et les effets autorisés sont la copie ou le déplacement. Le texte sera déposé dans un textBox:

Le contrôle de départ.

La fonctionnalité qui autorise la collecte des données au début de l'opération glisser dans la méthode DoDragDrop.

L'événement MouseDown du contrôle de départ est généralement utilisé pour démarrer l'opération glisser parce qu'il est le plus intuitif (la plupart des glisser-déplacer commencent par un appuie sur le bouton de la souris). Mais, souvenez-vous que n'importe quel événement peut servir à initialiser une procédure glisser-déplacer.

Remarque Les contrôles ListView et TreeView, , ont un événement ItemDrag qui est spécifique .

Private Sub Button1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Button1.MouseDown
   Button1.DoDragDrop(Button1.Text, DragDropEffects.Copy Or DragDropEffects.Move)
End Sub
Le premier argument indique les données à déplacer.

Le second les effets permis = copier ou déplacer.

Le contrôle d'arrivée

Toute zone d'un Windows Form ou d'un contrôle peut être configurée pour accepter les données déplacées en définissant la propriété AllowDrop et en gérant les événements DragEnter et DragDrop.

Dans notre exemple, c'est un contrôle TextBox1 qui est le contrôle d'arrivée.

TextBox1.AllowDrop  =True.     'autorise le contrôle TextBox à recevoir
Dans l'événement DragEnter du contrôle qui doit recevoir les données déplacées

Vérifier que le type des données est compatible avec le contrôle d'arrivée (ici, vérifier que c'est bien du texte).

Définir ensuite l'effet produit lorsque le déplacement a lieu en lui attribuant une valeur de l'énumération DragDropEffects.(ici il faut copier)

Private Sub TextBox1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox1.DragEnter
   If (e.Data.GetDataPresent(DataFormats.Text)) Then
     e.Effect = DragDropEffects.Copy
   Else
     e.Effect = DragDropEffects.None
   End If
End Sub
Dans l'événement DragDrop du contrôle d'arrivée, utilisez la méthode GetData pour extraire les données que vous faites glisser.

Private Sub TextBox1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox1.DragDrop
   TextBox1.Text = e.Data.GetData(DataFormats.Text).ToString
End Sub

IX-P-2. Exemple No 2 plus complexe:

Glisser déplacer une ligne d'une listBox 'ListBox1' vers une listBox 'ListBox2'.

Créer une ListBox1

Créer une listBox2 avec sa propriété AllowDrop=True 'listBox2 accepte le 'lâcher'

Dans l'en-tête du module ajouter:

Public IndexdInsertion As Integer    ' Variable contenant l'index ou sera inséré la ligne

'Eventuellement pour l'exemple charger les 2 ListBox avec des chiffres pour pouvoir tester.

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase

Dim i As Integer

For i = 1 To 100

ListBox1.Items.Add(i.ToString)

Next

For i = 1 To 100

ListBox2.Items.Add(i.ToString)

Next

End Sub

'Dans le listBox de départ, l'évènement MouseDown  déclenche le glisser déplacer par DoDragDrop.

Private Sub ListBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListBox1.MouseDown

ListBox1.DoDragDrop(ListBox1.Items(ListBox1.IndexFromPoint(e.X, e.Y)), DragDropEffects.Copy Or DragDropEffects.Move)

End Sub

'ListBox1.IndexFromPoint(e.X, e.Y) retourne l'Index de l'item ou se trouve la souris à partir des coordonnées e.x et e.y du pointeur)

'DoDragDrop a 2 arguments: l'élément à draguer et le mode

 

'DragOver qui survient quand la souris se balade sur le contrôle d'arrivé, vérifie si le Drop reçoit bien du texte et 
_met dans IndexdInsertion le listItem  qui est sous la souris.

'Noter que e.x et e.y sont les coordonnées écran , il faut les transformer en coordonnées client (du contrôle) par 
_PointToClient afin d'obtenir l'index de l'item ou se trouve la souris (en utilisant IndexFromPoint. 

Private Sub ListBox2_DragOver(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListBox2.DragOver

If Not (e.Data.GetDataPresent(GetType(System.String))) Then

e.Effect = DragDropEffects.None

Else

IndexdInsertion = ListBox2.IndexFromPoint(ListBox2.PointToClient(New Point(e.X, e.Y)))

e.Effect = DragDropEffects.Copy

End If

End Sub

 

'Enfin dans DragDrop, on récupère le texte dans Item et on ajoute un item après l'item pointé.

Private Sub ListBox2_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListBox2.DragDrop

Dim item As Object = CType(e.Data.GetData(GetType(System.String)), System.Object)

ListBox2.Items.Insert(IndexdInsertion + 1, item)

End Sub

IX-Q. Utiliser le 'Registre'

Le Registre est un fichier de stockage des informations relatives aux applications, aux utilisateurs et aux paramètres système. Les applications peuvent utiliser le Registre pour stocker les informations à conserver après leur fermeture et accéder à ces mêmes informations après leur rechargement. On peut stocker les paramètres de taille, couleur, les positions d'affichage ou la taille de la fenêtre. Vous pouvez contrôler ces paramètres pour chaque utilisateur en stockant les informations qui lui correspondent à un emplacement différent du Registre.

Le dictionnaire de l'informatique Microsoft (Microsoft Computer Dictionary, cinquième édition), définit le Registre :

Base de données hiérarchique centrale, utilisée dans Microsoft Windows 9x, Windows CE, Windows NT et Windows 2000, permettant de stocker les informations nécessaires pour configurer le système pour un ou plusieurs utilisateurs, programmes et périphériques matériels, les profils des utilisateurs, les applications installées sur l'ordinateur et les types de documents qu'elles peuvent créer, les paramètres de la feuille de propriétés pour les dossiers et les icônes des applications, le matériel du système et les ports utilisés.

Le Registre remplace la plupart des fichiers texte .ini utilisés dans les fichiers de configuration Windows 3.x et MS-DOS, tels que Autoexec.bat et Config.sys. Bien que le Registre soit commun à Windows 9x Xp Vista , il y a certaines différences.

voir Informations Microsoft sur le registre

On peut modifier directement le registre 'à la main' en lançant le logiciel Regedit mais un programme VB peut aller écrire ou lire dans le registre.

Le registre est composé de Clé, sous-clé et valeur. (une valeur a 'un nom de valeur' et une valeur); cela forme une arborescence.

Une clé donnée peut avoir des sous-clés. Chaque clé peut également avoir plusieurs valeurs qui servent à stocker les informations relatives à l'application qui vous intéresse. Chaque valeur contient des informations spécifiques qui peuvent être extraites ou mises à jour (noms de valeur et valeurs).

Vous remarquerez que les informations stockées dans le Registre sont accessibles aux autres applications et utilisateurs, aussi il est fortement déconseillé d'y mettre des codes d'accès.

Microsoft nous donne les Clés de base, (elles sont en lecture seule) Les clés de base sont le premier niveau de l'arborescence des clés:

CurrentUser
Stocke les informations relatives aux préférences de l'utilisateur.
LocalMachine
Stocke les informations de configuration pour l'ordinateur local.
ClassesRoot
Stocke les informations relatives aux types (et classes) et à leurs propriétés.
Users
Stocke les informations relatives à la configuration utilisateur par défaut. PerformanceData
Stocke les informations relatives aux performances pour les composants logiciels.
CurrentConfig
Stocke les informations concernant le matériel qui ne sont pas spécifiques à l'utilisateur.
DynData

Stocke les données dynamiques

Pour voir les clés de base et l'arborescence des clés exécutons 'Regedit':

Menu 'Démarrer'-> menu 'Exécuter' taper 'Regedit'

On voit ici les 2 premières clés de base HKEY_CLASSES_ROOT et HKEY_CURRENT_USER, on a développé les sous-clés de HKEY_CURRENT_USER qui sont 'AppEvents', 'AutoSetup'..., "Noms". La sous-clé 'Noms' à un nom de valeur nommé 'Nom' qui contient la valeur 'Philippe'.

Pour des raisons de sécurité, il est préférable d'écrire des données dans le dossier utilisateur (Microsoft.Win32.Registry.CurrentUser) plutôt que sur l'ordinateur local (Microsoft.Win32.Registry.LocalMachine).

warning Attention, c'est très dangereux de modifier des clés de registre: une erreur sur une clé important et une application ou Windows plante!!
L'auteur de ce cours décline toute responsabilité.... .... .... ....bla bla bla

Comment ça marche?

L'objet RegistryKey représente un nœud de niveau clé dans le Registre

On instance un noeud:

Dim key As Microsoft.Win32.RegistryKey
La classe Registry fourni les Clés de base (CurrentUser, LocalMachine, ClassesRoot, Users, CurrentConfig...)

On met par exemple dans key le noeud CurrentUser:

key = Microsoft.Win32.Registry.CurrentUser
Ensuite on peut:
  • Créer une sous-clé avec .CreateSubKey
  • Ouvrir une sous-clé avec .OpenSubKey
  • Ecrire ou lire une valeur avec .GetValue ou .SetValue
  • Effacer une valeur avec .DeleteValue
Création d'une Key, écriture de valeur.

Cet exemple ajoute le nom de valeur "Nom" et la valeur "Philippe" au Registre de l'utilisateur en cours.

Cela sous la clé "Noms" dans HKEY_CURRENT_USER du Registre.

Exemple

Dim key As Microsoft.Win32.RegistryKey
key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey("Noms")
key.SetValue("Nom", "Philippe")
Pour voir dans le registre le résultat:

Menu 'Démarrer'-> menu 'Exécuter' taper 'Regedit'

on obtient dans le registre:

Lecture de valeur.

Dim key As Microsoft.Win32.RegistryKey
key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Noms")
Dim name As String = CType(key.GetValue("Nom"), String)
La méthode GetValue retourne un Object. Si votre code comporte Option Strict On, vous devez effectuer un cast de la valeur de retour vers le type de données que vous avez placé précédemment dans la valeur.

GetValue retourne Nothing si la valeur n'existe pas.

Supprimer la Key

Dim key As Microsoft.Win32.RegistryKey
key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Noms", True)
key.DeleteValue("Nom")
Lorsque vous changez le paramètre True par False, la clé est accessible en lecture seule et vous ne pouvez pas la supprimer à l'aide de la variable key.

Bien sur on peut tout faire: ajouter, supprimer une Clé, une valeur, voir la liste des sous-clé, la liste des valeurs...

En VB 2005 la Classe My.Computer.Registry permet un accès à la base de registre:

Dim key As RegistryKey = My.Computer.Registry.ClasseRoot pointe sur la classe de base ClassRoot.
Pour un noeud on a les propriétés: Name, SubKeyCount;si ce dernier est supérieur à 0 GetSubKeyNames retourne un tableau de chaînes contenant le nom des sous-clés. On peut ensuite ouvrir le sous nœud grâce à OpenSubKey.

Si ValueCount est supérieur à 0, le noeud contient des valeurs GetValueNames retourne un tableau de chaîne contenant le nom des valeurs. On peut ensuite lire la valeur avec GetValue.

N'oublier pas de fermer tous les objets RegistryKey (ouverts ou crées) par Close.

Exemples pratiques:

Exemple 1:

Word est-il installé? il faut voir si le registre contient HKEY_CLASSES_ROOT\Word.Application

Dim key As RegistryKey = My.Computer.Registry.ClasseRoot.OpenSubKey ("Word.Application")
If key Is Nothing: Word n'est pas installé.
Exemple 2:

Lire rapidement une valeur? (sans instanciation)

Dim valeur As String = My.Computer.Registry.GetValue ("HKEY_CLASSES_ROOT\Noms","nom","")
3 paramètres: nom de la clé, nom de la valeur (mettre NOTHING pour la valeur par défaut), valeur à retourner si pas de valeur.

Exemple 3:

Modifier rapidement une valeur?

Il existe SetValue.

Avant de l'utiliser il faut ouvrir un registryKey en écriture:

Dim rc As RegistryKey = My.Computer.ClasseRoot.OpenSubKey ("Noms",True) 'True permet l'écriture

rc.SetValue("Nom valeur", valeur)
Il existe enfin DeleteValue, DeleteSubKey et DeleteSubTreeKey..

Exemple 4:

Ajouter une ligne dans le menu contextuel de Windows: clique droit sur un raccourci ou sur un fichier dans l'explorer. Cela ouvre un menu contextuel avec une ligne 'MonProgram'. Si on clique dessus, on lance l'exécutable 'MonProg.exe' et on charge le fichier pointé.

Dim regKey As RegistryKey

regKey = My.Computer.Registry.ClassesRoot.CreateSubKey("*\Shell\MonProgram\command")

My.Computer.Registry.SetValue("HKEY_CURRENT_USER\*\Shell\MonProgram\command", "", 
	_My.Application.Info.DirectoryPath & "\" & "MonProg.exe -o" & Chr(34) & "%L" & Chr(34))
Si MonProg.exe est en VB, il faut récupérer au démarrage le nom du fichier (voir 4-1)


IX-R. Utiliser le 'Presse papier'

On a tous coupé un bout de texte pour le coller à un autre endroit.

Pour cela on a utilisé le presse papier ou 'Clipboard' de Windows.

Comment faire cela par code?

Voyons cela en VB 2003 et VB 2005.


IX-R-1. En VB 2003 (Framework 1)


IX-R-1-a. Mettre dans le presse papier:


Clipboard.SetDataObject(Texte)
il y a une surcharge:

Clipboard.SetDataObject(Texte, True)
Le second paramètre spécifie si les données doivent rester dans le Presse-papiers lorsque l'utilisateur quitte l'application.


IX-R-1-b. Récupérer du presse papier:


Dim iData As IDataObject

iData = Clipboard.GetDataObject()
 
Pour la récupération, il faut s'occuper du format des données: si on récupère un BipMap et qu'on le colle dans un textbox, il y a problème!! On récupère donc un objet qui contient les données mais aussi des indications sur le format des données ;on peut tester ce format avant de 'coller'.

On récupère un objet de type IDataObject qui contient

La méthode GetFormats permettant de connaître tous les formats contenus dans IDataObject

        Dim myFormatsArray As String() = iData.GetFormats(False)
La méthode GetDataPresents permettant de savoir si un format est présent:

       If iData.GetDataPresent(DataFormats.Text) Then 
La méthode GetData permettant de récupérer les données (paramètre: le format)

        textBox2.Text = CType(iData.GetData(DataFormats.Text), String)
Les différents formats:


DataFormats.Text

DataFormats.Rtf

DataFormats.Html

DataFormats.CommaSeparatedValue

DataFormats.Dif

 

DataFormats.BitMap

DataFormats.Dib

DataFormats.WaveAudio

...

IX-R-1-c. Exemple:

Mettre le texte sélectionné de TextBox1 dans le presse papier:

Un Button1 nommé "Copier" contient le code:

If textBox1.SelectedText <> "" Then
    Clipboard.SetDataObject(textBox1.SelectedText)
End if
Remarque: si je voulais un button1 "Couper" il aurait fallu ajouter textBox1.SelectedText=""

Récupérer le texte du presse papier et le mettre dans TextBox2

Un Button2 nommé "Coller" contient le code:

Dim iData As IDataObject = Clipboard.GetDataObject()

' Détermine si c'est du texte.
If iData.GetDataPresent(DataFormats.Text) Then
' récupére le texte par GetData puis le cast en String
textBox2.Text = CType(iData.GetData(DataFormats.Text), String)
Else
' C'est pas du texte.
textBox2.Text = "Pas possible de récupérer."
End If

IX-R-1-d. Alternative:

Au lieu d'utiliser l'objet Clipboard, on peut utiliser une méthode plus simple:

Le formulaire étant actif et la textbox ayant le Focus envoyez CTRL C avec SendKeys.Send pour couper, CTRL V pour coller: c'est Windows qui s'occupe de tout!!


IX-R-2. My.Computer.Clipboard en VB

My.Computer.Clipboard : permet de récupérer des informations sur le contenu du presse-papier, de récupérer et de définir son contenu avec une certaine simplification.

On peut mettre du texte dans le presse-papier:

My.Computer.Clipboard.SetText(TextBox3.Text)
On peut même indiquer le format du texte (rtf, html, text, unicode..):

My.Computer.Clipboard.SetText(TextBox3.Text, TextDataFormat.Rtf)
Il existe aussi SetImage, SetAudio...

On peut vérifier si le Presse-papier contient une image(ContainsImage), du texte( ContainsText), du son (ContainsAudio).. et récupérer cette image (GetImage ) ou ce texte (GetText).

If My.Computer.Clipboard.ContainsImage Then
    PictureBox1.Image = My.Computer.Clipboard.GetImage
ElseIf My.Computer.Clipboard.ContainsText Then
    TextBox1.Text = My.Computer.Clipboard.GetText
End If
Dans VB (le Framework 2) pour copier coller dans un textbox , c'est encore plus facile:

La propriété ShortCutsEnabled = True permet à l'utilisateur d'ouvrir un menu contextuel avec le click droit; ce menu permet les annuler, couper, copier, coller, supprimer, Sélectionner tout; ce qui peut aussi être fait avec les raccourcis clavier Shift/Inser Ctrl/Inser..


IX-S. Paramètres de configuration(App.ini, registre, App.config)

En plus des données, une application a besoin d'utiliser des paramètres:

Ceux de l'application:

Base de données à ouvrir.

Chemin des bases de données.

Chaînes de connexion

Ceux de chaque utilisateur:

Etat, position et dimension des formulaires.

Couleurs.

Paramètres d'imprimante: dimension du papier, police de caractères.

Préférences de l'utilisateur.

..

Toutes ces informations doivent bien être stockées quelque part!!!

On peut les stocker dans:

De simples fichiers.

Des fichiers .INI

Le registre.

Des fichiers de configuration .Config (VB 2003)

Des fichiers de configuration .Config (VB 2005)

En VB2005 on peut même lier une propriété à un paramètre de configuration.


IX-S-1. Les Fichiers:

Il y a longtemps on utilisait un fichier séquentiel.

On ouvrait le fichier avec FileOpen(), on écrivait les paramètres avec Writeline.

Lors d'une utilisation ultérieure du logiciel on lisait les paramètres avec LineInput.

(voir chapitre 4-6)

On utilisait aussi parfois une table dans une base de données pour stocker les paramètres.

Avec Vb.Net certains stockent les paramètres dans un fichier XML (directement ou à l'aide de la serialization)

Mais VB offre d'autres méthodes dédiées à cet usage.


IX-S-2. Fichiers .INI.

Il y a quelques temps (jusqu'à Windows 95 et même après), on utilisait les fichiers .INI.

Chaque application avait son fichier INI, Windows avait aussi ses propres fichiers INI: System.Ini Boot.Ini..

Exemple d'un fichier MonApp.INI , il est situé dans le répertoire de l'application ou dans le répertoire Windows.

Si on le regarde avec NotePad:

[Configuration Matérielle]      
RépertoireDonnées=C:\M\Donnees  
RépertoireSauvegardes=C:\M\Sauve
RépertoireLocal=C:\M\Local      
[Configuration Logiciel]        
SoftAgenda=Calendar.Exe         
TypeAgenda=0                    
PathAgenda= 
Dans notre exemple, le fichier donne les répertoires de données et le nom de l'agenda à utiliser.

Il comporte de grande rubrique,[Configuration Matérielle] entourées de [].

Dans chaque rubrique, il y a des clés, RépertoireDonnées par exemple, suivis d'un = puis de la valeur correspondant à la clé C:\M\Donnees ici.

Comment lire ou écrire dans un fichier Ini 'Privé' (propre à l'application).

Il faut pour cela utiliser des fonctions fournis par les API Windows (elles se trouvent dans Kernel32.dll).

GetPrivateProfileString permet de lire une string correspondant à une clé.

GetPrivateProfileInt permet de lire un entier correspondant à une clé.

PutPrivateProfileString permet d'ecrire une string correspondant à une clé.

PutPrivateProfileInt permet d'écrire un entier correspondant à une clé

A- Avant, il faut les déclarer.

'Fonction lisant un Integer

Declare Function GetPrivateProfileInt Lib "Kernel32" Alias "GetPrivateProfileIntA" (ByVal lpApplicationName As String, ByVal lpKeyName As String, 
	_ByVal nDefault As Long, ByVal lpFileName As String) As Long

 

'Fonction lisant une string

Declare Function GetPrivateProfileString Lib "Kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, 
	_ByVal lpKeyName As String, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Short, 
		_ByVal lpFileName As String) As Integer

 

'Fonction écrivant une string

Declare Function WritePrivateProfileString Lib "Kernel32" Alias "WritePrivateProfileStringA" (ByVal lpApplicationName As String, 
	_ByVal lpKeyName As String, ByVal lpString As String, ByVal lplFileName As String) As Long

 

'Il existe aussi une fonction écrivant un Entier 

 
B- Pour utiliser plus simplement ces appels à la dll , écrivons des fonctions qui gèrent les appels.


Function Get_Private_Profile_Int(ByVal cAppName As String, ByVal cKeyName As String, 
	_ByVal nKeyDefault As Integer, ByVal cProfName As String) As Long

'

' LIRE UN ENTIER

' Parametres:

' cAppName Correspond à [Rubrique]

' cKeyName Nom de l'entrée, de la clé

' nKeyDefault Valeur par défaut de la chaîne cherchée

' cProfName Nom du Fichier "INI" Privé

' Sortie:

' La fonction retourne une valeur numérique entière

 Get_Private_Profile_Int = GetPrivateProfileInt(cAppName, cKeyName, nKeyDefault, cProfName)

End Function

 

Function Get_Private_Profile_String(ByVal cAppName As String, 
	_ByVal cKeyName As String, ByVal cKeyDefault As String, ByRef cKeyValue As String, 
		_ByVal cProfName As String) As Integer

'

' LIRE UNE STRING

' Parametres:

' cAppName Correspond à [Rubrique]

' cKeyName Nom de l'entrée, de la clé

' cKeyDefault Valeur par défaut de la chaîne cherchée

' cKeyValue Valeur lue en face de l'Entrée ou cKeyDefault si l'Entrée est vide

' cProfName Nom du Fichier "INI" Privé

'

' Sortie:

' Valeur lue dans cKeyValue

' La fonction retourne le nombre de caractères dans cKeyValue 

Dim iReaded As Integer

Const sLongueur As Short = 255

If cKeyName = "" Then

cKeyValue = Space$(1025)

iReaded = GetPrivateProfileString(cAppName, "", "", cKeyValue, 1024, cProfName)

Else

cKeyValue = Space$(255)

iReaded = GetPrivateProfileString(cAppName, cKeyName, cKeyDefault, cKeyValue, sLongueur, cProfName)

End If

cKeyValue = Trim$(cKeyValue)

'Enlever le dernier caractère?

'If Len(cKeyValue) <> 0 Then

' cKeyValue = Mid$(cKeyValue, 1, Len(cKeyValue) - 1)

'End If

Get_Private_Profile_String = iReaded

End Function

 

 

Function Put_Private_Profile_String(ByVal cAppName As String, ByVal cKeyName As String, 
	_ByVal cKeyValue As String, ByVal cProfName As String) As Boolean

' ECRIRE UNE STRING

' Parametres:

' cAppName Correspond à [Rubrique]

' cKeyName Nom de l'entrée de la clé

' cKeyValue Valeur lue en face de l'Entrée ou cKeyDefault si l'Entrée est vide

' cProfName Nom du Fichier "INI" Privé

' Sortie:

' La fonction retourne True si cela a marché

Dim Status As Long

Status = WritePrivateProfileString(cAppName, cKeyName, cKeyValue, cProfName)

If (Status <> 0) Then

Put_Private_Profile_String = True

Else

Put_Private_Profile_String = False

End If

End Function

End Class

 
C- Exemple de lecture et d'écriture:

- Lecture du répertoire de données dans MonApp.Ini:

 

Dim cRubrique As String = "Configuration Matérielle"    'Nom de la rubrique

Dim cKey As String = "RépertoireDonnées"                'Nom de la clé

Dim cRepertoire As String = Space(255)                  'Variable récupérant la string  

Dim cIniFile As String = "c:\MonApp\MonApp.ini"         'Nom du fichier Ini 

Dim istat As Integer

 

'Appel de la fonction

istat = Get_Private_Profile_String(cRubrique, cKey, "", cRepertoire, cIniFile)

'Affichage du répertoire de données dans une textbox par exemple

TextBox1.Text = Trim(cRepertoire)

 

' Dans notre exemple cela affiche C:\M\Donnees
- Ecriture :Dans MonApp.Ini, dans la rubrique "Configuration Matérielle", derrière la clé "cRepOld", écrire "No":

Dim cRubrique As String = "Configuration Matérielle"    'Nom de la rubrique  

Dim cIniFile As String = "c:\MonApp\MonApp.ini"         'Nom du fichier Ini 

Dim bOk As Boolean

 

bOk = Put_Private_Profile_String(cRubrique, "cRepOld", "No", cIniFile)

 

'on note que la clé "cRepOld" qui n'existait pas a été créée.
Il a bien été ajouté dans le fichier .Ini : cRepOld=No


IX-S-3. Registre.

A partir de Windows95 et WIndows NT

Attention : l'application doit posséder des droits d'accès au registre suffisants.

Ecriture dans le registre:

Exemple: ajouter la clé "Nom" et la valeur "Philippe" au Registre de l'utilisateur en cours.

Cela sous la clé "Noms" dans HKEY_CURRENT_USER du Registre.

Dim key As Microsoft.Win32.RegistryKey
key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey("Noms")
key.SetValue("Nom", "Philippe")
Pour voir dans le registre le résultat:

Menu 'Démarrer'-> menu 'Exécuter' taper 'Regedit'

Lecture de valeur.

Dim key As Microsoft.Win32.RegistryKey
key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Noms")
Dim name As String = CType(key.GetValue("Nom"), String)
La méthode GetValue retourne un Object. Si votre code comporte Option Strict On, vous devez effectuer un cast de la valeur de retour vers le type de données que vous avez placé précédemment dans la valeur.

GetValue retourne Nothing si la valeur n'existe pas.

voir le chapitre 4-16 pour les détails.


IX-S-4. Fichier de configuration. App.Config File de VB2003 (Framework 1)

On enregistre dans un fichier au format XML.

Créer le fichier de configuration:

Projet->Ajouter un nouvel élément-> cliquer sur 'Fichier de configuration':'App.config' le fichier de configuration en XML est ajouté au projet;(cela ne parrait pas possible en VB 2005 Express)

On le voit dans une fenêtre:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>                        

</configuration> 
Il faut ajouter la partie 'AppSettings' qui contient la configuration, cela donne:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>                        

<appSettings>                          

<add key="TaillePage" value="5" />     

</appSettings>                         

</configuration>  
On remarque que l'on a ajouté les balises <appSettings> et </appSettings>.

Entre ces balises, on peut ajouter des lignes contenant une clé et sa valeur:

<add key="TaillePage" value="5" />
On peut modifier les couples 'clé-valeur' dans l'ide ou bien en ouvrant le fichier App.config avec NotePad.

Pour lire un élément de la configuration:

Dim TaillePage As String = Configuration.ConfigurationSettings.AppSettings("TaillePage")
(on récupère une string :"5" dans l'exemple)

Pour lire tous les éléments:

Dim mAppSet As Specialized.NameValueCollection

mAppSet = Configuration.ConfigurationSettings.AppSettings

 

'Affiche dans MaList les clés:

If Not mAppSet Is Nothing Then

Me.maliste.Items.Clear()

Dim keys() As String

keys = mAppSet.AllKeys

Dim key As String

For Each key In keys

Me.maliste.Items.Add(key & ": " & mAppSet.Item(key))

Next

End If
On met utilise une collection mAppSet de type 'NameValueCollection', on y met AppSettings

On peut voir les clé grâce à mAppSer.GetKey et les valeurs grâce à mAppSet.Item()

Le problème est que pour modifier une valeur par code, il faut charger le fichier XML, modifier puis enregistrer le fichier XML. C'est complexe!! Il existe des classes qui font cela automatiquement.


IX-S-5. Configuration par paramètres Settings de VB2005 (Framework 2)

Dans le Framework 2 Configuration.ConfigurationSettings n'existe plus!!

il faut utiliser Configuration.ConfigurationManager mais il y a beaucoup plus simple avec la classe My .

Les valeurs des paramètres sont enregistrées automatiquement. (Si dans les propriétés du projet, dans l'infrastructure de l'application, "Enregistrer My.setting lors de l'arrêt" est coché. )

Les paramètres de configuration concernent l'application ou l'utilisateur.

Les paramètres d'application sont en lecture seule. Dans la mesure où ces paramètres sont des informations du programme, vous n'avez en principe pas besoin de les modifier. Ce sont par exemple le chemin d'une base de données ou un URL.

En revanche, les paramètres d'utilisateur peuvent être lus et modifiés. Ce sont les positions de formulaires, couleur..

On peut créer les paramètres dans le 'Projet designer':

En vb 2005, pas besoin d'ajouter le fichier comme en vb 2003, le fichier de configuration est crée et ajouté au projet dès que l'on crée un paramètre.

Les paramètres de configuration sont donc directement accessible dans les propriétés du projet (dans l'explorateur de solution double cliquer sur My Projet ou passer par le menu Projet-> Propriétés de..:

Exemple:

Onglet 'Paramètres' , créons un paramètre nommé 'Para1' et contenant '1' (c'est une string)

Un paramètre à un nom, un type, une portée (Application ou Utilisateur), une valeur.

Pour créer, se mettre dans la colonne 'Nom' dans la ligne '*' et taper le nom du paramètre, choisir le type en déroulant la liste avec le bouton de la colonne type, choisir la portée puis éventuellement une valeur.

Donc pas besoin de passer par NotePad et de manipuler de l'XML.

Les fichiers de configuration sont automatiquement crées lors du démarrage de l'application (avec les valeurs par défaut indiquées dans l'onglet 'paramètres').

Pour utiliser un paramètre dans le programme:

on fera:

MonParamètre= My.Parametre.Para1
Les Paramètres sont en Read-Only si la portée est 'Application', et en Read-Write (donc modifiable par code) si la portée est 'Utilisateur'.

Ces 'variables paramètres utilisateur' ont des valeurs qui seront conservées et enregistrées automatiquement dans l' 'environnement' d'un utilisateur (en WindowsForms). Si on en modifie la valeur, on retrouve la valeur modifiée lors d'une utilisation ultérieure ce qui permet de conserver les habitudes des utilisateurs.

Modifions un paramètre utilisateur:

My.Parametre.Para1= "666" 
La nouvelle valeur sera automatiquement enregistrée dans le fichier de config.

Bien sur le paramètre 'NomConnexuinS' qui est un paramètre application n'est pas modifiable.

En VB2005 vous pouvez créer des paramètres de type Color, Font, Point, Size:

My.Settings.MyFont= New Font (Me.Font, FontStyle.Italics)
Profil utilisateur:

On peut créer des 'Profils' avec plusieurs noms de profil qui auront chacun des paramètres ayant leur propre valeur pour chaque utilisateur Windows.

On peut par exemple créer un profil "Philippe" et, dans ce profil, donner à Para1 la valeur '333'. Créer un second profil "Odile" et, dans ce profil, donner à Para1 la valeur '222'. Dans ce cas si l'utilisateur Philippe ouvre une session Windows sous le nom l'utilisateur 'Philippe' et qu'il lance l'application, c'est la valeur '333' qui se trouvera dans My.Parametre.Para1


Evènement survenant lors du changement de valeur des paramètres.

En haut à droite, il y a un bouton ou un menu déroulant qui donne accès à 'Afficher le code'.

Cela donne accès à une Classe partielle Setting qui donne accès aux routines PropertySettings, ChangingSettings, SavingSettings; ainsi quand un paramètre change par exemple, on peut mettre ici le code nécessaire à la mise à jour.


Dans quels fichiers et ou est enregistré le 'setting'? :

Dans des fichiers XML.


En mode design:

Les paramètres d'application et utilisateurs (ceux de départ qui ont été écrits à la main dans les propriétés) sont stockés dans la section MonApplication.My.Settings de:

app.Config qui est dans le source, dans "c:\Documents and setting\NomUtilisateur\Mes Document\Visual Studio 2005\MonApplication\MonApplication"

MonApplication.exe.config dans les répertoires bin et release quand on génère l'application. (c'est ce fichier qui sera déployé)


En cours d'exécution:

Les paramètres d'application sont dans

MonApplication.exe.config dans le répertoire de l'exécutable. (c'est ce fichier qui sera déployé), on rappelle que ces paramètres ne sont pas modifiables.

Les paramètres utilisateurs sont dans

user.config dans le répertoire C:\Documents and Settings\NomUtilisateur\Local Settings\Application Data\NomSociete\MonApplication.exe_Url_43f52d0fihtu0kzyyxxngiyacs5ljtnb\1.0.0.0 . On remarque que VB crée un répertoire dans C:\Documents and Settings\NomUtilisateur\Local Settings\Application Data . Vb utilise ensuite le nom de la société qui distribue le logiciel (le nom qui est dans l'assembly) puis le nom de l'application et enfin la version du programme. Comme le framework s'occupe de tout, à priori, on n'a pas à s'occuper des chemin.


Contenu du fichier WindowsApplication1.exe.config :

Situé dans "c:\Documents and setting\NomUtilisateur\Mes Document\Visual Studio 2005\WindowsApplication1\WindowsApplication1" (et dans bin\release après génération)

L'application se nomme "WindowsApplication1" , on regarde ou est enregistré 'Para1':

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

<configSections>

<userSettings>

<WindowsApplication1.My.MySettings>

<setting name="parmetre1" serializeAs="String">

<value>12</value>

</setting>

</Bonjour.My.MySettings>

</userSettings>

</configuration>
On peut le voir plus rapidement en cliquant dans l'explorateur de solution sur App.Config


IX-S-6. Liaison propriétés <=> Settings de VB2005 (PropertyBinding)

En VB2005, on peut 'lier' la propriété d'un contrôle avec un paramètre. C'est à dire enregistrer automatiquement les valeurs d'une propriété dans les paramètres de configuration.

Prenons un exemple:

J'ai crée une Form1, je veux que l'utilisateur, lorsqu'il lance l'application, retrouve Form1 à la position où il l'avait laissée.

Il faut donc enregistrer la valeur de la propriété Location de Form1 dans le Setting, la configuration, pour cela on va faire du PropertyBinding: On va lier cette propriété à un paramètre du setting.

Dans la fenêtre de propriété de Form1, aller en haut de la liste, cliquer sur le '+'de (ApplicationSettings), puis au niveau de la ligne (PropertyBinding), cliquer sur le bouton à droite. Cela ouvre la fenêtre 'Paramètres d'application de Form1'

Cliquer sur la ligne "location", puis sur le bouton à droite.

Dans la liste qui s'ouvre, cliquer sur 'Nouveau": La fenêtre 'Nouveau paramètre d'application' s'ouvre:

Taper un nom pour le nouveau paramètre (mylocation par exemple), une valeur par défaut si necessaire.

Puis Ok, Ok

C'est fait: le paramètre 'mylocation' est lié à la propriété Location de Form1.

Regardons dans les paramètres de l'application (menu Projet=>Propriétés de..)

On voit bien le nouveau paramètre mylocation de type System.Drawing.Point. Il est lié à Form1.Location (Dans la fenêtre de propriété de form1, sur la ligne location, il y a une toute petite icône qui le signale).

La valeur de Form1.Location sera enregistrée automatiquement et restituée lorsque l'on lancera ultérieurement le programme.

En fait VB génère du code prenant en charge ce BindingProperty: dans l'explorateur de solution cliquer sur MyProjet->Setting.Setting->Setting.Designer.vb on voit le code généré.


IX-T. Utiliser les 'Ressources'

Ressources: Document informatique de toute nature (texte, image, son, programme).

Une ressource est une donnée non exécutable qui est déployée logiquement avec une application.

Les ressources sont un ensemble d'éléments,: images, icônes, textes(chaînes), sons, fichiers ou autres qui sont utilisées par le programme. Elles sont contenues dans un fichier .resx et dans un répertoire de ressource.


IX-T-1. Intérêt des ressources?

Si j'ai une image à utiliser dans un contrôle, pourquoi ne pas la mettre directement dans la propriété de mon contrôle?

Vous créer cette image, si une semaine plus tard vous trouvez une image hyper meilleur, avec les ressources, vous n'avez plus qu'à la placer dans le répertoire Ressources à la place de votre précédente image. Vous recompilez et c'est fait.

Si vous avec une même image qui est utilisée à plusieurs endroit de votre application, avec les ressources, vous n'aurez qu'une seule ressource (donc diminution en taille de l'exe) et une facilité de maintenance: plus besoin d'effectuer la modification partout où l'image est utiliser.

Enfin si vous voulez écrire une version de votre exécutable en français et en Anglais, avec les ressources, il n'est pas nécessaire d' écrire 2 programmes, il suffit de faire 2 fichiers de ressources.


IX-T-2. Les types de ressource?

Les types de ressources sont Chaînes, Images, Icônes, Audio, Fichiers et Autre. Chaînes est l'affichage par défaut.

Chaînes
Affiche des chaînes dans une grille de paramètres avec les colonnes Nom, Valeur et Commentaire . Vous pouvez accéder aux paramètres au moment de l'exécution via My.Resources en tant que String. Pour une description des colonnes dans cette grille, consultez la rubrique "Grille des paramètres" ci-après.

Images
Affiche tous les fichiers image, y compris les formats .bmp, .jpg .png et .gif. Ces fichiers sont exposés au moment de l'exécution en tant que Bitmap.

Icônes
Affiche les fichiers icône (* .ico) qui sont exposés en tant que Icon.

Audio
Affiche les fichiers audio, y compris les fichiers .wav, .wma et .mp3. Ces fichiers sont exposés en tant que tableaux d'octets. Le double-clic sur un élément audio permet de l'ouvrir et de le jouer dans Lecteur Windows Media.

Fichiers
Affiche tous les fichiers qui n'entrent pas dans les catégories précitées. Les éléments dans cet affichage peuvent être des fichiers texte exposés en tant que String ou des fichiers binaires exposés en tant que tableaux d'octets.

Autres
Affiche une grille de paramètres pour ajouter d'autres types qui prennent en charge la sérialisation de chaînes (par exemple, Font, Enum, Color et Point). La grille contient les colonnes suivantes : Nom, Type, Valeur et Commentaire.


IX-T-3. Voir les ressources:

Pour voir les ressources, il faut aller dans les propriétés du projet: double cliquez sur MyProjet dans l'explorateur de solution ou menu 'Projet'=>'Propriétés de..', Onglet 'Ressources')

On voit immédiatement les Chaînes; il est possible de voir les autres types de ressources en déroulant la liste à gauche.

Ici on voit une ressource 'chaîne' qui se nomme 'toto' (c'est nul!!) et qui contient "2".


IX-T-4. Ajouter des ressources:

1-Mettre du texte dans une ressources

Si nécessaire dérouler la liste à gauche et cliquez sur 'Chaînes'.

2 manières d'ajouter une chaîne:

Cliquez sur le bouton 'Ajouter une ressource' puis sur 'Ajouter une nouvelle chaîne'. le curseur se retrouve dans la zone de saisie du nouveau nom: tapez le nom puis la valeur.

Ou cliquez directement dans la zone du nom sur la ligne '*', tapez le nom puis la valeur.

L'enregistrement est automatique.

2-Mettre le dessin dans les ressources:

Aller dans les ressources

Dérouler la liste à gauche pour y mettre 'Images' puis cliquer sur 'ajouter une ressource'; on vous demande le nom de la ressource (tapez par exemple 'button_blue'), vous vous trouver dans Paint, dessinez (ou collez) l'image de votre bouton. Puis menu 'Fichier'=>'Enregistrer': le dessin apparaît dans les ressources. Fermez Paint.


IX-T-5. Ou se trouvent les ressources:

Dans l'explorateur de solutions, on voit bien le répertoire de ressources et la ressource qui vient d'être créee (le fichier Image1.bmp par exemple)

On peut d'ailleurs aller dans ce répertoire et modifier la ressource, remplacer le fichier par un autre, la modification est immédiatement mise à jour dans VB.

Vous créer une image, si une semaine plus tard vous trouvez une image hyper meilleur, vous n'avez plus qu'à la placer dans le répertoire Ressources à la place de votre précédente image.


IX-T-6. Modifier une ressource

Une image par exemple:

Cliquez sur la ressource, puis cliquez avec le bouton droit; dans le menu:

Ouvrir: ouvre l'éditeur par défaut (Paint pour une image)

Ouvrir avec : permet de modifier la ressource avec un autre programme.


IX-T-7. Utiliser une ressource dans le programme:

Les ressources sont accessibles par leur nom dans la Classe My.Ressources.

Mettre le texte d'un ressource dans la barre de titre d'un formulaire:

Me.Text = My.Resources.Form1Title
Mettre une ressource image dans le plan BackGround d'un formulaire:

Me.BackgroundImage = My.Resources.Form1Background
Mettre une ressource image dans le plan BackGround d'un bouton:

MyButton.BackGroundImage= MonProgramme.My.Ressources.Ressources.button_Blue
(voir 3-3 pour un exemple complet)

Mettre une ressource icône comme icône d'un formulaire:

Me.Icon = My.Resources.MyIcon
Jouer un son qui est dans les ressources.

My.Computer.Audio.Play(My.Resources.Form1Greeting, AudioPlayMode.Background)

IX-T-8. Ressources localisées:

On a parfois besoin d'avoir des ressources pour différentes langues. (Texte des boutons en Français ou en Anglais par exemple)

Pour chaque culture faire un fichier .resx

En fait, copier le fichier de ressources et attribuer au fichier de ressources le nouveau nom Resources.CultureSignature.resx

Il semble que les fichiers de ressources de la langue par défaut soit dans le répertoire ressources avec l'extension .resx et que pour chaque autre culture, un sous-répertoire soit nécessaire (sous-répertoire nommé 'fr', 'en-us'..) Enfin dans ce sous répertoire, le fichier se nomme monprogramme.Fr-fr.resx A vérifier!!

Quand la culture de l'ordinateur change, le fichier de ressources correspondant est utilisé.

Exemple: ici on modifie la culture puis on utilise la ressource correspondante.

    Dim Currentculture As String = My.Application.UICulture.Name
    My.Application.ChangeUICulture("fr-FR")
    MsgBox(My.Resources.MyMessage)
    My.Application.ChangeUICulture(Currentculture)

IX-T-9. Ressources liées ou incorporées

Les projets Visual Studio fournissent deux options différentes pour gérer les ressources : celles-ci peuvent être liées (par défaut) ou incorporées. S'il est possible d'avoir à la fois des ressources liées et incorporées dans un même projet, il est plus pratique dans la plupart des cas de choisir une option pour toutes les ressources du projet.

Les ressources liées sont stockées comme des fichiers dans le projet. Pendant la compilation, les données de ressources sont extraites des fichiers et placées dans le manifeste de l'application. Le fichier de ressources (.resx) de l'application stocke uniquement un chemin d'accès relatif ou un lien au fichier sur le disque.

Avec les ressources incorporées, les données de ressources sont stockées directement dans le fichier .resx dans une représentation textuelle des données binaires.

Dans l'un et l'autre cas, les données de ressources sont compilées dans le fichier exécutable.

Les ressources peuvent passer de la valeur « liées » à « incorporées » en modifiant la propriété Persistence du fichier de ressources.

Dans la fenêtre Propriétés, sélectionnez la propriété Persistance et affectez-lui la valeur Incorporé dans .resx.

Dans la fenêtre Propriétés, sélectionnez la propriété Persistance et affectez-lui la valeur Lié au moment de la compilation.

Les ressources incorporées sont le meilleur choix si vous devez partager des fichiers de ressources d'application (.resx) entre plusieurs projets. Par exemple, si vous disposez d'un fichier de ressources communes contenant des informations telles que les logos et les informations relatives aux marques de votre société, l'utilisation de ressources incorporées signifie que vous pouvez vous contenter de copier le fichier .resx et non les fichiers de données de ressources associés.

Vous ne pouvez pas modifier directement les ressources incorporées. Si vous tentez de modifier une ressource incorporée, un message vous invitant à convertir l'élément en ressource liée afin de la modifier s'affichera ; la conversion est recommandée mais facultative. Vous devez les exporter, effectuer vos modifications dans un programme externe, puis les réimporter dans votre projet.

Les ressources de type chaîne sont toujours incorporées et ne peuvent pas être modifiées. Les ressources de fichier sont toujours liées et ne peuvent pas être modifiées.


IX-T-10. Comment cela marche?

Quand on ajoute par exemple une image aux ressources, VB crée (si ce n'est déjà fait), un répertoire Ressources dans votre projet. Puis il copie votre fichier image dans ce répertoire. Ensuite, il crée (ou modifie) un fichier .resX avec une référence vers le fichier image correspondant et une classe interne Ressources. Cette dernière possède des propriétés en lecture seules statiques qui retourne les ressources de votre fichier ressource :

A la compilation, ces images seront incluses dans votre exécutable.

Vous créer cette image, si une semaine plus tard vous trouvez une image hyper meilleur, vous n'avez plus qu'à la placer dans le répertoire Ressources à la place de votre précédente image. Vous recompilez et c'est fait.


IX-U. Ou mettre les programmes et les données


IX-U-1. Il faut séparer les données des programmes !!!

Les programmes, les données n'ont pas la même vocation.

Les fichiers programmes ( les fichiers .exe)sont copiés sur votre disque au moment de l'installation du logiciel ou au moment de sa mise à jour. En dehors de ces périodes, ces fichiers ne changent pas.

Il n'est donc pas utile de sauvegarder fréquemment, car en plus, vous possédez ceux-ci par ailleurs sur un support d'installation (CD-ROM, fichier téléchargé).

Par contre les fichiers de données sont régulièrement créés, enregistrés ou modifiés: mails, documents Word ou Excel, photos, fichiers musicaux, bases de données. Pour ne pas perdre toutes ces informations, il faut les sauvegarder: les enregistrer régulièrement sur un autre support (CD-ROM, disque dur externe, clé USB, autre ordinateur d'un réseau..)

Pour favoriser vos sauvegardes, il est donc logique de séparer vos données de vos programmes, et de les mettre dans des répertoires différents.

Habituellement on a un répertoire de programmes et un répertoire de données, il est possible d'avoir un répertoire de données pour chaque utilisateur si les données sont distinctes et parfois un répertoire commun à tous les utilisateurs (AllUsers)

Ainsi on peut simplement sauvegarder régulièrement la totalité du répertoire de données et uniquement ce répertoire.

De même pour éviter les soucis lors de la réinstallation de Windows, il est plus facile de protéger les données si celles-ci se trouvent sur un disque ou une partition séparée.


IX-U-2. Sécurité:

Un virus, un ver ou un spyware est un programme qui va essayer d'utiliser votre accès à Windows (vos droits d'utilisateur) pour s' "auto-installer" et prendre la main de votre système.

Or par défaut sous Windows XP vous avez tous les droits (car vous avez un compte administrateur) : mettre à jour le système, installer des programmes, ce qui n'est pas vraiment indispensable pour lire vos mails, faire du traitement de texte ou surfer sur Internet.

Vous pouvez donc utiliser votre Windows de la manière suivante :
  • créer des comptes utilisateurs limités pour l'usage quotidien.
  • utiliser un compte administrateur pour toutes les installations et mises à jour.
C'est une contrainte mais cela garantit le maximum de sécurité.


IX-U-3. Quels répertoires utiliser ?

  • Windows 98:
Un répertoire 'Programs Files' contient des sous répertoires pour chaque programme contenant les exécutables.

Un répertoire 'Mes documents' contenant des sous répertoires pour chaque programme contenant les fichiers de données.

Les paramètres de l'application sont dans un fichier .ini qui se trouve dans le répertoire Windows ou le répertoire de l'application ou la base de registre.

  • Windows XP:
Un répertoire 'Programs Files' contient des sous répertoires pour chaque programme contenant les exécutables.

Un répertoire 'Documents ans Settings' contient des sous répertoires pour chaque utilisateur (ici le mien se nomme 'Phil') et un répertoire commun à tous les utilisateurs: AllUsers.

Dans chaque répertoire utilisateur il y a

un répertoire 'Application Data' pour chaque programme contenant les fichiers de données.

C:\Documents and Settings\phil\Application Data\OpenOffice.org2\user\database

un répertoire 'Mes documents'

C:\Documents and Settings\phil\Mes documents\Visual Studio 2005\Projects\chiffreromain

Mais aussi un répertoire 'Local Settings' pour les fichiers de configuration et les exécutables.

C:\Documents and Settings\phil\Local Settings\Application Data\Pentax\Digital Camera Utility

  • Windows Vista:
Version anglaise:

Dans le Desktop,(information trouvée sur le Net)

Il y a:

Un répertoire 'Programs Files'

Un répertoire 'Users' qui contient des répertoires au nom de chaque utilisateurs ('pch' ici par exemple)

Dans chaque répertoire utilisateur il y a un répertoire AppData pour les données (qui remplace Application Data). Dessous , il y a un répertoire Local et encore dessous un répertoire au nom de la société qui a fait le logiciel (ici Microsoft) puis un répertoire pour le programme et pour la version.

Ainsi les données du programme LDF version 1.1.0 crées par PolySoft seront dans le répertoire:

C:\Users\MyName\AppData\Local\PolySoft\LDF\1.1.0\


Version française:

Dans le Bureau (chez moi)

Il y a:

Un répertoire au nom de chaque utilisateurs ('guillaume' ici par exemple)pour les données.

Un répertoire 'Ordinateur'

Un sous répertoire 'Disque local(C:)

Un sous répertoire 'Programmes'

Un sous répertoire MonProgralle ou se trouvent le programme exe.

Ainsi l'exécutable du programme LDF est dans le répertoire:

C:\Programmes\LDF


Il 'faudrait' utiliser ces répertoires pour les exécutables et les données!!!

Quand, par exemple, on installe un logiciel avec Click once de VB2005 sur un ordinateur Windows XP, l'exécutable s'installe dans C:\Documents and Settings\Nom Utilisateur\Local Settings\Apps:

C:\Documents and Settings\phil\Local Settings\Apps\2.0\WD2P2BPB.7A5\OVEEZQLA.BC1\chif..tion_6625898959f0f00b_0001.0000_56fb0b87e9540260

Le fichier de configuration user.config et les données dans C:\Documents and Settings\Nom Utilisateur\Application Data

C:\Documents and Settings\phil\Application Data\Polytel\WindowsApplication1.vshos_Url_dhzke3q02e3bxuhunbsnp0jhjwtnzb1i\1.0.0.0

(On remarque que après '..Application Data' le chemin comporte \CompanyName\ProductName\ProductVersion)


Il ne 'faudrait' pas utiliser le répertoire 'Program Files\Mon Application' pour les données!!

En fait, beaucoup de programmes écrivent des données directement dans le répertoire courant de l'application (dans C;\Program Files\MonApplication); comment cela se passe?

  • Aucun problème avec Windows 98.
  • Avec Windows XP puisque les comptes limités (comptes utilisateurs standards) n'ont pas accès en écriture au dossier %Program Files% et n'ont pas accès à HKEY-Local_Machine du registre; le problème à été résolu simplement: De manière générale les utilisateurs ont un compte administrateur, donc, ils ont tous les droits et peuvent écrire leurs données dans Program Files et modifier le registre!!
  • Vista "contourne ce problème": si on installe un programme qui veut utiliser le répertoire 'Program Files', Vista utilise un répertoire VirtualStore dans lequel il place un faux répertoire 'Program Files', en effet tous les programmes qui tentent d'écrire vers %Program Files% ou %windir% seront automatiquement redirigés vers 'C:\Users\Nom Utilisateur\AppData\Local\VirtualStore\Program Files'. Si le programme tente ensuite de lire le fichier précédemment écrit, le programme lira automatiquement le bon fichier. Tout ceci est invisible pour le programme, c'est Vista qui gère tout( le répertoire AppData\Local\VirtualStore serait caché). On appelle cela la 'virtualisation'. Attention donc, si le programme veut écrire dans C:\Program Files\MonProg\utilisateur , en fait, il écrira dans C:\Users\nom d'utilisateur\AppData\Local\VirtualStore\Program Files\MonProg\utilisateur. .

IX-U-4. Obtenir le répertoire de l'exécutable et des données:

Rien de plus simple (dans un programme VB 2005 sous Windows XP), pour un utilisateur:

Application.StartupPath donne le répertoire de l'exécutable.

Exemple: dans l'environnement de développement VB 2005, pour le programme WindowsApplication2:

C:\Documents and Settings\phil\Mes documents\Visual Studio 2005\Projects\WindowsApplication2\WindowsApplication2\bin\Debug

Application.UserAppDataPath donne le répertoire de données.

C:\Documents and Settings\phil\Application Data\WindowsApplication1\WindowsApplication1\1.0.0.0

De même on peut obtenir la clé de Registre des données d'application.

Application.UserAppDatRegistry

Pour les données et le registre commun à tous les utilisateurs:

Application.CommonAppDataPath 

Application.CommonAppDatRegistry

IX-U-5. Droits d'accès des utilisateurs dans Vista : l'UAC.

Pour réduire les effets des logiciels malveillants, Windows Vista inclut un nouveau modèle de sécurité dénommé User Account Control (UAC) qui marque un tournant comparé au modèle traditionnel des privilèges accordés aux utilisateurs de Windows, et affecte presque tous les utilisateurs Windows. L'UAC vise à améliorer l'expérience des utilisateurs standards de Windows, tout en réduisant le risque constitué par les logiciels malveillants.

Dans l'UAC, tous les utilisateurs Windows Vista, dont ceux qui possèdent des droits d'administrateur, interagissent avec leurs PC en tant qu'utilisateurs standards la plupart du temps. Le compte utilisateur standard Windows continue de ne pas avoir de privilèges d'administrateur, ce qui évite à un logiciel malveillant téléchargé malencontreusement par un tel compte de s'installer sur l'ordinateur. Ainsi, le logiciel malveillant qui s'infiltre d'une façon ou d'une autre dans un PC ne peut accéder ni à la base des registres ni aux répertoires protégés.

Si vous essayez d'effectuer une tâche qui nécessite des privilèges d'administrateur, comme l'installation d'un logiciel ou le changement d'état du pare-feu Windows, Windows Vista vous invite explicitement à donner votre autorisation et à vous identifier avant de vous faire passer temporairement au rang d'administrateur pour achever la tâche en cours. Pour un utilisateur standard, cela signifie concrètement la saisie d'un nom d'utilisateur et d'un mot de passe qui appartiennent à un membre du groupe Administrateurs

Dans Windows Vista avec le modèle UAC, les comptes utilisateurs standards ont été modifiés pour offrir des privilèges supplémentaires:

  • visualiser les horloges systèmes et les calendriers
  • modifier les fuseaux horaires
  • changer les paramètres de gestion de la puissance
  • ajouter des imprimantes si les bons drivers sont installés sur l'ordinateur
  • créer et configurer des connexions VPN
  • installer les mises à jour Windows essentielles
Dans les versions précédentes de Windows, un non-administrateur ne pouvait pas facilement comprendre quelles actions lui étaient autorisées. Dorénavant, Windows Vista utilise une icône de protection pour vous aider à comprendre quelles tâches seuls les administrateurs ont le droit d'effectuer


IX-V. Choisir une icône, utiliser la barre de taches - Créer un raccourci, lancer au démarrage

En VB 2005.


IX-V-1. Icône de l'application

Pour avoir une icône liée à notre application, nous pouvons le faire au travers de l'onglet « Application » (dans les propriétés du projet) au niveau « Icône ». Remarquez que nous retrouvons les icônes importées dans les ressources projets


IX-V-2. Bouton dans la barre de tache:

Comment mettre un bouton correspondant à la form dans la barre de tache?

Mettre la propriété ShowInTaskBar de la form à True.

Il est préférable de le faire pour une seule form de l'application.


IX-V-3. Icone dans la barre de processus: NotifyIcon

Comment mettre une petite icône dans la barre de processus? Exemple : Mettre une icône bleu dans la barre de tache avec une info bulle indiquant le nom du programme (Ici: LDF).

Le Framework .Net 2.0 dispose de composants vous permettant d'ajouter très rapidement cette fonctionnalité. Ce sont le NotifyIcon et le ContextMenuStrip.

Dans la fenêtre « ToolBox », glissez un composant « NotifyIcon » sur notre formulaire. Il apparaît un composant NotifyIcon1 sous le formulaire:

Dans la fenêtre de propriétés de NotifyIcon1, donner à sa propriété « Text » la valeur «LDF» ; ceci correspond à l'info bulle qui s'affiche lorsque le pointeur de la souris vient se positionner au dessus de l'icône, dans la barre de processus.

Pour indiquer l'icône à utiliser dans la barre de tache:

Click droit sur le composant NotifyIcon1 en bas du formulaire, puis choisir une icône.(Fichier avec extension .ico)

Par code dans FormLoad par exemple: NotifyIcon1.Icon = MyIcone.ico

Noter que dans la fenêtre de propriétés on ne peut pas changer l'icône.


Création du menu associé à l'icône de la barre de tache.

L'idée à présent est de créer un menu contextuel sur l'action « click droit » de notre icône de notification.

Déposez un composant « ContextMenuStrip » sur notre formulaire dans la partie Design. Pour associer les 2 composants, dans les propriétés de « NotifyIcon1 », il suffit d' affecter à la propriété « ContextMenuStrip » le composant « ContextMenuStrip1 ».

Pour définir les menus du « ContextMenuStrip », il suffit de cliquer sur le composant « ContextMenuStrip » pour faire apparaître un menu (en mode design uniquement). Celui qui sera visible dans la barre de tache en cours d'exécution.

Il suffit de remplir le menu comme d'habitude. On ajoute par exemple 'Ouvrir' et 'Fermer'.

En double-cliquant sur le menu, vous générez automatiquement la procédure évènement dans la partie Code.

Exemple de code pour 'Ouvrir' et 'Fermer'.

Private Sub OuvrirToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OuvrirToolStripMenuItem.Click 

    If Me.WindowState = FormWindowState.Minimized Then 

        Me.WindowState = FormWindowState.Normal 

    End If 

End Sub 

  

Private Sub FermerToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles FermerToolStripMenuItem.Click 

    Application.Exit() 

End Sub

 
Au niveau du menu « Ouvrir », nous testons si l'application est réduite dans la barre des tâches. Si c'est le cas nous l'affichons normalement. Sur l'évènement « Fermer », nous allons tout simplement quitter l' application.


IX-V-4. Créer un raccourci sur le bureau:


'Il faut d'abord ajouter la référence wshom.ocx qui est dans C:\Windows\System32
(menu Projet=>Propriétés de.. Références , bouton Ajouter, Onglet Parcourir, aller dans C:\Windows\System32, cliquer sur wshom.ocx puis Ok)

Exemple: créer un raccourci sur le bureau avec l'icône ''euro.ico', comme texte LDF et qui lance c:\Program Files\LDF\ldf.exe

Dim Bureau As IWshRuntimeLibrary.WshShell

Dim Raccourci As IWshRuntimeLibrary.WshShortcut

Dim Nom As String

Bureau = New IWshRuntimeLibrary.WshShell

'   Chemin et nom du raccourci

Nom = My.Computer.FileSystem.SpecialDirectories.Desktop & "\LDF.lnk" 'pour 'LDF'

Raccourci = CType(Bureau.CreateShortcut(Nom), IWshRuntimeLibrary.WshShortcut)

'   Cible à exécuter

Raccourci.TargetPath = "c:\Program Files\ldf\ldf.exe"

'   Icône à utiliser

Raccourci.IconLocation = "C:\WINLDF\Icone\euro.ico"

'   Enregistrement du raccourci

Raccourci.Save()

IX-V-5. Lancer le programme au démarrage de Windows:

Pour cela, il faut dans le registre (Software\Microsoft\Windows\CurrentVersion\Run) ajouter le nom du programme.

Imports Microsoft.Win32 'en haut du module.

Dim obj_RegistryKey As RegistryKey

obj_RegistryKey = Registry.CurrentUser.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Run", True)

obj_RegistryKey.SetValue("LDF", "C:\Program Files\LDF.exe")
Voir aussi le chapitre sur le registre.


IX-W. Petits problèmes pratiques:

Avoir accès aux contrôles d'un autre formulaire

Mettre une couleur transparent.

Faire l'équivalent des groupes de contrôles.

Créer un bouton 'personnalisé'

Utiliser un contrôle ActiveX (.Ocx)

Créer des contrôles par code.

Séparateur décimal :point ou virgule?

Créer une image persistante

Validation dans une textbox

Comment associer un numéro à un élément d'une ListBox
(ItemData n'existant plus en VB.Net)


X. Déboguage:


X-A. Débogage ( ou comment rechercher les 'Bugs')

Le débogage est la recherche des bugs, les erreurs de logique.(voir 4-3 Traiter les erreurs)

Voir la vidéo au format 'Flash': ou au format AVI en Visual Basic 2005

Rappelons qu'il existe:
  • Les erreurs de syntaxe.
  • Les erreurs de logique.
  • Les erreurs d'exécution.
Les erreurs de syntaxe sont détectées automatiquement par l'éditeur de Visual Studio. ou lors de la génération du projet en mode Run. La compilation vérifie les types des données, les paramètres....

Les erreurs d'exécution surviennent lorsque l'exécution d'une instruction échoue ( tentative d'ouverture d'un fichier qui n'existe pas par exemple). Cela provoque l'apparition d'un message et provoque l'arrêt brutal de l'application. Il faut donc prévoir une gestion des éventuelles erreurs d'exécution afin d'éviter l'arrêt de l'application. A l'aide de Try Catch, on pourra intercepter l'erreur et informer l'utilisateur, prévoir une correction.

Les erreurs de logique sont plus difficiles à détecter. Le code est syntaxiquement correct, mais il ne réalise pas les opérations prévues. C'est là qu'intervient le débogage afin de diagnostiquer l'origine de l'erreur.

Pour déboguer, il faut lancer l'exécution du programme puis,
  • Suspendre l'exécution à certains endroits du code
  • Voir ce qui se passe puis faire avancer le programme pas à pas.
  • Afficher des informations de débogage quand le programme tourne.

X-A-1. A - Suspendre l'exécution.

Pour démarrer et arrêter l'exécution, on utilise les boutons suivants:

On lance le programme avec le premier bouton, on le suspend avec le second, on l'arrête définitivement avec le troisième..

On peut suspendre (l'arrêter temporairement) le programme:
  • avec le second bouton
  • grâce à des points d'arrêt (pour définir un point d'arrêt en mode de conception, cliquez en face d'une ligne dans la marge grise: la ligne est surlignée en marron. Quand le code est exécuté , il s'arrête sur cette ligne marron).
  • en appuyant sur Ctrl-Alt-Pause
    
      For i= 1 To 6
    
    ? Tableau(i)=i*i
    
      Next i
    
    En plus si on clique sur le rond de gauche avec le bouton droit de la souris, on ouvre un menu permettant de modifier les propriétés de ce point d'arrêt (il y a la possibilité d'arrêter au premier ou au Xième passage sur le point d'arrêt, ou arrêter si une expression est à True ou à changé)

  • en incluant dans le code une instruction Stop
warning Attention: Si vous utilisez des instructions Stop dans votre programme, vous devez les supprimer avant de générer la version finale.
Les transformer en commentaire :

' Stop
ou utiliser des instructions conditionnelles :

#If DEBUG Then
Stop
#End If
Dans ce cas, en mode Debug l'instruction Stop sera exécutée, pas en mode Release.


X-A-2. B - Débogage pas à pas.

Quand le programme est suspendu, on peut observer les variables, déplacer le point d'exécution, on peut aussi faire marcher le programme pas à pas (instruction par instruction) et observer l'évolution de la valeur des variables, on peut enfin modifier la valeur d'une variable afin de tester le logiciel avec cette valeur.

F11 permet l'exécution pas à pas, instruction par instruction (y compris des procédures appelées: si il y a appel à une autre procédure, le pas à pas saute dans l'autre procédure)

F10 permet le pas à pas (sans détailler les procédures appelées: exécute la procédure appelée en une fois)

Maj+F11 exécute jusqu'à la fin de la procédure en cours.

On peut afficher ou définir l'instruction suivante, exécuter jusqu'au curseur, insérer un point d'arrêt ou un espion en cliquant sur le bouton droit de la souris et en choisissant une ligne du menu (VB 2003).

Espion express (VB 2003 et 2005)permet de saisir une expression (variable, calcul de variables) et de voir ensuite dans une fenêtre 'espion' les modifications de cette expression au cours du déroulement du programme.

Exemple en VB 2005, c'est pareil en VB 2003: suivre la valeur de la variable de boucle 'i'.

Sur la ligne , bouton droit, 'espion express..' dans la fenêtre qui s'ouvre à droite,

Tapez 'i' puis 'Fermer', la fenêtre espion apparaît en bas avec la valeur de i

Tapez F10 , F10.. la boucle tourne et i est incrémenté.

Atteindre la définition permet d'afficher la déclaration de la variable et ainsi de voir quelle est sa portée et si elle est initialisée. S'il s'agit du nom d'une procédure, on se retrouve dans la procédure (pour voir ce qu'elle contient)


On peut grâce au menu 'Débogage' puis 'Fenêtre' ouvrir les fenêtres:

Automatique uniquement en VB 2003, qui affiche les valeurs des variables de l'instruction en cours et des instructions voisines.

Immédiat (VB 2003 2005) ou il est possible de taper des instructions ou expressions pour les exécuter ou voir des valeurs.

Taper "?I" (c'est l'équivalent de "Print I" qui veut dire: afficher la valeur de la variable I) puis valider, cela affiche la valeur de la variable I.

Autre exemple, pour voir le contenu d'un tableau A(), tapez sur une seule ligne: "For i=0 to 10: ?A(i): Next i"

Enfin, il est possible de modifier la valeur d'une variable: Taper" I=10" puis valider, cela modifie la valeur de la variable.

Espions permettant d'afficher le contenu de variables ou d'expressions.

Espions Express permet d'afficher la valeur de l'expression sélectionnée.

Points d'arrêts (VB 2003 et 2005) permet de modifier les propriétés des points d'arrêts. on peut mettre un point d'arrêt en cliquant dans la marge grise à gauche: l'instruction correspondante s'affiche en marron et l'exécution s'arrêtera sur cette ligne.

Me (VB 2003) affiche les données du module en cours.

Variables locales (VB 2003 et 2005)affiche les variables locales.

Modules (VB 2003 )affiche les dll ou .exe utilisés.

Mémoire, Pile d'appels, Thread, Registres, Code Machine permettent d'étudier le fonctionnement du programme à un niveau plus spécialisé et technique.


X-A-2-a. Comment voir rapidement la valeur des propriétés ou de variables.

Il est toujours possible de voir la valeur d'une propriété d'un objet en la sélectionnant avec la souris:

Exemple on sélectionne label1.Text et on voit apparaître sa valeur.

Pour les variables, il suffit que le curseur soit sur une variable pour voir la valeur de cette variable.

On peut aussi copier une expression dans la fenêtre 'immédiat' , mettre un ? avant et valider pour voir la valeur de l'expression.


Attention à l'affichage:

Parfois en mode pas à pas on regarde le résultat d'une instruction dans la fenêtre du programme. Par exemple on modifie la propriété text d'un label et on regarde si le label à bien changé. Parfois la mise à jour n'est pas effectuée car le programme met à jour certains contrôles seulement en fin de procédure. pour palier à cela et afficher au fur et à mesure, même si la procédure n'est pas terminée, on utilise la méthode Refresh de l'objet qui 'met à jour'.

Exemple:

Label1.text="A"

Label1.Refresh
Cela ne semble pas toujours fonctionner. Avez-vous une explication?


X-A-2-b. Modification du code source.

En version 2003, les modifications effectuées lors de la suspension de l'exécution, ne sont pas prises en compte lors du redémarrage.

En version Il y a maintenant le 'Edit and continue': en mode Debug, on peut modifier une ligne et poursuivre le programme qui tiendra compte de la modification (Sauf pour les déclarations).

En version 2005, Il est proposé des solutions pour corriger les erreurs de code:

Une fenêtre vous indique les corrections à faire.

Si je veux afficher une valeur numérique (avec option Strict=On),il y a erreur, VB me propose la correction:


X-A-2-c. C - Sortie des informations de débogage.

On veut parfois afficher automatiquement des résultats intermédiaires, un message destiné au programmeur dans telle circonstance...quand le programme tourne.


X-A-2-c-i. Objet Console.
On peut écrire sur la fenêtre console, quand on a parfois besoin d'afficher des informations, mais uniquement pour le programmeur:

Console.WriteLine( myKeys(i))
Mais dans un programme Windows, il n'y a pas de console!! la sortie est donc envoyée vers la fenêtre de sortie (voir Debug)(Menu Affichage>Autres fenêtres>Sortie pour voir la fenêtre)

Autre exemple:

Dim amis() As String = {"pierre", "jean", "jacques", "toto"}

For Each nom As String In amis

Console.Out.WriteLine(nom)

Next

X-A-2-c-ii. Objet Debug
L'espace de noms Systems.Diagnostics est nécessaire.

Pour déboguer du code, on a parfois besoin d'afficher des informations, mais uniquement pour le programmeur, en mode debug afin de suivre le cheminement du programme ou la valeur d'une variable ou si une condition se réalise; pour cela on utilise une fenêtre nommée 'Sortie'(Output). (Menu Affichage>Autres fenêtres>Sortie)

Pour écrire dans la fenêtre Output (sans arrêter le programme):

  • Du texte:

Debug.Write(Message)
et pour ajouter un passage à la ligne:

Debug.WriteLine(Message)
  • Le contenu d'une variable:

Debug.Write(Variable)
  • Les propriétés d'un objet:

Debug.Write(Objet)
Exemple:

Debug.Write("ça marche")    'Affiche 'ça marche'

Dim A as Integer=2

Debug.Write(A)    'Affiche 2

Debug.Write(A+2)  'Affiche 4
On voit que s'il y a une expression, elle est évaluée.

On peut aussi afficher un message si une condition est remplie en utilisant WriteLineIf ou WriteIf:

Debug.WriteLineIf(i = 2, "i=2")
Affiche 'i=2' si i=2

Cela vous permet, sans arrêter le programme (comme le fait Assert), d'être informé quand une condition est vérifiée.

Debug.Assert par contre affiche une fenêtre Windows et stoppe le programme si une assertion(une condition) passe à False.

Debub.Assert(Assertion)

Debub.Assert(Assertion, Message1)

Debub.Assert(Assertion, Message1, Message2)
L'exemple suivant vérifie si le paramètre 'type' est valide. Si le type passé est une référence null (Nothing dans Visual Basic), Assert ouvre une boite de dialogue nommé 'Echec Assertion' avec 3 boutons 'Abandonner, Recommencer' 'Ignorer'.. La liste des appels est affichée dans la fenêtre (procédure en cours en tête de liste, module et numéro de ligne en première ligne)

Public Shared Sub UneMethode (type As Type, Typedeux As Type)
Debug.Assert( Not (type Is Nothing), "Le paramètre Type est=Nothing ", 
	_"Je ne peux pas utiliser un Nothing")

....
End Sub UneMethode
 

Debug.Fail
Fait pareil mais sans condition.


X-A-2-c-iii. Trace:
Trace possède les mêmes fonctions que Debug (Write, WriteIf, Assert, Fail..) mais la différence est que Trace permet d'afficher à l'utilisateur final par défaut.


X-A-2-c-iv. Mode 'Trace', 'Release', Mode 'Debug'
En VB 2003, en haut de la fenêtre de l'IDE il y a une liste déroulante elle contient:

Release. (à utiliser pour générer la version à distribuer)

Debug (à utiliser pour générer une version à tester)

En VB 2005, si vous choisissez les paramètres de développement Visual Basic, l'outil qui permet de choisir entre la configuration Debug et Release n'apparaît pas dans la barre d'outils. Visual Studio choisit automatiquement la configuration Debug lorsque vous cliquez sur Démarrer dans le menu Débogueur et la configuration Release lorsque vous utilisez le menu Générer

Trace est activé par défaut. Par conséquent, du code est généré pour toutes les méthodes Trace dans les versions release et debug. Ceci permet à un utilisateur final d'activer le traçage pour faciliter l'identification du problème sans que le programme ait à être recompilé.

Par opposition, Debug est désactivé par défaut dans les versions release, donc aucun code exécutable n'est généré pour les méthodes Debug.

On peut utiliser une constante nommé DEBUG qui aura la valeur True si on est en mode Debug.

Cela permet d'écrire:

#If Debug Then

    Stop

#End If
Ici Stop se produira uniquement si on est en mode Debug; en mode Release, il n'y aura pas d'arrêt.


X-B. Comprendre les 'Messages d'erreur'

Quand il y a une erreur de syntaxe, VB souligne l'erreur. Mettre le curseur sur l'erreur, un message d'erreur apparaît:

En VB 2005 un panneau d'exclamation permet d'ouvrir une fenêtre proposant le moyen de corriger l'erreur:

Ici on met dans la propriété text d'un label un Integer, alors qu'il faut mettre une String (Option Strict est probablement égal à On); Vb montre la correction : CStr(i) converti i en String.


Certains messages d'erreur, pour les débutants, sont parfois totalement incompréhensible!!

Voyons quelques messages très fréquents:


X-B-1. Instance d'objet

"La référence d'objet n'est pas définie à une instance d'un objet".

La plupart du temps cela veut dire qu'on utilise un membre d'un Objet alors qu'on n'a pas instancié cet objet.

Il y a bien une Classe, mais pas d'objet instancié à partir de cette Classe, on veut utiliser une membre de la Classe alors qu'on ne peut utiliser un membre que sur une instance.

Exemple:

Dim bt As  Button

bt.BringToFront()
Il n'existe pas réellement d'objet Button : la référence d'objet (bt) n'est donc pas une instance.

Il aurait fallu écrire:

Dim bt As New Button

bt.BringToFront()

X-B-2. Membre absent

"Iexte n'est pas un membre de System.Windows.Forms.TextBox"

Parfois on fait une bête faute de frappe:

Il faut tapez : text!!

D'autres fois, on se trompe sur la classe et instance.

TextBox1.IsNullOrEmpty  donne le message:
"IsNullOrEmpty n'est pas un membre de System.Windows.Forms.TextBox"

On se trompe: on pense que IsNullOrEmpty est un membre de l'instance TextBox1, en fait c'est un membre de la classe String; il faut écrire:

If String.IsNullOrEmpty(TextBox1.Text)

X-B-3. Type Attendu.

"Type attendu"

Exemple:

Private MyVariable As New Obladioblada
Après As New VB attend un type (Integer , Short, String) ou un nom de classe (Form1..). Obladioblada n'est pas une classe (un type!!)

Exemple2:

' Déclaration Objet DataSet

Private ObjetDataSet As New dataset
dataset est souligné comme une erreur "type attendu"!!: Après New Vb attend un type d'objet, une classe, dataset n'est donc pas considéré comme une classe car il n'est pas reconnu: la Classe correspondante n'a pas été importée.

En fait dataset ne peut être utilisé que si Imports System.Data a été ajouté avant, dans ce cas Vb sait que c'est un type .


XI. Comprendre le fonctionnement de VB:


XI-A. Comprendre le FrameWork, la compilation, le garbage collector, le code managé, le code IL et binaire.

Comment fonctionne un programme VB.NET ?


XI-A-1. Le Framework.NET

Jusqu'à VB6, un programme VB avait besoin d'un RunTime (Fichier Dll: VBRUN300.DLL par exemple pour VB3)

En VB.net, pour qu'un programme fonctionne, il faut installer le Framework.NET:

C'est une plate-forme informatique, une couche entre Windows et l'application VB.

'Framework' veut dire: bibliothèque de classes.

Le Framework.Net est donc la bibliothèque de classes .NET et contient ADO.NET, ASP.NET et Windows Forms.

Cette infrastructure offre un vaste accès à :
  • l'ensemble du système d'exploitation.
  • une collection de Classes pour fournir des objets utilisables pour créer des programmes.
  • des routines d'exécution de programme.
ceci de manière homogène et très fiable.

L'exécutable en Visual Basic
  • utilise les objets (WindowsForms, Contrôles, type de variable,..)du Framework.
  • appelle les fonctions (exécution, affichage, gestion de la mémoire, lecture dans une base de donnée..)du Framework.
A la limite on peut considéré le Framework comme une machine virtuelle (comme celle de Java). Il suffirait de porter le FrameWork sous Linux pour que les programmes VB fonctionnent. (Info? Intox?, il existe bien le projet 'Mono' sous Linux, mais il ne contient pas les Windows Forms)


XI-A-2. Inconvénients?

La couche supplémentaire ralentit le programme?

A peine dit Microsoft, cela serait insignifiant! En fait cela ralentit beaucoup. Le Framework, quand il ouvre un formulaire appelle les routines de Windows, c'est bien une couche supplémentaire.

Et s'il y a une nouvelle version du Framework?

Les versions successives devront être compatible ascendante et descendante!!

En fait, on peut installer le Framework 1 et le Framework 2


XI-A-3. Intérêts?

On installe une seule fois le Framework.

Une fois le Framework installé, il suffit pour installer un nouveau programme de n'installer que l'exécutable.

On peut utiliser plusieurs langages.

Nous appelons les fonctions du FrameWork avec Visual Basic mais on peut aussi le faire avec C# et 30 autres langages. La vitesse d'exécution sera la même, les types de variables, les objets seront les mêmes. Plus de problèmes de transfert de paramètres.

Il est même possible de faire cohabiter plusieurs langages dans une même application.

Le code est homogène.

Plus de bidouille, de ficelle de programmation pour contourner les lacunes du langage et l'accès limité au système d'exploitation: Les milliers de Classes du FrameWork donne accès à une multitude de fonctions et aux services du système d'exploitation, cela nativement.


XI-A-4. Revoyons en détails le contenu du Framework:

Le CLS (Common Language Spécification) représente la partie visible , interface entre les langages VB, C++, C#, J# et le Framework.

Il contient deux composants principaux :
  • Le Common Language Runtime (CLR).
    Il permet:

    Exécution du code managé.

    Gestion de la mémoire (Garbage collector)

    Utilisation des objets du FrameWork

    Le runtime peut être considéré comme un agent qui manage le code au moment de l'exécution, qui l'exécute, fournit des services essentiels comme la gestion de la mémoire, la gestion des threads, et l'accès distant.

  • La bibliothèque de classes du .NET FrameWork. (FrameWork Class Library)
    C'est une collection complète orientée objet, que vous pouvez utiliser pour développer des applications allant des traditionnelles applications à ligne de commande ou à interface graphique utilisateur (GUI, Graphical User Interface) jusqu'à des applications qui exploitent les dernières innovations fournies par ASP.NET, comme les services Web XML et Web Forms.

    Par exemple, les classes Windows Forms sont un ensemble complet de types réutilisables qui simplifient grandement le développement Windows. Si vous écrivez une application Web Form ASP.NET, vous pouvez utiliser les classes Web Forms.

    Il existe un éventail de tâches courantes de programmation y compris des tâches comme la gestion de chaînes, la collection de données, la connectivité de bases de données, et l'accès aux fichiers.

    Il y a 3300 Classes dans le Framework 1!!

Plus d'appel aux Api Windows, on fait tout directement en utilisant les classes du Framework.


XI-A-5. Framework 1, 2, 3.

Un Framework est donc un ensemble de Classes.

Le framework 1.0 est utilisé par VB 2003

Le framework 2.0 est utilisé par VB 2005

Il contient des classes supplémentaires.

Le framework 3.0 peut être utilisé par VB 2005

Le framework 3.0 est composé du framework 2.0 auquel s'ajoute WCF (Windows Communication Foundation), WF (Windows Workflow Foundation), WPF (Windows Presentation Foundation) et infocard pour l'authentification des utilisateurs.

Windows Presentation foundation permet de gérer l' affichage des fenêtres. Celui-ci est basé sur directx (version 10).

Sous Windows 98, XP, il faut installer le framework (avant d'utiliser l'environnement VisualBasic ou un exécutable VB)

Sous Windows Vista le Framework 3 fait partie de Vista et est installé nativement.


XI-A-6. Code managé:

Le code écrit pour le FrameWork est dit managé (ou géré): il bénéficie des avantages du Framework: gestion de la mémoire, optimisation de cette mémoire, règles communes, utilisation de plusieurs langages..

Les anciens composants COM sont utilisables mais non managés.

L'interopérabilité entre les codes managés et non managés permet aux développeurs de continuer à utiliser des composants COM et des DLL nécessaires.


XI-A-7. Garbage Collector:

La destruction effective des objets et variables est effectuée par le 'garbage collector' (ou ramasse-miettes).

Avant .NET quand on détruisait une variable, en lui affectant Nothing, la destruction était immédiate (déterministe); si on oubliait (une application) de détruire une variable de multiple fois il y avait problème!!

Maintenant, quand on détruit une variable, elle reste présente en mémoire; c'est le garbage collector qui, quand il a le temps ou quand il n'y a plus de place, détruit la variable et fait le ménage. On ne sait pas quand il va le faire ( non déterministe).


XI-A-8. Compilation:

Le code que vous écrivez en Visual Basic est le code source.

Lors de la génération (compilation) du projet, un code intermédiaire est produit (IL: Intermédiaire Langage), ce code est commun à tous les langages.

Lors de la première exécution d'exécutable (.exe), le code IL est compilé en binaire par le compilateur 'Just in Time' puis exécuté. Les exécutions suivantes seront plus rapides.

En résumé:

Code Source (VB, C#..) => Intermediate Language (IL). par le compilateur syntaxique.

IL => Binaire exécutable par le compilateur 'Just in Time'


XI-A-9. Comment voir le code source ,le code IL, le code exécutable?

Prenons un exemple: il y a dans une form1 une procédure Button1_Click:


a-Voici le code source:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

TextBox1.Text = "hello"

End Sub
on génère ce code source cela donne un fichier .exe (dans le répertoite /bin)


b-Voir le code Intermédiaire (IL):

Avec Ildasm.exe (désassembleur code IL) qui est dans le SDK:

(C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin)

On peut ouvrir un fichier exe (menu 'Fichier'):

Outre le MANIFEST qui contient les méta données de l'assembly, il y a le code IL de l'application.

Si on clique sur la ligne _Button1 , on voit le code IL correspondant à la routine: (un menu de ildasm.exe permet de voir le code source en même temps)

c-Voir le code binaire ( en assembleur)?

Dans l'IDE, si je stoppe le fonctionnement de la routine (par un point d'arrêt), le menu 'fenêtre', 'Code machine' permet de voir l exécutable mais sous forme d'assembleur.

Le véritable code binaire est composé d'instructions ayant chacune un code:

Voici du code exécutable représenté en hexadécimal: 55 8b ec


Comme c'est totalement illisible, on affiche le code binaire sous une autre forme, en langage d'assemblage ou les instructions sont représentées par des mots mnémoniques: push (pour utiliser la pile), mov (pour déplacer un octet en mémoire..), le code est plus lisible.


Voici le code en assembleur de notre routine:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

00000000 push ebp 

00000001 mov ebp,esp 

00000003 sub esp,8 

00000006 push edi 

00000007 push esi 

00000008 mov dword ptr [ebp-8],edx 

0000000b mov esi,ecx 

0000000d nop 

TextBox1.Text = "hello"

0000000e mov ecx,esi 

00000010 mov eax,dword ptr [ecx] 

00000012 call dword ptr [eax+000005B8h] 

00000018 mov edi,eax 

0000001a mov edx,dword ptr ds:[020B1648h] 

00000020 mov ecx,edi 

00000022 mov eax,dword ptr [ecx] 

00000024 call dword ptr [eax+000000E8h] 

0000002a nop 

End Sub

0000002b nop 

0000002c pop esi 

0000002d pop edi 

0000002e mov esp,ebp 

00000030 pop ebp 

00000031 ret 4 
On note que pour information et amélioration de la lisibilité, le code source est ajouté.


d-Voir le véritable code binaire:

Si je fais menu 'Déboguer', 'Fenêtre', 'Mémoire', j'ai un dump de la mémoire en hexadécimal qui montre le véritable code binaire.


XI-A-10. Installation du Framework:

Les applications et contrôles écrits pour le .NET Framework imposent que celui-ci soit installé sur l'ordinateur où ils s'exécutent. Microsoft fournit un programme d'installation redistribuable, Dotnetfx.exe , qui contient les composants Common Language Runtime et .NET Framework nécessaire à l'exécution des applications .NET Framework.

Pour installer le FrameWork, il faut au moins:
  • Microsoft® Windows® 98
  • Microsoft® Windows® 98 Deuxième Édition
  • Microsoft® Windows® Millennium Edition (Windows Me)
  • Microsoft® Windows NT 4 (Workstation ou Server) avec le Service Pack 6a
  • Microsoft® Windows® 2000 (Professionnel) avec MAJ.
  • Microsoft® Windows® XP (Édition familiale ou Professionnel)
  • Famille Microsoft® Windows® Server 2003
Ou le trouver:

Dans le MSDN Download Center sur Internet:

http://msdn.microsoft.com/downloads/ puis

http://www.microsoft.com/downloads/details.aspx?FamilyID=262d25e3-f589-4842-8157-034d1e7cf3a3&displaylang=fr

(ou http://msdn.microsoft.com/downloads/list/netdevframework.asp)

Choisir autre langue=Français puis charger le FrameWork 1.1 Français (23.6 Mo) puis lancer l'installation avec Dotnetfx.exe.

(Bien choisir la version française car on ne peut pas installer plusieurs versions de langue différente)

Pour développer il faut ensuite installer Visual Studio.Net.

L'utilisateur final de l'exécutable installera le FrameWork (une seule fois pour tous les programmes) et l'exécutable (programme simple).

Ou est le Framework?

dans:

c:\Windows\Microsoft.NET\Framework\v1.1 4322\

On voit les DLL qui composent le Framework: System.dll, System.Drawing.dll..

La version 1.1 fait 73 Mo sur le disque

On peut installer à coté la version 1.0; Pourquoi installer les 2 si il y a compatibilité ascendante? c'est une question!!


XI-A-10-a. Nouvelle version 2:

VisualStudio 2005 utilise le Framework 2.0, bien sur il y a un SDK 2.0


XII. Diffuser le programme:


XII-A. Assembly

Avant VB.Net, on enregistrait les références des programmes, des dll.. dans le registre, l'installateur enregistrait le nom et l'emplacement du fichier .exe ou de la Dll; c'était une belle pagaille:

quand on installait 2 dll différentes de même nom.

quand il y avait plusieurs versions d'une même dll

quand on déplaçait un programme!!

quand on mettait à jour une dll qui ne respectait pas la compatibilité ascendante.

Maintenant cela ne se fait plus; en VB.Net on utilise les Assembly.


XII-A-1. Assembly: définition, composition.

Un Assembly est une unité de déploiement indivisible.

Il se caractérise par son identité (propriétés de l'assembly)

un nom

une version

un identificateur de culture

une clé publique

Il contient:

la liste de l'ensemble des fichiers (exe, dll, données, images, ressources)

les méta données (informations descriptives des Types et Classes publiques)

L'énumération des autres Assembly dont l'application dépend et leurs dépendances.

l'ensemble des autorisations requises pour que l'assembly fonctionne correctement.


Ces informations sont utilisées au moment de l'exécution pour résoudre les références, appliquer la stratégie de liaison des versions et valider l'intégrité des assemblys chargés.

Toutes ses informations sont stockées dans le "manifeste" de l'Assembly.

En conclusion:

Pour les installations de programme , mises à jour, utilisation de composants propres au programme ou partagés avec d'autres programmes; pour gérer les versions, éviter les problèmes de conflit de composants, VB.Net utilise donc les assembly (ou assemblage).


XII-A-2. Les propriétés de l'assembly:

Voir les propriétés de l'Assembly:

Pour cela ouvrir les propriétés du projet (cliquer sur MyProjet dans l'explorateur de solution ou passer par le menu Projet->Propriétés de..)

Dans l'onglet Application cliquer sur le bouton 'Informations de l'assembly':

On a accès au titre, à la description, à la société, au produit, au copyright, à la marque, à la version de l'assembly, à la version du fichier, au GUID, à la langue.

On peut aussi le voir en XML: dans l'explorateur de solution, double-cliquer sur Assemblyinfo.vb, la fenêtre principale s'ouvre permettant d'avoir accès à certaines données:

Imports System

Imports System.Reflection

Imports System.Runtime.InteropServices

' Les informations g‚n‚rales relatives  un assembly d‚pendent de 

' l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations

' associ‚es  un assembly.

' V‚rifiez les valeurs des attributs de l'assembly

<Assembly: AssemblyTitle("Bonjour")> 

<Assembly: AssemblyDescription("")> 

<Assembly: AssemblyCompany("Polytel")> 

<Assembly: AssemblyProduct("Bonjour")> 

<Assembly: AssemblyCopyright("Copyright ¸ Polytel 2006")> 

<Assembly: AssemblyTrademark("")> 

<Assembly: ComVisible(False)>

'Le GUID suivant est pour l'ID de la typelib si ce projet est expos‚  COM

<Assembly: Guid("9a8cb33c-3392-44a0-a86d-c7164dfa91c1")> 

' Les informations de version pour un assembly se composent des quatre valeurs suivantesÿ:

'

' Version principale

' Version secondaire 

' Num‚ro de build

' R‚vision

'

' Vous pouvez sp‚cifier toutes les valeurs ou indiquer les num‚ros de build et de r‚vision par d‚faut 

' en utilisant '*', comme indiqu‚ ci-dessousÿ:

' <Assembly: AssemblyVersion("1.0.*")> 

<Assembly: AssemblyVersion("1.0.0.0")> 

<Assembly: AssemblyFileVersion("1.0.0.0")> 

XII-A-3. Le manifeste:

Toutes les informations de l'assembly sont stockées dans le "manifeste".

Le manifeste qui est un fichier en XML se trouve dans:

myapplication\myapplication\bin\debug\myapplication.publish\myapplication_1_0_0_0\myapplivation.exe.manifest

myapplication\myapplication\publish\myapplication_1_0_0_0\myapplivation.exe.manifest

Pour info, voici un exemple de contenu:

<?xml version="1.0" encoding="utf-8"?>

<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<asmv1:assemblyIdentity name="myapplication.exe" version="1.0.0.0" publicKeyToken="612c3b94c96b9edf" language="neutral" processorArchitecture="msil" type="win32" />

<application />

<entryPoint>

<assemblyIdentity name="myapplication" version="1.0.0.0" language="neutral" processorArchitecture="msil" />

<commandLine file="myapplication.exe" parameters="" />

</entryPoint>

<trustInfo>

<security>

<applicationRequestMinimum>

<PermissionSet Unrestricted="true" ID="Custom" SameSite="site" />

<defaultAssemblyRequest permissionSetReference="Custom" />

</applicationRequestMinimum>

</security>

</trustInfo>

<dependency>

<dependentOS>

<osVersionInfo>

<os majorVersion="4" minorVersion="10" buildNumber="0" servicePackMajor="0" />

</osVersionInfo>

</dependentOS>

</dependency>

<dependency>

<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">

<assemblyIdentity name="Microsoft.Windows.CommonLanguageRuntime" version="2.0.50727.0" />

</dependentAssembly>

</dependency>

<dependency>

<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="myapplication.exe" size="28672">

<assemblyIdentity name="myapplication" version="1.0.0.0" language="neutral" processorArchitecture="msil" />

<hash>

<dsig:Transforms>

<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />

</dsig:Transforms>

<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />

<dsig:DigestValue>IK0J8Ge5ABv5RfyMrgdRoMoy/Gc=</dsig:DigestValue>

</hash>

</dependentAssembly>

</dependency>

<publisherIdentity name="CN=CABINET\Philippe" issuerKeyHash="6d35a155f760c5d6ce1866b24dc5b27e833af918" /><Signature Id="StrongNameSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod 

.....

.....
Vous n'avez pas à l'ouvrir et à le modifier.

Signature d'un Assembly:

Article par webman sur developpez.com+++


XII-B. Distribuer l' application

Comment distribuer un programme VB.NET ?

Il faut la "déployer".

Introduction.

  1. Avant de publier
  2. Installation simple
  3. Exemple Windows Installer en VB 2003
  4. Exemple ClickOnce en VB 2005

XII-B-1. Introduction:

  • le déploiement avec un programme d'installation traditionnel à l'aide de la technologie Windows Installer.
    Avec le déploiement Windows Installer, vous empaquetez l'application dans un fichier setup.exe et distribuez ce fichier aux utilisateurs ; ceux-ci exécutent le fichier Setup.exe pour installer l'application.

    Les fichiers du programme d'installation peuvent être distribués sur des disquettes ou des CD-ROM, ou peuvent être placés sur un lecteur réseau pour une installation sur un réseau.

    Pour déployer une application, vous créez d'abord un projet d'installation et définissez les propriétés du projet.

    Ce mode de déploiement est disponible en VB 2003 (c'est le seul d'ailleurs en VB 2003) et en VB 2005 (sauf pour le version Express)

    Voir ci dessous un exemple en VB 2003.

  • La publication d'une application à l'aide de la technologie ClickOnce
    Avec le déploiement ClickOnce, c'est très simple vous publiez l'application à un emplacement centralisé et l'utilisateur l'installe ou l'exécute à partir de cet emplacement.

    Les applications déployées avec ClickOnce se mettent à jour automatiquement et représentent le meilleur choix pour les applications exigeant des modifications fréquentes.

    Vous utilisez l'Assistant Publication pour empaqueter votre application et la publier sur un site Web ou un partage de fichiers réseau ; l'utilisateur installe et lance directement l'application à partir de cet emplacement en une seule étape.

    Ce mode de déploiement est disponible en VB 2005 (c'est le seul dans la version Express).

    Voir ci dessous un exemple en VB 2005.


XII-B-2. A - Avant de 'Publier':

  1. ATTENTION: Avant de publier votre programme, assurez-vous que vous l'avez testé et qu'il s'exécute sans erreur.
  2. On peut choisir le mode Release ou le mode Debug. En VB 2003, en haut de la fenêtre de l'IDE il y a une liste déroulante elle contient Release. (à utiliser pour générer la version à distribuer) Debug (à utiliser pour générer une version à tester) En VB 2005, si vous choisissez les paramètres de développement Visual Basic, l'outil qui permet de choisir entre la configuration Debug et Release n'apparaît pas dans la barre d'outils. Visual Studio choisit automatiquement la configuration Debug lorsque vous cliquez sur Démarrer dans le menu Débogueur et la configuration Release lorsque vous utilisez le menu Générer On peut utiliser une constante nommé DEBUG qui aura la valeur True si on est en mode Debug. Cela permet d'écrire: #If Debug Then Stop #End If Ici Stop se produira uniquement si on est en mode Debug; en mode Release, il n'y aura pas d'arrêt.
  3. Puis, il faut générer en utilisant le Menu Générer-> Générer la Solution. Le programme exécutable ainsi crée se trouve dans le répertoire \bin.

XII-B-3. B - Comment installer simplement un programme chez l'utilisateur?

S'il s'agit d'un programme exe simple isolé, sans dll ou avec des dll locales non partagées par d'autres programmes: on peut l'installer 'à la main'.

  • Il faut installer le Framework.NET sur l'ordinateur de destination:
  • Copier le répertoire \bin contenant l'exécutable (et éventuellement les fichiers de données et les dll) dans un répertoire destination.(Avec XCopy ou avec l'exploreur); On peut aussi le mettre sur un CD puis à partir du CD copier dans un répertoire sur un autre ordinateur.
Pour utiliser le programme, l'utilisateur lance l'exécutable.

On peut créer un raccourci permettant de lancer le programme: dans l'explorateur, cliquer sur le fichier.exe, puis click droit, cela ouvre un menu, cliquer sur 'Créer un raccourci'. Ensuite ce raccourci peut être déplacé sur le bureau par drag and drop.

Cette méthode ne prend pas en compte les composants, dll partagées avec d'autres applications. Il faut plutôt créer un programme d'installation qui est nécessaire dans les autres cas.


XII-B-4. C - Créer un programme d'installation classique en VB 2003 ( de type Windows Installer):

Le déploiement avec un programme d'installation traditionnel peut être effectué à l'aide de la technologie Windows Installer. Avec le déploiement Windows Installer, vous empaquetez l'application dans un fichier setup.exe et distribuez ce fichier aux utilisateurs ; ceux-ci exécutent le fichier Setup.exe pour installer l'application.

Pour cela, vous devez ajoutez un projet d'installation à votre solution et définir les propriétés du projet de déploiement afin de créer un fichier d'installation distribué aux utilisateurs . Les fichiers du programme d'installation peuvent être distribués sur des supports traditionnels, comme les disquettes ou les CD-ROM, ou peuvent être placés sur un lecteur réseau pour une installation sur un réseau.

Pour un déploiement via des supports traditionnels, vous copiez les fichiers à partir de l'emplacement de génération vers une disquette ou autre support.

L'utilisateur lance Setup.exe qui est sur un cd d'installation et ce programme installe le logiciel.

Voyons cela dans VB 2003:

Pour cela il faut créer un projet de configuration et déploiement, en modifier certaines propriétés puis le générer.

Menu Fichiers->Ajouter un projet->Nouveau Projet-> Cliquez dans la liste sur 'Projet de configuration et de déploiement.' puis sur l'icône 'Assistant de configuration'.

Il faut vérifier en bas de la fenêtre 'Ajouter un nouveau projet' le chemin.

Suivez les divers écrans en vous rappelant que vous utilisez une application Windows en sortie principale, n'oubliez pas de rajouter si nécessaire certains fichiers (les fichiers de données nécessaires ).

Après le bouton 'Terminez', il est ajouté dans la fenêtre de l'explorateur de solution une ligne nommé par défaut 'Setup1' correspondant au projet de l'installateur. Il est crée un onglet 'Système de fichiers' dans la fenêtre principale.

Vous venez de créer votre projet de configuration et déploiement, vous pouvez maintenant le modifier.

Le fait de cliquer sur le 'dossier d'application' ou sur sur ligne dans l'explorateur de solution affiche dans la fenêtre de propriétés, les propriétés de l'installation.

La propriété DefaultLocation donne par exemple l'emplacement, le répertoire d'installation. Il y a bien d'autres propriétés permettant de personnaliser votre installateur (Auteur, nom de l'entreprise, Version...)

Enfin quand on clique sur Setup1 dans l'explorateur de solutions, il apparaît des boutons donnant accès à des éditeurs de registre, de d'interface de l'installateur, de condition de lancement..

Si on clique sur le 3eme bouton on ouvre l'éditeur d'interface qui donne accès au déroulement de l'installateur. En cliquant sur la première fenêtre ('Bienvenue') on a accès aux propriétés de cette fenêtre: texte, image..

Pour créer effectivement l'installateur il faudra enregistrer puis utiliser le Menu Générer-> Générer Setup1.

Un répertoire nommé dans notre exemple 'SeptUp1' est crée; il contient

Setup.exe

Setup1.msi

Setup.ini

il suffit de mettre ces fichiers sur un cd et de le donner à l'utilisateur final qui installera votre logiciel en lançant Setup.exe.

Le logiciel d'installation vérifie si le FrameWork est bien installé.


XII-B-5. D - Créer un programme d'installation 'ClickOnce' en en VB 2005:

Avec le déploiement ClickOnce, vous publiez l'application à un emplacement centralisé et l'utilisateur l'installe ou l'exécute à partir de cet emplacement. ClickOnce se base sur le protocole HTTP pour effectuer les installations ou les mises à jour.

L'emplacement centralisé peut-être une page WEB.

Les applications déployées avec ClickOnce se mettent à jour automatiquement et représentent le meilleur choix pour les applications exigeant des modifications fréquentes.

Avec ClickOnce, vous utilisez l'Assistant Publication pour empaqueter votre application et la publier sur un site Web ou un partage de fichiers réseau ; l'utilisateur installe et lance directement l'application à partir de cet emplacement en une seule étape.

Exemple d'installation à partir d'un CD-ROM sans mise à jour:

- Lancer l'assistant de publication:

Une fois que vous êtes prêt à le publier( code vérifié, génération effectuée), vous pouvez lancer l'Assistant Publication en sélectionnant la commande Publier dans le menu Générer.

L'Assistant Publication comprend trois étapes :

- La première étape consiste à sélectionner l'emplacement où vous souhaitez placer le programme d'installation et tous les fichiers associés. Si vous publiez votre programme sur un CD-ROM, sélectionnez un dossier sur votre disque local. (Vous graverez ensuite ce dossier sur le CD-ROM).

(publish\ crée un répertoire sous les sources (au même niveau que le répertoire bin )

- La deuxième étape consiste à spécifier la manière dont les utilisateurs installeront votre programme ; dans le cas présent, à partir d'un CD-ROM.

- L'étape finale implique le fait de spécifier si votre programme vérifie ou non automatiquement à chaque démarrage la présence d'une version plus récente.

- Puis cliquez sur le bouton 'Terminer'.

Quand tout est terminé, cela ouvre une fenêtre montrant le contenu du répertoire \publish:

Il y a

Setup.exe

listgénéric.application

listgénéric_1_0_0_0.application

et un répertoire 'listgénéric_1_0_0_0'

listgénéric.exe.deploy

listgénéric.exe.manifest


Exemple d'installation à partir d'un Site WEB avec mise à jour automatique:

L''Assistant Publication' s'exécute.

Dans la page Où souhaitez-vous publier l'application ? entrez l'URL du site Web où vous souhaitez publier votre programme. Par exemple, http://www.mysite.com/myprogram.

Attention

Pour publier votre programme sur un serveur Web, ce dernier doit exécuter IIS (Internet Information Services), les extensions FrontPage doivent être installées, et vous devez disposer de privilèges d'administration dans IIS.

Dans la page suivante de l'Assistant.

Sur la page L'application sera-t-elle disponible hors connexion ?, sélectionnez Oui, cette application est disponible en ligne ou hors connexion, la valeur par défaut.

L'application peut être accessible que de façon online (retélechargée à chaque fois) ou de façon offline, téléchargée, installée et accessible via le menu Démarrer

Cliquez sur Terminer pour publier le programme.

Le programme est publié sur le site Web spécifié, et une page HTML est créée.

Sur un autre ordinateur, ouvrez Internet Explorer, naviguez jusqu'à l'URL saisie auparavant, puis cliquez sur le lien Installer pour installer le programme.


Configuration avancée du projet de déploiement.

Nous allons modifier plein de choses avant de déployer:

Veuillez ouvrir le panneau des propriétés de votre projet (menu Projet > Propriétés de nomdeprogramme ou double-cliquer sur MyProjet dans la fenêtre d'explorateur de solution) .


Signer le projet:

Cliquez sur l'onglet signature puis sur la case 'Signer les manifestes CliclOnce'.


Activer la Sécurité:

Onglet sécurité, activer les paramètres de sécurité.


Onglet publier:

Pour indiquer l'emplacement de la publication, si l'application est disponible en ligne ou hors connexion (installée).

Si on coche la case incrémenter.. cela incrémente automatiquement les versions.


4 boutons donnent accès :

Au fichier d'application.

Au composant requis

Au 'mise à jour':

Aux options de publication:

On peut ensuite utiliser les boutons qui sont en bas:

Bouton 'Assistant de publication' et 'Publier maintenant'.


Ajouter enlever des fichiers.

- Comment ajouter les fichiers publiés via ClickOnce:

Tous les fichiers du projet qui ne contiennent pas de code sont déployés avec l'application.

Il suffirait donc d'inclure dans le projet des fichiers de données et il seraient inclus!! A voir, je ne sais pas comment faire.

Les fichiers d'une application ClickOnce sont ensuite gérés dans la boîte de dialogue Fichiers d'application, accessible à partir de la page Publier du Concepteur de projets. Dans la fenêtre de l'explorateur de solutions à droite, double-cliquer sur 'MyProjet' puis sur l'onglet Publier enfin sur le bouton 'Fichiers d'application'.

Exclure un fichier

Dans la boîte de dialogue Fichiers d'application, sélectionnez le fichier que vous souhaitez exclure.

Dans le champ État de la publication, sélectionnez Exclure dans la liste déroulante.

Fichier de données:

Dans le champ État de la publication, sélectionnez Fichier de données dans la liste déroulante.

Composant requis:

Dans la boîte de dialogue Fichiers d'application, sélectionnez l'assembly d'application (fichier .dll) que vous souhaitez marquer comme composant requis. Notez que votre application doit posséder une référence à l'assembly d'application pour figurer dans la liste.

Dans le champ État de la publication, sélectionnez Composant requis dans la liste déroulante.


Comment cela se passe chez celui qui installe?

Par exemple il faut installer le programme chiffreromain, il a un CD avec les fichiers

Setup.exe

chiffreromain.application

chiffreromain_1_0_0_0.application

et un répertoire 'chiffreromain_1_0_0_0'

chiffreromain.exe.deploy

chiffreromain..exe.manifest

Pour installer , on double clique sur Setup.exe.

Si le Framework n'est pas installé et s'il y a une connexion Internet, la fenêtre suivante s'ouvre et permet de télécharger et d'installer le Framework.

Puis une fenêtre permet d'installer le programme.

Pour lancer le programme, pas de problème , l'installateur ajoute le nom du programme dans le menu 'Démarrer' et aussi dans le menu programme, menu 'nom de l'éditeur' puis chiffreromain.

Pour désinstaller, pas de problème, dans menu 'Démarrer', "Paramètres", "Ajouter et supprimer programmes", le programme est répertorié et un bouton permet de le désinstaller.

Mais, ou s'installe le programme?

C:\Documents and Settings\NomUtilisateur\LocalSettings\Apps\NomSociété\JHBVHR0G.E57\ZBOQP5EG.EYY\chif..tion_6625898959f0f00b_0001.0000_c9deafec99019f28

On remarque que l'exécutable n'est plus dans un répertoire de 'Programs Files' mais dans les documents , le Local Setting, sous le nom de la société (celui qui est dans l'assembly), sous le nom du programme mais aussi sous le numéro de version...


XII-C. Exemples de programme:


XII-C-1. Horloge numérique

Très Simple: Comment créer une horloge numérique?

15:21:45
Dans la fenêtre Form1.

Mettre un Timer (Timer1)

Mettre un label (Label1)

Ajouter le code

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    Timer1.Interval = 1000    'Timer1_Tick sera déclenché toutes les secondes.

    Timer1.Start()            'On démarre le Timer

End Sub

Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick

Label1.Text = Now.ToLongTimeString    'Affiche l'heure format long.

End Sub
Simple!! non!!


XII-C-2. 'Scribble' l'exemple de Microsoft

Un source fournis par Microsoft avec VB 2003: très didactique:

Il se trouve sur:

C:\Program Files\Microsoft Visual Studio .NET 2003\Vb7\VB Samples\WinForms-Scribble\Scribble\

Scribble est une petite application de dessin qui permet de dessiner à main levée à l'aide de la souris dans des fenêtres MDI et d'enregistrer les images dans un fichier.

Ouvrez la solution Scribble.sln.

Lorsque vous exécutez cet exemple de programme, vous obtenez une surface de dessin et les menus suivants :

  • menu File pour les opérations d'entrée et de sortie ;
    Pour lire une image à partir d'un fichier la procédure Open() de MainForm (Scribble.vb) contient une exemple d'utilisation de OpenFileDialog(). et d'enregistrement d'image.

  • menu Edit pour couper, copier et coller ;
  • menu Pen pour sélectionner l'épaisseur du stylet ;
  • menu View pour afficher ou masquer la barre d'outils et la barre d'état ;
  • menu Window pour créer des fenêtres ou les disposer en mosaïque ou en cascade.
    Exemple de gestion de formulaire MDI

  • menu Help pour afficher les rubriques d'aide et la zone de texte About.
Pour dessiner dans une fenêtre MDI la procédure est assez complexe, la prochaine page montre par contre un exemple simple de dessin.


XII-C-3. Programme simple de dessin

Un source très simple très didactique, pour dessiner avec la souris:

On appuie sur le bouton de la souris, on déplace la souris: cela dessine un trait.

Si on clique sur les boutons Rouge, Vert, Bleu cela change la couleur du trait.

Comment faire?

Dans Form1 on crée :

Une PictureBox définissant la zone de dessin: PictureBox1

Les boutons ButtonRouge, ButtonVert, ButtonBleu ayant dans leur propriété text respectivement 'Rouge', 'Vert', 'Bleu'.

Au niveau de la Classe on crée les variables ThePen de type Pen contenant la couleur en cours et PreviousPoint de type Point qui désigne le dernier point ou était la souris.

Les évènements Click des boutons ButtonRouge, ButtonVert, ButtonBleu modifie la couleur en cours:

ThePen.Color = Color.Blue
Le dessin est effectué par les procédures évènement de la souris:

MouseDown enregistre le précédent Point (les coordonnées de la souris sont fournis par le paramètre e, ce sont e.X et e.Y)

MouseMove: On teste si la souris est 'capturée' sur le PictureBox (c'est à dire si on est en glissé: déplacement de la souris bouton appuyé, cela donne à PictureBox1.Capture la valeur True).

Si la souris est capturée:

If PictureBox1.Capture Then
On récupère le Graphics de PictureBox1:

Dim NewGraphic As Graphics = PictureBox1.CreateGraphics()
On trace sur le graphics une ligne du PreviousPoint au Point actuel avec ThePen:

 NewGraphic.DrawLine(ThePen, PreviousPoint, NewPoint)
On détruit le graphics, puis on met dans PreviousPoint le point actuel.

Cela donne:

Imports System.Drawing

 

Public Class Form1

Inherits System.Windows.Forms.Form

 

Private PreviousPoint As Point ' Dernier point de la souris

Private ThePen As New System.Drawing.Pen(Color.Red) 'Un Pen pour dessiner.

 

Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown

Dim NewPoint As New Point(e.X, e.Y)

PreviousPoint = NewPoint

End Sub

 

 

Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove

If PictureBox1.Capture Then

Dim NewPoint As New Point(e.X, e.Y)

Dim NewGraphic As Graphics = PictureBox1.CreateGraphics()

NewGraphic.DrawLine(ThePen, PreviousPoint, NewPoint)

NewGraphic.Dispose()

PreviousPoint = NewPoint

End If

End Sub

 

 

Private Sub ButtonRouge_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonRouge.Click

ThePen.Color = Color.Red

End Sub

 

Private Sub ButtonVert_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonVert.Click

ThePen.Color = Color.Green

End Sub

 

Private Sub ButtonBleu_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonBleu.Click

ThePen.Color = Color.Blue

End Sub

End Class
Dans une version VB6 de ce programme, je n'utilisais pas Capture, aussi j'utilisais une variable Globale 'Tracer': MouseDown lui donnait la valeur True, MouseUp la valeur False et dans MouseMove on traçait si 'Tracer' était à True.

Mais c'est plus facile avec Capture.

Problème:

Si une fenêtre est positionnée sur notre fenêtre de dessin puis enlevée, le dessin disparaît!!

En VB6, la propriété AutoRedraw de l'image permettait de rappeler automatiquement le BitMap du dessin et de faire réapparaître l'image, cela n'existe plus en VB.Net!!

A- On peut écrire une nouvelle méthode OnPaint de l'image (on la substitue grâce à Overrides), elle est déclenchée à chaque fois que le contrôle est redessiné; on y met du code qui redessine (forme géométrique..).

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)

Dim myPen As New System.Drawing.Pen(System.Drawing.Color.Red)

Dim formGraphics As System.Drawing.Graphics

formGraphics = Me.CreateGraphics()

formGraphics.DrawLine(myPen, 0, 0, 200, 200)

myPen.Dispose()

formGraphics.Dispose()

End Sub
mais dans notre programme à moins d'enregistrer dans un tableau les coordonnées et couleur de chaque point puis de les redessiner un à un, ce n'est pas possible.

B- Comment faire l'équivalent de l'autoRedraw?

Class Form1

Private PreviousPoint As Point ' Dernier point de souris

Private ThePen As New System.Drawing.Pen(Color.Red)

Private MyBitMap As Bitmap = New Bitmap(200, 200) 'Je crée un BitMap

Private NewPoint As New Point 'point actuel


 

Private Sub PictureBox1_MouseDown(ByVal sender As Object, 
	_ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown

NewPoint = New Point(e.X, e.Y)

PreviousPoint = NewPoint

End Sub

 

Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove

If PictureBox1.Capture Then

Dim NewPoint As New Point(e.X, e.Y)

Dim newgraphic As Graphics = Graphics.FromImage(MyBitMap) 'je crée un Graphics à partir du BitMap


newgraphic.DrawLine(ThePen, PreviousPoint, NewPoint)      'je dessine sur le Graphics  

PictureBox1.Image = MyBitMap                              'je passe le BitMap dans le PictureBox1  

 

PreviousPoint = NewPoint

End If

End Sub

 

End Class
Quand on crée un Graphics depuis un contrôle comme dans la première version, le graphics ne pointe pas sur la propriété image mais sur son affichage à l'instant T. Ce n'est pas mémorisé.

Beaucoup de contrôles .net ont une propriété image. A chaque rafraîchissement du contrôle si un bitMap est "attaché" à la propriété, le fond du contrôle est affiché automatiquement. Le picturebox est le plus simple de ces contrôles ... il ne fait que ça.

Donc en fait pour dessiner sur un contrôle (quel qu'il soit) tu n'as que 2 possibilités :

  • Redessiner tout à chaque fois dans l'évènement Onpaint
  • Lui affecter une image de fond et travailler sur celle ci

XII-C-4. Exemples de petits applications par Microsoft:

101 exemples de programme Vb 2003: une mine.

101 exemples de programme Vb 2005: une autre mine


XIII. Programmation Objet: création de Classes et composant,


XIII-A. Programmation orientée objet, Propriétés des objets (Rappel)

VB.NET permet maintenant de faire de la POO (Programmation Orientée Objet)à part entière:

Il y a:

Les Classes du FrameWork.

On peut aussi CREER soi même (dans des modules de Classe) de nouvelles Classes qui suivront elles aussi les règles de la POO. Ces classes serviront à instancier des objets.

info Pour ce chapitre, nous sommes du coté de l'application utilisatrice des objets (et non dans les objets).
L'objet est une boite (jaune ici!!), je l'utilise , mais je ne sais pas ce qui se passe à l'intérieur.

XIII-A-1. Interface et Implémentation:

Nous savons déjà:

On utilise une Classe (le moule) pour instancier (créer) un objet.

Une classe est une combinaison de code et de données.
  • Le code et la définition des données constituent l'implémentation (c'est à l'intérieur de la boite).
  • L'interface de l'objet est l'ensemble de ses membres visibles et utilisables (les membres sont les propriétés, les méthodes, les évènements).
Exemple:

Prenons un objet d'une classe ListBox:
  • L'interface ListBox.Visible ListBox.AddItem...c'est Je la vois , je peux l'utiliser.
  • L'implémentation, je ne la vois pas, c'est le code qui gère la ListBox, la définition des éléments; c'est une 'boite noire', je ne sais pas ce qui s'y passe, je n'y est pas accès, et c'est tant mieux!!!

XIII-A-2. Encapsulation:

Le fait de ne pas voir l'implémentation (le code), c'est l'encapsulation.

Le code, les définitions de données sont privés à l'objet et non accessibles, ils sont enfermés, encapsulés dans une boite noire.

info L'encapsulation permet donc d'exposer aux applications clientes uniquement l'interface.
Les applications clientes n'ont pas à se soucier du fonctionnement interne.

Cela a une conséquence, si je modifie le code mais pas l'interface, l'application cliente n'a pas à être modifiée.


XIII-A-3. Héritage:

On a vu qu'un objet issu d'une Classe dérivée hérite des membres de la classe de base (la classe parent), cela crée une relation mère/fille (parent/enfant); la classe fille pouvant réutiliser les membres de la classe mère.

A noter qu'une classe ne peut hériter que d'une classe en VB.NET.

La Classe fille peut utiliser les membres de la classe mère, mais aussi ajouter ses propres membres ou redéfinir certains membres de la classe mère.

Exemple:

On a vu que quand on dessine une Form1, cela crée une Classe 'Form1' qui hérite des Windows.Forms (Inherits System.Windows.Forms.Form)

Autre exemple:

ListBox hérite de Control


XIII-A-4. Polymorphisme:

Le nom de polymorphisme signifie "qui peut prendre plusieurs formes".

Tous les sites français donnent les mêmes définitions et entretiennent une certaine confusion. Il indiquent 3 types de polymorphisme et la différence entre polymorphisme 'paramétrique' de surcharge et ad ohc n'est pas évidente. Je vais donc expliquer les choses à ma manière!!

Il y a 4 sortes de polymorphisme:

  • Le polymorphisme ad hoc.

    Le polymorphisme ad hoc permet d'avoir des fonctions de même nom, avec des fonctionnalités similaires, dans des classes sans aucun rapport entre elles . Par exemple, la classe Integer, la classe Long et la classe Date peuvent avoir chacune une fonction ToString. Cela permettra de ne pas avoir à se soucier du type de l'objet que l'on a si on souhaite le transformer en String.

  • Le polymorphisme de ou en anglais .

    Une méthode gère des paramètres de type et de nom différents

    Ce polymorphisme représente la possibilité de définir plusieurs méthodes de même nom mais possédant des paramètres différents (en nombre et/ou en type).

    pour ouvrir une fenêtre MessageBox, la méthode Show a 12 signatures, en voici 2:

    • Ici on donne 4 paramètres.
      
      Reponse= MessageBox.show(TexteAAfficher,Titre, TypeBouton etIcone, BoutonParDéfaut)
      
    • Ici 1 seul paramètre.
      
      Reponse= MessageBox.show(TexteAAfficher)
      
    On appelle signature chaque combinaison d'arguments d'une fonction (combinaison en nombre et en type). Une fonction a donc autant de signatures que de manière d'appeler cette fonction C'est donc la signature d'une méthode qui détermine quel code sera appelé.

  • Le polymorphisme d'héritage (redéfinition, spécialisation ou en anglais overriding)
    Quand une classe hérite d'une autre classe, elle hérite des méthodes. On peut redéfinir substituer une méthode de la classe parent par une méthode de même nom dans la classe enfant.

  • Le polymorphisme générique ( en anglais template)
    C'est la forme la plus naturelle du polymorphisme: elle permet d'appeler la méthode d'un objet sans devoir connaître son type. En VB 2005 cela correspond aux générics.


XIII-A-5. Constructeur, destructeur:

Un constructeur est une fonction effectuée lors de l'instanciation d'un objet de la Classe; il sert généralement à 'initialiser' l'objet. Il est appelé quand on fait New.

Souvent il y a plusieurs signatures. Il y a habituellement un constructeur par défaut qui n'a pas de paramètres.

Exemple: pour créer un objet graphique Point, j'utilise un constructeur permettant de définir les coordonnées du point:

Dim P As New Point(45, 78)
La destruction d'un objet est effectué lorsqu'on lui affecte la valeur Nothing ou lorsqu'on quitte la portée où il a été défini.

P= Nothing

XIII-A-6. Accesseur, mutateur:

Un accesseur (accessor en anglais) est un membre renvoyant la valeur d'une propriété d'un objet.

MyObjet.GetName est un accesseur car elle renvoie la valeur de la propriété Name.

Un mutateur (mutator en anglais) ou encore modifieur (modifier en anglais) est un membre qui modifie la valeur d'une propriété d'un objet.

MyObjet.SetName est un mutateur car elle modifie la valeur de la propriété Name.


XIII-A-7. Déclaration, instanciation:

On peut déclarer et instancier en même temps:

Dim P As New MaClasse
On peut séparer les 2 actions:

Dim P As Maclasse    'déclaration

P As New Maclasse    'instanciation
La déclaration et l'instanciation peuvent être effectuées dans les endroits différents:

Module Mon module

    Public P As As MaClasse

 

Sub MaRoutine

    P As New MaClasse

End Sub

End Module 
Ici P est déclaré comme Public, il est instancié dans une Sub.


XIII-A-8. Propriétés, Méthodes:

Un Objet peut avoir une ou des propriétés:

Dim B As New Button

B.Name ="toto"
Un Objet peut avoir une ou des Méthodes:

Dim B As New Button
B.Click est une méthode.


XIII-A-9. Les Objets: ils sont 'By Ref':

On rappelle que les Objets sont 'By Ref' (Par référence)

warning Il faut comprendre qu'une variable Objet contient la référence, le pointeur de l'objet, mais pas l'objet lui même.
Cela entraîne:


XIII-A-9-a. Création de variable objet


Soit une classe Class1.


Dim I As Class1
On crée un pointeur vide, entraîne: I contient Nothing: il ne pointe sur aucun objet.


	I = New Class1
Maintenant I contient la référence, le pointeur vers un objet de type Class1

le constructeur New a bien crée une instance de Class1

Habituellement on utilise en une fois:

Dim I As New Class1  

On peut voir si la variable contient Nothing : If IsNothing( I ) then.. ou If I Is Nothing..


XIII-A-9-b. Affectation:

Si on affecte une variable par référence à une autre, elle pointe toutes les 2 sur le même endroit mémoire: si j'en modifie une, cela modifie l'autre.

'Créons une Classe contenant un entier.

Class Class1
   Public Value As Integer = 0
End Class

Dim C1 As New Class1()
Dim C2 As Class1 =C1    'on crée C2, on affecte C1 à C2
C2.Value = 123          'on modifie C2
 

=> C1.Value=123  C2.Value=123    
Modifier C2 a modifié C1 car elles pointent sur le même endroit mémoire.

On le redit autrement: quand on crée C1 et C2, il n'y a pas 2 objets C1 et C2 mais 2 pointeurs vers le même objet.


XIII-A-9-c. Comparaison:

Deux objets peuvent être comparés par "Is".

Dim O As Object

Dim Q As Object  

If O Is Q then..
Equals peut être utilisé pour la comparaison:

Obj1.Equals(Obj2))  'Retourne True si Obj1 et Obj2 ont le même pointeur.

XIII-B. Créer une Classe


XIII-B-1. Création de Classe.

On a vu qu'il existait des classes prédéfinies (celle du Framework par exemple) mais on peut soi même

CREER SES PROPRES CLASSES:

Maintenant on est DANS la boite.

XIII-B-1-a. Revenons une nouvelle fois sur la notion de Classe et d'Objet.

On va créer une classe 'Médicament'( c'est l'objet de ce chapitre).

Un 'Médicament' possède les variables:

Nom
Laboratoire
Nombre de médicament.
.. 

Il faut donc pouvoir 'regrouper' ces variables pour un médicament précis. Pour regrouper ces variables, on utilise une structure particulière: la Classe.

Une Classe 'Medicament' aura:

Medicament.Nom
Medicament.Laboratoire
Medicament.NbdeMedicament

Avec cette Classe (la structure, le moule), on peut créer (instancier) un Objet MonMedicament.

Dim MonMedicament As New Medicament
Il comporte les variables (données):

MonMedicament.Nom
MonMedicament.Laboratoire
MonMedicament.NbdeMedicament

Il comporte des méthodes (comportement):

MonMedicament.GetNom est une méthode

L'utilisateur de l'objet ne voit que le nom de la méthode (l'interface), il ne voit pas le code de la procédure (l'implémentation). Il y a bien encapsulation.

Une fois cette classe créée, du coté utilisateur, comment l'utiliser?

Pour instancier un objet Medicament:

Dim MonMedicament As New Medicament()

Donner une valeur à une propriété:

MonMedicament.Nom= "Aspirine": MonMedicament.Laboratoire="RP"
Récupérer la valeur d'une propriété:

LeNom=MonMedicament.Nom  : Nb= MonMedicament.NombreMedicament
warning Pour la suite de ce chapitre, nous sommes DANS la Classe de l'objet ( et non dans l'application utilisatrice).

XIII-B-1-b. Créer une Classe

Menu Projet puis Ajouter une Classe.

Entrée 'Medicament' dans la zone nom puis OK

Une nouvelle fenêtre de module est ajoutée à notre projet, contenant le code suivant:

Public Class Medicament
…
End Class
Le mot avant Class indique la portée de la classe:

  • Public (Classe instanciable dans et hors du projet, utilisable par un autre programme)
  • Private (Classe instanciable que dans elle même!!)
  • Friend (Classe instanciable dans le projet )
  • Protected (Classe instanciable uniquement dans les classes dérivées)

On peut ajouter:

MustInherit: Cela donne une classe non instanciable, on ne peut pas créer d'objet avec!! Alors à quoi cela sert!! A fournir une base pour des classes qui en hériteront. on appelle ces classes des classes abstraites.

NotInheritable: Cette classe ne peut-être héritée.


XIII-B-1-c. Ajouter des variables dans une classe

On parle de variable ou 'Attribut' permettant d'associer des données à une Classe.

La variable peut être 'Privée' et non visible à l'extérieur:

Private _mNom As String 
Il est conseillé de mettre un '_' au début du nom d'une variable privée puis une majuscule au début de chaque mot sauf le premier.

Elle peut être 'Public' , visible à l'extérieur et donc non encapsulée.

Public Laboratoire As String
Il est conseillé de mettre une majuscule au début de chaque mot formant le nom de la variable public.

A l'extérieur , si on instance M comme un médicament (Dim M As New Médicament) , M.Laboratoire est valide.

On peut définir un champ 'Public' en lecture seule qui a une valeur constante:

Public ReadOnly NombreMedicament=2000
Vous pouvez ajouter à votre variable : Shared. Cela signifie que la variable déclarée comme Shared est partagée par toutes les instances de la classe : C'est une variable de classe et non une variable d'instance.
Une variable Shared est même utilisable sur le nom de la classe , sans instancier.


Exemple:

Public Class Medicament
    Public Laboratoire As String    'variable d'instance
    Public Shared Societe as String 'variable de classe Shared
End Class
 
Dim M1 As New Medicament
Dim M2 As New Medicament
 
M1.Laboratoire= "MVV"
M2.Laboratoire= "VVT" 
Chaque instance à sa propre variable Laboratoire (Non Shared)

M1.Societe="ooo" entraîne que M2.societe est aussi égal à "ooo"

La propriété Societe de toutes les instances de Medicament a la même valeur

Medicament.Societe est aussi égal à "ooo" Ici on a directement utilisé le nom de la classe.

(Ne pas confondre avec une variable Static qui est une variable qui conserve sa valeur, mais qui a une valeur pour chaque instance).

Une variable, comme tous les membres d'une classe peut être, Private, Public, mais aussi Protected (accessible par les seules méthodes de la classe ou des objets dérivés)

warning Il faut en général déclarer les variables interne en 'Private': elles sont internes et non accessible à l'extérieur de la Classe.

XIII-B-1-d. Ajouter des propriétés grâce à 'Property'

Les propriétés permettent d'associer des données à une Classe.

On rappelle qu'une Property peut être utilisée comme cela:

Dim MonMedicament As New Medicament()
MonMedicament.Nom= "Amoxicilline" : Nom est une Property.
Vu de l'extérieur cela pourrait ressembler à une variable, en fait dans l'implémentation c'est complètement différent. Il y a du code permettant d'écrire ou de lire la property.

Pour créer une Property:

Tapez 'Property Nom' puis validez, la définition de la propriété est générée en faisant apparaître

  • un bloc Get qui correspond à la lecture de la propriété par l'utilisateur.
  • un bloc Set qui correspond à l'écriture de la propriété par l'utilisateur, on récupère la valeur dans le paramètre value.

Property Nom() 
Get  
End Get
Set (By Val Value)
End Set
End Property
J'ajoute Public pour que cette propriété soit accessible hors de la classe, j'indique que c'est une String. Lors de la lecture de la propriété (par l'utilisateur de l'instance) Get retourne (grâce à Return) la valeur _mNom qui est une variable privée de la classe et qui sert à stocker la valeur de la propriété. Lors de l'écriture de la variable, Set récupère la valeur dans Value et la met dans _mNom:

Public Class Medicament
 
'Variable privée (Attribut) servant à stocké en interne le nom.
Private _mNom As String
 
'Propriété Nom
Public Property Nom() as String
Get  
    Return _mNom
End Get
Set(By Val Value)
    _mNom=value
End Set
End Property
 
End Class
Encapsulation:
La variable '-mNom' est encapsulée: l'utilisateur qui utilise une instance de la classe, ne voit pas ce qui se passe (ici c'est très simple) quand il utilise le nom, il ne voit pas l'implémentation (l'implémentation c'est Get...Set...), il ne voit que l'interface c'est à dire .Nom ; Il n'a pas accès à _mNom.


Si l'utilisateur tape: MonMedicament.Nom=" Aspirine" , c'est le code Set..EndSet qui est exécuté.

Si l'utilisateur tape: DIm s As String= MonMedicament.Nom , c'est le code Get..EndGet qui est exécuté.


Une propriété peut être en lecture seule:

Public ReadOnly Property InitialeNom() As String
Get
 Return Left(_mNom,1) 
End Get
End Property
Mais aussi en écriture seule grâce à WriteOnly.


Les propriétés comme les méthodes peuvent être Public, Private, Protected, Friend, ProtectedFrient:


XIII-B-1-e. Méthode

Une Classe peut contenir un comportement sous forme de procédures et fonctions contenant du code.

On peut ajouter une méthode à une Classe:

Les méthodes d'une classe sont les procédures Sub ou Function déclarées dans la classe.
Elles sont habituellement 'Public'.

Une méthode peut contenir du code effectuant un traitement:

Public Sub Dessine() As Double
' Code
End Sub

Une méthode peut aussi être utilisée pour lire ou écrire des variables privées, on parle dans ce cas d'accesseurs:
 
Public Class Medicament
'Variables ou Attributs
Private _nom As String
 
'Accesseurs
Public Sub GetNom() As String
    Return _nom
End Sub
 
'modificateurs
Public Sub SetNom (ByVal N As String)
    Me._nom= N
EndSub
End Class
 
SetNom est une mutateur.


XIII-B-1-f. Récapitulatif Property, méthodes.

  1. Un objet peut être vu comme un regroupement de données (variables et propriétés).
    La différence entre une variable et une Propriété (Property) est qu'alors que la variable est une simple variable , la Property est contrôlée par du code interne qui peut modifier le comportement de la lecture ou de l'écriture de la Property.


  2. Mais un objet va plus loin: il peut contenir un comportement sous forme de procédures et fonctions contenant du code. (Ce sont les méthodes de l'objet). Elles représentent le comportement commun de tous les objets appartenant à la classe.


Tous les éléments de la Classe peuvent être Public (visibles par l'utilisateur de la classe) ou Private (non accessibles à l'utilisateur de la classe et utilisés en interne dans la classe)

info On voit aussi qu'il faut que les variables soient 'Private' et les méthodes et Property 'Public'.

XIII-B-1-g. Constructeur

Un constructeur est une procédure exécutée lors de l'instanciation.

Dans le module de classe, elle est définie par:

Sub New()
End sub
On peut ajouter des paramètres qui serviront à instancier.

Par exemple pour instancier et donner le nom en même temps:

Sub New(ByVal LeNom As String)
    _mNom=LeNom
End sub
Cela permet Dim M As New Medicament("Aspirine")

On peut définir plusieurs constructeurs avec un nombre de paramètres différents (plusieurs signatures), dans ce cas il y a surcharge, le constructeur par défaut étant celui sans paramètres.


Une autre manière de faire est d'utiliser une méthode Initialise:

Créons une classe avec une méthode Initialise.

Classe Homme
Private _Nom As String
Private _Prenom As String
Public Sub initialise(ByVal N As String, ByVal P As String)
    Me._nom = N
    Me._prenom = P
End Sub
End Class

_nom, _prenom étant des données privées de la classe Homme, les instructions :

dim p as New Homme()
p._prenom="Philippe" est refusée
On écrira donc :
dim p as New Homme
p.initialise("Monnom", "Philippe")

XIII-B-1-h. Destructeur

Un objet est détruit:
  • en lui affectant la valeur Nothing.

  • si on sort de sa portée.
Une procédure Finalize (appartenant à la Classe Objet) est automatiquement appelée quand l'objet est détruit.

On peut ajouter une procédure Finalize à notre classe, qui redéfini la procédure Finalise de la Classe 'Objet'.

Protected Overrides Sub Finalize ()
End Sub

On peut y mettre le code libérant les ressources ou d'autres choses.

Noter que la procédure Finalize est ici la redéfinition (d'ou 'Overrides') de la procédure Finalize (qui est Overridable) de la Classe Objet.

Attention la méthode Finalize est exécutée quand l'objet est réellement détruit (Objet=Nothing le rend inutilisable mais il est toujours présent en mémoire). C'est parfois très tardivement que l'objet est détruit: quand il y a besoin de mémoire (c'est le Garbage Collector qui entre en action) ou à la sortie du programme.


Pour forcer la destruction on peut utiliser l'interface IDisposable:

Il faut mettre dans l'entête de la classe

Implements IDisposable

et mettre dans le code de la classe
 
Public Sub Dispose() Implements System.IDisposable.Dispose
' Code libérant les ressources (Base de données, connexion, Objets systèmes..)...
End sub

C'est une méthode Public, on peut l'appeler de l'application cliente:

M.Dispose()
M=Nothing
 
Là aussi attention, Dispose doit être appelé de manière explicite (il faut le faire, ce n'est pas automatique); quand on fait M.dispose, la procédure Dispose et le code qu'il contient sont exécutés immédiatement, par contre c'est toujours le Garbage Collector qui décide quand Finalise sera exécuté.


Dans la pratique quelle est d'utilité de gérer la destruction autrement que par Objet=Nothing si le Garbage Collector nettoie la mémoire? C'est une question.

Réponse donnée par Microsoft:

Votre composant a besoin d'une méthode Dispose s'il alloue des objets système, des connexions à la base de données et d'autres ressources rares qui doivent être libérées dès qu'un utilisateur a fini de se servir d'un composant.

Vous devez également implémenter une méthode Dispose si votre composant contient des références à d'autres objets possédant des méthodes Dispose.


XIII-B-1-i. Surcharge

On peut surcharger un constructeur.
Pour cela il suffit de rajouter autant de procédure New que l'on veut avec pour chacune un nombre de paramètre différent (signatures différentes).

Exemple: On peut surcharger un constructeur:

Class Figure
Sub New()
    Bla Bla
End Sub
 
Sub New( ByVal X As Integer, ByVal Y As Integer)
     Blabla
End Sub. 
End Class
 On peut donc instancier la classe correspondante de 2 manières:
Dim A As New Figure    'Constructeur par défaut
ou
Dim A As New Figure(100,150)
 
On peut surcharger une property.
Pour cela il suffit de rajouter des procédure Property ayant le même nom de méthode avec pour chacune un nombre de paramètre différent (signature différente)

On peut ajouter Overloads mais c'est facultatif.

Exemple surchargeons un membre:

Class Figure
Public Overloads Property Calcul()
    Bla Bla
End Sub
 
Public Overloads Property Calcul( ByVal X As Integer, ByVal Y As Integer)
     Blabla
End Sub. 
End Class

XIII-B-1-j. Evènement

On peut définir un évènement pour la classe.

Dans la classe:
  • Il faut déclarer l'évènement, avec le mot Event
  • Il faut utilisez l'instruction RaiseEvent pour le déclencher lorsqu'un état ou une condition le nécessite.
Exemple:

je crée une classe nommé 'Class1' qui contient un membre 'Texte'( Property Texte), si 'Texte' change, alors on déclenche l'évènement TextChange:


Public Class Class1
Private _mTexte As String
 
' Déclare un évènement
Public Event TextChange(ByVal UserName As String)
 
Public Property Texte()
Get
    Return _mTexte
End Get
Set(ByVal Value)
If Value <> _mTexte Then
  RaiseEvent TextChange("hello")'<= déclenchement de l'évènement par RaiseEvent
End If
_mTexte = Value
End Set
End Property
 
End Class

Si l'application cliente modifie la propriété .Texte d'un objet Class1 alors on compare l'ancien et le nouveau texte, s'il est différent on déclenche un évènement TextChange.


Dans l'application cliente:
  • Il faut définir dans la partie déclaration l'objet M de classe Class1 en indiquant qu'il gère des évènements.
    
    Private WithEvents  M As Class1
    

  • Dans Form_Load par exemple il faut instancier l'objet:
    
    M= New Class1()
    

  • Il faut écrire la procédure évènement avec son code:
    
    Private Sub M_TexteChange(ByVal v As String) Handles M.TextChange
        MsgBox("le texte a changé")
    End Sub
    

Ici on demande simplement quand le texte change, d'ouvrir une MessageBox.


Lors de l'utilisation:

M.Text="Nouveau text" 'déclenche la Sub M.TextChange qui dans notre exemple simple ouvre une MessageBox indiquant que le texte à changer.


On remarque que la Classe définit l'évènement, la procédure correspondant à l'évènement est dans l'application cliente.(De la même manière que quand on clique sur un objet bouton cela déclenche la procédure Bouton-Click.)


XIII-B-1-k. Exception

Il est parfois utile de déclencher une exception: si l'utilisateur de la classe donne par exemple une valeur invalide à une property, une exception se déclenche indiquant que la donnée est invalide.

Dans l'exemple suivant si l'utilisateur affecte à la propriété Mavaleur une valeur négative, une exception est déclenché (Maclasse.Mavaleur=-2)

Public Property MaValeur() As Integer
    Get
    ..
    End Get
    Set (ByVal Value As Integer)
        If Value>=0 Then
            _mValeur= Value
        Else
            Throw New Exception ("La valeur " & Value.ToString & " est invalide")
        End If
    End Set
End Property

XIII-B-1-l. Les Classes partielles

Les classes 'Partielles' sont possible en VB2005 (Framework 2).

Les types partiels permettent la définition d'une classe unique dans plusieurs fichiers source. La définition a une déclaration normale dans un fichier :

Public Class MaClasse
    'implementation...
End Class

Dans d'autres fichiers source, utilisez le mot-clé Partial pour indiquer au compilateur que ce code est la suite de la définition de classe d'origine :

Partial Public Class MaClasse
    'implementation...
End Class

XIII-B-2. Classe suite et astuces

warning Pour la suite de ce chapitre, nous sommes toujours DANS la Classe de l'objet ( et non dans l'application utilisatrice).
DANS la boite.

XIII-B-2-a. Me , My, MyClass, MyBase.

Résumons:

Me c'est l'instance en cours.

Me.text dans une form, c'est le texte de la barre de titre de la form en cours.

Me c'est un moyen rapide d'avoir accès à des classes de l'application, de l'ordinateur, des ressources...

Me.Icon = My.Resources.MyIcon
Jouer un son qui est dans les ressources.

My.Computer.Audio.Play(My.Resources.Form1Greeting, AudioPlayMode.Background)
MyClasse c'est l'instance en cours. Mais à la différence de Me, c'est le méthode de la classe de base (Parente) qui est appelée si cette méthode a été substituée.

MyBase c'est la classe parente.

MyBase est couramment utilisé pour accéder aux membres de la classe de base qui sont substitués ou occultés dans une classe dérivée. MyBase.New permet d'appeler explicitement un constructeur de classe de base (parente) d'un constructeur de classe dérivé.


XIII-B-2-b. Propriété par défaut

Default sert à indiquer de la propriété est la propriété par défaut.

Créons une property par défaut:

Class MyClasse
Default Property MonItem As String
..
End Property
End Class
 

Maintenant, il n'est plus nécessaire d'utiliser le nom de la propriété quand on y accède.

Dim MyCollection As New MyClasse
On peut écrire:

MyCollection.MonItem (index)
Ou

MyCollection(index)    'MonItem est omis

Bien sur, il ne peut y avoir qu'une seule property par défaut.


XIII-B-2-c. Méthode de Classe avec Shared:

Vous pouvez ajouter à votre membre : Shared. Cela signifie que la variable, la propriété ou la méthode déclarée comme Shared est partagée par toutes les instances de la classe: c'est une méthode de classe.


Une méthode déclarée dans une classe sans modificateur Shared est appelée méthode d'instance. Une méthode d'instance opère sur une instance donnée.

Pour une variable non Shared, dans chaque instance la variable a sa valeur propre.

Une variable Shared est commune à toutes les instances de la Class et même à la Classe elle-même sans avoir besoin de l'instancier. C'est une variable de Classe.

L'exemple suivant illustre les règles d'accès aux membres d'instance et Shared :


Class Test
   Private _x As Integer
   Private Shared _y As Integer
   
   Sub F()
      _x = 1 ' Ok, c'est équivalent à Me._x = 1.
      _y = 1 ' Ok, c'est équivalent à Test._y = 1.
   End Sub
   
   Shared Sub G()
      _x = 1 ' Erreur, on ne peut accéder à Me._x.
      _y = 1 ' Ok, c'est équivalant à Test._y = 1.
   End Sub
End Class
   
   Shared Sub Main()
      Dim t As New Test()
      t._x = 1 ' Ok.
      t._y = 1 ' Ok.
      Test._x = 1 ' Erreur, on accède à x seulement par une instance.
      Test._y = 1 ' Ok  on peut accéder à y avec le nom de la classe car y est shared.
   End Sub
La méthode F montre que, dans une fonction d'instance membre, un identificateur peut être utilisé pour accéder à des membres d'instance et à des membres Shared. La méthode G montre que, dans une fonction membre Shared, il est erroné d'accéder à une instance membre via un identificateur. En d'autres termes dans une méthode Shared on n'a accès qu'au variable Shared. Quant à la méthode Main, elle montre que, dans une expression d'accès au membre, l'accès aux membres d'instance s'effectue par l'intermédiaire des instances, alors que l'accès aux membres Shared est possible via des types ou des instances.


XIII-B-2-d. Création d'un compteur d'instance.

Je veux savoir combien il a été crée d'instance de 'Médicament':

Class MyClasse
'Créons une variable commune à toutes les instances

Private Shared Nb as Integer=0
'Le constructeur va l'incrémenter à chaque instanciation:

Sub New()
    Nb+=1
End sub
 

'Il suffit de lire sa valeur pour savoir le nombre d'objet Medicament:

Public ReadOnly Property NbInstance()
    Get
        NbInstance=Nb
    End Get
End Property 
 
End Class
 

XIII-B-2-e. Création d'un identifiant unique d'instance.

Pour chaque instance, je veux avoir un identifiant unique, un globally unique identifier (GUID).

Private m_ID As System.Guid
Sub New()
    m_ID = System.Guid.NewGuid
End Sub
Exemple d'identifiant unique:

'0f8fad5b-d9cb-469f-a165-70867728950e  
Chaque instance ayant un identifiant unique, je peux ainsi 'repérer' les instances (en créant une property ReadOnly afin de lire cet identifiant)

Il existe une très faible probabilité pour que le nouveau GUID soit égal à zéro ou égal à un autre GUID


XIII-B-2-f. Singleton

Parfois , on a une classe avec laquelle on veut créer une instance et une seule.

Private Sub New()
New doit-être toujours private pour empêcher d'instancier avec New

Un singleton est construit grâce à une méthodes de classe nommé 'GetInstance' (sans avoir à instancier).


Shared Function getInstance() As sing
Cette fonction qui s'appelle toujours getInstance va servir à instancier une fois la variable Instance.


Shared instance As sing
Cette variable est la base du Singleton. Elle s'appelle Instance (par convention) elle est du même type que la class et contient l'instance unique.


Public Class sing
'Déclaration de l'instance Singleton
Shared instance As sing
 
Private Sub New()'Pas oublier de mettre Private 
    MyBase.New()
End Sub
Shared Function getInstance() As sing 'Voici la méthode de classe
 
If IsNothing(instance) Then 'Si le singleton n'est pas créé, alors faut le créé
    instance = New sing
End If
Return instance
End Function
...
...
End Class

Comment utiliser cette Classe?

Dim t As sing =  sing.getInstance
Remarque:

  • Si on fait ensuite Dim t1 As sing = sing.getInstance c'est la même instance qui est retournée. On ne peut en créer qu'une..
  • Si on écrit Dim t As New sing :cela plante.

On peut ajouter une protection contre les multi thread trop rapide avec SyncLock GetType(sing)


    Shared Function getInstance() As sing
         
        If IsNothing(instance) Then 
            SyncLock GetType(sing) 
                 If IsNothing(instance) Then 
                    instance = New sing 
                end if 
            End SyncLock 
        End If 
        Return instance 
    End Function 

XIII-C. Créer un composant (Bibliothèque de Classe et de Contrôles)

On a vu qu'on pouvait CREER SES PROPRES CLASSES dans un projet, mais on peut aussi:
  • créer une Classe autonome qui sera utilisée par plusieurs autres programmes, c'est une Bibliothèque de Classe.
  • créer un contrôle utilisateur utilisé lui aussi par d'autres programmes.
Maintenant nous allons créer des classes ou contrôles, ils seront utilisés par une application cliente.


XIII-C-1. Créer une Bibliothèque de Classe

Pour créer une bibliothèque de Classe, il faut faire menu 'Fichier', 'Nouveau', 'Projet':

Cliquer sur l'icône 'Bibliothèque de Classes'.

Le nom par défaut est ClassLibrary1 , valider sur Ok.

Dans la fenêtre principale, il y a:

Public Class Class1
End Class
On peut écrire le code, la description d'une classe avec ses propriétés, ses méthodes, ses constructeurs...(Voir page précédente)

On peut ajouter une autre Classe (Menu Projet, ajouter une Classe), ou importer une Classe (Menu Projet, Ajouter un élément existant)

info Il n'y a pas de procédure Sub Main. (c'est évident, un composant n'est jamais autonome; c'est l'application cliente qui a cette procédure).
Une bibliothèque de classe ne possède pas les composants que possède une application Windows, il n'y a pas d'interface utilisateur, pas de MessageBox, pas de gestion du curseur; c'est l'application cliente qui s'occupe de gérer l'interface.

XIII-C-1-a. NameSpace:

Permet de créer un espace de nom dans le composant:

NameSpace Outils
End
 

Il peut y avoir plusieurs niveau:

NameSpace Outils
NameSpace Marteau
....
End
End
 

Equivalent à:

NameSpace Outils
Classe Marteau
....
End Class
End

Dans l'application il faudra après avoir référencé le composant (la Dll) importer l'espace de nom pour utiliser le composant.

Imports Outils.Marteau
 

XIII-C-1-b. Utilisation du composant:

Il faut enfin enregistrer la bibliothèque, la compiler.

Comment utiliser ce composant?
  • Si la bibliothèque de Classe a été compilée, on obtient une DLL:
    • Il faut la référencer: Ajouter la Dll au projet (Menu Projet, Ajouter une référence)
    • Importer l'espace de nom par Imports Espace de nom au début du module.
    • On peut ensuite utiliser la Classe dans l'application cliente.
  • On peut travailler en même temps sur l'application cliente et le projet de la bibliothèque de Classe en les chargeant tous les 2 dans une solution.

XIII-C-2. Créer un 'contrôle utilisateur' à partir d'un contrôle existant en le modifiant:

Permet de créer un contrôle spécifique qui enrichira la 'Boite à outils' :

(Pour les 'anciens' c'est comme un contrôle OCX, sauf que c'est un contrôle .NET et que c'est un fichier .dll)

Exemple: Créer un bouton avec un aspect spécifique à partir du bouton habituel (Ajout d'un cadre).

  1. Il faut créer une bibliothèque de contrôle:
    Pour créer une bibliothèque de Contrôle, il faut faire menu Fichier, Nouveau, Projet, Icône 'Bibliothèque de contrôle Windows' : Nom du projet: WindowControle par exemple.

    On obtient une fenêtre qui ressemble à un formulaire mais sans bord,on peut y ajouter un contrôle (un bouton par exemple )

    Si on regarde le code correspondant, Vb a crée une Classe UserControl1 qui hérite de la classe Forms.UserControl
    
    Public Class UserControl1
    Inherits System.Windows.Forms.UserControl
    End Class
    
    Il suffit de substituer à UserControl le nom du contrôle que vous voulez utiliser comme base pour hériter de tous ses éléments. On remplace donc par:
    
    Public Class MonBouton
    Inherits System.Windows.Forms.Button
    End Class
    
    Le 'Design' devient:

  2. Il faut modifier l'aspect graphique du bouton:
    Pour cela si vous voulez modifier l'apparence du contrôle, il faut remplacer la méthode OnPaint de Button par la votre(celle-ci dessine le contrôle). Au sein de cette méthode, vous devez appeler la méthode OnPaint de la base (de la classe mère), puis ajouter vos propres fonctions de dessin.

    Il faut donc ajouter la procédure:
    
    Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
    MyBase.OnPaint(e) 'Appel à la méthode de la classe de base, ce qui dessine le bouton
    Dim myPen As New Pen(Color.Purple, 3)
    e.Graphics.DrawRectangle(myPen, 3, 3, Me.Width - 6, Me.Height - 6) 'Ajoute un cadre sur le dessin du bouton
    End Sub
    
    On rappelle que l'argument e est le graphique du bouton.

  3. Compilation:
    Quand le composant est terminé il faut créer la Dll:

    Menu 'Générer' puis 'Générer WindowControle'

    On obtient WindowControle.Dll dans le répertoire /bin sous les sources.

  4. Utilisation du composant dans une autre application VB.
    Dans un autre projet VB, si je veux utiliser mon composant MonBouton, il faut l'ajouter dans la boite à outils:

    Pour cela cliquer avec le bouton droit de la souris dans la boite à outils. Un menu contextuel s'ouvre, cliquer sur 'Ajouter/Supprimer des éléments' puis dans la fenêtre qui s'ouvre cliquez sur 'parcourir'.. cliquez sur WindowControle.Dll , le composant MonBouton apparaît dans la Boite à outils.


    Il suffit de le saisir et de le déplacer dans un des formulaires comme un bouton normal.


    Toutes les procédures évènements (Comme MonBouton1_Click) sont disponibles; elles ont été héritées de Button.

Ce qu'il faut comprendre:

C'est que votre nouveau bouton hérite de Control, une classe qui possède un grand nombre d'événements et de méthodes qui n'apparaissent pas dans les listes déroulantes, car inutile dans l'utilisation de l'objet mais très utile dans le comportement d'un objet. C'est le cas de OnPaint OnKeyDown et OnMouseDown... qui déclenchent les évènement Paint, KeyDown, MouseDown. On redéfini ces méthodes (avec Overrides), dans la méthode redéfini on appelle quand même la méthode de la classe mère puis on ajoute les modifications de fonctionnalités .

Exemple:

Différencier une zone droite et une zone gauche sur le bouton:

On utilise l'évènement OnMouseDown, il a pour paramètre e qui contient les coordonnées de la souris (e.x et e.y)

Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
 
MyBase.OnMouseDown(e) 'Appel à la méthode de la classe de base
If e.X < Me.Width / 2 Then 
    MessageBox.Show("Click sur partie gauche") 
Else
    MessageBox.Show("Click sur partie droite") 
End if
End Sub
 
MessageBox peut être remplacé par un raisevent pour déclencher un évènement.

info On vient de créer un composant héritant d'un contrôle, puis on en a modifié les fonctionnalités.

XIII-C-3. Créer un 'contrôle utilisateur' contenant un ou plusieurs contrôles pilotés:

Pour créer une bibliothèque de Contrôle (un contrôle utilisateur), il faut faire menu Fichier, Nouveau, Projet, Icône 'Bibliothèque de contrôle Windows' : Nom du projet: WindowControle par exemple.

On obtient une fenêtre qui ressemble à un formulaire mais sans bord,on peut y ajouter un contrôle (un textBox par exemple comme ici) ou plusieurs contrôles.

warning Ici la zone de fond grise est importante, le contrôle crée correspond à la totalité de la zone grise du formulaire sans bord, ce qui n'est pas pratique quand on utilise le contrôle (j'en ai dessiné un petit, et je ne voyais pas la textebox!!) Il est donc conseillé de réduire la surface.
Si on regarde le code correspondant, Vb a crée une Classe UserControl1 qui hérite de la classe Forms.UserControl

Public Class UserControl1
Inherits System.Windows.Forms.UserControl
End Class
 

Dans ce Usercontrol il y a les procédures privées des évènements des composants,

Private Button1_Click
End Sub
Bien sur, elles ne seront pas visibles ni accessibles par l'utilisateur du composant.


L'interface du Usercontrol (ce que verra l'utilisateur du composant) est créer de toute pièce comme dans un module de Class. Si on double-clique sur le fond, on voit quand même apparaître:

Private Sub UserControl1_Load(..
End Sub
Mais il faut rajouter des membres publiques qui seront accessibles à l'utilisateur du composant. On utilise pour cela les 'Property', 'Sub' et 'variables' publiques pour créer une interface. Le code contenu dans ces procédures de l'interface va 'piloter' le ou les contrôles (comme le TextBox1). Ce code modifie (dans notre exemple) le comportement du TextBox initial.

Ici je vais créer une propriété LeTexte qui est le texte qui sera affiché dans le TextBox1. Cette propriété LeTexte va 'piloter' TextBox1.text. Je modifie le comportement de TextBox1.text en empêchant d'afficher Toto (c'est idiot!! ).

Public Property LeTexte() As String
    Get
        LeTexte=TextBox1.Text
    End Get
    Set (ByVal Value As String)
        If Value <> "toto" Then
            TextBox1.Text= Value
        End if
    End Set
End Property

Je génère la solution, ajouter WindowControle.Dll à la boite à outils, je met le nouveau composant sur un formulaire; il se nommera UserControl1.

Pour utiliser la propriété précédemment écrite :

UserControl1.LeTexte="lulu"    'lulu apparaît dans le textbox
 
UserControl1.LeTexte="toto"    'rien n' apparaît dans le textbox: : j'ai bien modifié le comportement du textbox et c'est transparent pour l'utilisateur.
 
info On vient de créer un composant avec la Classe UserControl (au lieu de Forms dans un formulaire ), on a écrit son interface.
Remarque: si on veut avoir accès à une sub événement du controle qui est dans un composant, il faut que dans le composant la Sub évènement soit Public.


Autre exemple:

Voir cet autre remarquable exemple de création d'un composant (par CGi et neo51 sur developpez.com): Composant horloge: code source, explication claire: un régal.


XIII-D. Les interfaces


XIII-D-1. Définition: Interface et implémentation:

Ce que je vois de l'objet, c'est son interface (le nom des propriétés, le nom des méthodes..) exemple: le nom de la méthode Clear fait partie de l'interface d'une ListBox. Par contre le code qui effectue la méthode (celui qui efface physiquement toutes les lignes de la listeBox), ce code se nomme implémentation, lui n'est ni visible ni accessible (Quand on est du coté du développeur qui utilise l'objet).

Un objet a donc une interface et une implémentation.

Quand maintenant on est du coté du créateur d'objet, dans un module de classe, si on a crée un objet et ses membres, sans le savoir, on crée en même temps l'interface et l'implémentation.

Mais il est possible de dissocier les 2.

Quel intérêt d'utiliser les interfaces?

Vous pouvez développer des implémentations avancées pour vos interfaces sans endommager le code existant, ce qui limite les problèmes de compatibilité. Vous pouvez également ajouter de nouvelles fonctionnalités à tout moment en développant des interfaces et implémentations supplémentaires.

Différences entre Classe et Interface:

Tout comme les classes, les interfaces définissent un ensemble de propriétés, méthodes et événements. Cependant, contrairement aux classes, les interfaces n'assurent pas l'implémentation. Elles sont implémentées par les classes et définies en tant qu'entités distinctes des classes.

Les interfaces ne peuvent pas être modifiées après publication. En effet, toute modification apportée à une interface publiée risque d'endommager le code existant. Il faut partir du principe qu'une interface est une sorte de contrat.(La partie qui publie une interface accepte de ne jamais modifier cette dernière et l'implémenteur accepte de l'implémenter exactement comme elle a été conçue.)

Comme d'habitude:

Il y a
  • les interfaces présentes dans les classes du Framework (IList, ICollection...)
  • les interfaces que vous créez de toutes pièces pour créer des objets.
Visual Basic .NET vous permet de définir des interfaces à l'aide de l'instruction Interface et de les implémenter avec le mot clé Implements.


XIII-D-2. Les interfaces présentes dans les classes du Framework.

Pour 'uniformiser' le comportement des objets, les interfaces sont largement utilisées dans VB.

Prenons l'exemple des collections:

Plutôt que de rendre communs à toutes les collections une méthode( Clear par exemple), VB donne la même interface à plusieurs types de Collections, ce qui uniformise la totalité des membres.

Les collections reposent sur l'interface ICollection, IList ou IDictionary. Les interfaces IList et IDictionary sont toutes les deux dérivées de l'interface ICollection.

info Le nom des interfaces commence toujours par 'I'.
Dans les collections fondées sur l'interface IList ou directement sur l'interface ICollection (telles que Array, ArrayList, Queue ou Stack), chaque élément contient une valeur unique. Dans les collections reposant sur l'interface IDictionary (telles que Hashtable ou SortedList), chaque élément contient à la fois une clé et une valeur.

Détaillons l'interface Ilist:

L'interface Ilist permet de présenter une collection d'objets accessibles séparément par index.

Les méthodes de l'interface IList sont répertoriées ici.

Méthodes publiques

Add Ajoute un élément.
Clear Supprime tous les éléments.
Contains Détermine si la liste contient une valeur spécifique.
IndexOf Détermine l'index d'un élément spécifique.
Insert Insère un élément dans la liste à la position spécifiée.
Remove Supprime la première occurrence d'un objet spécifique.
RemoveAt Supprime l'élément correspondant à l'index spécifié.

Propriétés publiques

IsFixedSide Obtient une valeur indiquant si IList est de taille fixe.
IsReadOnly Obtient une valeur indiquant si IList est en lecture seule.
Item Obtient ou définit l'élément correspondant à l'index spécifié.

Les tableaux (Array) utilisent l'interface Ilist, mais aussi les collections (ArrayList) , des contrôles utilisent aussi cette interface (les ListBox, ComboBox), mais aussi les DataView...

Les ListBox possédent donc l'interface Ilist , on s'en doutait car on utilisait les méthodes Clear, Insert, Item...

Il y a plein d'autres interfaces.

Autre exemple: IEnumerable.

La Classe System.Array ( et d'autres ) implémente l'interface IEnumerable, ce qui permet d'utiliser une boucle For Each pour parcourir tous les éléments de l'Array.

(Voir 8-5 pour plus de détail)


XIII-D-3. Les interfaces crées par le programmeur:

De même que vous savez créer des classes, il est possible de créer de toutes pièces des interfaces.

Pour créer une Interface:
  • Dans un nouveau Module, définissez votre Interface en commençant par le mot clé Interface et le nom de l'interface et se terminant par l'instruction End Interface. Par exemple, le code suivant définit une Interface appelée Cryptage :
    
    Interface Cryptage
    End Interface
    
  • Ajoutez des instructions définissant les propriétés, méthodes et événements pris en charge par votre Interface. Par exemple, le code suivant définit deux méthodes, une propriété et un événement :
    
    Interface Cryptage
       Function Encrypt(ByVal estring As String) As String
       Function Decrypt(ByVal dstring As String) As String
       Property CledeCodage() As Integer
       Event FinDecoding(ByVal RetVal As Integer)
    End Interface
    
    L'interface est créée.

Pour implémenter une Interface
  • Si l'interface que vous implémentez ne fait pas partie de votre projet, ajoutez une référence à l'assembly qui contient l'interface.
  • Créez une nouvelle classe qui implémente votre Interface et ajoutez le mot clé Implements dans la ligne à la suite du nom de la classe. Par exemple, pour implémenter l'interface Cryptage , vous pouvez nommer la classe d'implémentation MonEncrypte, comme dans le code suivant :
    
    Class MonEncrypte
    Implements Cryptage
    End Class
    
  • Ajoutez des procédures pour implémenter les propriétés, méthodes et événements de la classe :
    
    Class MonEncrypte
       Implements Cryptage
       Event FinDecoding(ByVal RetVal As Integer) Implements Cryptage.FinDecoding
    
       Function Encrypt(ByVal estring As String) As String Implements Cryptage.Encrypt
          ' Placer le code de cryptage ici.
       End Function
       Function Decrypt(ByVal dstring As String) As String Implements Cryptage.Decrypt
          ' Placer le code de décryptage ici.
       End Function
            
       Property CledeCodage() As Integer Implements Cryptage.CledeCodage
          Get
             'Placer ici le code qui retourne la valeur de la propriété.
          End Get
          Set
             'Placer ici le code qui donne une valeur à la propriété.
          End Set
       End Property
    End Class 
    

Noter que :

Pour chaque membre implémenté dans ce code, une instruction Implements indique le nom de l'interface et du membre implémenté.

Tous les membres de l'interface doivent être implémentés.


Enfin utiliser la classe MonEncrypte dans votre programme.

Dim C As New MonEncrypte()
C.CledeCodage=3
Dim ChaineEncryptée As String= C.Encrypt( "ChaineAEncrypter")
Ou

Il faut créer une instance de la classe qui implémente MonEncrypte, crée une variable du type de l'interface, qui associe un gestionnaire d'événements à l'événement déclenché par l'instance, qui définit une propriété et exécute une méthode via l'interface.

Dim C As New MonEncrypte() 'Classe
Dim I As Cryptage()'Variable d'interface (ne pas mettre de 'New'
I=C
I.CledeCodage=3
Dim ChaineEncryptée As String = I.Encrypt( "ChaineAEncrypter")
info Les 2 versions marchent.
S'il y a un RaiseEvent dans une procédure qui déclenche un évènement de la classe il faut aussi ajouter une ligne AddHandler.


Il peut y avoir héritage de plusieurs interfaces:

Interface IComboBox
   Inherits ITextBox, IListBox 
End Interface 
Public Class EditBox
   Inherits Control
   Implements ITextBox
   Implements IListBox
   Public Sub Paint()Implements ITextBox.Paint
      ...
   End Sub
   Public Sub Bind(b As string) Implements IListBox.Clear
   End Sub
End Class
 

XIII-E. L'héritage


XIII-E-1. Définition de l'héritage:

A partir d'une classe existante, la classe de base (ou classe mère), on peut créer une nouvelle classe,la classe dérivée (ou classe fille) qui héritent des propriétés de la classe de base. La classe fille peut être modifiée.

Exemple:

Soit la Classe 'Animal4, on peut créer une Classe 'Cheval' qui aura toutes les propriétés de 'Animal'.

La Classe 'Cheval' est un 'Animal'. Quant on peut dire 'est un', il s'agit bien d'héritage.


Une classe peut hériter d'une autre classe, il suffit d'utiliser :'Inherits'


Inherits permet de déclarer une nouvelle classe,la classe dérivée (ou classe fille), basée sur une classe existante, la classe de base (ou classe mère) . Les classes dérivées héritent des propriétés, des méthodes, des événements, des champs et des constantes de la classe de base et peuvent les étendre.


Voici une classe de base:

Class Salarié1
Public Property SalaireAnnuel() As Integer
...
End Property 

End Class

Créons une classe dérivée qui hérite de Salarié1:

Public Class Salarié2
Inherits Salarié1
 
End Class

On peut ajouter:

MustInherit: Cela donne une classe non instanciable, on ne peut pas créer d'objet avec!! Alors à quoi cela sert!! A fournir une base pour des classes qui en hériteront. on appelle ces classes des classes abstraites.

NotInheritable: Cette classe ne peut-être héritée.


XIII-E-2. Membres de la classe dérivée:

La classe fille possède tous les membres de la classe mère.

Cela si le membre est 'Protected' ou 'Public'; pas s'il est Private.


Exemple:Un variable Private n'est pas visible dans la Classe fille.

Un variable Public est visible dans la Classe fille, mais aussi par l'utilisateur de l'objet.

Un variable Protected est visible dans la Classe fille mais pas à l'extérieur.


Dans la classe Salarié2 on peut utiliser la méthode SalaireAnnuel.


Il est possible de rajouter des membres propre à la classe fille, mais aussi de redéfinir, de surcharger ou de masquer des membres de la classe mère.


XIII-E-2-a. Redéfinition de membres (Overrides)

Il est possible en plus de redéfinir (de substituer) un des membres de la classe mère dans la classe fille.(de créer une nouvelle définition du membre dans la classe fille et uniquement pour cette classe fille) si besoin. Pour que cela marche il faut que le membre de la classe mère soit modifiable (overridable) et que le membre de même nom de la classe fille soit modifié (Overrides)

Dans la Classe fille (classe dérivée):

Overrides
Indique que cette procédure Sub substitue une procédure de même nom dans une classe de base. Le nombre et les types de données des arguments doivent correspondre exactement à ceux de la procédure de la classe de base. Dans la Classe mère (classe de base):

Overridable
Indique que cette procédure peut être substituée par une procédure de même nom dans une classe dérivée. Overridable est le paramètre par défaut.

NotOverridable
Indique que cette procédure ne peut pas être substituée dans une classe dérivée. NotOverridable est le paramètre par défaut d'une procédure qui ne se substitue pas à une procédure de classe de base.

MustOverride
Indique que cette procédure Sub n'est pas implémentée dans cette classe et qu'elle doit l'être dans une classe dérivée pour que cette classe puisse être créée.


Exemple:


Créons une Classe Salarié1 avec une méthode 'Salaire annuel sur 13 mois'

Class Salarié1
Public Overridable ReadOnly Property SalaireAnnuel() As Integer
Get
    SalaireAnnuel = SalaireMensuel * 13 
End Get
End Property 
End Class
 
Créons maintenant une classe Salarié2 qui hérite de toutes les propriétés public et protected de la classe salarié1 donc la méthode SalaireAnnuel qui est sur 12 mois:

Public Class Salarié2
Inherits Salarié1
Public Overrides ReadOnly Property SalaireAnnuel() As Integer 
Get 
    SalaireAnnuel = SalaireMensuel * 12 
End Get 
End Property 
End Class
Quand on instance un objet avec la classe Salarié1, si on utilise la méthode SalaireAnnuel() il sera calculer sur 13 mois.

Quand on instance un objet avec la classe Salarié2, si on utilise la méthode SalaireAnnuel() il sera calculer sur 12 mois.

Attention le membre substitué doit avoir la même signature (Les mêmes paramètres).


XIII-E-2-b. Surcharge de membres (Overloads)

Cela crée plusieurs membres de même nom mais avec des signatures différentes. Il peut y avoir une version dans la classe de base et une version surchargée de même nom mais avec une signature différente dans la classe fille.

Overloads
Indique que ce membre surcharge une ou plusieurs membres définis avec le même nom dans une classe de base. La liste d'arguments de cette déclaration doit être différente de la liste d'arguments de chaque membre surchargé. Les listes doivent différer au niveau de leur nombre d'arguments, de leurs types de données ou des deux. Cela permet au compilateur de distinguer la version à utiliser.

Exemple:

Public Overloads ReadOnly Property SalaireAnnuel( Prime As Integer) As Integer 
Get 
    SalaireAnnuel = (SalaireMensuel * 12) + Prime 
End Get 
End Property 
Vous ne pouvez pas spécifier Overloads et Shadows dans la même déclaration.


XIII-E-2-c. Cacher un membre de la classe de base(Shadows)

Shadows
  • Indique que ce membre cache un élément de programmation de même nom ou un ensemble d'éléments surchargés, dans une classe de base. Vous pouvez occulter tout type d'élément déclaré par un autre type. Si vous masquez une procédure avec une autre procédure, les arguments et le type retourné n'ont pas besoin de correspondre à ceux de la procédure de la classe de base. Un élément occulté est indisponible à partir de la classe dérivée qui l'occulte, à moins que l'élément d'occultation soit inaccessible, comme c'est le cas de Private.

XIII-E-3. MyBase:

Dans le membre de la classe fille, on peut avoir besoin d'appeler le membre de la classe mère; on le fait avec MyBase:

Public Overrides Property OnPaint()  'on redéfini OnPaint 
MyBase.OnPaint			     'on appelle le OnPaint de la Classe mère	
...				     'on ajoute de nouvelles choses	
End Property

XIII-E-4. Constructeur dans une classe fille:

Les membres privés de la classe mère, comme on l'a dit, ne sont pas accessibles à partir de la classe fille.

Seuls les membres 'Public' et 'Protected' de la classe mère sont accessibles à partir de la classe fille, il faut donc utiliser ces membres dans la classe fille.

Exemple avec un constructeur:


Public Class Mere
'Attribut privé
Private _Nom As String
 
'Constructeur
Public Sub New( ByVal Nom As String)
	_Nom=Nom   
End Sub
End Class
 
 
Public Class Fille
Inherits Mere
'Constructeur
Public New ( ByVal Nom As String)
	MyBase.New (Nom)
End Sub
End Class

On voit ici que dans la classe fille, on appelle le constructeur de la classe mère.

Car dans la classe fille _Nom de la classe mère n'est pas accessible.

Dans une clase fille, on passe donc les paramètres à la classe mère en utilisant les membres 'Public' ou 'Protected' de cette classe mère, on initialise en plus directement les attributs propres à la classe fille si ils existent.


XIII-E-5. Héritage successif:exemple:

Une classe peut hériter d'une classe qui en hérite d'une autre:

Prenons l'exemple suivant :

C hérite de B qui hérite de A, les membres sont hérités s'il sont Overridable.

Class A
Public Overridable Sub F() ' le membre F pourra être modifié dans une classe fille
Console.WriteLine("A.F")
End Sub

Public Overridable Sub G()'le membre G pourra être modifié dans une classe fille
Console.WriteLine("A.G")
End Sub
End Class

Class B
Inherits A	'Hérite de A
Public Overrides NotOverridable Sub F()	'On interdit la modification de F dans une Classe fille
Console.WriteLine("B.F")
End Sub
Public Overrides Sub G()
Console.WriteLine("B.G")
End Sub
End Class

Class C	'Hérite de B qui hérite de A
Inherits B
Public Overrides Sub G()
Console.WriteLine("C.G")
End Sub
End Class
warning En VB.Net une Classe ne peut hériter que d'une seule Classe.

XIII-E-6. Création de Classe à partir de Classe du Framework:

Il est possible de créer une classe qui hérite d'une classe du Framework.

Exemple d'une classe MyArray héritant de la Collection ArrayList; on peut dans la classe appeler des membres de la classe de base (MyBase.Add(S))ou modifier les membres de cette classe de base (ici on 'cache' les membres de la classe de base par Shadows et on crée ses propres membres.

Imports System.Collections
Public Class MyArray
     Inherits ArrayList 'MyArray héritant de la Collection ArrayList

    
     Public  Shadows Sub Add(ByVal S As Salarié) 
          MyBase.Add(S)        'On appelle la méthode Add de la classe de base (classe mère) 
     End Function

      Public Shadows ReadOnly Property Index(ByVal i As Integer) As Salarié
          Get 
               Return Ctype (MyBase.Item(i), Salarié)
          End Get
     End Property

      
End Class

XIII-E-7. Création de composant et héritage:

On a vu que dans la création de composants, on peut utiliser un composant qui existe déjà:

Public Class MonBouton
Inherits System.Windows.Forms.Button
End Class
 

Ici on crée un composant MonBouton qui hérite de Button; ce composant Monbouton fonctionne exactement comme Button (le bouton habituel).

Pour modifier l'apparence du bouton, il faut remplacer (Overrides) la méthode OnPaint de Button par la vôtre (celle-ci dessine le contrôle). Au sein de cette méthode, vous devez appeler la méthode OnPaint de la base qui dessine le bouton habituel, puis ajouter vos propres fonctions de dessin.

Il faut donc ajouter dans la classe MonBouton la procédure:

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
MyBase.OnPaint(e) 'Appel à la méthode de la classe de base, ce qui dessine le bouton
Dim myPen As New Pen(Color.Purple, 3)
e.Graphics.DrawRectangle(myPen, 3, 3, Me.Width - 6, Me.Height - 6) 'Ajoute un cadre sur le dessin du bouton
End Sub
Si on compile cette Classe et qu'on ajoute le composant à un projet, on obtient le bouton suivant:


XIII-F. Les espaces de nom , portées des classes et membres (friend protected public private)


XIII-F-1. Intérêts des espaces de noms (NameSpace):

On peut créer une Classe dans un espace de noms.

Le but de ces espaces de noms est d'éviter les conflits et ambiguïtés sur les objets.

Exemple: deux programmeurs Prog1 et Prog2 distribuent des classes qui sont empaquetées et distribuées respectivement dans les dll, Prog1.dll et Prog2.dll.

Les deux programmeurs ont défini une classe nommée PrintText. N'ayant aucune relation , ils l'ont appelée de la même manière!!

Si dans un programme incluant les 2 dll, vous utilisez la classe PrintText, VB ne saura pas s'il doit prendre la classe PrintText de Prog1.dll ou celle de Prog2.dll.

Si le premier programmeur crée ses classes dans un espace de noms appelé Prog1 et le second programmeur dans un espace de noms appelé prog2, les deux classes s'appelleront alors Prog1.PrintText et Prog2.PrintText, ce qui lève toute ambiguïté.


XIII-F-2. Pour créer une classe dans un espace de noms:

On crée une Classe, puis on ajoute le NameSpace sur la ligne dessus.

Namespace Prog1
Public Class PrintText
' définition de la classe
...
...
End Class
End Namespace

Ensuite dans le programme on peut utiliser

Prog1.PrintText
ou bien

Imports Prog1
puis PrintText


Un programme a son propre espace de nom (qui est le nom du programme): Si dans MyProgramme, il y a le NameSpace MySpace contenant la classe MyClasse, on peut utiliser

MyProgramme.MySpace.MyClasse

XIII-F-3. Portée des Classes, procédures, membres.

On savait que les procédures pouvaient être Public ou Privée.

En fait pour indiquer une portée, en particulier dans une classe, les membres peuvent être:

Public
Les procédures déclarées avec le mot clé Public ont un accès public. Il n'existe aucune restriction quant à l'accessibilité des procédures publiques.

Protected

Dans un module de classe:
Les procédures déclarées avec le mot clé Protected ont un accès protégé. Elles sont accessibles seulement à partir de leur propre classe ou d'une classe dérivée.


Friend
Les procédures déclarées avec le mot clé Friend ont un accès ami. Elles sont accessibles à partir du programme contenant leur déclaration et à partir de n'importe quel autre endroit du même assembly.


Protected Friend
Les procédures déclarées avec les mots clés Protected Friend ont l'union des accès ami et protégé. Elles peuvent être utilisées par du code dans le même assembly, de même que dans les classes dérivées. L'accès Protected Friend peut être spécifié uniquement pour les membres des classes.


Private
Les procédures déclarées avec le mot clé Private ont un accès privé. Elles ne sont accessibles qu'à partir de leur contexte de déclaration, y compris à partir des membres de types imbriqués, tels que des procédures.


XIII-G. Composition et groupe d'objets :Tableau, collection d'objets, Classe contenant un groupe d'objets

Est-il possible mettre un objet dans un autre?

On a souvent besoin d'utiliser un ensemble, un groupe d'objets. Comment faire?


XIII-G-1. Un Objet dans un autre: Composition d'objets:

On parle de contenant-contenu.

On peut créer une Classe qui contient des Objets, une classe qui se compose d'objets.


Exemple classique:

Créons une Classe Point.

Class Point
Private _x As Integer
Private _y As Integer
Public Sub New(ByVal x As Integer, y As Integer)
          _x=x
          _y=y
End Sub 
...
End Class
On a écrit uniquement le constructeur, il faudrait aussi écrire les property permettant de lire et écrire les coordonnées du point.


Maintenant on a besoin de créer une Classe rectangle qui est définie par 2 points (le coin supérieur gauche et le coin inférieur droit):

Class Rectangle
Private _p1 As Point
Private _p2 As Point 
Public Sub New(ByVal x1 As Integer, ByVal y1 As Integer,ByVal x2 As Integer, ByVal y2 As Integer)
          _p1= New Point (x1,y1)
          _p2= New Point (x2,y2)
End Sub 
...
End Class
 

Et bien, on utilise la classe Point dans la Classe Rectangle. le constructeur de la classe rectangle instancie 2 points, ce qui appelle le constructeur de la Classe Point.


XIII-G-2. Groupe d'objets:

Exemple: créons une Classe 'Salarié' avec une Property Nom et un constructeur New nécessitant un nom.

Public Class Salarié
Private _sNom As String
Public Property Nom() As String
          Get
               Nom = _sNom 
          End Get
          Set 
               _sNom = Value
          End Set
     End Property

Public Sub New(ByVal sNom As String)
          Nom = sNom 
End Sub 
 
End Class
 

Ensuite pour travailler sur un ensemble de salariés on peut:

  • Utiliser un tableau ou une collection de Salariés (pas bien !!)
  • Créer une Classe contenant des Salariés (good!)

XIII-G-2-a. Comment utiliser un tableau ou une collection d'objets 'Salarié':

Voyons comment faire avec une approche non objet:
  • Tableau
    
    Dim LesSalaries(100)  As  Salarié
    
    Attention, cela crée un tableau de références d'objet, mais pas les objets (Salariées(1) contient Nothing).

    Il faut donc créer les objets:
    
    LesSalaries(0) = New Salarié("toto")
    LesSalaries(1) = New Salarié("lulu")
    LesSalaries(2) = New Salarié("tata")
    ..
     
    
    On peut ensuite utiliser LesSalaries(1).Nom pour connaître le nom du salarié d'index 1.

  • Collection
    
    Dim LesSalaries As New ArrayList  'On crée une collection d'objet ArrayList
    Dim s As New Salarié("toto")      'On crée un Salarié
    LesSalaries.Add (s)               'On l'ajoute dans l'Arraylist
     
    LesSalariées.Count   retourne 1
     
    

    Pour afficher dans une MsgBox le nom du Salarié d'index 1:
    
    MsgBox(CType(LesSalaries.Item(0), Salarié).Nom) 
    
    On remarque que LesSalaries.Item(0) est de type Objet (Les éléments d'un ArrayList sont des objets; Salaries.Item(0).GetType.BaseType.ToString retourne 'Objet') il faut donc caster en 'Salarié' à l'aide de CType:

    CType(LesSalaries.Item(0), Salarié) ensuite , on peut utiliser .Nom

    En Vb2005 (Framework 2):

    On peut utiliser des collections 'génériques'
    
    Dim LesSalaries As New System.Collections.Generic.List(Of Salarié)
    
    On peut ainsi créer une collection fortement typée de 'Salarié'.

    Mais utiliser un tableau ou une collection d'objets directement accessibles n'est pas une bonne méthode.

    La bonne méthode est de créer une classe qui encapsule la collection (Une Classe qui contient la collection). Voyons donc la suite.


XIII-G-2-b. Utiliser Une Classe contenant des Salariés:

Voyons comment faire avec une approche objet:


Il faut créer une classe 'LesSalariés' contenant:
  • un tableau ou une collection 'Private' complètement encapsulé, donc non accessible à l'extérieur.
  • les méthodes 'Public' permettant d'avoir accès au données et de les modifier.

Il y a 4 manières de faire:


XIII-G-2-b-i. Créer une Classe contenant une ArrayList
Voyons un exemple utilisant une ArrayList (collection d'objets):

L'arrayList est créée par le constructeur.

Noter l'encapsulation:
  • une méthode Add permet d'ajouter un 'Salarié' aux 'Salariés' (vu du coté utilisateur).
  • La méthode Remove permet d'enlever un Salarié.
  • Dans la classe une méthode Add permet d'ajouter un 'Salarié' à l'ArrayList.
  • La Property Item permet de retourner un Salarié d'index lIndex.
  • La Property Count retourne le nombre de Salarié.
 
Imports System.Collections
Public Class LesSalariésClasse
     Private maCol As ArrayList

     Public Sub New()
          maCol = New ArrayList()    'cela crée une ArrayList
     End Sub

     Public Function GetEnumerator() As IEnumerator    'permet d'utiliser For Each
          GetEnumerator = maCol.GetEnumerator
     End Function 

     Public Function Add(ByVal LeNom As String) As Salarié
          Dim UnSalarié As New Salarié(LeNom)
          maCol.Add(UnSalarié)
          Add = UnSalarié 
     End Function

      Public ReadOnly Property Item(ByVal lIndex As Integer) As Salarié
          Get 
               Item = (CType(maCol.Item(lIndex),Salarié)
          End Get
     End Property

      Public ReadOnly Property Count() As Integer
          Get 
               Count = maCol.Count 
          End Get
     End Property

      Public Sub Remove(ByVal Key As String)
          maCol.Remove(Key) 
     End Sub
End Class

Pour utiliser la Classe:

Dim LesSalariés As New LesSalariésClasse() 'création 
LesSalariés.Add("Philippe")    'Ajout d'un salarié
LesSalariés.Count retourne 1   'connaître le nombre de salariés
Pour afficher le nom du premier salarié dans une MessageBox:
MsgBox(LesSalariés.Item(0).Nom)

Bien sur on peut utiliser une boucle For Each pour avoir accès à l'ensemble des salariés.


XIII-G-2-b-ii. Créer une Classe héritant de la Classe ArrayList
On crée une classe héritant de ArrayList, ensuite on va créer une méthode Add pour ajouter un Salarié et une Property permettant de lire le nom du salarié d'index i; comme il existe déjà les membres Add et Index avec la même signature dans la classe parente, il faut remplacer ces membres, on le fait grâce à 'Shadows'.

Dans les nouveaux membres, on appelle les membres de la classe mère (grâce à MyBase)

Imports System.Collections
Public Class Salariés
     Inherits ArrayList

    
     Public  Shadows Sub Add(ByVal S As Salarié) 
          MyBase.Add(S) 
     End Function

      Public Shadows ReadOnly Property Index(ByVal i As Integer) As Salarié
          Get 
               Return Ctype (MyBase.Item(i), Salarié)
          End Get
     End Property

      
End Clas
Là aussi, les éléments d'un ArrayList sont des objets; il faut donc caster en 'Salarié' à l'aide de CType l'Item de l'ArrayList:


Dans l'exemple, on a utilisé une ArrayList, il est possible d'utiliser tout autre type de collections.


XIII-G-2-b-iii. Créer une Classe héritant de la Classe CollectionBase
CollectionBase est une classe abstraite (ne pouvant pas être utilisée telle quelle), on peut créer une classe qui en hérite.

Cela tombe bien: CollectionBase contient déjà quelques fonctions propres aux collections (Clear et Count), les fonctions qui manquent, qui n'existent pas (Add, Remove, Item) vont être implémentées par vous et à votre manière.

Une propriété Protected appelée List est fournit par CollectionBase et utilisée pour le stockage et l'organisation interne. Quand on crée Add, Remove, Item, on utilise cette propriété List.


Public Class MaCollection
Inherits System.Collections.CollectionBase
Public Sub Add(ByVal a As Salarié)
' Appelle la méthode Add de l'objet List pour ajouter un salarié.
List.Add(a)
End Sub

End Class

Remarquons que, bien que l'objet List soit non typé, cette méthode interdit l'ajout de tous les objets n'appartenant pas aux type Salarié. Alors que CollectionBase n'était pas typée, MaCollection est fortement typée car n'acceptant que des 'Salarié'.

On peut aussi ajouter une méthode éliminant un objet de la collection:

Public Sub Remove(ByVal index as Integer)
' Controle.
If index > Count - 1 Or index < 0 Then
    System.Windows.Forms.MessageBox.Show("Index non  valide!")
Else
' Appelle la méthode RemoveAt de l'objet List.
List.RemoveAt(index)
End If
End Sub

On peut enfin ajouter Item:

Public ReadOnly Property Item(ByVal index as Integer) As Salarié
Return CType(List.Item(index), Salarié)
End Get
End Property

Avec le Framework 2, il est possible d'utiliser, au leu de ListArray, une collection générique fortement typée:

System.Collections.Generic.List(Of Salarié)  

XIII-G-2-b-iv. Créer une Classe contenant une Classe générique
C'est possible avec le Framework 2

Au lieu de créer une ArrayList dans la Classe, on peut créer une collection générique (System.Collections.Generic) et lui imposer un type.

Ici on va créer une collection de salariés.

Imports System.Collections
Public Class LesSalariésClasse
     Private maCol As System.Collections.Generic.List(Of Salarié)

     Public Sub New()
          maCol = New System.Collections.Generic.List(Of Salarié)    'cela crée une Collection de salarié
     End Sub

     
     Public Function Add(ByVal Sal As Salarié)
          maCol.Add(Sal)
          Add = Sal 
     End Function
     Public ReadOnly Property Item(ByVal lIndex As Integer) As Salarié
          Get 
               Item = maCol.Item(lIndex)  'On a directement un Objet Salarié: pas besoin de CType
          End Get
     End Property
...
End Class

On peut aussi créer des Stack(Of..) Queue(Of..), Dictionnary(Of..) SortedList(Of..) ..


Cette méthode utilisant une collection d'objets complètement encapsulés est une bonne méthode.


XIII-G-2-b-v. Conclusion:
Si une classe doit contenir des objets:
  • Si la classe à besoin d'utiliser et d'exposer un petit nombre d'objets, implémentez chaque objet en tant que propriété.
  • Si le nombre d'objets contenus est grand (et que ce nombre n'est pas connu ou pas fixe) implémentez une propriété de collection.
Si vous ne voulez pas que des applications clientes puissent utiliser les objets contenus, définissez ces objets comme Friend ou Private.


XIII-H. Conservation (sauvegarde) d'objet, sérialisation

Quand un objet est détruit (fin de programme), les valeurs de ses attributs (les variables) sont perdues!!

Si les valeurs de l'objet changent et doivent être retrouvées lors d'une utilisation ultérieure du programme, il faut les enregistrer.

On pourrait enregistrer chaque attribut dans un fichier séquentiel (FileOpen puis Print..).

On peut aussi utiliser la sérialisation.


XIII-H-1. La Sérialisation

La sérialisation est le processus de conversion d'un objet ou d'un groupe d'objets en séquence linéaire d'octets pour stockage ou transmission à un autre emplacement. La désérialisation est le processus consistant à accepter des informations stockées et à recréer des objets à partir de celles-ci.

La sérialisation consiste donc à stocker les valeurs des attributs d'une instance d'un objet dans un fichier qui peut être au format binaire, xml ou Soap.
  • La sérialisation binaire concerne les champs publics et privés de l'objet et le nom de la classe, y compris l'assembly contenant la classe.
  • La sérialisation XML ne sérialise que les champs publics et les valeurs des propriétés d'un objet (si elles ne sont pas en lecture seule) dans un flux XML. La sérialisation n'inclut pas d'informations de type.
Lors de la sérialisation, les champs et propriétés sont convertis en un flux d'octets, qui est alors écrit dans un flux de données enregistré sur le disque ou envoyé sur internet.

Lorsque l'objet est ensuite désérialisé,le flux de données venant d'un fichier donne un flux d'octets qui donne une valeur aux champs et propriétés de l'objet, on obtient un objet identique à l'objet d'origine.

Vous pouvez aussi sérialiser un objet et le transporter sur Internet entre un client et un serveur à l'aide du protocole HTTP. À l'autre extrémité, la désérialisation reconstruit l'objet à partir du flux.


XIII-H-2. Exemple 1: Sérialisation binaire.

Créons une mini Classe:

<Serializable()> Public Class Compta
Public Total As Double 
Public Taux As Double
End Class

Notons que pour que la classe soit sérialisable , il faut ajouter

<Serializable()>.
L'attribut Serializable indique donc au compilateur que tout ce que contient la classe peut être conservé dans un fichier.

  • L'attribut NonSerialized peut être utilisé pour marquer les membres de la classe qui ne doivent pas être conservés.
  • Pour empêcher la sérialisation d'un membre Customer par exemple:
    
     <NonSerialized()> Public Customer As String
    

XIII-H-3. Sérialisation:

Dans le corps du programme, il faut mettre:

Imports System.IO
Imports System.Runtime.Serialization.Formatters.binary
Dans ce cas, vous utilisez un flux de sortie et un formateur binaire pour enregistrer l'objet dans un format binaire.

Dans l'entête du module créons une objet MyCompta:

Private myCompta As New Compta
Donnons des valeurs a ses membres.

myCompta.Taux = 2
myCompta.Total = 100
Si on quitte le programme, les valeurs sont perdues!!! On va donc les enregistrer dans un fichier "compta.bin"

Dim myFileStream As Stream = File.Create("Compta.bin")
Dim serializer As New BinaryFormatter
serializer.Serialize(myFileStream, myCompta)
myFileStream.Close()
Et voilà un fichier compta.bin a été crée sur le disque, il contient:

Bin=  ÿÿÿÿ Kserialisation, Version=1.0.1994.38183, Culture=neutral, PublicKeyToken=null serialisation.MaClasse Total Taux Y@ @ 
On a bien enregistré les valeurs des variables d'une instance dans un fichier.


XIII-H-4. Déserialisation:

Lors de la prochaine utilisation du logiciel,on crée de nouveau une instance de Compta:

Private myCompta As New Compta
Il faut ensuite 'récupérer' les valeurs de l'instance:

Dans Form1_Load par exemple:

Private Sub Form1_Load()
    If File.Exists("Compta.bin") Then
        Dim myFileStream As Stream = File.OpenRead("Compta.bin")
        Dim deserializer As New BinaryFormatter()
        myCompta = CType(deserializer.Deserialize(myFileStream), Compta)
        myFileStream.Close()
    End If
End Sub
A noter que vous devez d'abord vérifier que le fichier existe. S'il existe, créez une classe Stream pour lire le fichier binaire et une classe BinaryFormatter pour convertir le fichier. La méthode CType est utilisée pour la conversion du type d'objet Stream en type Compta.

Ca marche, on retrouve bien MyCompta.Taux=2

Bien sur , si on sérialise une nouvelle fois, cela écrase le précédent fichier.


XIII-H-5. Exemple 2: Sérialisation Xml.

Pour les applications Web ou les services Web XML, vous souhaiterez peut-être conserver l'objet dans un fichier XML à l'aide d'un format SOAP, ce qui facilite le partage de l'objet.

il faut charger dans les références la dll .Net

System.Runtime.Serialization.Formatters.Soap.dll
Ensuite Imports System.Runtime.Serialization.Formatters.Soap
Dim deserializer As New SoapFormatter
Remplacez "SavedCompta.bin" par "SavedCompta.xml".

Cela donne:

Imports System.IO
Imports System.Runtime.Serialization.Formatters.Soap
Private MyCompta As New MaClasse

Sérialisation:

MyCompta.Taux = 3
MyCompta.Total = 100
Dim myFileStream As Stream = File.Create("SaveCompta.xml")
Dim serializer As New SoapFormatter
serializer.Serialize(myFileStream, MyCompta)
myFileStream.Close()

Déserialisation:

Dim myFileStream As Stream = File.OpenRead("saveCompta.bin")
Dim deserializer As New soapFormatter
MyCompta = CType(deserializer.Deserialize(myFileStream), MaClasse)
MsgBox(MyCompta.Taux.ToString)
myFileStream.Close()
 

Si on regarde le fichier SavedCompta.xml (il est dans le répertoire bin) on voit que c'est de l'Xml:

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:MaClasse id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/serialisation/serialisation%2C%20Version%3D1.0.1995.
30938%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<Total>100</Total>
<Taux>3</Taux>
</a1:MaClasse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

On se rend compte que la sérialisation binaire produit un fichier plus petit.


XIII-H-6. Exemple 3: Sérialisation d'une collection

On peut sérialiser un objet, on peut donc sérialiser toutes sortes objets (dit serialisable) , une image, une collection, un tableau....

Une collection est un objet, pour enregistrer son contenu, on peut donc le sérialiser.

Imports System.IO
Imports System.Collections
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Runtime.Serialization


Module MonModule
    
' Creation d'une hashtable contenant des noms et adresses.
        Public addresses As New Hashtable
        addresses.Add("Phil", "12 grand rue,69872")
        addresses.Add("Bob", "98 petite rue, 196")
        addresses.Add("Marie", "BP 89, Paris, 75200")

    Sub Serialisation()

        
        ' Pour serialiser la hashtable (et les clé/valeur),  
        Dim fs As New FileStream("MesAdresses.dat", FileMode.Create)
        Dim formatter As New BinaryFormatter
        Try
            formatter.Serialize(fs, addresses)
        Catch e As SerializationException
            Console.WriteLine("Echec serialisation. Cause: " &amp; e.Message)
            Throw
        Finally
            fs.Close()
        End Try
    End Sub



    Sub Deserialisation()
        ' Declaration de la HashTable.
        Dim addresses As Hashtable = Nothing
        Dim fs As New FileStream("DataFile.dat", FileMode.Open)
        Try
            Dim formatter As New BinaryFormatter

            addresses = DirectCast(formatter.Deserialize(fs), Hashtable)
        Catch e As SerializationException
            Console.WriteLine("Echec de deserialisation. Cause: " &amp; e.Message)
            Throw
        Finally
            fs.Close()
        End Try

    End Sub
End Module

XIII-H-7. Exemple 4: Sérialisation d'un tableau

 
Private MyCompta(10) As String
MyCompta(1) = "3"
MyCompta(2) = "100"
Sérialisation:

Dim myFileStream As Stream = File.Create("SaveCompta.xml")
Dim serializer As New SoapFormatter
serializer.Serialize(myFileStream, MyCompta)
myFileStream.Close()
Déserialisation:

Dim myFileStream As Stream = File.OpenRead("saveCompta.xml")
Dim deserializer As New soapFormatter
MyCompta = DirectCast(deserializer.Deserialize(myFileStream), String())
MsgBox(MyCompta(1).ToString)
myFileStream.Close()
Vous avez compris. Seule difficulté: le caste en String().

Bien sur, cela marche avec un tableau à plusieurs dimensions. Voyons les lignes à modifier

Private MyCompta(10,10) As String
MyCompta(1,1) = "3"
Dans la déserialisation:

MyCompta = DirectCast(deserializer.Deserialize(myFileStream), String(,))

XIII-H-8. Exemple 5: Sérialisation d'une collection généric

Ici nous enregistrons les données dans un fichier XML nommé "Meslivres.Xml" (il sera dans le répertoire bin/Debug lors de la conception, et dans le répertoire de l'exécutable si on installe le logiciel).

Les Sub SaveData et LoadData ont en paramètre un type de collection généric list( Of ClasseLivre) C'est une collection d'objets typés ClasseLivre .Ce paramètre est passé avec ByRef .

(Pour l'exemple complet voir le chapitre architecture)

Imports System.Xml.Serialization
Imports System.IO
 
Public Class AccesAuxDonnees
 
Public Sub SaveData(ByVal list As Collections.Generic.List(Of ClasseLivre))
' Déclaration
Dim serialXML As Xml.Serialization.XmlSerializer = Nothing
Dim streamIO As StreamWriter = Nothing
Try
serialXML = New Xml.Serialization.XmlSerializer(GetType(Collections.Generic.List(Of ClasseLivre)))
' Ouverture d'un flux en écriture sur le fichier XML des contacts
streamIO = New StreamWriter("Meslivres.Xml")
' Sérialisation de la liste des contacts
serialXML.Serialize(streamIO, list)
Catch ex As Exception
' Propagrer l'exception
Throw ex
Finally
' En cas d'erreur, n'oublier pas de fermer le flux en écriture si ce dernier est toujours ouvert
If streamIO IsNot Nothing Then
streamIO.Close()
End If
End Try
End Sub
 
Public Sub LoadData(ByRef list As Collections.Generic.List(Of ClasseLivre))
' Déclaration
Dim streamIO As StreamReader = Nothing
Dim serialXML As Xml.Serialization.XmlSerializer = Nothing
Try
' Tester l'existance du fichier
If System.IO.File.Exists("Meslivres.Xml") = True Then
serialXML = New Xml.Serialization.XmlSerializer(GetType(Collections.Generic.List(Of ClasseLivre)))
' Ouverture d'un flux en lecture sur le fichier XML des contacts
streamIO = New StreamReader("Meslivres.Xml")
' Désérialisation de la liste des contacts
list = CType(serialXML.Deserialize(streamIO), Collections.Generic.List(Of ClasseLivre))
End If
Catch ex As Exception
' Propagrer l'exception
Throw ex
Finally
' En cas d'erreur, n'oublier pas de fermer le flux en lecture si ce dernier est toujours ouvert
If streamIO IsNot Nothing Then
streamIO.Close()
End If
End Try
End Sub
End Class
Voila ce que donne le fichier XMl:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfClasseLivre xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ClasseLivre>
<Titre>Livre1</Titre>
<Auteur>Auteur1</Auteur>
</ClasseLivre>
<ClasseLivre>
<Titre>Livre2</Titre>
<Auteur>Auteur2</Auteur>
</ClasseLivre>
<ClasseLivre>
<Titre>Titre3</Titre>
<Auteur>Auteur3</Auteur>
</ClasseLivre>
</ArrayOfClasseLivre>

XIII-I. Surcharge

Quand on utilise une méthode avec des paramètres, il y a parfois possibilité d'utiliser, avec la même méthode, un nombre différent de paramètres ou des paramètres de nature différente: on appelle cela surcharger la méthode.

Chaque manière d'écrire les paramètres s'appelle une signature.

Exemple:

Voici une fenêtre MessageBox:


pour ouvrir une fenêtre MessageBox il y a 12 signatures, en voici 2:


Reponse= MessageBox.show(TexteAAfficher,Titre, TypeBouton etIcone, BoutonParDéfaut)
Ici on donne 4 paramètres.


Reponse= MessageBox.show(TexteAAfficher)
Ici 1 seul paramètre.

On voit qu'on peut appeler la méthode MessageBox.Show avec un nombre différent de paramètres.

Comme on ne peut pas connaître toutes les signatures, VB nous aide:

Si on tape R= MessageBox.show ( VB affiche dans un cadre une signature, de petites flèches permettent de faire défiler tous les autres signatures:

Quand on crée une Classe, il est bien sur possible d'écrire une property ou un constructeur qui accepte la surcharge:


XIII-I-1. Surcharge en VB 2003

  1. On peut surcharger un constructeur.
    Pour cela il suffit de rajouter autant de procédure New que l'on veut avec pour chacune un nombre de paramètre différent (signatures différentes).

    Exemple: On peut surcharger un constructeur:
    
    
    Class Figure
    Sub New()
        Bla Bla
    End Sub
     
    Sub New( ByVal X As Integer, ByVal Y As Integer)
         Blabla
    End Sub. 
    End Class
    
    On peut donc instancier la classe correspondante de 2 manières:
    
    
    Dim A As New Figure    'Constructeur par défaut
    
    ou
    
    
    Dim A As New Figure(100,150)
    
  2. On peut surcharger une property.
    Pour cela il suffit de rajouter des procédure Property ayant le même nom de méthode avec pour chacune un nombre de paramètre différent (signature différente) On peut ajouter Overloads mais c'est facultatif.

    Exemple: surchargeons un membre:
    
    
    Class Figure
    Public Overloads Property Calcul()
        Bla Bla
    End Sub
     
    Public Overloads Property Calcul( ByVal X As Integer, ByVal Y As Integer)
         Blabla
    End Sub. 
    End Class
    
info C'est un bon exemple de polymorphisme.

XIII-I-2. Surcharge en VB 2005: nouveautés


  • Exemple: surchargeons l'opérateur +
    
    
    Public Structure height
        ...
        Public Shared Operator +(ByVal h1 As height, ByVal h2 As height)As height
            Return New height(h1.feet + h2.feet, h1.inches + h2.inches)
        End Operator
    End Structure
    
La routine doit être Shared, de plus si on surcharge certains opérateurs, il faut aussi surcharger leur inverse: si on surcharge '>' , il faut surcharger '<'.

Surcharge de IsTrue, IsFalse Ctype

Si on teste un boolean, il a la valeur True ou False.

Si par contre je crée une classe nommée 'Personne', je peux définir comment une instance sera considérée comme égale à True. Il faut surcharger l'opérateur IsTrue en lui indiquant dans quelle condition l'instance sera considérée comme =True:

Exemple:

J'ai une instance e de type Personne, si e.Present =True, dans ce cas je veux que e soit considéré comme True; il faut écrire dans la Classe 'personne':

Public Shared Operator IsTrue(ByVal e As Personne) As Boolean
If e Is Nothing Then
    Return False
Else
    Return e.Present
End If
End Operator
Pour définir l'opérateur IsFalse, c'est simple: c'est Not e
 
Public Shared Operator IsFalse(ByVal e As Personne) As Boolean
    Return Not e
End Operator

Ensuite je pourrais utiliser des instructions de la forme:

If e then.. 

Surcharge de Ctype:

Je peux définir dans une classe comment CType va fonctionner:

Pour cela dans la classe Personne, je vais définir les 3 possibilités:

Public Shared Widening Operator CType(ByVal e As Personne) As String
Return e.Nom + " " + e.Prenom
End Operator
 
Public Shared Widening Operator CType(ByVal  e As Personne) As Date
If e Is Nothing Then
    Return Nothing
Else
    Return e.DateDeNaissance
End If
End Operator
 
Public Shared Widening Operator CType(ByVal  e As Personne) As Boolean
    If e Is Nothing Then Return False Else Return e.Present
End Operator

Ainsi

Ctype(UnePersonne,String) retourne Nom Prenon

Ctype(UnePersonne,Date) retourne la date de naissance

Ctype(UnePersonne,Boolean) retourne True ou False.

Les exemples sont des surcharges, car le type des paramètres est modifié.


XIII-J. Structure de programme: programmation à 3 couches


XIII-J-1. Introduction:

Les programmes les plus fréquemment développés sont ceux utilisant une interface utilisateur permettant de travailler sur un ensemble de données, par exemple les clients d'une entreprise. Il faut pouvoir ajouter, supprimer, modifier les clients, en afficher la liste. Une base de données permet de stocker les données.

Il y a quelques années, dans l'interface utilisateur, du code lisait, modifiait la base de données. Très vite, sur un projet important cette approche, non architecturée, montrait ses limites.

Aussi très rapidement, en programmation fonctionnelle, le besoin de travailler sur des couches est apparu:

Pour afficher la liste des client de l'entreprise:
  • La couche présentation: une windowsForm affichait la liste ; elle faisait appel à:
  • La couche métier: une routine ChargeListe située dans un module standard sélectionnait les clients, elle faisait appel à:
  • La couche données qui lisait la base de données.
Cela a été formalisé en programmation objet.

A noté que si les divers couches sont sur les ordinateurs différents, on parle d'architecture distribuée.


XIII-J-2. Architecture n-tiers

De l'anglais tier signifiant étage ou niveau.

Architecture logicielle impliquant plusieurs composants, chaque composant étant le client d'un et le serveur d'un autre.

Le cas le plus simple de ce type d'architecture est le modèle Client/Serveur qui est en 2-tiers.

Tier 'Client' - Contient l'interface utilisateur, adresse des requêtes au serveur.

Tier 'Serveur' - Contient la base de données. Reçoit les requêtes, renvoie des données.

Dans les modèles 3-tiers et plus, il existe des composants intermédiaires qu'on appelle également middleware.


Un exemple typique d'un système 3-tier est le suivant :

  • Tier de présentation - c'est principalement l'interface utilisateur. contient les différents types de clients, léger (Web, ASP, JSP) ou lourd (Swing, WinForm)
  • Tier des règles de gestion: couche métier: Business Logic.
  • Tier de base de données - les programmes du deuxième tier font appel à ce dernier pour consulter ou mettre à jour les données relatives à l'entreprise.
Sur le même schéma, on peut ajouter des intermédiaires supplémentaires et obtenir une architecture 4, 5, …, n-tier.

Un exemple d'architecture à 5 couches logicielles :
  • Présentation: Contient tous les composants graphiques du module composant l'interface homme-machine (fenêtres, contrôles utilisateur…) avec le code propre à l'affichage de leur représentation et de leur contenu. Cette couche ne peut référencer que les couches "Référence" et "Application". Mettre le moins de code possible dans cette couche.
  • Application: Contient tous les contrôleurs de cas d'utilisation du module. cette couche assurent le liant entre les composants graphiques et les composants métier. Cette couche ne peut référencer que les couches "Métier", "Persistance" et "Référence"
  • Métier: Contient tous les composants métier dont le module a la responsabilité. Ces composants métier ont en charge la gestion du cycle de vie des objets métier gérés par le module. Cette couche ne peut référencer que les couches "Référence" et "Persistance"
  • Référence: Cette couche contient les objets de données pures qui transitent entre toutes les autres couches. Ces objets sont aussi parfois nommés DataValues ou DataObjects.
  • Persistence: Contient les composants assurant le mapping entre les objets définis dans la couche Métier et les composants de stockage définis dans la base de Données. Cette couche ne peut référencer que les couches "Référence" et la base de données. Concrètement, il s'agit de la seule couche ayant un lien avec la base de données.

XIII-J-3. Architecture 3 tiers

  • L'architecture 3-tier (de l'anglais tier signifiant étage ou niveau) vise à séparer très nettement trois couches logicielles au sein d'une même application ou système, à modéliser et présenter cette application comme un empilement de trois couches, étages, niveaux ou strates dont le rôle est clairement défini :
  • la présentation des données : correspondant à l'affichage, la restitution sur le poste de travail, le dialogue avec l'utilisateur,
  • le traitement métier des données : correspondant à la mise en œuvre de l'ensemble des règles de gestion et de la logique applicative, c'est à ce niveau que se trouvent toutes les règles de gestion, et toute l'intelligence de la démarche.
  • et enfin l' accès aux données persistantes (persistancy en anglais) : correspondant aux données qui sont destinées à être conservées sur la durée.

Relation entre les couches: Les services d'une couche sont mis à disposition de la couche supérieure.


XIII-J-4. Exemple 1:Ma bibliothèque (En écrivant du code)

Créons une application permettant de saisir , d'enregistrer, de voir des fiches 'Livre':

Il faut créer des objets 'Livre' puis un objet 'Livres' contenant une collection de tous les livres (Couche métier). Cette collection doit pouvoir être enregistrée puis lue sur disque (Couche d'accès au données). Enfin on doit pouvoir afficher le détail d'un livre (Interface utilisateur).

Couche métier :
  • Classe " ClasseLivre " : entité métier, classe permettant d'instancier un livre avec comme propriété : Titre, auteur..
  • Classe " ClasseLivres " (avec un 's'): classe comprenant une collection d'objet " Livre ". Elle possède des méthodes permettant d'ajouter un livre, de récupérer un livre dans la collection, de passer au précédent, au suivant...
Couche d'accès aux données :
  • LoadData pour lire la collection de livres à partir d'un fichier (xml dans notre exemple)
  • SaveData pour enregistrer la collection de livres dans un fichier (xml dans notre exemple)
Interfaces graphiques :
  • 1 Formulaire principal permettant de saisir un nouveau livre et de faire défiler les livres.

XIII-J-4-a. Couche métier

Créons la ClasseLivre", elle doit contenir:

2 property public : 'Titre' et 'Auteur'

2 variables private : m_titre et m_Auteur


Cela permettra d'instancier un objet livre et d'utiliser ses propriétés:

Exemple:

Dim livre As New ClasseLivre : livre.Nom= "Cours VB"


Voici la classe:

 
Public Class ClasseLivre
Private m_Titre As String
Private m_Auteur As String
 
' Propriété Titre
Public Property Titre() As String
Get
Return m_Titre
End Get
Set(ByVal value As String)
m_Titre = value
End Set
End Property
 
' Propriété Auteur
Public Property Auteur() As String
Get
Return m_Auteur
End Get
Set(ByVal value As String)
m_Auteur = value
End Set
End Property
 
End Class
 
Créons la ClasseLivres" (avec un 's'), elle doit contenir:

1 collection nommé ListLivre d'objet générics: Collection.Generic.List (Of Classelivre)

C'est une collection typée, elle ne peut contenir que des 'Livre'

On instancie aussi un objet ad d'accès aux données.

La méthode public LivrePointé retourne le livre en cours, les méthodes FirstLivre, LastLivre, NextLivre, PreviousLivre permettent de se déplacer dans les livres. On peut ajouter un livre avec AddLivre.


Une variable nommée m_numéro sert dans la classe de "pointeur" du livre courant.

Pour enregistrer ou charger la collection de livre sur disque , il y a les 2 méthodes SaveData et LoadData. Elle appelle des méthodes de la couche de données.

Quand cette classe est instanciée elle charge les données (la procédure New appelle LoadData).

Imports System.Collections.Generic
 
Public Class ClasseLivres 
Private ListLivre As New List(Of ClasseLivre) 'Collection de Livre
Private m_numero As Integer
Private ad As New AccesAuxDonnees
 
'Constructeur, charge la collection
Public Sub New()
Me.LoadData()
End Sub
 
Public Sub LoadData()
ad.LoadData(ListLivre)
m_numero = 0
End Sub
 
Public Sub SaveData()
ad.SaveData(ListLivre)
End Sub
 
'Retourne le livre courant
Public Function LivrePointé() As ClasseLivre
If ListLivre.Count <> 0 Then
If m_numero < ListLivre.Count Then
Return ListLivre.Item(m_numero)
Else
Return Nothing
End If
Else
Return Nothing
End If
End Function
 
'Ajouter un livre
Public Sub AddLivre(ByVal l As ClasseLivre)
ListLivre.Add(l)
End Sub
 
'Effacer le livre courant
Public Sub RemoveLivre()
ListLivre.RemoveAt(m_numero)
End Sub
 
'Mettre à jour un livre
Public Sub UpdateLivre(ByVal l As ClasseLivre)
ListLivre.Item(m_numero) = l
End Sub
 
'Livre suivant
Public Sub NextLivre()
If m_numero < ListLivre.Count Then
m_numero += 1
End If
End Sub
 
'Livre précédent
Public Sub PreviousLivre()
If m_numero > 0 Then
m_numero -= 1
End If
End Sub
 
'Premier Livre 
Public Sub FirstLivre()
m_numero = 0
End Sub
 
'Dernier livre
Public Sub LastLivre()
m_numero = ListLivre.Count - 1
End Sub
End Class
 
 

Il aurait été plus élégant d'intancier l'objet d'accès au données dès le début de la classe comme cela:

Public Class ClasseLivres
Private ListLivre As New List(Of ClasseLivre) 'Collection de Livre
Private m_numero As Integer
 
Dim ad As New AccesAuxDonnees
 

XIII-J-4-b. Couche d'accès aux données:

Ici nous enregistrons les données dans un fichier XML nommé "Meslivres.Xml" (il sera dans le répertoire bin/Debug lors de la conception, et dans le répertoire de l'exécutable si on installe le logiciel). On utilise la sérialisation et les Stream. (Voir chapitre sur la sérialization pour plus de détails)


Les Sub ont un paramètre: la collection de ClasseLivre.Ce paramètre est passé avec ByRef .

 
Imports System.Xml.Serialization
Imports System.IO
 
Public Class AccesAuxDonnees
 
Public Sub SaveData(ByVal list As Collections.Generic.List(Of ClasseLivre))
' Déclaration
Dim serialXML As Xml.Serialization.XmlSerializer = Nothing
Dim streamIO As StreamWriter = Nothing
Try
serialXML = New Xml.Serialization.XmlSerializer(GetType(Collections.Generic.List(Of ClasseLivre)))
' Ouverture d'un flux en écriture sur le fichier XML 
streamIO = New StreamWriter("Meslivres.Xml")
' Sérialisation de la liste des contacts
serialXML.Serialize(streamIO, list)
Catch ex As Exception
' Propager l'exception
Throw ex
Finally
' En cas d'erreur, n'oublier pas de fermer le flux en écriture si ce dernier est toujours ouvert
If streamIO IsNot Nothing Then
streamIO.Close()
End If
End Try
End Sub
 
Public Sub LoadData(ByRef list As Collections.Generic.List(Of ClasseLivre))
' Déclaration
Dim streamIO As StreamReader = Nothing
Dim serialXML As Xml.Serialization.XmlSerializer = Nothing
Try
' Tester l'existance du fichier
If System.IO.File.Exists("Meslivres.Xml") = True Then
serialXML = New Xml.Serialization.XmlSerializer(GetType(Collections.Generic.List(Of ClasseLivre)))
' Ouverture d'un flux en lecture sur le fichier XML des contacts
streamIO = New StreamReader("Meslivres.Xml")
' Désérialisation de la liste 
list = CType(serialXML.Deserialize(streamIO), Collections.Generic.List(Of ClasseLivre))
End If
Catch ex As Exception
' Propager l'exception
Throw ex
Finally
' En cas d'erreur, n'oublier pas de fermer le flux en lecture si ce dernier est toujours ouvert
If streamIO IsNot Nothing Then
streamIO.Close()
End If
End Try
End Sub
End Class
 

XIII-J-4-c. Couche de présentation: interface graphique ]


On instancie un objet Livres, cet objet contient la collection de livre.

Il suffit ensuite d'utiliser Livres.LivrePointé qui est le livre en cours, Livres.NextLivre() pour passer au livre suivant, Livres.PreviousLivre pour passer au précédent.

Quand on clique sur 'Enregister livre' on effectue Livres.AddLivre.

Quand on clique sur 'Enregister tous les livres' on effectue Livres.SaveData ( qui fait appel à la couche de données).

Deux petites Sub LireLivre et AfficheLivre permettent de remplir ou de lire les TextBox à partir d'un objet livre.


 
Public Class InterfaceGraphique
 
Dim Livres As New ClasseLivres
Dim iFlagNewLivre As Integer
 
Sub LireLivre(ByVal l As ClasseLivre)
l.Titre = TextBoxTitre.Text
l.Auteur = TextBoxAuteur.Text
End Sub
 
Sub AfficheLivre(ByVal l As ClasseLivre)
If l IsNot Nothing Then
TextBoxTitre.Text = l.Titre
TextBoxAuteur.Text = l.Auteur
End If
End Sub
 
Private Sub ButtonNext_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonNext.Click
Livres.NextLivre()
AfficheLivre(Livres.LivrePointé)
iFlagNewLivre = False
End Sub
 
 
Private Sub ButtonPrevious_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ButtonPrevious.Click
Livres.PreviousLivre()
AfficheLivre(Livres.LivrePointé)
iFlagNewLivre = False
End Sub
 
Private Sub ButtonNew_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonNew.Click
TextBoxTitre.Text = ""
TextBoxAuteur.Text = ""
iFlagNewLivre = True
End Sub
 
Private Sub ButtonEnregister_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonEnregister.Click
Dim NouveauLivre As New ClasseLivre
If iFlagNewLivre = True Then
  LireLivre(NouveauLivre) 
  Livres.AddLivre(NouveauLivre)
  Livres.LastLivre()
Else
  LireLivre(NouveauLivre)
  Livres.UpdateLivre(NouveauLivre)
End If
iFlagNewLivre = False
End Sub
 
Private Sub ButtonEnregistertous_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonEnregistertous.Click
    Livres.SaveData()
End Sub
End Class
 

XIII-J-5. Exemple 2: Ma bibliothèque (Avec un BindingSource et génération automatique de l'IU)(VB 2005)

C'est le même programme, mais on va laisser le soin à VB de générer automatiquement l'interface utilisateur et les liens (Binding) entre cette interface et les données.

La couche d'accès aux données est la même.

On a une Form vide.


XIII-J-5-a. Couche métier:

ClasseLivre est identique, par contre ClassesLivres est plus simple: elle contient uniquement la collection généric ListLivre contenant les livres

(Et SaveData et Load Data)

 
Imports System.Collections.Generic
Public Class ClasseLivre
 
Private m_Titre As String
Private m_Auteur As String
' Propriétés Titre
Public Property Titre() As String
Get
Return m_Titre
End Get
Set(ByVal value As String)
m_Titre = value
End Set
End Property
 
' Propriétés Auteur
Public Property Auteur() As String
Get
Return m_Auteur
End Get
Set(ByVal value As String)
m_Auteur = value
End Set
End Property
 
Public Function GetTitre() As String
Return m_Titre
End Function
End Class
 
Public Class ClasseLivres
Public ListLivre As New Collections.Generic.List(Of ClasseLivre)
Private ad As New AccesAuxDonnees
 
Public Sub LoadData()
ad.LoadData(ListLivre)
End Sub
 
Public Sub SaveData()
ad.SaveData(ListLivre)
End Sub
 
End Class
 
Ici ListLivre est Public.


XIII-J-5-b. Création de la source de données:

Il faut ensuite créer une source de données:

Comme on affiche des livres, la source c'est la ClasseLivre.

Menu 'Données'=> 'Ajouter une nouvelle source de données'


Ici la source de données n'est pas une base de données mais un Objet:

On clique sur 'Objet' puis bouton 'Suivant'.


On déroule livre, qui est le nom de la solution, puis on clique sur 'ClasseLivre' et sur le bouton suivant.

Puis Ok; la source de données est créée.


XIII-J-5-c. Génération automatique de l'interface utilisateur:

Visual Studio dispose d'une fenêtre 'Sources de données' depuis laquelle vous pouvez faire glisser des éléments jusqu'à un formulaire pour créer automatiquement des contrôles liés aux données qui affichent des données.

Afficher les sources de données:

Menu 'Données' puis 'Afficher les sources de données'


Il apparaît à droite la fenêtre 'Sources de données'

Dérouler 'livre' et cliquer sur 'ClasseLivre'

Pour générer, non par une grid mais des zones de saisie, dérouler la liste de ClasseLivre et cliquer sur 'Détails'.

Enfin faire un drag ans drop à partir de ClasseLivre et déposer le sur la form de gauche (qui est vide au départ)


Miracle: il apparaît automatiquement:
  • des zones textbox pour chaque properties de la classe avec un label devant.
  • une barre de navigation (tout est généré automatiquement: les bitmap des boutons dans les ressources Setting...)
  • Un composant BindingSource.(Il fait le lien entre l'interface et la source de données)
  • Un composant BindingNavigator.(Il gère la barre de navigation)
On voit bien en dessous les 2 composants qui ont été ajoutés.


XIII-J-5-d. Création du Binding:

Maintenant ,il faut indiquer la source de données, le Datasource du BindingSource: c'est la collection MesLivres.ListLivre (C'est pour cela que la collection ListLivre est Public)


Public Class Form1
Dim MesLivres As New ClasseLivres
 
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 ClasseLivreBindingSource.DataSource = MesLivres.ListLivre
End Sub
 
'On peut ajouter dans la form 2 boutons permettant la sauvegarde ou la lecture sur disque.
Private Sub SauveLivres_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    MesLivres.SaveData()
End Sub
 
Private Sub LoadLivre_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    MesLivres.LoadData()
    ClasseLivreBindingSource.DataSource = MesLivres.ListLivre
End Sub
End Class

P.... !!ça marche!!


Ici ,les différentes parties du logiciel sont dans la même solution. Rien n'empêche de:
  • Mettre les classes dans un même fichier .vb
  • Mettre les classes dans différents fichiers .vb
  • Créer les Classes dans une solution, la générer, inclure dans les références du projet principal les dll.
  • Enfin si divers parties sont sur différentes machines, on parle d'architecture distribuée.

XIII-K. Utilisation de Patron (Design Pattern)

Un motif de conception (design pattern) est un concept destiné à résoudre les problèmes récurrents en POO. En français on utilise aussi les termes modèle de conception, patron de conception ou de Patron.

Pour ne pas avoir à réinventer la roue, les patrons décrivent des solutions standards pour répondre à des problèmes de conception ou d'architecture .C'est une formalisation de bonnes pratiques, ce qui signifie qu'on privilégie les solutions éprouvées.

Il ne s'agit pas de fragments de code, mais d'une méthode de conception.

Les auteurs des principaux design patterns (il y en a 23), plus connus sous le nom de Gang Of Four, sont Erich Gamma, Richard Helm, Ralph Johnson et John Vlissides. Les DP qu'ils ont conçus sont considérés comme la base de tout les autres .


XIII-K-1. Singleton

Parfois , on a besoin d'une classe avec laquelle on veut créer une instance et une seule.

Il faut créer une classe:
  • Ou il ne soit pas possible de créer plusieurs instances:
    New , le constructeur, doit-être toujours private : cela empêche d'écrire 'Dim myobjet As New MyClasse' et empêche donc d'instancier.

    On utilise donc:
    
    Private Sub New() 
    
  • Ou une méthode de classe permet de créer une instance et une seule. Une méthodes de classe nommée habituellement 'GetInstance' peut être appelée (sans avoir à instancier) directement sur le nom de la classe. Shared Function getInstance() As sing
    Cette fonction qui s'appelle toujours getInstance va servir à instancier une fois la variable Instance.

Shared instance As sing

Cette variable est la base du Singleton. Elle s'appelle Instance (par convention) elle est du même type que la class et contient l'instance unique.



Public Class sing
'Déclaration de l'instance Singleton
Shared instance As sing
 
Private Sub New()'Pas oublier de mettre Private 
    MyBase.New()
End Sub
Shared Function getInstance() As sing 'Voici la méthode de classe
 
If IsNothing(instance) Then 'Si le singleton n'est pas créé, alors faut le créé un et un seul
    instance = New sing
End If
Return instance
End Function
...
...'Ici les autres membres de la classe 
End Class
Comment utiliser cette Classe?

Dim t As sing =  sing.getInstance
Remarque:
  • Si on fait ensuite Dim t1 As sing = sing.getInstance c'est la même instance qui est retournée. On ne peut en créer qu'une..
  • Si on écrit Dim t As New sing :cela plante.
On peut ajouter une protection contre les multi thread trop rapide avec SyncLock GetType(sing)


    Shared Function getInstance() As sing
         
        If IsNothing(instance) Then 
            SyncLock GetType(sing) 
                 If IsNothing(instance) Then 
                    instance = New sing 
                end if 
            End SyncLock 
        End If 
        Return instance 
    End Function
 

XIII-K-2. Itérateur

Un itérateur est un objet qui permet de parcourir tous les éléments contenus dans un conteneur.

Dans la programmation fonctionnelle on utilise souvent une boucle (for next) avec un index , pour accéder séquentiellement à tous les éléments d'un tableau. Cette méthode se nomme Indexation.

En programmation objet, le but d'un itérateur est de permettre à son utilisateur de parcourir le conteneur, c'est-à-dire d'accéder séquentiellement à tous ses éléments, de consulter l'élément courant. L'itérateur permet isoler l'utilisateur de la structure interne du conteneur, parfois complexe.

Les itérateurs ont certains avantages:
  • Une simple boucle n'est pas adapté à toutes les structures de données, en particulier celles qui n'ont de méthode d'accès à un élément quelconque ou celles à accès à un élément quelconque très lent.
  • Les vrai itérateurs peuvent être écrit pour toutes sortes de structures de données: liste arbre , liste chaînée.., s'il y a changement dans l'organisation de la structure de données, celui qui utilise l'itérateur n'a pas à s'en soucier.
  • Un vrai itérateur peut implanter des conditions additionnelles sur l'accès aux éléments, par exemple pour "sauter ou ne pas sauter".
  • Un vrai itérateur peut dans certains cas permettre que le conteneur soit modifié, sans être invalidé pour autant. Par exemple, après qu'un itérateur s'est positionné derrière le premier élément, il est possible d'insérer d'autres éléments au début du conteneur avec des résultats prévisibles. Avec un index on aurait plus de problèmes, parce que la valeur de l'index devrait elle aussi être modifiée en conséquence.
En VB, il existe des itérateurs 'clé en main' pour les collections par exemple, mais ils n'ont pas tous les avantages décrit ci-dessus.

La Classe System.Array et celles qui implémentent l'interface IEnumerable possèdent 2 méthodes pour itérer:

  • Une boucle For Each pour parcourir tous les éléments de l'Array.
  • L'utilisation d'un énumérateur.
Voyons comment faire:

On peut aussi utiliser dans ce cas Getenumerator pour créer un énumérateur: Il permet de lire du premier élément au dernier:

Dans l'énumérateur l'élément courant est Current.

Pour passer au suivant , on utilise MoveNext.

Reset réinitialise.

Initialement le pointeur est avant le premier élément, aussi avant d'utiliser Current il faut faire MoveNext.

Attention, on ne peut que lire les données dans l'ordre; si on modifie la collection, il faut redémarrer la lecture.

 ' Créer un tableau
Dim myArr(4) As String
myArr(0) = "toto"
myArr(1) = "lulu"
myArr(2) = "bibi"
myArr(3) = "tata"
 
Dim i As Integer = 0
 
'Créer un énumérateur
Dim myEnumerator As System.Collections.IEnumerator = myArr.GetEnumerator()
 
'Afficher sur la console successivement les élément du tableau
'en utilisant MoveNext et Current
While myEnumerator.MoveNext() And Not (myEnumerator.Current Is Nothing)
  Console.WriteLine("[{0}] {1}", i, myEnumerator.Current)
  i += 1
End While
 

XIV. Un peu de théorie pour en déduire de bonnes règles :


XIV-A. Diverses sortes de programmation .

Programmation impérative.

Programmation structurée.

Programmation fonctionnelle.

Programmation procédurale.

Programmation évènementielle.

Programmation défensive.

Programmation Objet.


XIV-A-1. Programmation impérative

On en fait sans le savoir:

Le programmeur spécifie explicitement l'enchaînement des instructions devant être exécutées :

Fais ceci, puis cela.

Fais ceci, si cela est vrai.

Fais ceci, tant de fois .


Un programme impératif est composé de différentes instructions indiquant de manière explicite comment résoudre un problème.


On l'a déjà vu, les instructions sont effectuées de manière séquentielle:

Instruction1
Instruction2
Instruction3
...

Il y a des choix:

If.. Then

Il y a des boucles:

For .. next

L'action de base dans la programmation impérative est l'affectation, c'est-à-dire la modification de la valeur associée à une variable du programme.

A=3
L'affectation va être soit effectuée en séquences successives, soit avec des choix, soit itérée selon les compositions définies par les algorithmes.

En programmation impérative, on travaille sur le modèle de la machine de Turing, avec une mémoire centrale et des instructions qui modifient son état grâce à des assignations successives.

Le langage machine et l'assembleur sont des langages impératifs. Le code en Visual Basic l'est aussi.

Exemple: réinitialiser un tableau en donnant la valeur 0 à tous ses éléments.

10 Dim tableau (10) as Integer
20 Dim compteur As Integer
30 compteur= 0
40 boucle:
50 tableau(compteur)=0
60 compteur= compteur + 1
70 If Compteur <11 Then Goto boucle
Ici on utilise un Basic très ancien avec un goto pour faire une boucle et des numéros de ligne; c'est pas très 'lisible'.


Et c'est quoi la programmation non impérative?

C'est par exemple la programmation déclarative, elle consiste à énoncer les propriétés d'un système de résolution (à les déclarer) plutôt qu'à décrire les opérations à effectuer comme dans le cas de la programmation impérative. VB ne permet pas la programmation déclarative.

Un programme déclaratif définit (ou "déclare") différentes entités et leurs relations, à charge ensuite pour le programme d'utiliser ces relations pour résoudre le problème.


XIV-A-2. Programmation structurée

Pour éviter les programmes 'spaghetti', on a structuré et utilisé les procédés suivant:


Découpage en fonction:

L'approche structurée découpe le problème en fonctions:

L'analyse se fait de manière descendante: on découpe un problème complexe en problèmes plus simples qui sont eux mêmes découpés en problèmes plus simples. On découpe jusqu'à ne plus avoir que des problèmes simples.

Il existe aussi l'analyse ascendante: ayant à sa disposition des procédures simples, on les assemble en les faisant appeler par des procédures plus complexes pour atteindre la solution.

Si le projet est entièrement nouveau, on fait plutôt une analyse descendante; si on travaille sur un projet possédant déjà toutes les procédures simples, on raisonnera en analyse ascendante.

Rien d'empêche d'avoir une analyse mixte.

Les programmeurs doivent donc décomposer leur code en petites fonctions, assez petites pour être facilement comprises et claires.


Utilisation de variables locales:

En général les programmes doivent éviter d'utiliser des variables globales.

Au lieu de cela, les sous-programmes doivent utiliser des variables locales et agir sur des arguments ou paramètres qui leurs sont envoyés.


Organisation hiérarchique simple du code:

La programmation structurée recommande une organisation hiérarchique simple du code. Pour cela on utilise des structures de contrôles while, Do Loop, for, if .. then .. else.

Il est également recommandé de n'avoir qu'un point d'entrée pour chaque boucle (et un point de sortie unique dans la programmation structurée originelle).


Eviter les 'Goto'

L'instruction Goto, directement héritée des instructions de saut des langages machines (Jmp), était nécessaire dans les langages primitifs (Fortran, Assembleur) comme instruction de base permettant de réaliser des boucles et autres structures de contrôles (voir exemple sur la programmation impérative).

En programmation structurée (depuis les années 1970), l'instruction Goto n'est guère appréciée des programmeurs, car elle casse la structure séquentielle du programme et rend souvent les programmes plus difficiles à comprendre et à maintenir (on parle dans ce cas de programmation spaghetti). On utilise plus généralement des structures comme les sauts conditionnels (si .. alors .. sinon .. ) ou les boucles (pour, tant que, etc.)

En VB, des instructions effectuent des sauts conditionnels ou inconditionnels (If.. Then) et remplacent usage de l'instruction Goto, d'autres ( For..Next, Do.. Loop) permettent d'élégantes boucles.


Rupture de séquence:

Il y a même des instructions qui 'cassent' élégamment les sorties de boucles; c 'est le cas des instructions comme Continue ou Exit For. L'erreur majeure de Goto, se situe dans le fait que cette instruction renvoie vers une position précédente du code (aboutissant à ce que l'on appelle le "code spaghetti"), tandis que les deux autres renvoient (le plus souvent) vers un point du code situé logiquement après la boucle qu'elles interrompent.

While condition
    ..Continue While
End While

Exemple: réinitialiser un tableau en donnant la valeur 0 à tous ses éléments.

initialisetableau:
Dim tableau (10) as Integer
Dim compteur As Integer
For compteur= 0 To 10
  tableau(compteur)=0
Next compteur
Return

On crée un sous-programme nommé initialisetableau qui a la fonction d'initialiser le tableau. Il n'utilise plus de GoTo mais une boucle For Next.

Ce sous-programme était appelé par un Gosub (Gosub n'existe plus en VB.Net)


XIV-A-3. Programmation fonctionnelle

C'est une programmation généralisant l'usage des fonctions. En "programmation fonctionnelle", les entités sont des fonctions au sens mathématique du terme.

Une fonction est un sous programme comportant une suite d'instruction Cette fonction peut ensuite être appelée par le programme principal ou par une autre fonction. La longueur du code du programme principal est, du coup, fortement diminuée.
Une fonction se rappelant elle-même est une récursive. (source dictionnaire devellopez.com)


Comme on l'a vu, la programmation structurée découpe les problèmes en fonctions, ce découpage s'il est systématiquement employé aboutit à la programmation fonctionnelle qui consiste en un emboîtement de fonctions que l'on peut voir comme des " boîtes noires " que l'on peut imbriquer les unes dans les autres. Chaque boîte possédant plusieurs paramètres en entrée mais une seule sortie.

Le programme principal est lui-même considéré comme une fonction qui fait appel à d'autres fonctions qui elles-mêmes...


Les langages de programmation fonctionnelle dits "purs" (Vb n'en fait pas partie) ne proposent ni affectation de variable, ni allocation de mémoire, ni boucles. Ces deux derniers procédés sont respectivement remplacés par les allocations automatiques et l'usage intensif de la récursivité.


XIV-A-4. Programmation procédurale

La programmation procédurale utilise des fonctions nommées 'procédure'. Une procédure, aussi appelée routine, sous-routine, méthode ou fonction (Sub et Function en VB) contient simplement une portion de code qui effectue une fonction précise. N'importe quelle procédure peut être appelée à n'importe quelle étape de l'exécution du programme, incluant d'autres procédures ou même la procédure elle-même (récursivité).

On peut , en appelant la procédure , envoyer des paramètres.

Avantages:
  • La possibilité de réutiliser le même code à différent emplacement dans le programme sans avoir à le retaper.
  • Une façon plus simple de suivre l'évolution du programme.
  • La création d'un code plus modulaire et structuré.
Exemple: réinitialiser un tableau en donnant la valeur 0 à tous ses éléments.

Sub InitialiseTableau ( tableau() As Integer)
Dim compteur As Integer
For compteur= 0 To Ubount (tableau,1)
  tableau(compteur)=0
Next compteur
End Sub
Ici on utilise une procédure, une Sub qui a pour seule fonction la réinitialisation du tableau.


XIV-A-5. Programmation défensive

Se dit d'une programmation où l'on considère que le programme peut contenir des erreurs et que l'utilisateur est parfaitement malveillant et fera tout pour faire planter le programme. Ainsi donc, il faut s'en défendre.

Elle consiste à ajouter du code vérifiant systématiquement l'état du système ainsi que la valeur des paramètres des fonctions et s'assurant que le changement d'état est consistant. Si une erreur est détectée, elle sera traitée.

En premier lieu donc on vérifiera que toutes les entrées ( saisie au clavier, lecture de fichier..) sont valides pour le programme et ne contiennent pas, par exemple, une valeur pouvant provoquer une exception non gérée ultérieurement.

Pour se défendre des entrées invalides, on utilise la 'tolérance de faute':

Pour toutes entrées:
  • On teste les valeurs, on accepte uniquement les valeurs permises.
  • On gère les exceptions avec Try.. Catch.
  • On utilise les assertions.

Une entrée invalide entraîne grâce à la programmation défensive:
  • soit l'arrêt du programme (programmation défensive forte).
  • soit l'utilisation de valeur par défaut ou d'une ancienne valeur.
  • soit l'envoie à l'appelant l'indication qu'il y a une mauvaise entrée:
    • retour d'une valeur de diagnostic
    • déclenchement d'une exception chez l'appelant ( utilisation de Throw en VB dans une classe).

L'appelant, le client doit donc tester si la valeur de retour est valide ou bien gérer les exceptions qui sont retournées (solution qui semble préférable). Il devra donc traiter l'erreur.

Exemple

Try 
SaveFile (maFile)
Catch E As Exception
    MsgBox (Exception.Message)
End Try

XIV-A-6. Programmation sécurisée:

La programmation sécurisée va au delà de la programmation défensive; Elle consiste à prendre en compte la sécurité informatique à tous les moments de la conception, de la réalisation et de l'utilisation d'un programme. Cela permet d'éviter au maximum les trous de sécurité et autres bugs.


XIV-A-6-a. Conception

Lors de la conception, il s'agit de concevoir le programme de façon modulaire et nécessitant le moins de droits utilisateurs possible. Il est préférable d'avoir plusieurs programmes de taille réduite qui collaborent entre eux, qu'un gros programme.


XIV-A-6-b. Réalisation

Ensuite, lors de la réalisation, il faut penser à bien valider les données entrées par l'utilisateur. L'idée générale et la plus importante est de ne jamais faire confiance à l'utilisateur. Ne jamais faire des hypothèses sur les entrées sans les vérifier soi-même (par exemple taille de l'entrée, signe du nombre,...)C'est la programmation défensive.

Mais on peut généraliser ce processus:
  • En testant les entrées de toutes les procedures (Préconditions)
  • En testant les sorties de toutes les procédures afin qu'elles soient conformes à ce qu'attend l'appelant (Postconditions)
On peut aussi faire de la programmation par contrat: l'appelant vérifie que les préconditions sont remplis et envoie à la procédure des 'paramètres valides'. La procédure effectue sont code et vérifie que ce qu'elle retourne est valide. Il y a contrat entre l'appelant et la procédure appelée: l'appelant vérifie les pré conditions seulement et sait qu'on lui retournera des informations valides. La procédure sait que les paramètres qu'elle recevra sont valides ; elle vérifiera la validité de ses résultats avant de les retourner.

Invariants : en plus des pré et post conditions, tous les objets inclus dans l'échange doivent être laissés dans le même état entre le début et la fin de celui-ci. Il faut s'assurer que le système entier conserve une certaine uniformité (et que l'on évite donc les effets de bords disgracieux).


XIV-A-6-c. Exécution

Enfin lors de l'exécution, il faut penser par exemple à appliquer les différentes mise à jour de sécurité lorsqu'elles sortent. Pour ce faire, il peut être pratique de la part du concepteur de l'application de proposer un système de mise à jour simplifié de l'application.

Effet de bord:
  • Il peut arriver qu'une variable dispose d'une portée qui dépasse la procédure qui la contient, ceci afin d'être accessible à partir d'autres procédures. Certaines procédures peuvent ainsi modifier une variable dans le seul but de les maintenir dans un état donné, fixé par le développeur. Cette capacité d'une fonction de modifier l'état d'une valeur (variable globale ou statique, argument d'une autre fonction, affichage ou écriture des données) autre que celle qu'elle renvoie définit l'effet de bord.
  • Ce mécanisme crée une sorte d'interdépendance entre les fonctions, rendant souvent plus complexe la compréhension d'un programme... D'autant que la modification d'une fonction peut dès lors avoir des conséquences inattendues sur le résultat d'autres fonctions "liées".

XIV-A-7. Programmation évènementielle

Avant VisualBasic 1 :

Programme Basic SANS programmation évènementielle :


10 PRINT "Donne ton nom";
20 INPUT N$
30 PRINT "Donne ton prénom";
40 INPUT P$
50 PRINT "Bonjour "; P$; " "; N$
60 END

L'exécution de ce programme conduit au résultat suivant :



????????

<font color="#510051">			C: ></font> <font color="#008040"><b>RUN</b></font><br/>
<font color="#510051"><b>Donne ton nom ?</b></font> <font color="#008040"><b>LASSERRE</b></font><br/>
<font color="#510051"><b>Donne ton prénom ?</b></font> <font color="#008040"><b>PHILIPPE</b></font><br/>
<font color="#510051"><b>Bonjour PHILIPPE LASSERRE</b></font><br/>
<font color="#510051">C: ></font>

Le programme affiche des informations à l'écran avec PRINT et utilise la commande INPUT lorsqu'il a besoin que l'utilisateur lui communique une information, au moyen du clavier.

Le programmeur indique la succession des lignes , leur ordre est imposé. Le programme s'arrête quand il attend une frappe au clavier puis redémarre quand l'utilisateur a validé sa réponse (en appuyant sur la touche 'Return'). On constate que l'ordre de saisie des informations est totalement déterminé par le programme. Il n'est pas question ici que l'utilisateur indique son prénom avant son nom.

Parfois pour assouplir les choses, on créait une boucle qui lisait à la volée, le clavier et qui en fonction de la touche appuyée permettait un choix.


Depuis Visual Basic 1:

En environnement graphique, l'interaction avec l'utilisateur est beaucoup plus élaborée :
  • Il y a un environnement graphique.
  • la saisie d'informations peut s'effectuer au moyen du clavier , mais aussi de champs de saisie, boutons, listes, sélecteurs, cases à cocher, menus.
  • et surtout, l'ordre d'exécution des différentes opérations n'est pas strictement déterminé à l'avance.
  • Toute action de l'utilisateur sur l'interface graphique déclenche des évènements. Si l'utilisateur clique sur un bouton l'évènement bouton.Click est déclenché.
  • Pour chaque évènement on exécute une procédure (une Sub).
Du point de vue du développeur, cela change complètement la donne : ce n'est plus lui qui décide ce que va faire l'utilisateur ! Au contraire, il doit s'attendre a priori à n'importe quelle action de la part de ce dernier.

C'est ici qu'intervient la notion de programmation événementielle : le programme est structuré non plus pour exécuter une séquence d'instructions dans un ordre prédéfini, mais pour réagir à des événements qu'il consomme l'un après l'autre.

Exemple pratique: l'utilisateur saisie son nom et son prénom, il clique sur le bouton 'Ok' ; une boite s'ouvre indiquant "Bonjour..'

Pour faire ce programme, il faut dessiner l'interface utilisateur, Vb fourni les évènements et leur procédure. Il faut ensuite écrire dans la procédure correspondant à l'évènement 'Bouton1-Click' le code qui affiche 'Bonjour..'.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    MsgBox("Bonjour " &amp; TextBox1.Text &amp; TextBox2.Text)
End Sub 
Il existe d'autres évènements (Form.Load; Button1.MouseDown...) qui peuvent ne pas être utilisés.


Décortiquons le code; comment cela se passe en VB?

Le composant (le bouton) doit se lier à un écouteur d'événement à qui il va déléguer le traitement de l'événement

Le traitement de l'événement est délégué à l'écouteur et l'écouteur exécute une méthode spécifique qui prend en paramètre l'événement qui s'est produit

Dans la Région " Code généré par le Concepteur Windows Form " il y a:

Friend WithEvents Button1 As System.Windows.Forms.Button

On crée une variable Button1 pour le bouton de commande; WithEvents indique que l'objet Button1 a des évènements.

On voit dans le code la procédure évènement Button1_Click

Protected Sub Button1_Click(ByVal sender As System.Object, _ 
ByVal e As System.EventArgs) Handles Button1.Click

End Sub
Le terme Handles provoque l'association d'un événement (Button1.Click situé après Handles) à un gestionnaire d'événements ( la Sub Button1_Click) il crée une délégation. Ainsi, à l'évènement Button1.Click correspond la procédure Sub Button1_Click.

la Sub pourrait d'ailleurs se nommer différemment, cela n'a pas d'importance.

Plusieurs évènement peuvent déclencher une seule Sub.

L'association d'événements aux gestionnaires d'événements se fait au moment de la compilation et ne peut pas être modifiée.


En conclusion avant la programmation évènementielle on imposait:

Faire ceci.
Faire cela.  
Lire le clavier
Faire ceci.
..
Avec la programmation évènementielle, c'est plutôt:

Si l'utilisateur tape du texte faire ceci.
Si l'utilisateur clique sur le bouton faire cela.
...
 

XIV-A-8. Programmation Objet

Les objets sont les choses physiques ou abstraits qui nous entourent. Typiquement, dans un programme de fiches de paie, le bulletin de salaire, l'employé, etc. sont des objets.

Un objet est une entité cohérente rassemblant des données et du code travaillant sur ses données.

Un logiciel est alors vu comme des d'objets communiquant par des méthodes.

Une classe peut être considérée comme un moule à partir duquel on peut créer des objets.

" Ne commencez pas par demander ce que fait le système, demandez À QUOI il le fait ! "


XIV-B. Programmation 'fonctionnelle' ou 'objet'?

On a vu qu'on pouvait créer des programmes avec des Sub et des Functions mais aussi avec des objets. Détaillons.


XIV-B-1. L'approche fonctionnelle

Elle découpe le problème en fonctions:

Chaque fonction effectue une tache précise. Avec l'aide de variables et de structures.

La base de la réflexion est effectuée autour des traitements. Le concepteur considère ainsi les tâches que doit accomplir le programme, en décomposant celui-ci en une série de tâches simples (approche descendante) ou en le construisant par composition de traitements (fonctions) disponibles (approche ascendante).


Il y a donc

Exemple:

Calcul du salaire d'un employé. (Nombre d'heure * Taux horaire)

Il faut écrire une Fonction CalculSalaire:

Public Function CalculSalaire(Taux As Single, Heure As Single) As Single
    Return Taux*Heure
End Function

Pour calculer un salaire il faut appeler la fonction avec les bons paramètres.

Dim TauxHoraire As Single
Dim HeuresTravaillées As Single
Dim Salaire As Single
TauxHoraire=30
HeureTravaillées=70
 Salaire=CalculSalaire(TauxHoraire,HeuresTravaillées)

Pour structurer le programme, on utilise des 'Modules Standards' contenant les divers fonctions Un module contient par exemple Function CalculSalaire.

Le point d'entrée du programme est une procédure Main():
 
Module module1
 
Sub main()
....Créer une instance du formulaire de démarrage et l'ouvrir
End Sub
 
 
Public Function CalculSalaire(Taux As Single, Heure As Single) As Single
    Return Taux*Heure
End Function
 
 
End Module

Si on utilise des variables globales visible dans la totalité du programme (c'est à éviter), il faut les mettre dans un module standard et les définir comme Public:

Exemple: Nom du programme et version du programme.


Exemple nom et version du programme:

Module module1
Public nomProgramme As String= "Calcul Salaire"
Public versionProgramme As String= "1.2"
....
 
End Module

Ainsi le nom du programme et sa version sont accessibles partout:

Dans un formulaire on peut afficher le nom du programme dans la barre supérieure.

Me.Text= nomProgramme
Cette accessibilité semble un avantage, en fait c'est dangereux: n'importe quelle procédure peu modifier les données.

Pour structurer les données, on peut utiliser les Structures.

Exemple: créons une structure 'Salarié'

Structure Salarié
Public Nom As String
Public TauxHoraire As Single
Public HeuresTravaillées As Single
End Structure
Ensuite pour avoir 100 salariés

Dim Salaries(100) As Salarié
On pourra utiliser Salaries(1).Nom ou Salaries(2).TauxHoraire

On verra plus loin qu'utiliser des variables dites 'globales'( visible partout) n'est pas une bonne chose, il vaut mieux créer des procédures d'accès aux données.

Plutôt que d'écrire Salaries(1).Nom="Lulu" il est préférable d'écrire une procédure SalariesAdd() qui ajoute un salarié avec son nom dans le tableau.


XIV-B-2. Approche Objet

Elle est centrée sur les Objets (et non sur les taches).

Elle nécessite de créer une Classe (le moule).

Avec l'aide de la classe on peut déclarer des objets.

Chaque Objet à des propriétés, des méthodes.

Exemple:

Calcul du salaire d'un employé. (Nombre d'heure * Taux horaire)

Il faut écrire dans un module de Class une Class Employé:


Public Class Employé
Private T As Single     'propriétés privées à la classe pour stocker les heures et taux horaires
Private H As Single
 
Public Property Taux As Single 'propriété Taux
Get
    Return T
End Get
Set(By Val Value)
    T=value
End Set
End Property
 
Public Property Heure As Single 'propriété heure
Get
    Return H
End Get
Set(By Val Value)
    H=value
End Set
End Property
 
Public Property Salaire As Single 'méthode Salaire
Get
    Return T*H
End Get
End Property
End Class

Pour calculer un salaire il faut créer un objet Employé,donner les bonnes valeurs aux propriétés et appeler la méthode salaire.

Dim UnEmployé As new Employé
UnEmployé.Taux=30
UnEmployé.Heure=70
 Dim Salaire As Single =UnEmployé.Salaire
On voit donc qu'il faut créer des 'Modules de Classe' pour y mettre les nouvelles classes.

On évitera les modules standards qui ne sont pas dans l'esprit 'Objet'.

Le point d'entrée du programme pourrait être une Classe statique (Classe ne nécessitant pas d'instancier un objet):

Public Class main2
Public Shared Sub main()
...
End Sub
End Class
Si on utilise des variables qui doivent être accessibles, il faut les mettre dans une Classe et les définir comme Shared: Ainsi une variable partagée d'une classe (Shared) a non seulement une valeur commune à toutes les instances de la classe, mais en plus on peut travailler directement sur la Classe (sans instancier):

Exemple nom et version du programme:

Class MonProgramme
Public Shared nomProgramme As String= "Calcul Salaire"
Public Shared versionProgramme As String= "1.2"
....
 
End Class

Ainsi le nom du programme et sa version sont accessibles partout:

Dans un formulaire on peut afficher le nom du programme dans la barre supérieure.

Me.Text= MonProgramme.nomProgramme
 
On peut créer une classe qui hérite des propriétés d'une autre classe:

Dans notre exemple en programmation Objet, on créera une Class 'Patron' qui hérite de la classe 'Employé', mais dont la méthode Salaire sera redéfinie ( Overrides ). (En programmation fonctionnelle il faudra écrire une nouvelle fonction SalairePatron).

 
Public Class Patron
Inherit Employé

Public Property  Overrides  Salaire As Single 'méthode Salaire
Get
    Return T*H
End Get
End Property
End Class

Pour gérer un ensemble, un groupe de données, on utilise une classe encapsulant une collection privée d'objets voir chapitre 5-7.

Public Class LesEmployes
     Private maCol As ArrayList

     Public Sub New()
          maCol = New ArrayList()    'cela crée une ArrayList
     End Sub


     Public Function Add(ByVal LEmploy As Employe) As Employe     
      ...
     End Function

     Public Property Item(ByVal lIndex As Integer) As Employe 
     ...     
     End Property

     
End Class

On rappelle que les classes peuvent contenir des méthodes, des variables publiques ou privées, mais elles sont 'PAR REFERENCE'

Les partisans de la programmation Objet auront tendance à utiliser exclusivement les classes du Framework plutôt que les instructions de Microsoft.VisualBasic dans leur code.


XIV-B-3. Conclusion

La programmation fonctionnel se focalise sur les actions à effectuer, alors que la programmation Objet se focalise sur les données.


La méthode fonctionnelle est plus intuitive, on a l'impression d'être plus proche de la réalité 'physique', le code est probablement plus rapide.

L'emploi d'objet permet une abstraction plus importante, une puissance inégalée grâce à l'héritable, aux surcharges.


On peut être puriste et ne programmer qu'en fonctionnelle ou ne programmer qu'en objet.

Visual Basic permet de mélanger les 2 approches.


XIV-C. Programmation 'fonctionnelle': faire de bonnes procédures.

Quand on fait de la programmation fonctionnelle: on n'utilise pas de classe mais des modules standards, des Sub et des Functions.

Suivant quelles règles découper son programme?

Si on programme depuis longtemps, on le sait de manière 'intuitive' (après de nombreuses erreurs); il est tout de même intéressant de connaître les grandes règles à suivre. Très peu de sites ou d'ouvrages en parlent!!

Analyse ascendante, descendante?

Pourquoi découper en procédures?

La cohésion doit elle être importante?

Le couplage doit-il être modéré?

Comment utiliser les paramètres?

Sub ou Function?

Programmation défensive?


XIV-C-1. Approche fonctionnelle, analyse 'descendante' ou 'ascendante'

L'approche fonctionnelle découpe le problème en fonctions (ou procédures):

L'analyse se fait de manière descendante: on découpe un problème complexe en problèmes plus simple qui sont eux mêmes découpés en problèmes plus simples. On découpe jusqu'à ne plus avoir que des problèmes simples.

Il existe aussi l'analyse ascendante: ayant à sa disposition des procédures simples, on les assemble en les faisant appeler par des procédures plus complexes pour atteindre la solution.

Si le projet est entièrement nouveau, on fait plutôt une analyse descendante; si on travaille sur un projet possédant déjà toutes les procédures simples, on raisonnera en analyse ascendante.

Rien d'empêche d'avoir une analyse mixte.


On rappelle:

Chaque procédure effectue une tache précise.

Les procédures sont composées des ' Sub ' et des ' Function '.

Une procédure est un ensemble d'instructions, de lignes de code , un groupement d'instructions bien définies effectuant une tache précise.

Les procédures 'Sub':

Elles débutent par le mot Sub et se terminent par End Sub.

Exemple:

Sub MaProcédure()
   A=1
End Sub
Pour appeler la Sub:

MaProcedure()
Les procédures 'Function':

Les 'Function' retournent une valeur.

Elles débutent par Function et se terminent par End Function.

Exemple:

Function SurfaceCercle( Rayon as Single)
    Return 3.14*Rayon*Rayon        'Return indique ce que la fonction doit retourner 
End Function
Dans la procédure qui appelle, il faut une variable pour récupérer la valeur retourner par la Fonction:

S= SurfaceCercle()
infoOn rappelle que le nom de la procédure doit être en minuscule avec la première lettre de chaque mot en majuscule.
SurfaceCercle() est correct.

XIV-C-2. Pourquoi utiliser des procédures?

D'abord , dans certains cas, c'est obligatoire!! Il y a les procédures évènements automatiquement crées par VB. Ensuite, dès que l'on veut écrire du code, il faut créer des procédures Sub ou Function dans les modules de formulaire ou dans les modules standard (voir 5-10)

La programmation fonctionnelle avec découpage en procédures a des avantages:
  • On évite la répétition du même code:
    Si il faut 30 lignes de code pour faire un calcul et que le calcul est effectué 10 fois dans le programme, il est pratique de créer une Sub CalculTotal() contenant les 30 lignes de calcul et d'appeler 10 fois la Sub.

    Voici la Sub:
    
    Public Sub CalculTotal()
    A=B+C
    D=E+3
    ..
    End Sub 
    

    Voici les appels:
    
    CalculTotal()
    ..
    CalculTotal()
    

  • On simplifie les modifications:
    S'il y a une modification à faire dans le calcul, la modification est effectuée 1 fois (Avec 10 fois le code du calcul disséminé dans le programme, on risque d'oublier de modifier un des codes).


  • On introduit une abstraction qui clarifie le code:
    CalculTotal() est plus compréhensible que A=B+C....

    On oublie le code interne à la procédure, pour ne plus se souvenir que de la fonction de la procédure: La procédure fait le Calcul du total..

    On masque ainsi l'implémentation.


  • On réduit la complexité:
    Chaque tache complexe est décomposée en plusieurs procédures qui elles-mêmes sont décomposées en procédures plus simples.


  • On améliore la portabilité:
    On isole dans les procédures le code non portable et on le groupe.

    Si on doit effectuer un changement (changement de type de base de données par exemple en modifiant un programme pour qu'il fonctionne sous MySQL alors qu'il fonctionnait sous Acces), il suffit de modifier uniquement les procédures d'accès à la base de données.


  • On peut masquer certains fonctions:
    Certaines fonctions sont complexes et leur code est peu intéressante, une fois écrite il faut mieux ne plus les voir. (fonction booléens complexes)


XIV-C-3. La 'cohésion' de la procédure doit être importante

info La 'cohésion' fait référence aux liens établis entre les opérations de la procédure DANS la procédure.
Un exemple:

La Sub Carré() à une forte cohésion: elle est entièrement consacrée à une tache: le calcul du carré d'un nombre.

La Sub CarréEtCube() qui calcul le carré ou le cube d'un nombre a une cohérence faible!! (Il vaut mieux dans ce cas écrire une procédure Carré() et une procédure Cube() )

Compris?

Si la cohésion est faible , il a été prouvé que les procédures contenaient plus d'erreurs de programmation.

warningDonc une procédure ne doit faire qu'une seule chose.
  • On parle ici de cohésion fonctionnelle: la fonction de la procédure est unique.
    EffaceFichier(), CalculAge() ont une bonne cohésion fonctionnelle, SaisirDate&CalculAge() a une moins bonne cohésion.

Il existe d'autres sortes de cohésion:
  • La cohésion temporelle:
    Différentes opérations qui n'ont rien a voir entre elles doivent être effectuées au même moment:

    Exemple: La Sub Demarrage() appelée au début d'un programme va ouvrir les fichiers, initialiser les variables, lire le fichier de configuration.


  • La cohésion séquentielle:
    Lorsque les opérations qui n'ont rien à voir entre elles doivent impérativement être effectuées dans un ordre précis:

    Exemple: La Sub CalculAnnéeRetraite() qui a partir de la date de naissance va calculer l'age puis l'année de retraite. (On pourrait aussi dans ce cas écrire une routine CalculAge() qui serait appelée par CalculAnnéeRetraite() )


Certaines cohésion sont à éviter:
  • La cohésion de communication:
    Les opérations travaillent sur les mêmes données mais n'ont pas de relation.

    ImprimeAndEffaceTableau() me parait à éviter: écrire les procédures ImprimeTableau() et EffaceTableau()


D'autres sont à bannir:
  • La cohésion logique:
    La sélection des opérations (sans relation entre elles) à effectuer est pilotée par un paramètre.

    Seul le paramètre est commun!!

    La Sub ImprimerTableauAfficherResultat (Flag) ou le Flag indique s'il faut imprimer ou afficher est à bannir.


XIV-C-4. Le 'couplage' entre procédures doit être modéré

info Le couplage traite des connexions entre les différentes procédures, il doit être modéré, ce qui signifie qu'il doit y avoir peu de connexions.
  • Une procédure doit ne communiquer qu'avec un nombre " minimum " d'autres procédures du logiciel. L'objectif est de minimiser le d'interconnexions entre les procédures. L'intérêt de cette règle est de garantir un meilleur respect de la protection des procédures.

  • Lorsque deux procédures communiquent entre elles, l'échange d'information doit être minimal. Il s'agit de minimiser la taille des interconnexions entre modules.
    Eviter le tout 'variables globales'.
    Une Sub ayant 2 paramètres c'est bien, une Sub en ayant 15 c'est trop.


  • Lorsque deux procédures communiquent, l'échange d'information doit être explicite:
    Eviter qu'une variable soit visible dans une procédure, alors qu'elle est déclarée dans une autre.
    Si vous modifié des variables globales utilisées par un autre module c'est dangereux!!
    Si vous utilisez un paramètre pour passer une données, c'est explicite, c'est Ok.


  • Toute information dans une procédure doit être répartie en deux catégories : l'information privée et l'information publique. Ce principe permet de modifier la partie privée sans que les clients () soient confrontés à un quelconque problème à cause de modifications ou de changements.
    Plus la partie publique est petite, mieux c'est..
    On déclarera en début de procédure des variables privées, et on travaillera sur ses variables privées; seul le résultat sera accessible de l'extérieur.


Une procédure doit donc être autonome:

warningUne procédure est autonome et ne doit pas lire ni modifier directement les variables du programme qui l'appelle, sans passer par des paramètres.

XIV-C-5. Squelette d'un programme

Exemple simpliste de l'agencement des procédures:

De manière générale, le programme est composé de procédure, en appelant d'autres, qui en appelle d'autres..

'Squelette' de programme:
 
Sub Démarrage
    OuvrirFichier()
    LireConfig()
    InitialiserVariable()
    LireDonnées()
End Sub
 
Sub Quitter
        EnregistrerDonnée()
        FermerFichier()
End Sub

Voici la Sub Main(), procédure de démarrage du programme :

Sub Main()
    Démarrage()
    'puis affiche le formulaire principal
End Sub
 

Dans le formulaire principal, un bouton 'Quitter' déclenche la Sub suivante:

Sub BoutonQuitter_Click(..)
    Quitter()
End Sub
 

Un bouton 'Nouveau' (travail sur de nouvelle données) contient:

Sub Nouveau_Click(..)
       EnregistrerDonnée()
       InitialiserVariable()
End Sub
 

On remarque que EnregistrerDonnée() et InitialiserVariable() sont appelés de plusieurs endroits.


Ensuite il suffit d'écrire tous le code des Sub.


XIV-C-6. Les paramètres

Dans quel ordre les mettre?

Un Sub reçoit 3 paramètres: P1 qui est une donnée qu'utilise la Sub, P2 qui est modifié par la Sub , P3 qui contient un résultat retourné par la Sub.

Et bien il est conseillé de les mettre dans l'ordre P1, P2, P3 (Entrée, Modification, Sortie)

Exemple Sub CalculCarré(nombre, carré) 'quand on appelle cette Sub on envoie un nombre, on récupère le carré.


S'il y a une variable d'erreur ou d'état, la mettre en fin.

        Sub Divise(Nombre1, Nombre2, CalculImpossible) 
'cette routine calcule Nombre1/Nombre2 mais retourne CalculImpossible=True si Nombre2 est égal à zéro.


Nombre de paramètres?

7 maximum, au delà de 7 on s'y perd!!

Dans les 7, il peut y avoir des tableaux.


Paramètres pour plusieurs routines:

Si plusieurs routines utilisent les mêmes paramètres, les mettre dans le même ordre.


AfficheText(LeTexte, Couleur) et ImprimeText(LeTexte, couleur) sont cohérent.


Ne pas utiliser de paramètre comme variable de travail.

Sub calcul (A, B)
A=A+2                    Est à éviter: le paramètre A ne contient plus la valeur d'entrée!!
...                      car on a utiliser A comme variable de travail.
End Sub
 

Faire plutôt:

Sub calcul (A, B)
Dim V As Integer= A      'On passe la valeur du paramètre dans une variable locale.
V=V+2                    'C'est mieux! A contient toujours la valeur d'entrée.
...
End Sub
 

Il faut donc déclarer en début de Sub des variables locales propres à la Sub et travailler avec elles dans la Sub.


Mettre des commentaires en début de sub:

Sub Divise(Nombre1, Nombre2,Resultat, CalculImpossible)
'***Division de 2 Nombres
'Entrée: Nombre1, Nombre2 de type Single
'Sortie: Résultat de type Single
'Teste Nombre2 si =0 retourne CalculImpossible=True
If Nombre2= 0 then
    CalculImpossible=True: Exit Sub
End If
Resultat=Nombre1/Nombre2
End Sub
 

Tester la validité des paramètres en début de Sub:

Voir l'exemple précédent

If Nombre2= 0 then    'teste le paramètre Nombre2 et quitte la Sub s'il n'est pas valide. 
C'est mieux de le faire au début pour tous les paramètres plutôt que de le faire dans toute la procédure.


XIV-C-7. Utiliser une 'Sub' ou une 'Function'?

Les puristes diront qu'il faut utiliser une fonction quand on a une valeur de sortie (une seule).

Plusieurs paramètres d'entrée sont possible par contre.

Exemple:

La fonction FileExist(), avec comme entrée le nom d'un fichier, retourne uniquement un Booléen (True ou False), c'est bien une fonction qu'il fallait utiliser.

On peut élargir la définition en employant une fonction quand l'objectif principal est de retourner la valeur indiquée dans le nom de la fonction:


MetAuFormat( In, Out) transforme le texte 'In' en 'Out'; si la fonction à échoué elle retourne False.


On l'utilisera comme cela:

If MetAuFormat(In, Out) = True Then  LeText.Text=Out

On aurait pu utiliser une Sub, avec comme troisième paramètre une variable indiquant le succès ou l'échec.


MetAuFormat( In, Out, Succes)

Certains utilisent des noms de variable commençant par Is afin d'indiquer clairement que c'est une fonction et ce qu'elle retourne:

IsOpen() pour voir si un fichier est ouvert (retourne True si le fichier est ouvert). ce qui permet d'utiliser:

If IsOpen("monfichier") Then...
 

XIV-C-8. Programmation défensive

C'est comme quand on conduit une voiture; il faut se méfier des autres: bien regarder aux croisements et ralentir, même si on a la priorité!!

Il faut donc:

Tester la validité des paramètres en début de Sub:

On l'a déjà vu:

If nombre2= 0 then 'teste le paramètre Nombre2 et quitte la Sub s'il n'est pas valide ce qui évite une division par zéro si l'expression nombre1/nombre2 est utilisée.

C'est mieux de le faire au début pour tous les paramètres plutôt que de le faire dans toute la procédure.

Il faut le faire surtout si les données viennent de l'"extérieur": fichier, réseau.

Il faut encore plus le faire si c'est l'utilisateur qui a saisi les données.

Vérifier si la données est dans la plage attendue:

Si on attend le numéro d'un jour du mois, vérifier que c'est un nombre, s'il est positif, compris entre 1 et 31, entier..

Vérifier si la données est une String valide:

Si on attend un nom de fichier, vérifier que c'est du texte, éliminer les espaces en début et fin, y a t-il une extension? des caractères invalides?

En VB il y a des fonctions qui font cela.


Tester la validité des paramètres de sortie:


Prendre en charge les erreurs:

Il y a des procédures 'tolérantes':

  • Si une valeur n'est pas valide, on peut donner une valeur par défaut, redonner la précédente valeur..
  • C'est le cas des prises de température à une fréquence importante. S'il manque une valeur; reprendre la précédente.
Il y a des procédures 'strictes', cela entraîne une des actions suivantes:

  • L'arrêt du programme!!
  • La procédure redemande la valeur.
  • Elle retourne une variable indiquant qu'elle a échoué

Pendant le développement utiliser les assertions

C'est une manière de se contrôler soi-même en cours de développement.

On place des assertions dans le code:

Si elles sont vraie c'est que cela se passe comme prévu.

Si elles sont fausses c'est qu'une erreur inattendue, inacceptable se produit.

Debug.Assert affiche une fenêtre Windows et stoppe le programme si une assertion(une condition) passe à False.

Debub.Assert(Assertion)
Debub.Assert(Assertion, Message1)
Debub.Assert(Assertion, Message1, Message2) 
L'exemple suivant vérifie si le paramètre 'type' est valide. Si le type passé est une référence null (Nothing dans Visual Basic), Assert ouvre une boite de dialogue nommé 'Echec Assertion' avec 3 boutons 'Abandonner, Recommencer' 'Ignorer'.. La liste des appels est affichée dans la fenêtre (procédure en cours en tête de liste, module et numéro de ligne en première ligne)

Public Shared Sub UneMethode (type As Type, Typedeux As Type)
Debug.Assert( Not (type Is Nothing), "Le paramètre Type est=Nothing ", "Je ne peux pas utiliser un Nothing")
....
End Sub UneMethode
Il n'est pas souhaitable que l'utilisateur puisse voir les messages des assertions, elles disparaissent dans le code de production.

En résumé: Une procédure doit avoir:

  • de la modularité: un sous-programme réalise une tâche et une seule (par exemple, une fonction de calcul ne doit pas afficher de résultat) ;
  • de l'autonomie: un sous-programme est autonome et ne doit pas lire ni modifier directement les variables du programme qui l'appelle, sans passer par des paramètres ;
  • de la transparence: un sous-programme doit être conçu de façon à ce que le programmeur qui y fait appel (non nécessairement son concepteur) n'ait pas à tenir compte des choix du concepteur ;
  • de la convivialité: l'appel du sous-programme doit être la plus évidente possible.

XIV-D. Programmation 'objet': faire de bonnes Classes

warning Ce chapitre tente de clarifier mes connaissances, ne pas hésiter à critiquer et me donner des conseils.
Quand on programme avec une approche Objet, on crée des classes, on n'utilise par de modules standard ni de Sub et de Fonction.

Quelles règles suivre pour créer des objets?

Si on programme depuis longtemps, on le sait de manière 'intuitive' (après de nombreuses erreurs); il est tout de même intéressant de connaître les grandes règles à suivre. Très peu de sites ou d'ouvrages en parlent!!

Comment faire de bonnes Classes?

Comment bien utiliser l'héritage?


XIV-D-1. Rappel:

On rappelle: Une Classe sert à créer (instancier) des objets.

En programmation Objet, dans un module de Classe, on crée la Classe:

Classe MyClasse
..
End Class
 

puis dans le corps du programme, on crée un objet:

Dim MonObjet As New MyClasse.

XIV-D-2. Pourquoi utiliser 'Classe' et 'Objet'?

Ils permettent:

Modélisation des objets réels.

Le programme travaille avec des objet réels: une facture, un client.

Créer une classe par objet puis:

  • Y mettre les données liées à l'objet (le nom, l'adresse du client)
  • Y ajouter les méthodes contenant le comportement de l'objet (Calcul de la facture)

Modélisation des objets abstraits.

Dans un programme de comptabilité, les classes 'technicien' , 'ouvrier', dirigeant' sont concrètes; une classe 'Salarié' est plus abstraite. Les 3 premières pourront hériter de cette dernière.

Autre exemple classique: Les classes Line, Triangle sont concrètes, la classe Shape (forme en français) est abstraite, ici aussi Line et Triangle hériterons de Shape

Il existe même des Classes abstraites: Un Classe abstraite est une Classe qu'on ne peut pas instancer, elle sert uniquement à définir des caractéristiques de base pour créer des classes qui seront dérivées de la Classe abstraite.


Facilité pour réutiliser le code.

Une fois crées, les Classes servent de briques pour construire un nouveau projet.

L'héritage permet la création de nouvelle Classe héritant d'une autre.

Réduction et isolement de la complexité.

Une tache complexe est découpée en plusieurs Classes.

Masquage de l'implémentation

Un fois la Classe créée, il faut oublier les détails et l'utiliser sans connaître son fonctionnement interne.


C'est l'encapsulation.

Masquage des données globales.

Si vous devez absolument utiliser des données globales vous les masquez derrière une interface de classe.


XIV-D-3. Identifier les objets

Identifier les Objets pour définir ensuite les classes:
  1. On identifiera les objets nécessaire et leurs attributs (méthodes, données)
    Exemple:

    Système de facturation:

    Objet:Client Objet:Facture Objet: FicheHoraire
    NomClient
    Adresse
    Date
    NomClient
    Montant
    Date
    NonClient
    NombreDheure
    TauxHoraire
      CalculerFacture()
    ImprimerFacture()
     

  2. Déterminer ce que l'on peut faire avec chaque objet:
    Exemple:

    Modifier l'adresse du Client.


  3. Déterminer ce que chaque objet peut faire aux autres objets
    Une facture peut contenir plusieurs fiches horaires.

    Un Objet peut en hériter d'un autre.


  4. Déterminer les parties visible (l'interface publique)

  5. En conclusion, pour chaque objet il faut définir:
    1. Définir l'interface utilisateur :
      • Identifier les requêtes (information demandée à la classe); Ce sont les Property
      • Identifier les commandes (procédures): Ce sont les méthodes. Sub ou Function
      • Identifier les contraintes (pré-, post-condition).
    2. Définir les constructeurs. Sub New()
    3. Choisir une représentation de l'information (attributs).
    4. Implanter les fonctions, procédures et opérateurs.
    5. Définir (si nécessaire) le constructeur de copie, le destructeur

XIV-D-4. Faire un 'couplage' modéré

info Le couplage traite des connexions entre les différentes Classes, il doit être modéré, ce qui signifie qu'il doit y avoir peu de connexions.
  • Une Classe doit ne communiquer qu'avec un nombre " minimum " d'autres Classes du logiciel. L'objectif est de minimiser le nombre d'interconnexions entre les Classes. L'intérêt de cette règle est de garantir un meilleur respect de la protection des Classes.
  • Lorsque deux Classes communiquent entre elles, l'échange d'information doit être minimal. Il s'agit de minimiser la taille des interconnexions entre Classes.
    Un classe qui possède 4 méthodes Public c'est mieux qu'une Classe qui en possède 15.

    Il faut donc réduire l'accessibilité des classes et des membres.

  • Lorsque deux Classes communiquent, l'échange d'information doit être explicite:
  • Toute information dans une Classe doit être répartie en deux catégories : l'information privée et l'information publique. Ce principe permet de modifier la partie privée sans que les clients (fonctions utilisant cette classe) soient confrontés à un quelconque problème à cause de modifications ou de changements. Plus la partie publique est petite, mieux c'est...

XIV-D-5. Conserver une bonne abstraction et une bonne cohérence

Une classe qui:

  • met en forme les données.
  • qui initialise le programme.
  • qui imprime un rapport.
n'est pas cohérente.


Une classe qui:

  • Initialise une donnée
  • Charge une donnée
  • Sauve une donnée
est cohérente.


De plus l'abstraction est constante: elle se situe au même niveau (celui d'une donnée); si on rajoutait dans la classe une fonction effectuant une recherche dans une liste de données cela ne serait plus le cas.


XIV-D-6. Créer des méthodes par paires

Une méthode doit entraîner l'écriture de la méthode contraire.

Activation/désactivation.

Ajout/Suppression...

Si il existe la méthode 'AddLine' , on aura forcement besoin de 'RemoveLine'.


XIV-D-7. L'encapsulation doit être bonne

L'encapsulation est une barrière qui empêche l'utilisateur de voir l'implémentation..


Il ne faut pas exposer les données:

Eviter les variables Public, directement accessible par l'utilisateur de la Classe.

Class MaClasse
Public X As Single
..
End Class
C'est pas génial!!


Class MaClasse
Private mX As Single
Public Property X() as Single
Get
    Return mX
End Get
Set(By Val Value)
    mX=value
End Set
End Property
..
End Class
C'est mieux , l'utilisateur n'a pas accès directement à 'mX', l'utilisateur voit 'X', il peut modifier X ce qui entraîne une modification de mX mais sous contrôle, on peut même rajouter des conditions qui seront testées avant de modifier mX.


XIV-D-8. Initialisez les données dans le constructeur d'une Classe.

Il est important de ne pas oublier d'initialiser les variables dans une classe, le moment idéal est quand on crée une instance de cette Classe.

Class MaClasse
Private mX As Integer
 
Sub New()
    mX=2
End sub
End Class 
 

XIV-D-9. Problèmes liés à l'héritage.

Ne pas multiplier les classes dérivées:

Si on a une Classe 'Animal', on peut créer les classes 'Cheval' et 'Poisson' qui dérivent de la Classe 'Animal'.

Par contre il ne faut pas créer les classes 'PoissonRouge' ou 'ChevalNoir' car la couleur est plus un attribut d'une classe qu'un déterminant de Classe.


Eviter trop de classe intermédiaire:

Si 'Cheval' dérive de 'Mammifèreà4Pattes' qui dérive de 'Mammifère' qui dérive d'Animal', c'est lourd!! surtout si 'Mammifèreà4Pattes' et 'Mammifère' sont des classes abstraites qui ne seront pas instanciées.


Eviter l'héritage de construction:

Eviter de dériver une Classe en ajoutant des attributs qui modifie le concept de la classe mère.

Une classe 'Triangle' peut dériver de 'Polygone', la classe 'Carré' peut difficilement dériver de 'Triangle' (En y ajoutant les attributs d'un quatrième point!!)

Un Carré est un Polygone,oui. On ne peut pas dire qu'un Carré est un Triangle avec un sommet de plus!!


Bien comprendre la différence entre héritage et agrégation:

Comme on l'a vu dessus, quand une classe dérive d'une autre, on peut dire que la classe dérivée 'est une' classe mère.

'Carré' est un 'Polygone'

Par contre 'Carré' est composé de 4 'Point' (possède 4 points): un objet 'Carré' contient 4 objets 'Point'. On parle d'agrégation (ou de composition pour certains).


XIV-E. Faire du bon 'code ' bonnes variables.


XIV-E-1. Usage des variables


XIV-E-1-a. Utilisez OptionStrict=On et Option Explicit= On

Travailler avec

Option Strict=On
Vous serez obligé de faire du 'cast' à longueur de temps (conversion d'une variable d'un type vers un autre), mais au moins le code sera rigoureux.

Les conversions seront évidentes, explicites:

Dim I As Integer
Dim J As Long
J= Ctype(I, Long)

et avec

Option Explicit=On
Vous serez obligé de déclarer les variables avant de les utiliser. C'est indispensable.

Voir chapitre 1-7 pour le détail.


XIV-E-1-b. Donner à chaque variable un seul rôle

A l'époque ou il y avait très peu de mémoire, un octet était un octet, aussi on utilisait parfois une même variable pour différentes choses:

Dim total As Integer
total= nbArticle*3
Affiche (total)
total= nbFacture*2
Affiche (total)
Ici total contient le total des articles puis le total des factures!!


Il vaut mieux créer 2 variables et écrire:

Dim totalArticle As Integer
totalArticle= nbArticle*3
Affiche (totalArticle)
Dim totalFacture As Integer
totalFacture= nbFacture*2
Affiche (totalFacture)

Dans le même ordre d'idée, éviter les variables nommées 'temp'(temporaire) qui serviront à plusieurs reprises pour des résultats temporaires successifs.


XIV-E-1-c. Eviter les variables avec des significations non évidentes

Eviter les significations cachées.

Exemple à ne pas faire:

  • nbFichier contient le nombre de fichier sauf s'il prend la valeur -1 , dans ce cas cela indique qu'il y a eu une erreur de lecture!!

  • clientId contient le numéro du client sauf s'il est supérieur à 100000 dans ce cas soustraire 10000 cela donne le numéro de la facture.

Dans le premier exemple, la solution est d'utiliser en plus de nbFichier une variable isReadOk indiquant si la lecture s'est bien déroulée.


XIV-E-1-d. Initialisez les variables dés leur déclaration.

Cela évite de l'oublier. Les erreurs d'initialisation sont très fréquentes.

Dim Taux As Integer= 12

Un truc: si vous initialisez ou réinitialisez une variable avec NoThing, elle prend la valeur obtenu après déclaration pour ce type. Pour une structure, c'est valable pour chaque variable.

Exemple:

Soit une structure Adresse

Public Structure Adresse
Dim Numero As Integer
Dim Id As Integer
Dim Rue As String
Dim Ville As String
End Structure

Je déclare une variable Adresse

Dim MonAdresse As Adresse
J'initialise:

MonAdresse.Numero = 12
MonAdresse.Id= 15
MonAdresse.Ville = "lyon"

Maintenant si je fais:

MonAdresse = Nothing

Cela entraîne:

MonAdresse.Numero = 0
MonAdresse.Id= 0
MonAdresse.Ville = Nothing

XIV-E-1-e. Utilisez le principe de proximité

Déclarer, initialiser une variable le plus prêt possible de sa première utilisation, puis grouper les instructions dans lesquelles la variable est utilisée:


Mauvais exemple: (chaque variable est repérée par une couleur)

Dim Prixtotal As Integer
Dim Taux As Integer
Dim Prix As Integer
Dim Quantité As Integer
Dim  Ristourne As Integer
Taux=12
Ristourne=0
Prix=0
Prixtotal= Quantité*Prix
Ristourne=Taux*Quantité

Prixtotal n'est pas initialisé, on utilise les variables loin de leur déclaration...

Code dur à lire, source d'erreur.


Bonne manière de faire:

Dim Taux As Integer=12
Dim Prix As Integer=0
Dim Quantité As Integer=2
 
Dim Prixtotal As Integer=0
Prixtotal= Quantité*Prix
 
Dim  Ristourne As Integer=0
Ristourne=Taux*Quantité

XIV-E-1-f. Travaillez sur des variables qui restent actives le moins de temps possible.

Les instructions utilisant une même variables doivent être si possible regroupées.

Exemple : la variable Acte est utilisée dans les lignes rouges:


Mauvaise méthode: il y a plusieurs lignes entre 2 lignes contenant la même variable, le cheminement est difficile à suivre!!


Dim Acte As Integer
Dim Bib As Integer
Dim C As Integer
C=2
Call Calcul()
Call Affiche()
Acte=Acte+1
Call CalculTaux()
Call AfficheResultat (Acte)
Bonne méthode: le cheminement est clair, les lignes utilisant la variable Acte sont regroupées,la lecture est facile est facile à suivre.

Dim Acte As Integer
Acte=Acte+1
Call AfficheResultat (Acte)
Dim Bib As Integer
Dim C As Integer
C=2
Call Calcul()
Call Affiche()
Call CalculTaux()

XIV-E-1-g. Si vous codez la valeur d'une variable en 'dur' utiliser plutôt des constantes

Une valeur codé en dur est une valeur imposée par le programmeur et écrite sous forme d'un littéral:

I=123  'c'est codé en dur!! Que représente 123?
Ecrire:
Const nbMaxLignes As Integer= 123
I=nbMaxLignes 'c'est plus significant

Autre exemple:

Plutôt que:


For i= 0 To 120
Next i

Ecrire:


Const  MAXELEMENT As Integer =120
 
For i= 0 To MAXELEMENT
Next i
Cela a tous les avantages: Quand on regarde le code, MAXELEMENT est plus explicite que 120.

De plus si on change la valeur de MAXELEMENT , la modification est prise en compte partout dans le code et les boucles fonctionnent toutes bien.


On peut utiliser des '0' (pour démarrer les boucle: For i= 0 to..) ou des '1' pour incrémenter des compteurs (i=i+1) mais on évitera les autres littéraux.


Usez aussi des énumérations.


XIV-E-1-h. Groupez les instructions liées

Regroupez les instructions faisant référence aux mêmes choses:


Mauvaise méthode: c'est un peu fouillis

CalculNewTotal()
CalculOldTotal()
AfficheNewTotal()
AfficheOldTotal()
ImprimeNewTotal()
ImprimeOldTotal()

Bonne méthode:


CalculNewTotal()
AfficheNewTotal()
ImprimeNewTotal()
 
CalculOldTotal()
AfficheOldTotal()
ImprimeOldTotal()

XIV-E-1-i. Réduisez la portée des variables (problème des variables globales)

Une variable 'globales' est une variable visible dans la totalité du programme.

Exemple: créons une variable globale nommé Index


Module MonModule
Public Index As Integer
..
End Module

A l'inverse une variable 'locale' est visible uniquement dans une procédure ou une Classe:

Class Form1
Private Dim Index As Integer
..
End Class

Avantages et inconvénients des 2 manières de faire:


Utilisation de variables globales:

Exemple:

Public maVariable As Integer
 
Sub Mescalculs()
.. maVariable=12
End Sub
Toutes les procédures ont accès à la variable globale.

Les variables globales sont commodes, d'accès facile, il n'y a peu de paramètres à passer quand on appelle une fonction. Mais on prend des risques: n'importe quelle procédure peut modifier la variable globale.


Utilisation de variables locales:

La variable a une portée limitée, pour qu'une procédure l'utilise, il faut lui fournir en paramètre:

Exemple:


Sub Main()
 Dim maVariable As Integer
 Call MesCalculs(maVariable)
End Sub
 
Sub Mescalculs(V As Integer)
.. V=12
End Sub
La variable locale aide à la maniabilité, vous restez maître de ce à quoi chaque procédure a accès.

Chaque procédure est autonome. Cela conserve donc une bonne modularité et un bon masquage des informations.


Autre danger des variables globales que l'on utilise comme paramètre:

Si on a des variables globales et en plus on utilise ces variables comme paramètres d'une procédure, la même variable peut être modifiée en utilisant 2 noms différents:


Public maVariable As Integer
Call Mescalculs (maVariable)
 
Sub Mescalculs(By Ref v As Integer)
.. maVariable=12            'maVariable et v sont la même variable c'est dangereux!!
.. v=15
End Sub

Utiliser le maximum de variables locales.

(Il sera toujours possible et plus facile d'augmenter la portée si nécessaire, plutôt que la diminuer)

Eviter donc les variables globales qui sont visibles dans la totalité du programme.


Procédures d'accès aux variables:

Si vous tenez quand même à utiliser des variables globales utilisez des 'procédures d'accès à ces variables'.

Le programme n'ira pas modifier directement la valeur de la variable globale mais passera par une Sub ou une Classe qui ira modifier la variable.


Exemple avec un Sub:

Public maVariable As Integer
Au lieu d'écrire maVariable=12 ce qui modifie directement l'accès à la variable globale, créer une Sub modifiant cette variable:

Sub SetVariable ( Valeur As Integer)
    maVariable=Valeur
End Sub
Cela a l'avantage de pouvoir ajouter un contrôle des données, on peut ajouter par exemple des conditions, interdire des valeurs..


Pour modifier la variable globale on écrira SetVariable(12)


De manière plus générale plutôt que de créer un tableau de variables globales du genre:

Public Variables(100) As Variable
et d'écrire Variables(50)=485


créer une procédure SetVariable() une procédure LetVariable() une procédure VariableCount()..


En programmation objet, on crée une classe contenant les données (tableau, collection) mais 'Privé', on crée aussi des membres de cette classe qui permettent de lire (les accesseurs)ou de modifier(les mutateurs) les données.


XIV-F. Règles de bonne programmation.

Pour faire un code solide, éviter les bugs, avoir une maintenance facile, il faut suivre quelques règles.

Relire les chapitres :

5-11 pour faire de bonnes procédures.

5-12 pour faire de bonnes Classes

5-13 pour faire du bon code: bonnes variables

5-210 pour faire de bons commentaires et rendre le code lisible

Voici un résumé des points forts.


XIV-F-1. Séparer l'interface utilisateur et l'applicatif.

Exemple: un formulaire affiche les enregistrements d'une base de données:

Créer:

  • Les fenêtres dont le code gère uniquement l'affichage. C'est l'interface utilisateur ou IHM (Interface Homme Machine)
  • une Classe gérant uniquement l'accès au base de données.
Cela facilite la maintenance: si on désire modifier l'interface, on touche au fenêtre et pas du tout à la Classe base de données.

Architecture à 3 niveaux.

Elle peut être nécessaire dans certains programmes, les 3 niveaux sont:

  • Application ,interface.
  • Logique.
  • Données.
Exemple: Un formulaire affiche certains enregistrements d'une base de données.

  • L'interface affiche les enregistrements.
  • Les classes ou modules 'logiques' déterminent les bons enregistrements.
  • Les classes ou modules données vont chercher les données dans la base de données.
Si au lieu de travailler sur une base Access, je travaille sur une base SQLServer, il suffit de réécrire la troisième couche.

Utiliser des design pattern: ce sont des 'patrons', des modèles en programmation objet.


XIV-F-2. Utiliser le typage fort.

Cela consiste à spécifier le type de données pour toute variable, en plus il faut utiliser des variables le plus typées possible.


Éviter le type 'Object'.


Le code en sera plus rapide, le compilateur interceptera des erreurs (cela évitera des erreurs à la compilation).


XIV-F-3. Forcer la déclaration des variables et les conversions explicites

Option Explicit étant par défaut à On, toute variable utilisée doit être déclarée. Conserver cette option. Cela évite les erreurs liées aux variables mal orthographiées.


Si Option Strict est sur On, seules les conversions de type effectuées explicitement sur les variables seront autorisées. Le mettre sur On.




XIV-F-4. Utiliser des constantes ou des énumérations

L'usage de constantes facilite les modifications.


Exemple : un programme gère des utilisateurs;:

Faire:


Créer une constante contenant le nombre maximum d'utilisateurs.

Const NombreUtilisateur= 20
Dim VariableUtilisateur (NombreUtilisateur)  'on utilise NombreUtilisateur et non 20
For i=  0 To NombreUtilisateur-1
Next i

Plutôt que:

Dim VariableUtilisateur (20)
For i=  0 To 19
Next i
Si ultérieurement on veut augmenter le nombre d'utilisateurs possibles à 50, il suffit de changer une seule ligne:

Const NombreUtilisateur= 50
Utiliser les constantes VB, c'est plus lisible:

Form1.BorderStyle=2 est à éviter

Form1.BorderStyle= vbSizable   c'est mieux

XIV-F-5. Vérifier la validité des données que reçoit une Sub une Function ou une Classe

Vous pouvez être optimiste et ne pas tester les paramètres reçus par votre Sub. Les paramètres envoyés seront toujours probablement bons!! Bof un jour vous ferez une erreur, ou un autre n'aura pas compris le type de paramètre à envoyer et cela plantera!!


Donc, il faut vérifier la validité des paramètres.


On peut le faire au fur et à mesure de leur utilisation dans le code, il est préférable de faire toutes les vérifications en début de Sub.


Vérifier aussi ce que retourne la procédure.


XIV-F-6. Se méfier du passage de paramètres 'par valeur' ou par 'référence'

Par défaut les paramètres sont envoyés 'par valeur' vers une procédure. Aussi, si la variable contenant le paramètre est modifiée, cela ne modifie pas la valeur de la variable de la procédure appelante.

Si on a peur de se tromper utilisons 'ByVal' et 'ByRef' dans l'en-tête de la Sub ou de la Fonction.


XIV-F-7. Les Booléens sont des Booléens

Utiliser une variable Integer pour stocker un Flag dont la valeur ne peut être que 'vrai' ou 'faux' et donner la valeur 0 ou -1 est à proscrire.

Faire:

Dim Flag As Boolean
Flag=True
(Utiliser uniquement True et False)

Eviter aussi d'abréger à la mode Booléens ce qui n'en est pas.

Dim x,y As Integer
If x And y then  (pour tester si x et y sont = 0)  est à éviter.
Faire plutôt:

If x<>0 And y <>0

XIV-F-8. Utiliser les variables Date pour stocker les dates

Ne pas utiliser de type Double.

Dim LaDate As Date
LaDate=Now

XIV-F-9. Ne faire aucune confiance à l'utilisateur du logiciel

Si vous demandez à l'utilisateur de saisir un entier entre 1 et 7.


Vérifier:

qu'il a tapé quelque chose!!

Qu'il a tapé une valeur numérique.

Que c'est un entier.

Que c'est supérieur à 0 et inférieur à 8.


Accorder les moindres privilèges:

Ne permettre de saisir que ce qui est valide.


XIV-G. Rendre le code lisible: commentaires, noms de variable .

Pour faire un code lisible:

  • Mettre des commentaires.
  • Choisir de bons noms de variable.
  • Aérer le code.

XIV-G-1. Ajoutez des commentaires.

Pour vous; pour les autres.

Au début de chaque routine, Sub, Function, Classe , noter en commentaire ce qu'elle fait et quelles sont les caractéristiques des paramètres:

  • Le résumé descriptif de la routine, la Sub ou Function.
  • Une description de chaque paramètre.
  • La valeur retournée s'il y en a une.
  • Une description de toutes les exceptions..
  • Un exemple d'utilisation
  • Une explication sur le fonctionnement de la routine.

Ne pas ajouter de commentaire en fin de ligne (une partie ne sera pas visible) mais plutôt avant la ligne de code. Seule exception ou on utilise la fin de ligne: les commentaires après les déclarations de variable.


Dim i As Integer    'Variable de boucle
'Parcours du tableau à la recherche de..
For i=0 To 100
...

Paradoxalement, trop de commentaires tue le code autant que le manque de commentaires. Pour éviter de tomber dans le tout ou rien, fixons nous quelques règles:

  • Commentez le début de chaque Sub, Fonction, Classe
  • Commentez toutes les déclarations de variables
  • Commentez toutes les branches conditionnelles
  • Commentez toutes les boucles
Commentaire en Xml

On peut ajouter des commentaires en xml dans VB2005.

Exemple:

Pour une Sub: Sur une ligne blanche au dessus de la Sub Calcul, tapez "'''" (3 "'").


ou


Pour une variable: Curseur sur la variable, bouton droit puis 'Insérer un commentaire' dans le menu.


Un bloc Xml "Summary" se crée automatiquement; pour l'exemple de la Sub, ajouter 'Fonction Calculant le total'


Quand ensuite on tape le nom de la Sub , le commentaire s'affiche.

De plus Visual Basic génère automatiquement un fichier de documentation XML lorsque vous créez le projet. Ce fichier apparaît dans le répertoire de sortie de l'application sous le nom AssemblyName.xml.


XIV-G-2. Choisissez les noms de procédures et de variables avec soins

On concatène plusieurs mots pour former un nom de fonction, de variable de Classe..

Il y a 3 manières d'utiliser les lettres capitales dans ces mots (on appelle cela la capitalisation!)

  • Pascal Case: La première lettre de chaque mot est en majuscule:
    
    CalculTotal()
    
  • Camel Case: La première lettre de chaque mot est en majuscule, sauf la première:
    
     iNombrePatient
    
  • UpperCase: Toutes les lettres sont en majuscule:
    
     MACONSTANTE
    

De plus le nom doit être explicite.

Microsoft propose quelque règles:

  • Sub , Fonctions
    Utilisez la 'case Pascal' pour les noms de routine (la première lettre de chaque mot est une majuscule).

    Exemple: CalculTotal()

    Évitez d'employer des noms difficiles pouvant être interprétés de manière subjective, notamment Analyse() pour une routine par exemple.

    Utilisez les verbe/nom pour une routine : CalculTotal().

  • Variables
    Pour les noms de variables, utilisez la 'case Camel' selon laquelle la première lettre des mots est une majuscule, sauf pour le premier mot.

    Exemple: iNombrePatient

    noter ici que la première lettre indique le type de la variable (Integer), elle peut aussi indiquer la portée(gTotal pour une variable globale).

    Évitez d'employer des noms difficiles pouvant être interprétés de manière subjective, 'YYB8' ou 'flag' pour une variable.

    Ajoutez des méthodes de calcul ( Min, Max, Total) à la fin d'un nom de variable, si nécessaire.

    Les noms de variable booléenne doivent contenir Is qui implique les valeurs True/False, par exemple fileIsFound.

    Évitez d'utiliser des termes tels que Flag lorsque vous nommez des variables d'état, qui différent des variables booléennes car elles acceptent plus de deux valeurs. Plutôt que documentFlag, utilisez un nom plus descriptif tel que documentFormatType.

    Même pour une variable à courte durée de vie utilisez un nom significatif. Utilisez des noms de variable d'une seule lettre, par exemple i ou j, pour les index de petite boucle uniquement.

  • Paramètre
    Pour les noms de paramètres, utilisez la 'case Camel' selon laquelle la première lettre des mots est une majuscule, sauf pour le premier mot.

    Exemple: typeName

  • Constantes
    Utiliser les majuscules pour les constantes: MYCONSTANTE

    N'utilisez pas des nombres ou des chaînes littérales telles que For i = 1 To 7. Utilisez plutôt des constantes par exemple For i = 1 To DAYSINWEEK, pour simplifier la maintenance et la compréhension.

  • Objet, Classe
    Pour les noms de Classe, utiliser le case Pascal:

    Exemple Class MaClasse

    Idem pour les évènement, espace de nom, méthodes:

    Exemple: System.Drawing, ValueChange..

    Dans les objets, il ne faut pas inclure des noms de classe dans les noms de propriétés Patient.PatientNom est inutile, utiliser plutôt Patient.Nom.

    Les interfaces commencent par un I

    Exemple: IDisposable

    Pour les variables privées ou protégées d'une classe utilisez le case Camel:

    Exemple: lastValue (variable protégée)

    En plus pour les variables privées d'une classe mettre un "_" avant:

    Exemple: _privateField

    Pour une variable Public d'une classe:

    Exemple TotalAge

  • Tables
    Pour les tables, utilisez le singulier. Par exemple, utilisez table 'Patient' plutôt que 'Patients'.

    N'incorporez pas le type de données dans le nom d'une colonne.

  • Divers
    Minimisez l'utilisation d'abréviations,

    Lorsque vous nommez des fonctions, insérez une description de la valeur retournée, notamment GetCurrentWindowDirectory().

    Évitez de réutiliser des noms identiques pour divers éléments.

    Évitez l'utilisation d'homonymes et des mots qui entraînent souvent des fautes d'orthographe.

    Évitez d'utiliser des signes typographiques pour identifier des types de données, notamment $ pour les chaînes ou % pour les entiers.

    Un nom doit indiquer la signification plutôt que la méthode.


XIV-G-3. Eclaircir, aérer le code

Eviter plusieurs instructions par ligne.

Ajouter quelques lignes blanches.

Décaler à droite le code contenu dans une boucle ou une section If.. End If:

Une mise en retrait simplifie la lecture du code, par exemple :


If ... Then
    If ... Then
        ...
    Else
        ...
    End If
Else
...
End If

XV. Les bases de données


XV-A. Notion sur les bases de données

Comment lire et écrire des informations complexes et structurées?


XV-A-1. Généralités:

Pour travailler avec du texte, des octets, des données très simple (sans nécessité d'index, de classement..), on utilise les fichiers séquentiels, aléatoires, binaires (chapitre 4-6).

Mais dès que les informations sont plus structurées, il faut utiliser les bases de données (Data Base en anglais).

Une base de données peut être:

  • locale: utilisable sur un ordinateur par un utilisateur.
  • répartie, c'est-à-dire que la base est stockée sur des machines distantes et accessibles par réseau.
Plusieurs utilisateurs peuvent accédés à la base simultanément.

Exemple de type de base de données:

Dbase Format très utilisé, qui date maintenant un peu, les fichiers contenant ses bases ont l'extension .dbf

Paradox

FileMaker

FoxPro

Interbase

Access Format très répandu, les fichiers contenant ses bases ont l'extension .mdb

SQLServeur les fichiers contenant ses bases ont l'extension .dbo

SyBase

MySql

Oracle..

Pour pouvoir contrôler les données, l'accès à ces données et les utilisateurs utilisant une base de données, un système de gestion est nécessaire. La gestion de la base de données se fait grâce à un système appelé SGBD (système de gestion de bases de données), si la base de données est relationnelle (Existence de relation entre les tables) on parle de SGBDR (système de gestion de bases de données relationnelles)

./images/vicocher.gif
Un SGBD est un logiciel qui joue le rôle d'interface entre les utilisateurs et la base de données.

Un SGBD permet de décrire, manipuler et interroger les données d'une 'Base de Données'.


XV-A-2. Tables

Dans une base de données, il y a des tables:

Une table sert à stocker physiquement des données sous forme d'un tableau comportant des lignes (rows) et des colonnes (columns).


XV-A-2-1. Exemple

Une base de données Access nommée Cabinet.mdb contient les patients d'un cabinet, leurs consultations, les ordonnances, les médicaments..

Dans cette base il y a plusieurs tables: une table patient, une table consultation...

Examinons la table patient:

Sur chaque ligne (row), il y a un patient,.

Chaque colonne (column) représente un type de données (première colonne= civilité, seconde=nom, troisième=prénom, quatrième= numéro interne propre à chaque patient. )

L'ancienne terminologie parlait d'enregistrements (lignes) et de champs (colonnes)

Ici la seconde ligne (le 2eme enregistrement, le second row) contient la civilité, le nom, le prénom, le numéro du patient Dupont Josette.

Chaque colonne à un type bien définie: dans notre cas la première colonne contient du texte, ainsi que la seconde, la troisième; la quatrième colonne contient un numérique long par exemple.

Examinons la table consultation:

Sur chaque ligne, il y a une consultation,.

Chaque colonne représente un type de données (première colonne= numéro correspondant au patient, seconde=date, troisième=texte de la consultation, quatrième= Courrier. )

Il n'est pas question pour chaque consultation d'enregistrer de nouveau le nom et le prénom du patient, cela enregistrerait 2 fois la même information puisque le nom et le prénom du patient sont déjà dans la table 'patient'. On va donc, pour éviter les redondances, utiliser un numéro interne: chaque patient a un numéro unique (4éme champ de la table 'nom'); il suffit de noter dans chaque consultation le numéro du patient.

Ensuite, si je consulte le patient Durand Luc, sachant que son numéro interne est '1', il suffit de rechercher dans la table consultation les consultations dont le premier champ est 1: Durand Luc à 2 consultations.

Le nom de la colonne est souvent nommé en utilisant le terme Id (pas ici) , 'IdPatient' par exemple, synonyme de 'numéro patient', cela permet de repérer les champs 'numéro interne'.


XV-A-3. Type de colonne

Il existe des types de colonne (de champs) alphanumériques

  • de longueur fixe (pour le champ 'nom' je prévois 30 caractères par exemple).
  • de longueur variable (champ mémo dans la base Dbase par exemple)
Il existe aussi

  • des champs numériques,
  • des champs dates
  • et dans certains base de données des champs booléens, image...

XV-A-4. Clé primaire

Quand il est nécessaire de différencier chaque enregistrement de manière unique, il faut définir un champ comme clé primaire.

Ce champ doit être unique pour chaque enregistrement (il ne doit pas y avoir de doublons: 2 enregistrements ne peuvent pas avoir la même clé primaire), et la valeur de la clé primaire ne peut pas être égale à null.

Dans notre exemple de la table patient, on ne peut pas utiliser le champ 'nom' comme clé primaire car plusieurs patients peuvent avoir le même nom, il est judicieux de choisir le champ 'numéro interne' comme clé primaire car chaque patient (donc chaque enregistrement) à un numéro interne unique.

Quand on enregistre une nouvelle fiche patient, il faut donc donner un nouveau 'numéro interne' qui n'a jamais été utilisé, en pratique:


XV-A-5. Index

Un index permet d'optimiser les recherches dans une table, de les rendre beaucoup plus rapide.

Expliquons:

Si j'ai une table contenant les noms des médecins utilisateurs et que je veux chercher un nom, comme il y a au maximum 5 à 6 médecins dans un cabinet, pour rechercher un nom, il suffit de lire successivement chaque enregistrement et de voir si c'est celui recherché. C'est suffisamment rapide.

Par contre si je recherche dans la table patient un patient, comme il y a 4000 à 8000 enregistrements, je ne peux pas les lire un à un , c'est trop long, aussi je crée un index: c'est comme l'index d'un livre, le nom me donne directement l'endroit ou se trouve l'enregistrement correspondant.

On peut combiner plusieurs champs pour en faire la base d'un index.

Pour ma table 'patient', je peux créer un index nommé IndexPatient qui sera indexé sur Nom +Prenom.

Il peut y a voir plusieurs index sur une même table.

./images/vicochev.gif
Les index accélèrent les recherches mais s'il y en a trop, cela alourdit le fonctionnement; on ne peut pas tout indexer!!


XV-A-6. Relations entre les tables: différents types de relations.

On a déjà vu que 2 tables peuvent être liées et avoir un champ commun présent dans les 2 tables.

Sur ce champ commun, il peut exister plusieurs types de relation:

Relation 1 à N

Relation 1 à 1

Relation N à M

Voyons cela en détail:


XV-A-6-a. 1 à N (relation un à plusieurs)

Dans notre exemple la table 'patient' et la table 'consultation' ont chacune un champ numéro interne. Ce qui permet de lier à l'enregistrement du patient de numéro interne X toutes les consultations pour ce patient (elles ont dans leurs champs 'numéro interne' la valeur X.

Comme pour UN patient il peut y avoir N consultations, on parle de relation 1 à N.

Un enregistrement unique est lié à plusieurs enregistrements de l'autre table par un champ présent dans les 2 tables.

On remarque que le champ 'numéro interne' du coté patient est une clé primaire, pas du coté consultation.

Table 'patients'

Le patient Durand Luc a 2 consultations : le 02/12/2003 et le 05/04/2004 (Le numéro interne de ce patient est 1, mais l'utilisateur final n'a pas à le savoir ni à le gérer: la relation utilisant le numéro interne est transparente pour l'utilisateur final)

Il existe aussi les relations:


XV-A-6-b. 1 à 1

Un enregistrement unique est lié à un autre enregistrement unique par un champ présent dans les 2 tables.

On peut imaginer dans notre exemple, créer une table Antécédents contenant aussi un champ numéro interne; pour chaque enregistrement de la table patient, il y a un enregistrement unique dans la table Antécédents, de même numéro interne contenant les antécédents du patient.

Enfin existe les relations:


XV-A-6-c. N à M

Relation plusieurs à plusieurs. Plusieurs enregistrements de la première table peuvent être liés à plusieurs de la seconde table et vice versa.

Exemple:

J'ai une table 'ordonnances' qui peut contenir plusieurs médicaments, et une table 'médicaments' dont les médicaments peuvent être utilisé dans plusieurs ordonnances différentes.

Il faut dans ce cas avoir la table 'ordonnances' avec une clé primaire sur un numéro d'ordonnance (numéro d'ordonnance unique s'incrémentant à chaque nouvelle ordonnance), une table 'médicaments' avec une clé primaire sur le numéro unique du médicament, et créer une troisième table gérant la relation ordonnance-médicament.

Ici le patient de numéro interne 2 (Dupont Josette) a une ordonnance visible dans la table 'Ordonnances'(numéro interne: 2; numéro de l'ordonnance: 1); si on cherche dans la table 'Contenu ordonnance' (Index crée sur le numéro d'ordonnance) on retrouve 2 enregistrements (ayant un numéro d'ordonnance 1), on constate que l'ordonnance contient les médicaments 1 et 2 qui correspondent (table 'médicaments') à de l'amoxicilline et de l'oméprazone.

On remarque qu'une ordonnance peut avoir autant de médicaments que l'on veut.


XV-A-6-d. Relation N à M avec N fixe et petit

Dernier cas non décrit dans les livres:

J'explique: si chaque ordonnance à au maximum 3 médicaments ( que la sécu serait contente si c'était vrai!!), il est possible de créer une table 'ordonnances' contenant 3 champs médicaments. Dans ce cas on se passe de la 3eme table.


XV-A-7. Contraintes

Un champ peut avoir certaines contraintes:

  • On peut interdire la valeur Null: Cela empêche d'enregistrer un champ vide. On peut aussi donner une valeur par défaut.
  • On peut empêcher les doublons.
  • On peut exiger l'intégrité référentielle: La valeur d'un champ doit exister dans le champ d'une autre table.(On ne peut pas enregistrer une consultation pour le patient de numéro interne 2000 s'il n'existe pas de fiche patient ayant le numéro 2000)
  • On peut exiger des règles de validation pour un champ: interdire les valeurs négatives par exemple.

XV-A-8. Serveur de fichier, Client serveur.

Si plusieurs utilisateurs sont connectés à une base Access à travers un réseau, chaque utilisateur a sur son poste un 'moteur' Access, qui récupère l'ensemble des données à utiliser et qui les traite en local. On parle de serveur de fichier.

Le moteur d'accès est présent sur chaque poste.

Si plusieurs utilisateurs sont connectés à une base SQLServer: la base est sur le serveur avec le logiciel SQLServeur.

Un logiciel utilisateur situé sur un autre ordinateur(le client) envoie au serveur une requête.

Le logiciel SQLServer traite la requête sur le serveur et retourne au logiciel client uniquement le résultat de la requête.

On parle d'architecture Client-serveur.

Le moteur d'accès est présent uniquement sur le serveur.

Si on cherche un enregistrement parmi 60 000 enregistrements, en serveur de fichiers, les 60 000 enregistrements sont envoyées par le réseau vers le moteur Access de l'utilisateur ; le moteur les traite pour en sortir un.

En client serveur, le logiciel utilisateur envoie une requête au serveur, le logiciel serveur cherche sur le serveur dans la base l'enregistrement, il le trouve et envoie à travers le réseau vers le logiciel client uniquement un enregistrement.


XV-A-9. Opérations sur les enregistrements

De manière générale, on peut:

Ouvrir une base de données (Open)

Ajouter un enregistrement (Add)

Effacer un enregistrement (Delete)

Modifier un enregistrement (Update)

Chercher un ou des enregistrements.

Fermer la base. (Close)

Avant:

Il y a bien longtemps, on choisissait un index, on cherchait un enregistrement (avec Seek), on le lisait, le modifiait, on avançait (MoveNext) ou on reculait (MovePrevious) d'un enregistrement dans la base, mais c'est de l'histoire ancienne!!

Chaque type de base de données avait ses propres commandes.

Ensuite , il y a eu les RecordSet, sorte de tableau avec un curseur pointant un élément.

./images/vicochev.gif
Avec ADO.NET:

Maintenant quelle que soit la base de données, on utilise un langage unique: le 'SQL' pour faire une requête sur une base de donnée (extraction de certains enregistrements ou de certains champs en fonction de critères), le résultat (un ensemble d'enregistrements ou de champs) se retrouve dans un DataSet.


XV-B. Généralités sur ADO.NET

Comment travailler sur les Base de données en VB.NET? Avec ADO.NET


XV-B-A. Généralités:

Pour avoir accès à partir de VB.NET aux bases de données il faut utiliser ADO.NET.

ADO veut dire Activex Database Objet .

C'est la couche d'accès aux bases de données, le SGBD (Système de Gestion de Base de Données) de VB.

ADO.NET est ".NET" donc managé et géré par le CLR.

Il est indépendant de la base de donnée: alors que initialement chaque type de gestionnaire de base de données avait ses instructions, sa manière de fonctionner, ADO.NET à un langage unique pour ouvrir, interroger, modifier une base de données quelle que soit la base de données.

Le langage de requête est le SQL.


XV-B-B. Les Managed Providers

Pour avoir accès aux données il faut charger les DRIVERS (ou providers).

Comme d'habitude, il faut:

  • Charger les références des drivers (les Dll)
  • Importer les espaces de nom.
Ainsi on a accès aux objets.

Voyons cela:

  • OLE DB Managed Provider est fourni dans 'System'; après avoir importé le NameSpace System.Data.OLEDB, on peut travailler sur des base Access par exemple.
  • SQL Server Managed Provider est fourni dans 'System'; après avoir importé le NameSpace System.Data.SqlClient, on peut travailler sur des base SqlServeur.
  • Un composant ODBC et un composant ORACLE sont disponible sur le site MSDN , il faudra charger la référence de la Dll puis le NameSpace.
  • Pour travailler sur une base MySQL lisez le très bon didacticiel MySQLDotNet (sur developpez.com bien sur);il utilise le Managed Provider ByteFX
Exemple, pour travailler sur une base Access, il faudra taper:

Imports System.Data.OLEDB


XV-B-C. Les Objets ADO.NET

Il faut disposer d'un objet Connexion pour avoir accès à la base de données, on met dans la propriété ConnectionString les paramètres de la base de données (nom de la base de données, chemin, mot de passe..).

En fonction de la BD les paramètres sont déférents. Un site nommé ConnetionStrings.com donne une mine de renseignements pour écrire les paramètres pour une BD.

Avec la méthode Open on ouvre la base.

on peut ensuite travailler de 2 manières:

A- On envoie une requête Sql 'SELECT' à la base , on récupère le résultat dans un objet.

  • Avec un objet DataReader on extrait les données en lecture seule: une requête SQL (sur un objet command) charge le DataReader. c'est rapide; on peut lire uniquement les données et aller à l'enregistrement suivant. Il travaille en mode connecté. Pour gérer un DataReader on a besoin d'un objet Command.
  • Avec un objet DataSet on manipule les données: une requête SQL (sur un objet command) charge le DataSet avec des enregistrements ou des champs, on travaille sur les lignes et colonnes du DataSet en local, en mode déconnecté(une fois que le DataSet est chargé, la connexion à la base de données est libérée). Pour alimenter un DataSet on a besoin d'un objet DataAdapter qui fait l'intermédiaire entre la BD et le DataSet.
B- On manipule directement la base. (sans retour de résultats)

  • Avec un objet Command on peut manipuler directement la BD (UPDATE, INSERT, DELETE CREATE DROP..), on utilise la propriété ExecuteNonQuery pour cela.
Avec la méthodes Close on ferme la base.

Résumons les différents objets nécessaires pour travailler sur une BD:

Noter bien le sens des flèches:

  • le DataReader est en lecture seule, les données lues dans la BD sont accessibles dans le DataReader.
  • le DataSet peut lire et écrire des données dans la BD, il faut un DataAdapter en plus de la connexion.
  • l'objet Command peut modifier la BD.
Ce schéma souligne aussi les objets intermédiaires nécessaires:

  • un objet connexion dans tous les cas,
  • un objet Command pour le DataReader,
  • un objet DataAdapter plus un objet Command pour le DataSet .
L'objet Command permet d'envoyer des ordres en SQL à la BD et de la modifier, il permet aussi, quand on utilise un DataSet, d'envoyer une requête SELECT en SQL afin de remplir le DataSet avec le résultat de la requête.

Enfin certains contrôles comme les DataGrid, les ListBox par exemple peuvent afficher des données à partir d'un DataSet.

Pour mettre à jour la base après modification du DataSet ou de la Grid il faut un objet CommandBuilder.

Mode connecté ou déconnecté:

  • le DataReader fonctionne en mode connecté,la connexion entre la BD et le DataReader est ouverte tant que le DataReader fonctionne.
  • le DataSet peut travailler en mode déconnecté: on ouvre la connexion, on charge le DataSet, on ferme la connexion (il faut le faire, ce n'est pas automatique), on travaille sur le DataSet, on peut le rouvrir plus tard pour les mises à jour.
Remarque: En fonction du provider, le nom des objets change:

Avec le provider OleDb, après Imports System.Data.OleDb

on utilisera OleDbConnexion, OleDbAdapter...

Avec le provider SQL, après Imports System.Data.SqlClient

on utilisera SqlConnexion, SqlAdapter...

Un site nommé ConnetionStrings.com donne une mine de renseignements pour écrire les paramètres pour une BD.


XV-B-D. Le DataReader

Le DataReader permet donc de lire très rapidement une table, enregistrement par enregistrement, du début à la fin.

Il n'y a pas possibilité d'écrire dans la base.


XV-B-E. Le DataSet

Le DataSet a la structure d'une base de données mais en local; il contient:

Des DataTable qui contiennent des DataRow et des DataColumn.

Pour utiliser DataSet, DataTable, DataRow.. il faut importer l'espace de nom Data:

Imports System.Data

On peut créer un Dataset de toutes pièces, mais la plupart du temps, on charge le DataSet à partir d'une base de données.

Une requête SQL charge le DataSet, on travaille sur les lignes et colonnes du DataSet en local ( sur des enregistrements ou des champs), en mode déconnecté (une fois que le DataSet est chargé, la connexion à la base de données peut être libérée).

La structure de données du DataSet reflétera automatiquement et exactement celle des données extraites. Si j'extrais 2 colonnes de données avec l'instruction Sql fournis à l'objet Command, le DataSet aura une table de 2 colonnes avec les données extraites.

Exemple :

Avec ADO.NET je lance une requête SQL demandant toutes les fiches de la table 'nom' dont le champ 'prénom' est 'Philippe', je récupère un DataSet local contenant tous les fiches (Le DataColumn "Prénom" ne contient que des 'Philippe'). Je peux modifier en local le DataSet, (modifier une date de naissance par exemple) et mettre à jour automatiquement la base de données distante.


XV-C. Syntaxe SQL

Comment adresser une requête vers une Base de données de ADO.NET? Avec SQL


XV-C-A. Généralités:

SQL veut dire Structured Query Language : Langage d'interrogation structurée

SQL grâce au couplage avec un SGBD relationnelle permet un traitement interactif des requêtes.

SQL est le langage unique qui permet de décrire, manipuler, contrôler l'accès et interroger les bases de données relationnelles.

C'est un langage déclaratif, qui est régi par une norme (ANSI/ISO) qui assure la portabilité du langage sur différentes plates-formes aussi bien matérielles que logicielles. Une commande SQL écrite dans un environnement Windows sous ACCESS peut, souvent sans modification, être utilisée directement dans un environnement ORACLE sous Unix...

SQL est utilisé dans ADO.NET pour manipuler toutes les bases de données.


XV-C-B. Les commandes SQL


XV-C-C. A - SELECT: interrogation.

Permet d'extraire ,de sélectionner des données.

Syntaxe simplifiée:

SELECT champ FROM table WHERE condition

Dans la table 'table' sélectionner les enregistrements vérifiant la condition 'condition' et en afficher les champs 'champs'

Exemple

Exemple:

Soit la table patient:

SELECT Nom FROM Patient

Cela signifie: dans la table Patient extraire les champs 'nom'

SELECT Nom FROM Patient WHERE Prenom='Luc'

WHERE ajoute un critère de sélection.

Cela signifie: dans la table Patient extraire le champ Nom de tous les enregistrements dont le prénom est "Luc" .

SELECT Nom, Prenom FROM Patient WHERE Sexe='F'

Cela signifie: dans la table Patient extraire le champ Nom et prénom de tous les enregistrements dont le champ sexe est "F"( F comme féminin) .

Dans l'exemple on obtient :

SELECT * FROM Patient WHERE Datenais>=#01/01/1950#

Cela signifie: dans la table Patient extraire tous les champs de tous les enregistrements dont le champ date de naissance est supérieur ou égal à 01/01/1950 .

Dans l'exemple on obtient

On remarque que

* signifie : extraire tous les champs.

Pour utiliser les dates , il faut les entourer de "#".

Les dates sont au format mm/jj/aaaa

SELECT * FROM Patient WHERE Datenais>= #01/01/1950# AND Datenais<= #01/01/1980#

Cela signifie: dans la table Patient extraire tous les champs de tous les enregistrements dont le champ date de naissance est supérieur ou égal à 01/01/1950 et inférieur ou égal à 01/01/1980 .

On remarque que on peut utiliser avec Where, les opérandes

AND OR NOT.

Il est bien sur possible de combiner des conditions sur des champs différents:

Sexe='M' AND Prenom='Luc"

SELECT * FROM Patient WHERE BETWEEN #01/01/1950# AND #01/01/1980#

Même signification que le précèdent mais en utilisant BETWEN AND qui est plus performant.

SELECT Nom FROM Patient WHERE Prenom IN ('Luc' , 'Pierre', 'Paul')

Cela signifie qu'il faut extraire les enregistrements dont le prénom est Luc, Pierre ou Paul .

SELECT Nom FROM Patient WHERE Prenom LIKE 'D%'

Cela signifie qu'il faut extraire les enregistrements dont le prénom commence par un 'D'.

LIKE recherche des chaînes de caractères avec l'aide de caractères génériques:

% représente une chaîne de caractères même vide.

_ représente un caractère.

On peut spécifier une série de caractères en les mettant entre ""

Exemple :

LIKE 'D%' commence par D

LIKE '%D%' contient D

LIKE '[DF]%' commence par D ou F

LIKE '___' contient 3 caractères

SELECT Nom FROM Patient WHERE SEXE IS NULL

Cela signifie qu'il faut extraire les enregistrements dont le sexe n'a pas été enregistré.

SELECT DISTINCT Nom FROM Patient WHERE SEXE IS NULL

DISTINCT permet d'éviter les doublons

Si dans les Noms extraits il y a 2 fois le même (2 membres d'une même famille) , il n'en est gardé qu'un.


XV-C-D. TRI des enregistrements:

ORDER BY sert à trier les enregistrements.

Il est placé à la fin.

DESC sert à trier par ordre décroissant.

SELECT Nom, Prenom , Sexe, DateNais FROM Patient WHERE Sexe='F' ORDER BY DateNais

Trie les enregistrements de sexe 'F' par date de naissance

SELECT Nom, Prenom, DatNais, NumInt FROM Patient WHERE Sexe='F' ORDER BY DateNais DESC, NumInt

Trie les enregistrements de sexe 'F' par date de naissance mais décroissante et pour une même date de naissance par numéro interne croissant.


XV-C-E. Statistiques:

SELECT COUNT(*) AS NombrePatient FROM Patient

Compte le nombre total d'enregistrement dans la table Patient et met le résultat dans le champ NombrePatient

On peut aussi utiliser:

MIN retourner la plus petite valeur.

MAX retourner la plus grande valeur.

SUM retourner la somme.

AVG retourner la moyenne.

VAR retourner la variance

STDEV retourner l'écart type.

SELECT Prenom ,COUNT(*) AS NombrePrenom FROM Patient GROUP BY Prenom

Extrait la liste des prénom avec le nombre de fois que le prénom est utilisé.

GROUP BY regroupe les enregistrements par valeur.

SELECT Prenom ,COUNT(*) AS NombrePrenom FROM Patient GROUP BY Prenom HAVING CONT(*)>3

Extrait la liste des prénoms avec le nombre de fois que le prénom est utilisé. S'il est utilisé plus de 3 fois..

HAVING rajoute un critère au regroupement.


XV-C-F. Extraction de données sur plusieurs tables:

Parfois on a besoin d'extraire des champs de plusieurs tables différentes, mais ayant une relation (un champ commun); pour cela on utilise une jointure.

Pour chaque enregistrement de la première table, on affiche en regard les enregistrements de la 2eme table qui ont la même valeur de jointure.

Exemple:

Soit la table patient

Comment récupérer nom et ville (en clair, pas son numéro)

SELECT Patient.Nom, Ville.NomVille From Patient INNER JOIN Ville ON Patient.NuméroVille= Ville.NuméroVille

On obtient:

En ADO.Net, on verra qu'on passe la chaîne SQL à un objet Command.

Ces données extraites à partir d'une base de données grâce à l'instruction SQL vont se retrouver dans un DataSet (sorte de Bd en local, en mémoire).


XV-C-G. B - Ajout, suppression, modification d'enregistrement:

Il est impossible d'insérer, de modifier ou de supprimer dans plusieurs tables simultanément

Une requête de mise à jour (INSERT, UPDATE ou SELECT) est une transaction ,tout doit être réalisé, sinon rien ne se passe (en particulier si une seule donnée viole une contrainte, toutes les opérations sont annulées )

Insertion d'enregistrement:

Syntaxe:

INSERT [INTO] nomdelatable [(listedescolonnes)]

{VALUES (listedesvaleurs) | requêteselect | DEFAULT VALUES }

Exemple:

INSERT INTO TablePatient (Civilité, Nom, Prenom, NumeroVille, Datenais, Sex)

VALUES ('M', 'Dupont', 'Pierre', '2',' 02/12/51/, 'M')

Effacement d'enregistrement:

Syntaxe:

DELETE [FROM] nomtable [WHERE condition]

Exemple:

DELETE FROM Patient WHERE Nom LIK'%d'

Mise à jour d'enregistrement:

Syntaxe:

UPDATE nomtable SET colonne1 = valeur1 , colonne2 = valeur2 ... WHERE condition

WHERE condition est facultatif et permet de sélectionner les enregistrements correspondant

à un critère et de modifier ceux là.

En Ado.Net on verra qu'il y a 2 méthodes pour modifier ajouter, supprimer un enregistrement:

  • On peut effectuer directement les commandes en SQL: on exécute ces commandes par la méthode ExecuteNoQuery d'un objet Command.
  • Il est plus simple de lier la base à un DataSet, de modifier le DataSet et de mettre à jour la base par un Update (du DataAdapter). Dans ce cas, on n'écrit pas de commande SQL.

XV-C-H. C - Ajout de table:

On utilise CREATE TABLE puis le nom de la table, on ajoute les différents champs (entre parenthèses et séparés par des virgules)avec pour chaque champ les conditions (NOT NULL..) et le type.

CREATE TABLE PARENT (CLI_ID INTEGER NOT NULL PRIMARY KEY, CLI_NOM CHAR(32) NOT NULL, CLI_PRENOM VARCHAR(32))

En Ado.Net on verra qu'on exécute ces commandes par la méthode ExecuteNoQuery d'un objet Command.

Pour aller plus loin:

Série d'articles sur SQL chez developpez.com:



XV-D. Lire rapidement en lecture seule: le DataReader

Comment lire rapidement des enregistrements? Avec un DataReader.

Comment compter les enregistrements? Avec ExecuteScalar

Etudions en détail les objets Connexion, Command, DataReader.

Et s'il y a une erreur ?


XV-D-A. Généralités:

Un objet DataReader fournit des données en lecture seule en un temps record. La seule possibilité est de se déplacer en avant.

En contrepartie de sa rapidité il monopolise la connexion.

Il faut créer un objet Connexion puis un objet Command, ensuite on exécute la propriété ExecuteReader pour créer l'objet DataReader; enfin on parcourt les enregistrements avec la méthode Read.


XV-D-B. Exemple de DataReader avec une base access.

Il existe une base Access nommée 'consultation.mdb', elle contient une table 'QUESTIONS', dans cette table existe un champ 'NOM', je veux récupérer tous les noms et les afficher rapidement dans une ListBox.

Il faut importer les NameSpaces nécessaires.

			Imports System.Data

Imports System.Data.OleDb
Il faut créer un objet connexion:

Dim MyConnexion As OleDbConnection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data source=" & _

"C:\consultation.mdb")
Il faut donner les paramètres Provider= et Data source=

Dans le cas d'une base Access le provider (le moteur à utiliser est le moteur OLEDB Jet 4.

Il faut créer un objet Command:

Dim Mycommand As OleDbCommand = MyConnexion.CreateCommand()
Il faut donner dans la propriété CommandText la requête SQL permettant d'extraire ce que l'on désire.

Mycommand.CommandText = "SELECT NOM FROM QUESTIONS"
Ici dans la table QUESTIONS, on extrait le champ NOM

Il faut ouvrir la connexion:

MyConnexion.Open()
Il faut créer un objet DataReader:

Dim myReader As OleDbDataReader = Mycommand.ExecuteReader()
On crée une boucle permettant de lire les enregistrements les uns après les autres, on récupère le champ (0) qui est une String, on la met dans la ListBox

Do While myReader.Read()

ListBox1.Items.Add(myReader.GetString(0))

Loop
Remarquons que le champ récupéré est récupéré typé (ici une string grâce à GeString); il y a d'autres types: GetDateTime, GetDouble, GetGuid, GetInt32, GetBoolean, GetChar, GetFloat, GetByte, GetDecimal etc..; il est possible de récupérer sans typage: on aurait écrit myReader(0) ou utiliser GetValue (on récupère un objet).

Read avance la lecture des données à l'enregistrement suivant , il retourne True s'il y a encore des enregistrements et False quand il est en fin de fichier; cela est utilisé pour sortir de la boucle Do Loop.

On ferme pour ne pas monopoliser.

myReader.Close()

MyConnexion.Close()
On aurait pu libérer la connexion automatiquement dès la lecture terminée en ajoutant un argument:

Dim myReader As OleDbDataReader = Mycommand.ExecuteReader(CommandBehavior.CloseConnection)
Simple, non!! (Je rigole!!)

Cela donne:

Imports System

Imports System.Data

Imports System.Data.OleDb

Imports Microsoft.VisualBasic

Public Class Form1

Inherits System.Windows.Forms.Form

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim MyConnexion As OleDbConnection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data source=" & _

"C:\consultation.mdb")

Dim Mycommand As OleDbCommand = MyConnexion.CreateCommand()

Mycommand.CommandText = "SELECT NOM FROM QUESTIONS"

MyConnexion.Open()

Dim myReader As OleDbDataReader = Mycommand.ExecuteReader()

Do While myReader.Read()

ListBox1.Items.Add(myReader.GetString(0))

Loop

myReader.Close()

MyConnexion.Close()

End Sub

End Class
Dans le cas d'une base SQLSERVEUR, on aurait les changements suivant:

Imports System.Data.SqlClient

Dim MyConnexion As SqlConnection = New SqlConnection("Data Source=localhost;" & _
"Integrated Security=SSPI;Initial Catalog=northwind")
Dim Mycommand As SqlCommand = MyConnexion.CreateCommand()

Dim myReader As SqlDataReader = Mycommand.ExecuteReader()

XV-D-C. Comment compter?

Avec ExecuteScalar de l'objet Command on peut récupérer les résultats d'une requête Sql qui contient une instruction COUNT (comptage) AVG (moyenne) MIN (valeur minimum) MAX (valeur maximum) SUM (somme)

Exemple: compter le nombre de questions:

Mycommand.CommandText = "SELECT COUNT(*) FROM QUESTIONS"

MyConnexion.Open()

Dim iResultat As Integer = Mycommand.ExecuteScalar()
Voyons en détails les objets utilisés:


XV-D-C-1. L'objet Connection:

Il permet de définir une connexion.

Il faut donner les paramètres 'Provider='indiquant le moteur de BD et 'Data source=' indiquant le chemin et le nom de la BD. Il peut être nécessaire de donner aussi 'Password=' le mot de passe , 'User ID=' Admin pour l'administrateur par exemple.

Il faut mettre ces paramètres avec le constructeur, ou dans la propriété ConnectionString.

Dans le cas d'une base Access le provider (le moteur à utiliser) est le moteur OLEDB Jet 4.

Il y a d'autres propriétés:

State état de la connexion (Open, Close, Connecting, Executing, Fetching, Broken)

Open, Close

ConnectionTimeOut,

BeginTransaction,

..


XV-D-C-2. L'objet Command:

Pour chaque provider il y a un objet Command spécifique:

SqlCommand, OleDbCommand, mais tous les objets 'Command' on la même interface, les mêmes membres.

CommandType indique comment doit être traité la commande CommandText:

  • Text ; par défaut (exécution direct des instructions SQL contenues dans CommandText)
  • StoredProcedure: exécution de procédure stockée dont le nom est dans CommandText.
  • Tabledirect?
Command permet de définir la commande à exécuter: SELECT UPDATE, INSERT, DELETE. en utilisant le membre CommandText

(Seul SELECT retourne des données)

CommandTimeOut indique la durée en secondes avant qu'une requête qui plante soit abandonnée.

ExecuteReader exécute le code SQL de CommandText et retourne un DataReader.

ExecuteScalar fait de même mais retourne les champs de la premier colonne pour une fonction Count ou Sum.

ExecuteNoQuery exécute le code SQL de CommandText (généralement une mise à jour par UPDATE, INSERT, DELETE ou un ajout de table) sans retourner de données.


XV-D-C-3. L'objet DataReader

Pour chaque provider il y a un objet 'DataReader' spécifique:

SqlDatReader, OleDbDataReader

On a vu le membre Read qui avance la lecture des données à l'enregistrement suivant , il retourne True s'il y a encore des enregistrements et False quand il est en fin de fichier.

On a vu GetDateTime, GetDouble, GetGuid, GetInt32, GetBoolean, GetChar, GetFloat, GetByte, GetDecimal permettant de récupérer les valeurs typées des champs.

Il a bien d'autres propriétés:

GetName retourne le nom du champ (numéro du champ en paramètre)

GetOrdinal fait l'inverse: retourne le numéro du champ (nom en paramètre)

FieldCount retourne le nombre de colonne.

GetDataTypeName retourne le nom du type de donnés.

IsDBNull retourne True si le champ est vide

......


XV-D-C-4. Exceptions:

Chaque SGDB a des erreurs spécifiques. Pour les détecter il faut utiliser les types d'erreur spécifiques: SqlException et OleDbException par exemple:

Exemple d'interception d'erreur:

Try

    MyConnection.Open()

Catch ex  As OleDbException

    MsgBox(ex.Message)

End Try

XV-E. Travailler sur un groupe de données: le DataSet

Comment travailler (lire écrire, modifier, trier..) sur des enregistrements d'une base de données ?

Avec un DataSet.


XV-E-A. Généralités:

Le DataSet est une représentation en mémoire des données. On charge le DataSet à partir de la base de données. Une fois chargé on peut travailler en mode déconnecté. Pour effectuer une modification, on modifie le DataSet puis on met à jour la base de donnée à partir du DataSet.

Pour remplir un DataSet il faut une Connexion puis un DataAdapter.

Il faut créer un objet Connexion puis un objet DataAdapter qui par sa propriété Fill charge le DataSet.

Les données sont extraites à l'aide de requête SQL sur l'objet Command, et on utilise un CommandBluider pour mettre à jour la base de donnée à partir du DataSet.

Le DataSet est organisé comme une base de données en mémoire, il possède:

  • Une propriété Tables qui contient des DataTable (Comme les tables d'un BD)
  • Chaque DataTable contient une propriété Columns qui contient les DataColomn (les colonnes ou champs des BD) et une propriété Rows qui contient des DataRow (Les lignes ou enregistrements des BD)
DataColumn contient des informations sur le type du champ.

DataRow permet d'accéder aux données.

Un DataSet possède aussi la propriété Constraints qui contient les Constraint (Clé primaire ou clé étrangère), et la propriété Relations qui contient les DataRelations (Relation entre les tables).

On peut créer des DataTable 'autonomes' et y mettre une table provenant d'un dataSet:

On peut créer des DataView : Vue, représentation d'une table. A partir d'une table, on peut créer plusieurs DataView avec des représentations différentes: DataView trié, DataView donc les ligne ont été filtrées (RowFilter)

Enfin une DataTable ou un DataView peut être affichés dans un contrôle (grid par exemple).

En conclusion: on connecte la base de donnée au DataSet par l'intermédiaire de Connexion et DataAdapter. Ensuite, il y a 2 manières de 'travailler':

  • A - On utilise les membres du DataSet pour lire ou modifier les données.
  • B - On lie le DataSet, une DataTable ou un DataView à un contrôle DataGrid ou ListBox..Et tout s

XV-E-B. A - Utilisation du DataSet, du DataView :En pratique:

Soit une base de données Access nommée 'Nom.mdb', elle contient une table 'FichePatient' qui contient les champs (ou colonnes) 'Nom', 'Prenom'.

Je vais me connecter à cette base, extraire les enregistrements de la table 'FichePatient' et les mettre dans un DataSet. Chaque ligne du DataSet contient un patient. Je travaillerais sur ces lignes.

En tête du module, il faut importer l'espace de nom permettant d'utiliser les DataSet et OleDB.

Imports System.Data

Imports System.Data.OleDb
Dans la zone Général, Déclarations du module, il faut déclarer les objets Ado:

'  Déclaration Objet Connexion

Private ObjetConnection As OleDbConnection

' Déclaration Objet Commande

Private ObjetCommand As OleDbCommand

'  Déclaration Objet DataAdapter

Private ObjetDataAdapter As OleDbDataAdapter

' Déclaration Objet DataSet

Private ObjetDataSet As New DataSet() 'Attention au New

'String contenant la 'Requête SQL'

Private strSql As String

' Déclaration Objet DataTable

Private ObjetDataTable As DataTable

' Déclaration Objet DataRow (ligne)

Private ObjetDataRow As DataRow

'Numéro de la ligne en cours

Private RowNumber As Integer    'Numéro de l'enregistrement courant

'Paramêtres de connexion à la DB

Private strConn As String

'Pour recompiler les données modifiées avant de les remettre dans le

'"DataAdapter"

Private ObjetCommandBuilder As OleDbCommandBuilder
</code>

				<paragraph>
					<b>'Ouverture</b>
				</paragraph>

<code langage="vb">
'Initialisation de la chaîne de paramètres pour la connexion

strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" &amp; _

"Data Source= c:\nom.mdb;"

'Initialisation de la chaîne contenant l'instruction SQL

strSql = "SELECT FICHEPATIENT.* FROM FICHEPATIENT"

'Instanciation d'un Objet Connexion

ObjetConnection = New OleDbConnection()

'Donner à la propriété ConnectionString les paramètres de connexion

ObjetConnection.ConnectionString = strConn

'Ouvrir la connexion

ObjetConnection.Open()

'Instancier un objet Commande

ObjetCommand = New OleDbCommand(strSql)

'Instancier un objet Adapter

ObjetDataAdapter = New OleDbDataAdapter(ObjetCommand)

'initialiser l'objet Command

ObjetCommand.Connection() = ObjetConnection

'Avec l'aide de la propriété Fill du DataAdapter charger le DataSet

ObjetDataAdapter.Fill(ObjetDataSet, "FICHEPATIENT")

'Mettre dans un Objet DataTable une table du DataSet

ObjetDataTable = ObjetDataSet.Tables("FICHEPATIENT")
</code>
			
				<paragraph>
						Ici le code est simplifié, mais dans la réalité, il est <b>indispensable d'user de Try Catch</b> pour capter les exceptions surtout pour ObjetConnection.Open() et pour l'update.
				</paragraph>		

				<paragraph>
					 Les extraits (snippets) de VB 2005, donne un exemple de code plus condensé pour ouvrir un DataSet:
				</paragraph>       

<code langage="vb">
Dim conn As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=AccessFile.mdb;Persist Security Info=False"

        Dim cmd As String = "Select * from Topics"

        Dim adapter As New OleDbDataAdapter(cmd, conn)

        Dim topics As New Data.DataSet

        adapter.Fill(topics)
</code>        

				<paragraph>
				<b>	Voir un enregistrement:</b>
				</paragraph>

				<paragraph>
					Routine affichant un enregistrement:
				</paragraph>

				<paragraph>
					Une TextBox nommée 'Nom' et une TextBox 'Prenom' afficheront les noms et prénom des patients.
				</paragraph>

				<paragraph>
					On rappelle que RowNumber est une variable contenant le numéro de la ligne en cours ( allant de 0 à Rows.Count-1)

				</paragraph>
<code langage="vb">
If RowNumber &lt; 0 Then Exit Sub

'Lors de l'ouverture de la BD, s'il n'y a aucun enregistrement

If RowNumber > ObjetDataTable.Rows.Count - 1 Then Exit Sub

' ObjetTable.Rows(Numéro de lignes).Item( Nom de colonne) donne le contenu d'un champ dans une ligne donnée

Me.Nom.Text = ObjetDataTable.Rows(RowNumber).Item("Nom").ToString

Me.Prenom.Text = ObjetDataTable.Rows(RowNumber).Item("Prenom").ToString

'Item peut avoir en paramètre le nom de la colonne ou sont index
Pour se déplacer:

Voir la ligne suivante par exemple:

RowNumber += 1 incrémente le numéro de la ligne en cours puis on affiche par:

Me.Nom.Text = ObjetDataTable.Rows(RowNumber).Item("Nom").ToString

Me.Prenom.Text = ObjetDataTable.Rows(RowNumber).Item("Prenom").ToString

RowNumber -= 1 pour la précédente.

RowNumber = 0  pour la première.

RowNumber =  ObjetDataTable.Rows.Count - 1  pour la dernière.
On remarque qu' il n'y a pas d'enregistrement courant,pas de pointeur sur un enregistrement, c'est vous même qui gérez RowNumber une simple variable qui contient le numéro de l'enregistrement (l'index du DataRow) sur lequel vous travaillez.

Modifier un enregistrement:

' Extraire l'enregistrement courant

ObjetDataRow = ObjetDataSet.Tables("FICHEPATIENT").Rows(RowNumber)

 

'Modifier les valeurs des champs en  récupérant le contenu des TextBox

ObjetDataRow("Nom") = Me.Nom.Text

ObjetDataRow("Prenom") = Me.Prenom.Text

 

'Pour modifier les valeurs changées dans le DataAdapter

ObjetCommandBuilder = New OleDbCommandBuilder(ObjetDataAdapter)

 

'Mise à jour

ObjetDataAdapter.Update(ObjetDataSet, "FICHEPATIENT")

 

'On vide le DataSet et on le 'recharge' de nouveau.

ObjetDataSet.Clear()

ObjetDataAdapter.Fill(ObjetDataSet, "FICHEPATIENT")

ObjetDataTable = ObjetDataSet.Tables("FICHEPATIENT")
Attention: quand la commande Update est effectuée, si l'enregistrement ne répond pas au spécification de la base ( doublon alors que c'est interdit, pas de valeur pour une clé primaire, Champ ayant la valeur Null alors que c'est interdit..), une exception est levée; si vous ne l'avez pas prévue cela plante!!

Il faut donc mettre la ligne contenant l'Update dans un Try Catch.

Ajouter un enregistrement:

ObjetDataRow = ObjetDataSet.Tables("FICHEPATIENT").NewRow()

ObjetDataRow("Nom") = Me.Nom.Text

ObjetDataRow("Prenom") = Me.Prenom.Text

ObjetDataSet.Tables("FICHEPATIENT").Rows.Add(ObjetDataRow)

'Pour modifier les valeurs changées dans le DataAdapter

ObjetCommandBuilder = New OleDbCommandBuilder(ObjetDataAdapter)

'Mise à jour

ObjetDataAdapter.Update(ObjetDataSet, "FICHEPATIENT")

'On vide le DataSet et on le 'recharge' de nouveau.

ObjetDataSet.Clear()

ObjetDataAdapter.Fill(ObjetDataSet, "FICHEPATIENT")

ObjetDataTable = ObjetDataSet.Tables("FICHEPATIENT")
il peut y avoir génération d'une exception au niveau de la ligne Update si l'ObjetDatarow présente un 'défaut', par exemple si un champ de l'ObjetDatarow a une valeur null (il n'a pas été renseigné) alors qu'il sert l'index.

Effacer l'enregistrement en cours:

ObjetDataSet.Tables("FICHEPATIENT").Rows(RowNumber).Delete()

ObjetCommandBuilder = New OleDbCommandBuilder(objetDataAdapter)

ObjetDataAdapter.Update(objetDataSet, "FICHEPATIENT")
Fermer

'Objet connectée

ObjetConnection = Nothing

ObjetCommand = Nothing

ObjetDataAdapter = Nothing

'Objet déconnectée

ObjetDataSet = Nothing

ObjetDataTable = Nothing

ObjetDataRow = Nothing
Trier,Filtrer, rechercher.

Il existe une méthode Select pour les DataTable mais qui retourne des DataRow.


Dim expression As String = "NOM='LASSERRE'"   'expression à rechercher

Dim sortOrder As String = "Nom DESC"

Dim foundRows() As DataRow     'résultat dans des DataRow

foundRows = ObjetDataTable.Select(expression, sortOrder)

Dim objetDatat1 As New DataTable

For Each r As DataRow In foundRows

objetDatat1.ImportRow(r)

Next

'MsgBox(objetDatat1.Rows.Count)

Dim dv As New DataView(objetDatat1)

DataGrid1.DataSource = dv
Travailler sur une DataTable.

Comment ajouter une ligne (Row)


Dim LeNewRow As DataRow = ObjetDataTable.NewRow()  'On crée un DataRow

LeNewRow("NOM") = "Smith"  'On remplit la première cellule

ou
LeNewRow(1) = "Smith"

ObjetDataTable.Rows.Add(LeNewRow) 'On ajoute la Row au DataTable
Utiliser un DataView.

Mais on peut aussi passer la table dans un DataView et utiliser Find Sort RowFilter sur le DataView.

Le DataView est un objet qui ressemble à une table mais qui correspond à une représentation et permet les tris ou l'utilisation d'un filtre:

'On crée un DataView, on y met une table.

Dim dv As DataView

dv.Table =  ObjetDataSet.Tables("FICHEPATIENT")
ou

Dim dv As New DataView(ObjetDataSet.Tables("FICHEPATIENT")) 'on met une table dans le dataview
ensuite on peut trier le DataView:

dv.Sort = "Nom DESC"  'on trie  sur le champ Nom en ordre décroissant (ASC pour un tri croissant).
On peut filtrer le DataView:

dv.RowFilter = " PreNom = 'Philippe'"  'bien respecter les  '. et les majuscules/minuscules.
Le DataView ne contient plus que les rows dont la col ="Philippe". On peut afficher dans une grid.

DataGrid1.DataSource = objetDataView
On peut rechercher dans le DataView avec Find:

    Dim dv As DataView = New DataView(Mytable)
    dv.Sort = "CustomerID"

    ' Cherche le customer named "DUPONT" dans la première colonne
    Dim i As Integer = dv.Find("DUPONT")
    Console.WriteLine(dv(i))'Affiche sur la console
FindRows lui retourne des DataRow

Ensuite on peut lier le DataView à une Grid.

Dim somme As Objet= ObjetDataTable.Compute("Sum (PRIX)", "Categorie=5")

On peut aussi utiliser Count() et dans le second paramètre (le filtre)) utiliser des And.


XV-E-C. B - Remplir un DataGrid ou une ListBox avec un DataSet:

Une fois que le dataSet existe, en UNE lignede code, on peut l'afficher dans un DataGrid.(Grille avec des lignes et des colonnes comme un tableur)

DataGrid1.SetDataBinding(ObjetDataSet, "FICHEPATIENT") en VB2003 on associe le dataset à la grid

On peut aussi passer par l'intermédiaire d'une DataTable en VB 2003 et VB 2005:

Dim matable As New DataTable

matable = ObjetDataSet.Tables("FICHEPATIENT")

DataGrid1.DataSource = matable
Remplir une Listbox ligne par ligne

Dim matable As New DataTable

matable = ObjetDataSet.Tables("FICHEPATIENT")

Dim Ligne As DataRow()

For Each Ligne In Matable.Rows

          List1.Items.Add(ligne.Item(" Nom "))

Next

XV-E-D. Etudions en détails un DataSet:

Un DataSet est un groupe de données. On a vu qu'on pouvait le remplir avec une base de données mais on peut imaginer le créer de toute pièce et le remplir en créant des tables, des colonnes, des données.

Dans un DataSet on peut donc ajouter des tables, dans les tables des colonnes, des enregistrements.

L'exemple suivant crée un objet DataTable, qui sera ajouté au DataSet.

			Private myDataSet As DataSet


' Créer une nouvelle DataTable.
Dim myDataTable As DataTable = new DataTable("ParentTable")
' Declaration de variables DataColumn et DataRow objects.
Dim myDataColumn As DataColumn
Dim myDataRow As DataRow

' Créer un nouveau DataColumn, lui donner un DataType, un nom, divers valeurs pour ses propriétés  et l'ajouter à la DataTable.
myDataColumn = New DataColumn()
myDataColumn.DataType = System.Type.GetType("System.Int32")    'Type de la colonne
myDataColumn.ColumnName = "id"                                 'Nom de la colonne
myDataColumn.ReadOnly = True                                   'Colonne ReadOnly
myDataColumn.Unique = True                                     'Evite les doublons 
myDataTable.Columns.Add(myDataColumn)

' Créer une seconde column.
myDataColumn = New DataColumn()
myDataColumn.DataType = System.Type.GetType("System.String")
myDataColumn.ColumnName = "ParentItem"
myDataColumn.AutoIncrement = False
myDataColumn.Caption = "ParentItem"
myDataColumn.ReadOnly = False
myDataColumn.Unique = False
myDataTable.Columns.Add(myDataColumn)

'La colonne id doit être une clé primaire.
Dim PrimaryKeyColumns(0) As DataColumn
PrimaryKeyColumns(0)= myDataTable.Columns("id")
myDataTable.PrimaryKey = PrimaryKeyColumns
 

'la colonne peut être une colonne auto incrémentée: (la valeur du champ "CustomerID" démarre à 100 , s'incrémente de 2 automatiquement à chaque création de DataRow.

Dim MyDataColumn2 As DataColumn = MyDataTable.Columns.Add("CustomerID", typeof(Int32))
MyDataColumn2.AutoIncrement = true
MyDataColumn2.AutoIncrementSeed = 100
MyDataColumn2.AutoIncrementStep = 2
Il est bon de la mettre en readonly


' Créer un objet DataSet
myDataSet = New DataSet()
' Ajouter la Table au DataSet.
myDataSet.Tables.Add(myDataTable)

' Créer 3 DataRow objects (3 lignes)  et les ajouter à la DatTable
Dim i As Integer
For i = 0 to 2
myDataRow = myDataTable.NewRow()
myDataRow("id") = i
myDataRow("ParentItem") = "ParentItem " + i.ToString()
myDataTable.Rows.Add(myDataRow)
Next i
End Sub

 

'parcourir dans la table 'ParentTable' toutes les lignes et lire le premier élément (1ère colonne)


For compteur=0 To myDataSet.Tables("ParentTable").Rows.Count -1

    Element= myDataSet.Tables("ParentTable").Rows.(compteur).Item(0)

Next compteur
Travailler avec la Base MySQL

Pour travailler sur une base MySQL lisez le très bon didacticiel MySQLDotNet (sur developpez.com bien sur)


XV-F. Liaison DataGrid, ListBox et base de données: le "DataBinding"

A - Comment remplir des listBox avec des tables venant de base de données?

B - Comment remplir des DataGrid avec des tables venant de base de données?

C - Comment avec quelques click et sans une ligne de code, créer une application permettant d'afficher le contenu d'une base de données? (en VB 2005)

Cette liaison de données entre une source de données et un contrôle se nomme'DATABINDING'


XV-F-A. A - Remplir une ListBox avec une colonne d'une table d'une BD:

Exemple:

Dans une base de données Accès nommé 'BaseNom', j'ai une table 'NomPatient' avec plusieurs colonnes, je veux afficher la colonne des noms dans une listBox:

On peut utiliser un 'DataReader'


C'est de la 'lecture seule' très rapide.

On peut utiliser un 'DataSet', créer un 'DataTable' et la lier au contrôle.

Le DataSet est une représentation en mémoire des données; Une fois chargé on peut travailler en mode déconnecté.

Pour le remplir il faut un DataAdapter.

Bien sur il faut importer des espaces de nom:


Imports System

Imports System.Data

Imports System.Data.OleDb
Dans la zone déclaration de la fenêtre:

'Déclarer la connexion

Private ObjetConnection As OleDbConnection

' Déclaration l'Objet Commande

Private ObjetCommand As OleDbCommand

' Déclaration Objet DataAdapter

Private ObjetDataAdapter As OleDbDataAdapter

' Déclaration Objet DataSet

Private ObjetDataSet As New DataSet

'String contenant la 'Requête SQL'

Private strSql As String

' Déclaration Objet DataTable

Private ObjetDataTable As DataTable

'Paramêtres de connexion à la DB

Private strConn As String
Dans une routine Button1_Click créer les divers objets et remplir la listbox.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

'Initialisation de la chaîne de paramètres pour la connexion

strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" & "Data Source= c:\Basenom.mdb;"

'Initialisation de la chaîne contenant l'instruction SQL

strSql = "SELECT FICHEPATIENT.* FROM FICHEPATIENT"

'Instanciation d'un Objet Connexion

ObjetConnection = New OleDbConnection

'Donner à la propriété ConnectionString les paramètres de connexion

ObjetConnection.ConnectionString = strConn

'Ouvrir la connexion

ObjetConnection.Open()

'Instancier un objet Commande

ObjetCommand = New OleDbCommand(strSql)

'Instancier un objet Adapter

ObjetDataAdapter = New OleDbDataAdapter(ObjetCommand)

'initialiser l'objet Command

ObjetCommand.Connection() = ObjetConnection

'Avec l'aide de la propriété Fill du DataAdapter charger le DataSet

ObjetDataAdapter.Fill(ObjetDataSet, "FICHEPATIENT")

'Mettre dans un Objet DataTable une table du DataSet

ObjetDataTable = ObjetDataSet.Tables("FICHEPATIENT")

 

'Indiquer au ListBox d'afficher la table "fichepatient" (indiquer la source)

ListBox1.DataSource = ObjetDataSet.Tables("FICHEPATIENT")

'Indiquer quelle colonne afficher

ListBox1.DisplayMember = "NOM"

End Sub

 
Voilà, cela affiche la liste des noms.

Bien respecter les minuscules et majuscules dans les noms de tables et de champs+++

Récupérer la valeur d'un autre champ

On a vu que dans la table, chaque enregistrement avait un champ 'Nom' mais aussi un champ 'NumInt' (numéro interne)

Dans les programmes, on a souvent besoin de récupérer le numéro interne (un ID) quand l'utilisateur clique sur un des noms; le numéro interne servira a travailler sur ce patient.

Exemple: comment récupérer le numéro interne 3 quand l'utilisateur clique sur 'Thomas'?

Il faut indiquer à la ListBox que la Value de chaque ligne est 'NumInt' en utilisant la propriété ListBox1.ValueMember.

Quand l'utilisateur clique sur une ligne de la ListBox, cela déclenche l'évènement ListBox1_SelectedIndexChanged, là on récupère la valeur de NumInt correspondant; elle se trouve dans ListBox1.SelectedValue. (C'est un Int32)

Attention:

Les exemples de Microsoft ne fonctionnent pas!! car, on n'explique nulle part l'importance de l'ordre des lignes remplissant la ListBox.

C'est DataSource qui semble déclencher le chargement de la ListBox avec la prise en compte de DisplayMember et ValueMember.

Si on fait comme Microsoft (renseigner ListBox1.DataSource en premier):

ListBox1.DataSource = ObjetDataSet.Tables("FICHEPATIENT")

ListBox1.DisplayMember = "NOM"

ListBox1.ValueMember = "NUMINT"
ValueMember ne fonctionne pas bien, et ListBox1.SelectedValue retourne un objet de type DataRowView impossible à utiliser.

Il faut donc renseigner le DataSource en dernier.

ListBox1.DisplayMember = "NOM"

ListBox1.ValueMember = "NUMINT"

ListBox1.DataSource = ObjetDataSet.Tables("FICHEPATIENT")

Dans ce cas ListBox1.SelectedValue contient bien un Int32 correspondant au 'NutInt' selectionné.

'Ensuite on peut récupérer sans problème NumInt (et l'afficher par exemple dans une TextBox)

Private Sub ListBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged

Dim o As New Object

If ListBox1.SelectedIndex <> -1 Then

TextBox1.Text = CType(ListBox1.SelectedValue, String)

End If

End Sub

XV-F-B. B - Remplir un DataGrid avec une base de données via un DataSet

Avec mise à jour de la base de donnée, si on fait une modification dans le Datagrid. Oui ça marche.(Depuis que j'ai ajouté le CommandBluider)

Il faut créer une Connection, un DataAdapter et un DataSet, puis en UNE ligne de code, on peut l'afficher dans un DataGrid.(Grille avec des lignes et des colonnes comme un tableur), ne pas oublier le CommandBuilder sinon Update ne marche pas.

Dans la zone de déclaration:

' Déclaration Objet Connection

Private ObjetConnection As OleDbConnection

' Déclaration Objet Commande

Private ObjetCommand As OleDbCommand

' Déclaration Objet DataAdapter

Private ObjetDataAdapter As OleDbDataAdapter

' Déclaration Objet DataSet

Private ObjetDataSet As New DataSet

' Déclaration Objet DataTable

Private ObjetDataTable As New DataTable

'String contenant la 'Requête SQL'

Private strSql As String

'Paramêtres de connexion à la DB

Private strConn As String

' Déclaration d'un  OleDbCommandBuilder

Private ObjetCB As OleDbCommandBuilder
Le bouton ButtonAfficheGrid remplie le DataGrid avec nom.mdb table 'FICHEPATIENT'


Private Sub ButtonAfficheGrid_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonAfficheGrid.Click

'Initialisation de la chaîne de paramètres pour la connexion

strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" & "Data Source= c:\nom.mdb;"

'Initialisation de la chaîne contenant l'instruction SQL

strSql = "SELECT FICHEPATIENT.* FROM FICHEPATIENT"

'Instanciation d'un Objet Connexion

ObjetConnection = New OleDbConnection

'Donner à la propriété ConnectionString les paramètres de connexion

ObjetConnection.ConnectionString = strConn

'Ouvrir la connexion

ObjetConnection.Open()

'Instancier un objet Commande

ObjetCommand = New OleDbCommand(strSql)

'Instancier un objet Adapter

ObjetDataAdapter = New OleDbDataAdapter(ObjetCommand)

'initialiser l'objet Command

ObjetCommand.Connection() = ObjetConnection

'initialiser l'objet OleCBComandBuilder (sinon pas d'update)

ObjetCB = New OleDbCommandBuilder(ObjetDataAdapter)

'Avec l'aide de la propriété Fill du DataAdapter charger le DataSet

ObjetDataAdapter.Fill(ObjetDataSet, "FICHEPATIENT")

'Créer une datatable à partir du dataset

ObjetDataTable = ObjetDataSet.Tables("FICHEPATIENT")

'Mettre dans le DataGrid une table  DataTable

DataGrid1.DataSource= ObjetDataTable

End Sub
Le bouton ButtonMiseA jour met à jour nom.mdb si on a fait une modification dans le DataGrid.

Private Sub ButtonMiseAJour_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonMiseAJour.Click

    'Mettre à jour

    ObjetDataAdapter.Update(ObjetDataSet, "FICHEPATIENT")

End Sub
Les lignes, colonnes, nom des champs, ascenseurs... sont crées automatiquement avec la table "FICHEPATIENT"!! Génial.

On peut cliquer dans une cellule, la modifier..rajouter ou enlever des lignes.

On peut aussi remplir le Datagrid avec:

DataGrid1.DataSource = ObjetDataSet

DataGrid1.DataMember = "FICHEPATIENT"
En mode Design, on peut modifier l'aspect du DataGrid dans la fenêtre de propriété ou en utilisant la mise en forme automatique (lien en bas de la fenêtre de propriétés.)en VB 2003!!


XV-F-B-1. Comment ne pas écrire de code.

Il est possible de remplir un DataGrid avec les tables d'une base de données sans taper une ligne de code. On crée des objets Connections, Objet DataAdapter.. à la souris.

Voici un très bon didacticiel: http://www.profsr.com/vbnetfr/15440n9.htm

On peut aussi mettre les cellules d'une base de données dans des textBox:



XV-F-B-2. Mise à jour:

Comment la mise à jour fonctionne-t elle en interne?

On n'a pas à s'en occuper, dans c'est sympa à comprendre.

Exemple: votre application utilise un groupe de données contenant une seule table. L'application extrait deux lignes de la base de données. La table de données en mémoire ressemble à ceci :

(RowState) CustomerID Name Status

(Unchanged) A Philippe Yes

(Unchanged) B Paul Yes

Votre application modifie le statusde 'Paul' en " No ". La valeur de la propriété DataRow.RowState de cette ligne passe de Unchanged à Modified. La valeur de la propriété RowState de la première ligne reste Unchanged. La table de données ressemble maintenant à ceci :

(RowState) CustomerID Name Status

(Unchanged) A Philippe Yes

(Modified) B Paul No

Votre application appelle à présent la méthode Update pour transmettre le groupe de données à la base de données. Cette méthode examine chaque ligne. Pour la première ligne, la méthode ne transmet pas d'instruction SQL à la base de données car cette ligne n'a pas été modifiée depuis son extraction de la base de données.

Pour la seconde ligne, la méthode Update appelle automatiquement la commande de données appropriée et la transmet à la base de données. La syntaxe particulière de l'instruction SQL dépend du langage SQL pris en charge. Mais il est intéressant de considérer les caractéristiques suivantes de l'instruction SQL transmise :

  • L'instruction SQL transmise est une instruction UPDATE. L'adaptateur de données sait qu'il faut utiliser une instruction UPDATE, car la valeur de la propriété RowState est Modified.
  • L'instruction SQL transmise comprend une clause WHERE indiquant que la cible de l'instruction UPDATE est la ligne dont le CustomerID = 'B'. Cette partie de l'instruction SELECT distingue la ligne cible des autres lignes car CustomerID est la clé primaire de la table cible. Les informations de la clause WHERE proviennent de la version d'origine de l'enregistrement (DataRowVersion.Original), si des valeurs nécessaires à l'identification de la ligne ont été modifiées.
  • L'instruction SQL transmise comprend une clause SET pour définir les nouvelles valeurs des colonnes modifiée.

XV-F-C. C - Remplir un DataGrid avec une base de données sans une ligne de code (VB 2005):

On a une base de données Access (Nom.MDB), on veut afficher le contenu d'une des tables (la table 'FICHEPATIENT') dans une grille.

A - Il faut créer une source de données: la BD Nom.MDB.

B - Il faut créer automatiquement l'interface utilisateur et les liens entre cette interface et une table de la BD.


XV-F-C-1. A - Création de la source de données:

Il faut créer une source de données:

Menu 'Données'=> 'Ajouter une nouvelle source de données'

Ici la source de données est une base de données:

On clique sur 'Base de données' puis bouton 'Suivant'.

Ensuite il faut faire le choix de la connexion (Cela correspond au choix d'une base de données existante).

Cliquer sur 'Nouvelle connexion'. Une nouvelle fenêtre nommée 'Ajouter une connexion' s'ouvre:

Indiquer le type de source de données (ici Microsoft Access (OLEDB), puis le nom de la base de données; enfin cliquer sur "Ok".

On retrouve le nom de la bd dans la zone connexion, cliquer sur "Suivant".

Ensuite VB vous demande s'il faut copier la BD dans le projet: Si oui la BD sera copiée dans le répertoire de travail quand vous installerez votre application. A vous de voir.

Ensuite VB vous propose d'enregistrer les chaînes de connexion (nom de la base...) dans le fichier de configuration afin qu'elles soient stockées et lues lors de l'utilisation ultérieure. (Automatiquement bien sur) A vous de voir.

Ensuite il faut choisir dans la base les objets qui seront chargés dans le dataset.

C'est habituellement les Tables. Cocher 'Tables'.

Cliquer sur "Terminer".


XV-F-C-1-B. B - Génération automatique de l'interface utilisateur:

Visual Studio dispose d'une fenêtre 'Sources de données' depuis laquelle vous pouvez faire glisser des éléments jusqu'à un formulaire pour créer automatiquement des contrôles liés aux données qui affichent des données.

Afficher les sources de données:

Menu 'Données' puis 'Afficher les sources de données'

Il apparaît à droite la fenêtre 'Sources de données'

Dérouler 'NomDataSet'(c'est le nom donné par VB à la connexion) et cliquer sur 'FICHEPATIENT' (c'est le nom d'une table de la BD).

Enfin faire un drag ans drop à partir de FICHEPATIENT et déposer le sur la form de gauche (qui est vide au départ)

Miracle: il apparaît automatiquement:

  • un datagrid.
  • une barre de navigation (tout est généré automatiquement: les bitmap des boutons dans les ressources Setting...)
  • Un DataSet, un TableAdapter
  • Un composant BindingSource.(Il fait le lien entre l'interface et la source de données)
  • Un composant BindingNavigator.(Il gère la barre de navigation)
On voit bien en dessous les 4 composants qui ont été ajoutés.

C'est terminé!!

Il suffit de lancer le programme, et on se voit la bd dans la grille, on se ballade dedans avec le curseur ou la barre de navigation, on peut ajouter, effacer une ligne, enregistrer les modifications:

Pour générer, non par une grid mais des zones de saisie textbox pour chaque champ, avant de faire le drag and drop, dérouler la liste contre la Table dans les sources de données et cliquer sur 'Détails'.

Il y a un exemple dans la section 5-10 qui donne ceci:


XV-G. Créer une BD, ajouter une table à une base de données.

Comment créer une base de données

Comment ajouter une table?

Pour consulter une base de données vous pouvez utiliser L'explorateur de serveurs.

Pour accéder à l'Explorateur de serveurs, sélectionnez Explorateur de serveurs dans le menu Affichage et regarder la doc.


XV-G-A. Créer une base de données:

Base Access.

Avec un Provider OleDB: (System.Data.OLEDB) impossible de créer une BD Access par du code.

On rappelle qu'on peut créer rapidement une BD Access 'à la main':

Sur le fond d'écran: Bouton droit->Nouveau->Application Microsoft Access

Si on veut absolument créer une BD Access par code, il faut passer par DAO.

    Référence: ajouter le composant COM 'Microsoft DAO 3.6 Library 5'

    Imports DAO

    Imports DAO.LanguageConstants

    Dim result As Boolean = False

    Dim dbe As New DBEngine

    Dim db As Database

    Try

    db = dbe.CreateDatabase("c:\test.mdb", dbLangGeneral)

    If Not (db Is Nothing) Then result = True

    Catch ex As Exception : MsgBox(ex.Message)

    Finally : If Not (db Is Nothing) Then db.Close()

    End Try
Ensuite, on peut travailler en OleDB.

(merci les forums de developpez.com)

SqlServer.

Avec un Provider SqlServer: (System.Data.SqlClient) on peut créer une BD Sql Server par du code.

Exemple:


    Protected Const SQL_CONNECTION_STRING As String = _

    "Server=localhost;" & _

    "DataBase=;" & _

    "Integrated Security=SSPI"

     

    Dim strSQL As String = _

    "IF EXISTS (" & _

    "SELECT * " & _

    "FROM master..sysdatabases " & _

    "WHERE Name = 'HowToDemo')" & vbCrLf & _

    "DROP DATABASE HowToDemo" & vbCrLf & _

    "CREATE DATABASE test"

     

    Dim northwindConnection As New SqlConnection(connectionString)

    Dim cmd As New SqlCommand(strSQL, northwindConnection)

    northwindConnection.Open()

    cmd.ExecuteNonQuery()

    northwindConnection.Close()
Code non testé.


XV-G-B. Ajouter une table à une BD existante:

Dans un Dataset, on peut ajouter des données puis par un update mettre à jour la base de données.

On peut aussi ajouter des tables en local dans le Dataset, mais updater la base ne rajoute pas les tables dans la base.

Comment donc ajouter une table à la base?

En fait pour ajouter une table à la base il faut le faire avec l'objet Command et sa méthode ExecuteNoQuery et une requête SQL:

On crée une Connexion et un objet Command, on indique à la propriété TypeCommand que l'on envoie du texte (pas une procédure stockée), on prépare le texte SQL avec CREATE puis on exécute avec ExecuteNoQuery.

Exemple :

Il existe une BD Acces nommée NOM.MDB , je veux y ajouter une Table nommée PARENT avec 3 champs CLI_ID CLI_NOM CLI_PRENOM:


Imports System

Imports System.Data

Imports System.Data.OleDb
Dans la zone déclaration de la fenêtre:

'Déclarer la connexion

Private ObjetConnection As OleDbConnection

' Déclaration l'Objet Commande

Private ObjetCommand As OleDbCommand

 

'Paramètres de connexion à la DB

Private strConn As String
Dans une routine Button1_Click créer une table avec 3 champs dans la base de données.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 

strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" & "Data Source= c:nom.mdb;"

ObjetConnection = New OleDbConnection

'Donner à la propriété ConnectionString les paramètres de connexion

ObjetConnection.ConnectionString = strConn

'Ouvrir la connexion

ObjetConnection.Open()

'Instancier un objet Commande

ObjetCommand = New OleDbCommand

'Lier Commande et Connexion

ObjetCommand.Connection = ObjetConnection

'Indiquer le type de commande

ObjetCommand.CommandType = CommandType.Text

'Donner le texte de la commande SQL

ObjetCommand.CommandText = "CREATE TABLE PARENT (CLI_ID INTEGER NOT NULL PRIMARY KEY, CLI_NOM CHAR(32) NOT NULL, CLI_PRENOM VARCHAR(32))"

'Ici on crée une table PARENT avec 3 champs ; CLI_ID est un entier non nul qui sert de clé primaire, CLI_NOM  CLI_PRENOM sont des chaînes de 32 caractères.

'on exécute la commande

ObjetCommand.ExecuteNonQuery()

'Fermer la connexion

ObjetConnection.Close()

End Sub
			

XVI. Migration VB6=>VB.NET 2003=>VB.NET 2005

Cela concerne surtout ceux qui passent de VB6 à VB.NET, pour les autres c'est une révision.

Les petits nouveaux qui ne connaissaient pas VB6 (précédente version de VB) ne doivent pas lire ce qui est en vert.


XVI-A. Les objets

En VB.NET tout est objet: les fenêtres, les contrôles, les variables....

Set et Let ne sont plus pris en charge.

Les objets peuvent être assignés par une simple opération d'assignation :

Object1 = Object2

Pour définir une propriété par défaut d'un objet, vous devez désormais référencer explicitement la propriété. Exemple

Object1.Text = Object2.Text

Vous pouvez définir vous même un nouveau type d'objet, une Classe.

Puis instancer des objets à partir de cette Classe.

VB.NETpermet une vraie programmation objet: héritage, polymorphisme, surcharge, Interface ...


XVI-B. Les Classe du Framework

Il existe toujours les mots clefs de Visual Basic (Len, Trim, Rnd..) mais en plus le Framework met à disposition une multitude de Classes qui possèdent des méthodes permettant de faire une multitude de choses sans programmer:

Exemple:

La Classe Array (les tableaux) possède une méthode Sort qui trie les tableaux.

Dim T() As Integer
	T(0)=78
	..
	Array.Sort(T)

XVI-C. Les formulaires ou fenêtres:

On se rend compte que quand on dessine une fenêtre Form2 par exemple, VB crée une nouvelle classe 'Class Form2'

Public Class Form2
				Inherits Systeme.Windows.Forms.Form 
				End Class
Elle hérite de System.Windows.Forms.Form: on le voit bien dans le code.

Pour utiliser cette fenêtre, il faut créer une instance de cette fenêtre à l'aide de la Classe :

On tape Dim f As New Form2(), on crée une instance de la Class Form2.

Enfin la fenêtre sera ouverte grâce à la méthode ShowDialog ou Show.

Comme pour un Objet en général, la fenêtre créée sera visible dans sa portée. Si une fenêtre est instanciée dans une procédure, l'objet fenêtre f ne sera visible que dans cette procédure.

Comment passer de VB6 à VB.net?

  • Avant en VB6, on avait:

	Form2.Load
			
    Form2.Show
  • Avec le programme de conversion VB6=>VB.Net on a:

	Form2.DefInstance.Show()
car il ajoute une routine qui créée automatiquement une instance de form2:

#Region "Prise en charge de la mise à niveau "

Private Shared m_vb6FormDefInstance As form2
Private Shared m_InitializingDefInstance As Boolean
Public Shared Property DefInstance() As form2
	Get
		If m_vb6FormDefInstance Is Nothing OrElse m_vb6FormDefInstance.IsDisposed Then
			m_InitializingDefInstance = True
			m_vb6FormDefInstance = New form2()
			m_InitializingDefInstance = False
		End If
			DefInstance = m_vb6FormDefInstance
	End Get
	Set
			m_vb6FormDefInstance = Value
	End Set
End Property
#End Region
  • En fait il faut mieux avec VB.net écrire:

Dim F As New Form2
				
F.Show
On remarque que Load n'existe plus, par contre, le Dim crée le formulaire sans l'afficher, c'est à peu prêt équivalent..

Les Forms ont 2 contrôles menu:

Les MainMenu

Les ContextMenu.

Visual Basic .NET ne prend pas en charge la méthode Form.PrintForm


XVI-D. Les Controles

La plupart des objets ne possèdent plus de propriétés par défaut.

En VB6:

Dim str As String = TextBox1
Maintenant il faut écrire:

Dim str As String = TextBox1.Text
Visual Basic .NET ne prend pas en charge le contrôle conteneur OLE .

Il n'existe pas de contrôle carré rectangulaire ligne . On peut les remplacer sous la forme d'étiquettes (Label), tandis que les ovales et les cercles qui n'existent pas non plus, ne peuvent pas être mis à niveau.

Visual Basic .NET est doté d'un nouvel ensemble de commandes graphiques faisant partie de GDI+. Circle, CLS, PSet, Line et Point n'existent plus. Étant donné que le nouveau modèle objet est assez différent de celui de Visual Basic 6.0,il faut tout réécrire.

Visual Basic .NET ne prend pas en charge l'échange dynamique de données (DDE, Dynamic Data Exchange).

Bien que Visual Basic .NET prenne en charge la fonctionnalité de glisser-déplacer, le modèle objet est différent de celui de Visual Basic 6.0. Il faut tout réécrire.

Le .NET Framework est doté d'un objet Clipboard amélioré (System.Windows.Forms.Clipboard) qui offre plus de fonctionnalités et prend en charge un plus grand nombre de formats de Presse-papiers que l'objet Clipboard de Visual Basic 6.0. Il faut tout réécrire.

Les groupes de contrôle n'existent plus. Il y a des moyens de les remplacer.


XVI-E. Les Variables

Option Explicit étant activé par défaut, toutes les variables doivent être déclarées avant d'être utilisées.

Le type de données Variant n'existe plus. Celui-ci a été remplacé par le type Object.

Le type de données Integer est désormais de 32 bits ; le type de données Long est de 64 bits.

On peut utiliser les type Booléens qui ne peuvent prendre que 2 valeurs :True et False (pas 0 et -1)

En VB.NET Option Strict étant activé, il faut convertir explicitement une donnée d'un type vers un autre si c'est nécessaire.

Response.Write("Le total est " & CStr(total))

on attend des String, la variable total qui est numérique est donc transformée en String par CStr.

Les variables créées dans la même instruction Dim seront du même type. Par exemple, dans VB.NET, l'instruction Dim i, j, k As Integer crée chacun des trois objets (i, j, et k) comme Integer. Les versions précédentes de VB créaient i et j comme Variants et k comme Integer (c'était nul!!).

Il existe un type Char qui contient un seul caractère.

Le type Currency est remplacé par le type Decimal.

Les String de longueur fixe n'existent plus. Il y a quelques ficelles pour contourner cela mais bonjour la simplicité!!

Les String et Char sont en Unicode (chaque caractère est codé sur 2 octets).

Une variable peut avoir une portée locale, publique ou, et c'est nouveau, une portée au niveau d'un bloc:

For i=0 to 100
	Dim Str As String 'Str est visible uniquement entre For et Next
	...
	next i

XVI-F. Les Tableaux

Le premier élément d'un tableau a l'indice 0 obligatoirement; plus d'Option Base.

On peut initialiser un tableau en même temps qu'on le déclare:

Dim Tableau(3) As Integer ={7,2,3,5}

A noter que ce tableau contient 4 élément d'index 0, 1, 2, 3.

Dim S(4 to 15) n'est plus accepté.

Dim est utilisé pour la déclaration initiale, Redim pour le redimensionnement uniquement.

Les tableaux font partie de la Classe Array, ce qui autorise l'utilisation de méthodes bien pratiques: Sort par exemple trie automatiquement le tableau.


XVI-G. Les Collections

Elles sont omniprésentes. C'est fondamental de bien comprendre leur fonctionnement: Ce sont des listes ayant un nombre d'élément non défini, on peut y ajouter des éléments, en retirer, il y a des méthodes pour trier, rechercher..

Cela peut être :

Des listes d'objet: ArrayList

Des listes de booléens: BitArray

Des listes Clé-Valeur :HashTable

Des Queue

Des Piles :Stack

La notion de collection est généralisée et utilisée dans beaucoup d'objets: Une ListeBox possède une collection d'Item (les éléments de la listBox)


XVI-H. Les Structures

Elles remplacent les "Types définis par l'utilisateur".

Structure MaStructure
	Public i As Integer
	Public c As String
End Structure

XVI-I. Les Fonctions et Sub

Les parenthèses sont désormais requises autour de la liste de paramètres dans tous les appels de méthodes y compris pour les méthodes qui ne prennent pas de paramètres. Exemple :

If Flag = False Then
   	AfficheMessage()
End If
Par défaut, les arguments sont passés par valeur, et non pas référence . Si vous voulez passer des arguments par référence, vous devez utiliser le mot clé ByRef devant l'argument comme dans l'exemple suivant :

Call MaFunction(argbyvalue, ByRef argbyref)

Il peut y avoir des paramètres optionnels.

Return est un nouveau mot clé qui permet à une fonction de retourner une valeur.

Private Function MaFonction (Byval Chaine As String)
	Return Chaine.ToLower()
End Function

XVI-I-1. Dans le code

Simplification d'écriture:

A +=2 est équivalent à A=A+2

Nouveau type de boucle

While condition

End While

Boucle tant que condition est vraie.

Wend n'existe plus.

Le Multithreading est possible.


XVI-J. Gestion des erreurs

La gestion des erreurs est structurées:

Elle utilise

Try

Code a tester

Catch

interception de l'erreur

Finally

suite

End Try

On error goto reste utilisable.


XVI-K. Les graphiques

En GDI (VB6) on utilisait les handles(HDC) pour spécifier un image.

En GDI+ (VB.Net) on travaille sur les Graphics et leurs méthodes. Graphics.DrawLine..

L'unité de mesure est le pixels. (Plus de Twips)


XVI-L. Les bases de données

Visual Basic .NET contient une version améliorée des objets de données actifs (ADO, Active Data Objects) appelée ADO.NET.

DAO, RDO et ADO peuvent toujours être utilisés dans du code Visual Basic .NET, avec toutefois quelques petites modifications . Toutefois, Visual Basic .NET ne prend pas en charge la liaison de données DAO et RDO aux contrôles ou contrôles de données ni la connexion utilisateur RDO.


XVI-M. Les Classes

La syntaxe des propriétés de classe a changé et ne contient plus Property Let, Property Get, et Property Set. La nouvelle syntaxe des propriétés est analogue à celle de C#.

Public Property ThisProperty As String
    Get
      	ThisProperty = InternalValue
    End Get
    Set
        InternalValue = value
    End Set
End Property
Les classes sont totalement objet et acceptent le polymorphisme, la surcharge , l'héritage..


XVI-N. GOSUB et ON GOSUB n'existent plus

Il faut remplacer une une routine qui était appelée par gosub par une sub ou une fonction.

Remplacer

Sub Mon Programme
	..
		Gosub Routine
	..
End SuB

Routine:
		Code de la routine
Return
Par

Sub Mon Programme
	..
		Call Routine()
	..
		End Sub
		
Sub Routine()
		
    code de la routine
			
End Sub
Il faudra simplement faire attention aux variables, les variables locales à Mon Programme ne seront pas accessible dans la routine.

Pour On Gosub, il faut remplacer par un SelectCase.


XVI-O. Les Timers

S'agissant du contrôle Timer, le fait d'affecter à la propriété Interval la valeur 0 ne désactive pas la minuterie ; l'intervalle est réinitialisé à 1. Dans vos projets Visual Basic 6.0, vous devez affecter à la propriété Enabled la valeur False plutôt que d'affecter à Interval la valeur 0.


XVI-P. Conversion VB6 vers VB.NET

Il existe un outil de conversion (Menu Fichier, Ouvrir, Convertir, Assistant de mise à niveau de VB.NET) pour convertir un source VB6 en VB.NET.

Le problème est qu'il donne un code, à mon avis, inutilisable avec:

  • Conversion des instructions VB6=>VB.NET quand il le peut.
  • Conversion en utilisant une classe de compatibilité contenant des instructions spécifiques à VB6 (qui ne sont PAS du VB.NET) produisant un code hybride. Cette classe de compatibilité disparaîtra probablement dans les prochaines versions.
  • Conversion en utilisant des ficelles avec ajout de plein de code: voir l'exemple des Forms au dessus ou l'outil de conversion crée une complexe fonction nommée 'DefInstance' permettant de créer des formulaires.
  • Des instructions impossible à convertir automatiquement et qui seront à réécrire à la main.
Il faut convertir les programmes VB6 avec l'outil de conversion pour voir ce que cela donne: c'est instructif de voir le nouveau code.

Mais il faut réécrire totalement une bonne partie du code: l'appel des fenêtres en particulier.

Il faut rapidement ne pas utiliser du tout la classe de compatibilité VB 6 , éviter les instructions héritées de VB6, privilégier l'usage des classes du FrameWork.


XVII. Nouveautés dans VB.NET 2005 (Framework 2)

Le matériel

L'IDE (environnement de développement)

Les nouveaux Objets (My).

Les instances de Form.

Les nouveaux contrôles.

Les nouvelles variables.

Les nouvelles collections.

Le code et les nouvelles instructions.

Les nouveautés dans les classes.







XVII-A. Le matériel

Support des plateformes 64 bits.(Pas dans la version Express)

Support du 'multi monitor'


XVII-B. L'IDE


XVII-B-a.

On peut créer des fenêtres toutes faites, avec les contrôles..:

Il y a des fenêtres toutes faites pour accélérer le travail (les templates) comme les 'AboutBox' les 'Explorer Form'...



XVII-B-b. Edit and Continue:

Il y a maintenant le 'Edit and continue': en mode Debug, on peut modifier une ligne et poursuivre le programme qui tiendra compte de la modification (Sauf pour les déclarations).

Il y a des exemples de code.

Les Snippets (bride, morceau de code) permettent d'insérer du code tout fait.

Dans le code d'une procédure, le click droit de la souris ouvre un menu. Cliquer sur Insérer un extrait (Insert Snipper) puis double-cliquer sur la rubrique que vous cherchez.


On obtient le code suivant:

' Copy the active window.

SendKeys.SendWait("{PRTSC}")

System.Threading.Thread.Sleep(1000)

Dim window As Bitmap

window = CType(Clipboard.GetDataObject().GetData("Bitmap"), Bitmap)

' Copy the entire screen.

SendKeys.SendWait("+{PRTSC}")

System.Threading.Thread.Sleep(1000)

Dim screen As Bitmap

screen = CType(Clipboard.GetDataObject().GetData("Bitmap"), Bitmap)

Génial!!

Il est proposé des solutions pour corriger les erreurs de code:

Une fenêtre vous indique les corrections à faire.

Si je veux afficher une valeur numérique (avec option Strict=On),il y a erreur, VB me propose la correction:



XVII-B-c. Le Projet Designer:

Toutes les propriétés de l'application peuvent être modifiées dans le 'Projet Designer', il est directement accessible dans l'explorateur de solution (My Projet)ou par le menu Affichage-> Page de propriétés:

Le nom de l'application , son icône,

Le formulaire de démarrage (startUp Form),

L'écran de démarrage (Splash Screen), il suffit d'indiquer son nom (VB l'affiche et le fait disparaître quand le formulaire de démarrage s'ouvre).

Le mode d'arrêt de l'application: A la fermeture du formulaire de démarrage ou lorsque tous les formulaires sont fermés.

Les Option Strict, Explicit.(Onglet Compiler)


On peut utiliser aussi les paramètres (Settings), et les ressources....

a- Exemple de ressource.

Onglet 'Ressources' , créons une ressource nommée 'toto' et contenant '2' (c'est une string)


Pour l'utiliser dans le programme, on fera:

My.Resources.toto

Les ressources sont en Read-Only.

On vient de créer une ressource 'chaines' mais en déroulant la liste en haut à gauche , on voit qu'il y a des ressources Image, Icône, Audi, Fichier, Autre.

b- Exemple de paramètre.

Onglet 'Paramètres' , créons un paramètre nommé 'Para1' et contenant '1' (c'est une string)


Pour l'utiliser dans le programme, on fera:

My.Parametre.Para1

Les Paramètres sont en Read-Only si la portée est 'Application', et en Read-Write si la portée est 'Utilisateur'.

Ces 'variables paramètres utilisateur' ont des valeurs qui seront conservées et enregistrées automatiquement dans l' 'environnement' d'un utilisateur. Si on en modifie la valeur, on retrouve la valeur modifiée lors d'une utilisation ultérieure ce qui permet de conserver les habitudes des utilisateurs.


XVII-B-d. L'alignement automatique des contrôles:

Si on modifie la taille ou l'emplacement d'un contrôle, VB signale par un trait bleu que le contrôle modifié et le contrôle voisin sont alignés:




XVII-B-e. Le déplacement des contrôles ou l'accès aux principales tâches est amélioré:


La croix à gauche permet de déplacer le contrôle, la petite flèche à droite permet d'ouvrir un menu qui donne accès aux tâches les plus fréquentes.


XVII-B-f. Renommer un nom: modification automatique.

On nomme cela 'Refactoring': Cliquer sur une variable, puis bouton droit, dans le menu cliquer sur 'Renommer'. Modifier le nom de la variable, valider. Dans toute la Classe la variable est renommée.


XVII-B-g. Commentaire en Xml

On peut ajouter des commentaires en xml

Exemple:

Pour une Sub: sur une ligne blanche au dessus de 'Sub', tapez "'''" (3 "'").

ou

Pour une variable: curseur sur la variable , bouton droit puis 'Insérer un commentaire' dans le menu.

Un bloc Xml se crée automatiquement; Ajouter 'Fonction Calculant le total' entre les basiles


Quand ensuite on tape le nom de la Sub , le commentaire s'affiche. Pratique quand on travaille en equipe.

De plus Visual Basic génère automatiquement un fichier de documentation XML lorsque vous créez le projet. Ce fichier apparaît dans le répertoire de sortie de l'application sous le nom AssemblyName.xml.


XVII-C. Les nouveaux Objets


XVII-C-i. My: le SUPER RACCOURCI.
My permet d'avoir accès rapidement à certaines fonctionnalités:

My.Application

Permet d'accéder rapidement aux propriétés de l'application en cours.

Vous pouvez ainsi récupérer des informations sur l'assembly, la culture (langue) de l'application.

MsgBox(My.Application.Culture.ToString) 'affiche 'fr-FR'

(My.Application.ChangeCulture 'permettra de changer la culture )

MsgBox(My.Application.Info.DirectoryPath) 'affiche le nom du répertoire ou est l'exécutable.
My.Application.SetCurrentUser() retourne l'utilisateur

My.Application.SetCurrentUser()

My.Application.OpenForms qui retourne les formulaires ouverts.

Exemple: rajouter le texte 'ouvert' à la barre de tache des formulaires ouverts:

For Each F As System.Windows.Forms.Form In My.Application.OpenForms
	F.Text += "[ouvert]"
Next
My.Computer

Permet d'accéder aux propriétés de l'ordinateur, du hardware.

Aux ressources logicielles et/ou matérielles de l'ordinateur.

Audio : permet de jouer des fichiers wav, ainsi que les sons systèmes de windows.

My.Computer.Audio.Play("c:\mysound.wav")

Clipboard : permet de récupérer des informations sur le contenu du presse-papier, de récupérer et de définir son contenu.

 If My.Computer.Clipboard.ContainsImage Then
            PictureBox1.Image = My.Computer.Clipboard.GetImage
        ElseIf My.Computer.Clipboard.ContainsText Then
           TextBox1.Text = My.Computer.Clipboard.GetText
    	End If
Clock : permet de récupérer l'heure courante ainsi que le nombre de millisecondes écoulées depuis le démarrage.

MsgBox(My.Computer.Clock.LocalTime.ToString) 'Affiche date et heure

FileSystem : permet d'effectuer les opérations d'entrées/sorties standards.

Récupérer le nom des disques:

MsgBox(My.Computer.FileSystem.Drives.Item(0).ToString)'affiche 'A:'

(la collection Drives contient des items indiquant les disques)

Un répertoire existe t-il?

MsgBox(My.Computer.FileSystem.DirectoryExists("c:\").ToString) 'affiche True si c:\ existe.

Possibilité de copier, créer, effacer répertoires ou fichiers:

Exemple: copie d'un répertoire:

My.Computer.FileSystem.CopyDirectory(sourcedirectory, destinationdirectory)

Voir les sous répertoires:

FileSystem.GetDirectories("c:\").item(0) permet de voir le premier sous répertoire.

GetFiles fait de même avec les fichiers.

Mettre le contenu d'un fichier texte dans une variable:

Dim LeTexte As String = My.Computer.FileSystem.ReadAllText("c:\devicetable.log")

(Il existe aussi WriteAllText)

Info : Obtient des informations concernant l'ordinateur et le système d'exploitation (mémoire vive libre, nom de l'os, version de l'os, etc).

MsgBox(My.Computer.Info.TotalPhysicalMemory.ToString) 'affiche la mémoire physique

Il y a aussi AvailablePhysicalMemory, OSVersion, OSFullName..

Keyboard : permet de tester l'état des touches CTRL, ALT, etc… et de simuler l'appuie de touche grâce à la méthode Sendkeys.

MsgBox(My.Computer.Keyboard.AltKeyDown.ToString)' teste si la touche Alt est enfoncée.

My.Computer.Keyboard.SendKeys("a")' simule l'appuie d'une touche.

Mouse : permet de récupérer des informations sur la souris (présence de la souris, présence de molette, boutons inversés, etc.)

MsgBox(My.Computer.Mouse.WheelExists.ToString) 'affiche True s'il y a une molette.

Name : récupère le nom de l'ordinateur

MsgBox(My.Computer.Name.ToString)

Network : permet de télécharger et d'uploader des fichiers, de vérifier si l'ordinateur est connecté à Internet, d'effectuer des pings, et de récupérer les évènements lors des connexions et déconnexions.

Charger un fichier à partir du réseau:

My.Computer.Network.DownloadFile(AdresseCompleteFichierACharger, DestinationFileNane)

 With My.Computer.Network
            If .IsAvailable And .Ping(txtIpAdress.text) Then
               .UploadFile("c:\filetupload.ext", txtIpAdress.Text)
           End If
      	End With
Ports : permet de récupérer la liste des ports séries, et de les ouvrir.

Printers : permet de récupérer la liste des imprimantes installées et de définir l'imprimante par défaut. (absent dans la version bêta)

Registry : permet de manipuler la base de registre facilement.

Screen : permet de récupérer les informations concernant les écrans installés.

My.User

Permet de récupérer les informations sur l'utilisateur courant.

My.User.Identity.Name

My.User.IsInRole("Administrators") 'contient l'administrateur

My.Ressources

Permet de manipuler et récupérer très facilement les ressources incorporées à l'assembly.

My.Setting

Fichiers de configuration.

My.Forms

Donne accès à tous les formulaires.

My.Forms.HelpForm.Show()

My.WebService

Permet de manipuler directement les services web référencés dans le projet.

GZIPStreamClass

Permet d'enregistrer ou de lire des fichiers compressés au format zip .

Support du SMTP et du FTP


XVII-D. Les instances de Forms:

En VB2003 il fallait instancier une Form avant de l'utiliser.

Dim newForm1 As NewForm1
    newForm1.BackColor = System.Drawing.Color.Green
    newForm1.Show()
On peut toujours le faire en 2005 mais on peut aussi utiliser la Class Form1 sans instancier:

	Form1.ForeColor = System.Drawing.Color.Coral
 	Form1.BackColor = System.Drawing.Color.Cyan
    Form1.Show()
Comme il n'y a pas d'instance de Form1, VB en crée une.


XVII-E. Les nouveaux Contrôles


XVII-E-i. DataGridView
Il remplace le DataGrid dans VB.Net 2005 Il est bien plus simple à utiliser surtout pour modifier directement la grille sans passer par un DataSet.


MyDataGridView.ColumnCount = 5 indique le nombre de colonne.

MyDataGridView.Columns(0).Name = "Date" met un texte dans le haut de la colonne.

MyDataGridView.Rows.Add(t) 'Ajout de ligne; t est un tableau de 5 strings.

MyDataGridView.CurrentCell est la cellule courante (CurrentCellAdress contient les numéro de ligne et colonne)

MyDataGridView.EditMode = DataGridViewEditMode.EditOnEnter autorise de modifier les cellules.


XVII-E-ii. MaskedTextBox
Permettant d'utiliser un masque pour la saisie de caractères. Le masque indique quels caractères interdire ou permettre.

La propriété Mask permet d'indiquer le masque de saisie.

On peut la modifier en mode 'Design' :


On voit bien dans la fenêtre ci dessus: le masque '00:00' permet de saisir 2 groupes de 2 chiffres. L'utilisateur voit que qu'il y a dans l'aperçu '__:__' et est obligé de taper 2 chiffres puis 2 chiffres.

On peut utiliser des masques tout faits (Heure, date..) ou créer un masque personnalisé.

On peut aussi modifier le masque par code:

maskedTextBox1.Mask = "LL"

Pour le masque personnalisé on utilise:

0   Chiffre requis (lettres refusés)

9   Chiffre ou espace optionnel. (lettres refusés)

#   Chiffre ou espace optionnel. (+) (-) sont permis.

L   Lettre requise. (chiffres refusés)

?   Lettre requise optionnelle. (chiffres refusés)

&   Caractère requis.(Chiffres et lettres permises)

C   Caractère, requis optionnel.(Chiffres et lettres permises %*& permis)

A   Alphanumérique requis opt.(Chiffres et lettres permises %*& refusés)

.   Point Decimal; celui de la culture.

,   Séparateur de millier; celui de la culture.

:   Séparateur de temps; celui de la culture.

/   Séparateur de date; celui de la culture.

$   Symbole monétaire; celui de la culture.

<    Convertir les caractères qui suivent en minuscule.

>   Convertir les caractères qui suivent en majuscule.

|   Stop la conversion minuscule ou majuscule.

\   Escape. Le caractère qui suit devient un littéral.“\\” affichera '\'.

Autres caractères Littéraux. Affichés tels quels

Exemple:

"00/00/0000" permet de saisir une date.

"LLL" permet de saisir trois lettres (pas des chiffres)

/ $ , : sont dépendant de la culture en cours:

Si le Mask="0$" il apparaîtra "_€ en culture française.

On peut modifier cela par FormatProvider property.

MaskCompleted indique si la saisie est conforme.

Dim returnValue As Boolean
   returnValue = maskedTextBox1.MaskCompleted
MaskedTextBox1.text permet de lire le contenu du texte.

L'évènement le plus souvent utilisé est TextChanged

Private Sub MaTextBox_TextChanged(sender As Object, _ 
  e As EventArgs) Handles MaTextBox.TextChanged
End Sub

XVII-E-iii. SoundPlayer
Pour écouter des sons .Wav


XVII-E-iv. SplitContainer:
Permettant de créer facilement une séparation déplaçable entre 2 zones.


On met le SplitContainer, dans les 2 zones on met par exemple 2 textbox. Il faut mettre la propriété Dock de ces 2 textbox à Fill.

En mode Run, cela marche : si je déplace la zone de séparation centrale, cela agrandit un textbox et diminue le second.


Margin indique la largeur de la séparation.

Orientation permet une séparation horizontale ou verticale.


XVII-E-v. ListView

XVII-E-v-1. WebBrowser:
Pour ouvrir une zone internet.


XVII-E-vi. LayoutPanel:
Permettent de positionner les contrôles dans une Form en conception.

FlowLayoutPanel: Place les contrôles à droite du précédent, passe 'à la ligne' si nécessaire, c'est génial pour créer plusieurs lignes de label, TextBox, Bouton:


TableLayoutPanel:On crée un tableau de panel, puis on met les contrôles dans les cellules:



XVII-E-vii. MenuStrip :
Remplace les MainMenu


On peut même mettre des images dans les menus. Il peut y avoir des combobox et des zones de texte.

Il y a aussi les ContextMenuStrip qui remplace les ContextMenu.


XVII-E-viii. ToolStrip:
Création de barre n'importe ou dans le formulaire.

Exemple de barre de menu comprenant:

Un bouton.

Un label

Un bouton déroulant un menu.

Un comboBox

Une zone texte

Une barre de progression.


Images possible dans les menus, il peut y avoir des séparateurs.


XVII-E-ix. StatuStrip:
Pour créer une barre d'état en bas d'un formulaire; remplace les StatusBar.

Peut contenir des LabelStrip (Label ou LinkLabel), des ProgressBar, DropDownButton et ToolsStripButton.


XVII-E-x. ProgesBarr:

Idem le contrôle de 2003 avec des fonctionnalités en plus:

La propriété Style permet la progression par blocks, en continue, ou en oscillation droite gauche ( comme lors de l'ouverture de Windows XP.

Il y a aussi le toolstripcontainer et un contrôle permettant l'usage port série.


XVII-F. Les nouvelles 'Variables'

VB 2005 prend en charge les types non signés:

UInteger Entier codé sur 32 bits pouvant prendre les valeurs 0 à 4 294 967 295.

ULong Entier codé sur 64 bits :0 à 18 446 744 073 709 551 615

UShort Entier sur 16 bits 0 à 65 535.

et

SByte codé sur 1 octet, valeur de -128 à 127


XVII-G. Les nouvelles 'Collections'

On peut utiliser des collections 'génériques'

System.Collections.Generic.List(Of String)

On peut ainsi créer des collections fortement typées.

Il y a en plus les Collections spécialisées (nouveau type de collection):

L'espace System.Collections.Specialized fournit ce nouveau type de collection:

Exemple: ListDictionary avec Clé et Valeur:

Dim l As New System.Collections.Specialized.ListDictionary


XVII-H. Dans le Code: les nouvelles instructions

  • Continue dans une boucle Do While ou For permet de passer à l'itération suivante sans effectuer le code.

	   While condition

        ..Continue While

       End While
Continue For existe aussi.

  • IsNot simplifie l'écriture:
If Not (Objet1 Is Nothing ) Then..

devient

If Objet1 IsNot Nothing Then

  • Using
Permet de créer un bloc qui libère les ressources en fin de bloc:

	Using sqc As New System.Data.SqlClient.SqlConnection(s)
           	MsgBox("Connected with string """ & sqc.ConnectionString & """")
    End Using
  • TryCast
En plus de CType et de Cast, il y a maintenant TryCast qui retourne Nothing si la conversion est impossible.

  • Procédures avec paramètres différents.
On peut 'overloader' une procédure afin de pouvoir l'appeler avec des paramètres différents.

 	Overloads Sub LireEnregistrement(ByVal Name As String, ByVal amount As Single)

       ' Code permettant de rechercher l'enregistrement à partir du nom.

    End Sub

    Overloads Sub LireEnregistrement(ByVal Numero As Integer, ByVal amount As Single)

    	' Code permettant de rechercher l'enregistrement à partir du numéro

    End Sub

XVII-I. Les nouveautés dans les Classes:

Les classes 'Partielles' sont possible.

		Partial Class MaClasse

        End Class
Ainsi une Classe peut être scindée en plusieurs parties situées dans des endroits différents du code.

On peut surcharger les opérateurs + - * / mais aussi _ ^ & Like And Or Xor Not <>=<<>>Ctype IsTrue, IsFalse

Exemple: surchargeons l'opérateur +

Public Structure height
   ...
Public Shared Operator +(ByVal h1 As height, ByVal h2 As height)As height
      Return New height(h1.feet + h2.feet, h1.inches + h2.inches)
   End Operator
End Structure
La routine doit être Shared, de plus si on surcharge certains opérateurs, il faut aussi surcharger leur inverse: si on surcharge '>' , il faut surcharger '<'.

Surcharge de IsTrue, IsFalse Ctype

Si on teste un boolean, il a la valeur True ou False.

Si par contre je crée une classe nommée 'Personne', je peux définir comment une instance sera considérée comme égale à True. Il faut surcharger l'opérateur IsTrue en lui indiquant dans quelle condition l'instance sera considérée comme =True:

Exemple:

J'ai une instance e de type Personne, si e.Present =True, dans ce cas je veux que e soit considéré comme True; il faut écrire dans la Classe 'personne':

Public Shared Operator IsTrue(ByVal e As Personne) As Boolean

If e Is Nothing Then

   Return False

Else

   Return e.Present

End If

End Operator
Pour définir l'opérateur IsFalse, c'est simple: c'est Not e

Public Shared Operator IsFalse(ByVal e As Personne) As Boolean

    Return Not e

End Operator
Ensuite je pourrais utiliser des instructions de la forme:

If e then..

Surcharge de Ctype:

Je peux définir dans une classe comment CType va fonctionner:

Pour cela dans la classe Personne, je vais définir les 3 possibilités:

Public Shared Widening Operator CType(ByVal e As Personne) As String

Return e.Nom + " " + e.Prenom

End Operator

Public Shared Widening Operator CType(ByVal  e As Personne) As Date

	If e Is Nothing Then

    	Return Nothing

	Else

    	Return e.DateDeNaissance

	End If

End Operator

Public Shared Widening Operator CType(ByVal  e As Personne) As Boolean

    If e Is Nothing Then Return False Else Return e.Present

End Operator
Ainsi

Ctype(UnePersonne,String) retourne Nom Prenon

Ctype(UnePersonne,Date) retourne la date de naissance

Ctype(UnePersonne,Boolean) retourne True ou False.

On peut créer des Property avec une portée différente pour le Set et le Get:

Public Class employee
    Private salaryValue As Double
    Protected Property salary() As Double
        Get
          Return salaryValue
       End Get
      Private Set(ByVal value As Double)
        salaryValue = value
       End Set
  End Property
End Class
Utilisation des 'générics'

Un type 'generic' permet de créer une Classe ayant des Data Types non définis au départ.

Créons une classe MyClasse; Of permet d'indiquer le genéric:

Public Class MyClasse(Of t)
    Public Sub NewItem(ByVal newItem As t)
     Dim tempItem As t
      ' Insert code that processes an item of data type t.
   End Sub
End Class
On peut ensuite utiliser cette classe avec des Integer ou des String:

Public UneClass As New MyClasse(Of Integer)
Friend stringClass As New MyClasse(Of String)
voir la rubrique 'générique' pour le détails.


XVIII. Optimisation en vitesse


XVIII-A. Comparaison VB6 VB.Net

VB.NET est t-il rapide?


XVIII-A-a. Comment VB.NET 2003 est situé en comparaison avec les autres langages de programmation?

Le site OsNews.com publie les résultats d'un petit benchmark comparant les performances d'exécution sous Windows de plusieurs langage de programmation.

Les langages .NET - et donc le code managé en général - n'ont pas à rougir devant Java, pas plus que face au langage C compilé grâce à GCC. Voici un aperçu des résultats chiffrés (valeurs les plus faibles = les meilleures performances) :

int long double trig I/O TOTAL

Visual C++ 9.6 18.8 6.4 3.5 10.5 48.8

Visual C# 9.7 23.9 17.7 4.1 9.9 65.3

gcc C 9.8 28.8 9.5 14.9 10.0 73.0

Visual Basic 9.8 23.7 17.7 4.1 30.7 85.9

Visual J# 9.6 23.9 17.5 4.2 35.1 90.4

Java 1.3.1 14.5 29.6 19.0 22.1 12.3 97.6

Java 1.4.2 9.3 20.2 6.5 57.1 10.1 103.1

Python/Psyco 29.7 615.4 100.4 13.1 10.5 769.1

Python 322.4 891.9 405.7 47.1 11.9 1679.0


Article publier sur www.DotNet-fr.org


XVIII-A-b. VB.NET(2003 ou 2005) est-il plus rapide que VB6?

Exemple No1

Sur une même machine P4 2.4 G faisons tourner un même programme: 2 boucles imbriquées contenant une multiplication, l'addition à un sinus et l'affichage dans un label:

  • En VB6

Private Sub Command1_Click()
Dim i As Long
Dim j As Long
Dim k As Long
For i = 0 To 100
For j = 0 To 1000
Label1.Caption = Str(k * 2 + Sin(4)): Label1.Refresh
k = k + 1
Next
Next
End Sub
9 secondes dans l'IDE , 7 secondes avec un exécutable après compilation.

  • En Vb.Net 2003

Imports System.Math

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim i As Integer
Dim j As Integer
Dim k As Integer
For i = 0 To 100
For j = 0 To 1000
Label5.Text = (k * 2 + Sin(4)).ToString : Label5.Refresh()
k = k + 1
Next
Next
End Sub
35 secondes dans l'IDE, 25 secondes avec un exécutable après compilation.

En utilisant des 'Integer' ou des 'Long', il y a peu de différence.

  • En Vb.Net 2005 beta2
Même code:

55 secondes dans l'IDE, 45 secondes avec un exécutable après compilation.

Dur, dur!!!.

Exemple No2

Sur une même machine P4 2.4 G faisons tourner un même programme: On crée un tableau de 10000 String dans lequel on met des chiffres Puis on trie le tableau.

  • En VB6

Private Sub Command1_Click()

Dim i As Integer
Dim A(10000) As String
Dim j As Integer
Dim N As Integer
Dim Temp As String
N = 9999
'remplir le tableau
For i = 9999 To 0 Step -1
    A(i) = Str(9999-i)
Next i
'trier
For i = 0 To N - 1
    For j = 0 To N - i - 1

       If A(j) > A(j + 1) Then
            Temp = A(j): A(j) = A(j + 1): A(j + 1) = Temp
        End If
 Next j
Next i
End Sub
35 secondes

  • En Vb.Net 2003

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim i As Integer
Dim A(10000) As String
For i = 9999 To 0 Step -1
A(i) = (9999 - i).ToString
Next i
Array.Sort(A)
Label1.Text = "ok"
End Sub
< 1 seconde

  • En Vb.Net 2005 beta2
Même code:

< 1 seconde

Moins d'une seconde avec VB.NET, 35 secondes en VB6.

La méthode 'Sort' est hyper plus rapide que la routine de tri.

(Pour être honnête, il faut dire que mon test n'est pas rigoureux car le tri VB.NET est probablement un tri 'rapide' alors qu'en VB6 la routine basic n'est pas optimisée, je ne compare donc pas les mêmes routines.)

En conclusion:

La couche du Framework semble ralentir considérablement la vitesse du code.

Mais, en VB.net, il faut raisonner différemment et utiliser judicieusement les classes et les méthodes au lieu de taper de longues routines.

Cela fait que en VB.Net:

Le code est plus court et compact (moins de temps de développement)

Le code est plus rapide.


XVIII-B. Chronométrer le code.

On veut comparer 2 routines et savoir laquelle est la plus rapide.

On peut pour compter le temps écoulé:

Utiliser un Timer

Utiliser l'heure système

Utiliser la Classe Environment.Tickcount

Appeler QueryPerformanceCounter, une routine de Kernel32

Utiliser System.Diagnostics.Stopwatch (Framework 2 Vb 2005)


XVIII-B-a. Pour chronométrer une évènement long.

Entendons par évènement long, plusieurs secondes ou minutes.

3 solutions:

- On utilise un Timer, (dans l'évènement Ticks qui survient toutes les secondes, une variable s'incrémente comptant les secondes).(4-5).

- On peut utiliser l'heure Système.

Dim Debut, Fin As DateTime

Dim Durée As TimeSpan

Debut=Now

...Routine...

Fin=Now

Durée=Fin-Debut
(Utiliser Durée.ToString pour afficher)

- On peut utiliser la variable Environment.tickcount()

Dim Debut, Fin As int32

Debut=Environment.tickcount()

...Routine...

Fin=Environment.tickcount()
Durée=Fin-Debut
Cela donne un temps écoulé en ms, sachant toutefois que le compteur de ticks (1tick=100 nanosecondes) n'est mis à jour que toutes les 16ms environ...


XVIII-B-b. Créer un compteur pour les temps très court (Framework 1 , VB2003)

C'est le cas pour chronométrer des routines de durée bien inférieure à une seconde.

Cela semblait à première vue facile!!!

J'ai en premier lieu utilisé un Timer, (dans l'évènement Ticks un compteur de temps s'incrémente) mais les intervalles de déclenchement semblent longs et aléatoires.

J'ai ensuite utilisé l'heure système:

Mais 'Durée' est toujours égal à 0 pour les routines rapides car il semble que Now ne retourne pas les millisecondes ou les Ticks.

J'ai trouvé la solution chez Microsoft:

Utilisation d'une routine de Kernel32 qui retourne la valeur d'un compteur (QueryPerformanceCounter).

De plus QueryPerformanceFrequency retourne le nombre de fois que le compteur tourne par seconde.

Exemple: comparer 2 boucles, l'une contenant une affectation de variable tableau (b=a(2)) l'autre une affectation de variable simple (b=c), on gagne 33%.

Declare Function QueryPerformanceCounter Lib "Kernel32" (ByRef X As Long) As Short

Declare Function QueryPerformanceFrequency Lib "Kernel32" (ByRef X As Long) As Short

Private Sub ButtonGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonGo.Click

Dim debut As Long

Dim fin As Long

Dim i As Long

Dim a(5) As String

Dim b As String

Dim c As String

Dim d1 As Long

Dim d2 As Long

'**********première routine

QueryPerformanceCounter(debut)

For i = 0 To 10000

b = a(2)

Next

QueryPerformanceCounter(fin)

d1 = fin - debut

Label1.Text = d1.ToString

'**********seconde routine

QueryPerformanceCounter(debut)

c = a(2)

For i = 0 To 10000

b = c

Next

QueryPerformanceCounter(fin)

d2 = fin - debut

Label2.Text = d2.ToString

 

Label5.Text = "Gain 2eme routine:" & 100 - Int(d2 / d1 * 100).ToString

End Sub
C'est cette routine qui est utilisée pour étudier l'optimisation du code.

Elle n'est pas parfaite, car sujette à variation: les valeurs sont différentes d'un essai à l'autre en fonction des processus en cours !

Avec VB .Net (version antérieur au Build 1.1.4322.SP1) le problème est catastrophique: 2 routines identiques ne donnent pas les mêmes temps (bug du compilateur VB?).

Il reste que le problème de la variabilité des performances est absolument inévitable puisque Windows est un système préemptif qui peut prendre le contrôle de l'ordinateur à tout moment.

C'est pourquoi la seule façon fiable de faire des tests consiste à avoir une approche expérimentale : on répète la mesure un certain nombre de fois et on fait une moyenne des essais individuels.

Pour des routines très très rapides, une autre façon de faire consiste à effectuer des tests sur de longues durées (en répétant des milliers de fois la routine rapide à l'aide d'une boucle)pour arriver à des temps de plusieurs dizaines de secondes, de manière à diluer les interventions de Windows dans le processus.

Il y a peut-être d'autres solutions?


XVIII-B-c. Créer un compteur pour les temps très court (Framework 2 , VB2005)

Le Framework 2.0 comporte une classe qui encapsule l'utilisation de l' API QueryPerformanceCounter: System.Diagnostics.Stopwatch.

Dim Stopwatch As System.Diagnostics.stopWatch = System.Diagnostics.Stopwatch.StartNew()

' Code à mesurer
Debug.WriteLine(stopWatch.ElapsedMilliseconds.ToString())
La première ligne crée une instance d'un Stopwatch et démarre le compteur.

La propriété ElapsedMilliseconds nous donne le temps mesuré en millisecondes.

On a également la propriété ElapsedTicks pour compter les Ticks (1 Ticks: 100 nanosecondes).

Enfin si l'on veut compter en TimeSpan, utilisons la propriété Elapsed.

On peut arrêter et redémarrer le compteur plusieurs fois.

stopwatch.Stop     'arrête le compteur

stopwatch.Start    'fait redémarrer le compteur

stopwatch.Reset()  'remet le compteur à zéro
				

XVIII-C. Optimiser en vitesse.

L'optimisation est la pratique qui consiste généralement à réduire le temps d'exécution d'une fonction, l'espace occupé par les données et le programme. Elle ne doit intervenir qu'une fois que le programme fonctionne et répond aux spécifications. L'expérience montre qu'optimiser du code avant revient le plus souvent à une perte de temps et s'avère néfaste à la clarté du code et au bon fonctionnement du programme.


XVIII-C-a. Comment accélérer une application VB.net?


XVIII-C-a-i. Utilisation des nouvelles fonctionnalités:
Il faut raisonner différemment et utiliser judicieusement les classes et les méthodes au lieu de taper de longues routines.

Exemple:

La méthode 'Sort' d'un tableau est hyper plus rapide que la routine de tri écrite en code.

Array.Sort(A)
est hyper plus rapide que:

For i = 0 To N - 1
    For j = 0 To N - i - 1

        If A(j) > A(j + 1) Then
            Temp = A(j): A(j) = A(j + 1): A(j + 1) = Temp
        End If

    Next j
Next i
La méthode BinarySearch de la Classe Array est hyper plus rapide que n'importe quelle routine écrite en code pour rechercher un élément dans un tableau trié.

I=Array.BinarySearch(Mois, "Février")

XVIII-C-b. Choix des variables:
Les types de données les plus efficaces sont ceux qui emploient la largeur de données native de la plateforme d'exécution. Sur les plateformes courantes, la largeur de données est 32 bits, pour l'ordinateur et le logiciel d'exploitation.

Sur les ordinateurs actuels et en VB la largeur de donnée native est donc de 32 bits:

Pour les entiers les Integer sont donc les plus rapides car le processeur calcul en Integer . Viennent ensuite les Long, Short, et Byte.

Dans les nombres en virgule flottante, les Double sont les plus rapides car le processeur à virgule flottante calcul en Double, ensuite se sont les Single puis les Decimal.

Si c'est possible utiliser les entiers plutôt que les nombres en virgules flottantes car le travail sur les nombres entiers est beaucoup plus rapide.

Bon choix des unités:

Exemple: pour stocker les dimensions d'une image, on utilisera les pixels: l'image aura un nombre entier de pixels et on peut ainsi utiliser une variable Integer, alors que si on utilise les centimètres on devra travailler sur des fractionnaires donc utiliser par exemple des Singles ce qui est plus lent.

L'usage de constantes est plus rapide que l'usage de variable, car la valeur d'une constante est directement compilée dans le code.

Pour stocker une valeur, une variable est plus rapide qu'une propriété d'objet.

Les variables 'par valeur' peuvent être plus rapide que celle 'par référence'. Les premières sont stockées directement dans la pile, les secondes sur le 'tas':

Si vous utilisez une valeur entière, créer une variable Integer et non une variable Object.


XVIII-C-c. Tableau:
Le CLR est optimisé pour les tableaux unidimensionnel. Employer le moins de dimension possible dans un tableau.

L'usage des tableaux de tableau 'A(9),(9)' est plus rapide que les tableaux multidimensionnels 'A(9,9)'.

Tableau ou Collections?

Pour rechercher un élément dans un ensemble l'élément à partir de son index , utilisez un tableau (l'accès à un élément d'index i est plus rapide dans un tableau que dans une collection)

L'accès a une variable simple est plus rapide que l'accès à un élément d'un tableau:

Si vous utilisez de nombreuse fois à la suite le même élément d'un tableau, le mettre dans une variable simple, elle sera plus rapide d'accès:

Dim a As Integer= P(6)

b=a*3

c=a+2

...

z=a*5
Est plus rapide que:

b=P(6)*3

c=P(6)+2

...

z=P(6)*5
L'usage d'un tableau est plus rapide qu'une multitude de SelectCase ou de If Then:

Exemple: obtenir le nom du mois en fonction de son numéro d'ordre.

Dim Mois() As String ={Janvier,Février,Mars,Avril,Mai,Juin,Juillet}

nomDuMois=Mois(i-1)
Est plus rapide que:

Select Case i

    Case 1

        nomDuMois="Janvier"

    Case 2

        nomDuMois="Février"

    ....

End Select.
Pour rechercher rapidement un élément dans un tableau:

Utiliser la méthode Binaryscearch plutôt que IndexOf.

Pour la méthode Binaryscearch , le tableau doit être trié. (Le trier avant la recherche).

On peut utiliser des méthodes génériques (VB 2005) pour travailler sur les tableaux. c'est beaucoup plus rapide.

Exemple recherche dans un tableau de short nommé monTab l'élément 2

index= Array.indexOf (Of Short)(monTab, 2) est hyper plus rapide que

index= Array.indexOf (monTab, 2) car la première version avec généric est directement optimisée pour les Short.

Il est est de même pour Binarysearch et Sort.

Cela est valable pour les types 'valeur' (peu d'intérêts pour les strings par exemple).


XVIII-C-d. Collections:
Si on ne connaît pas le nombre d'éléments maximum et que l'on doit ajouter, enlever des éléments, il vaut mieux utiliser une collection (ArrayList) plutôt qu'un tableau avec des Dim Redim Preserve. Mais attention une collection est composée d'objets, ce qui implique une exécution plus lente.

Pour rechercher un élément dans un ensemble d'éléments à partir d'un index, utilisez un tableau.

Pour rechercher un élément dans un ensemble d'éléments à partir d'une clé (KeyIndex) , utilisez une collection (l'accès à un élément ayant la clé X est plus rapide dans une collection que dans un tableau; dans une tableau il faut en plus écrire la routine)

En VB2005 on peut utiliser les Collections génériques plus rapides car typées (Les éléments ne sont pas des Objets).


XVIII-C-e. Eviter la déclaration de variables 'Objet' et les liaisons tardives, les variables non typées:
Eviter de créer des variables Objet:

Pour créer une variable et y mettre une String:

Dim A  crée un 'Objet' A
Il est préférable d'utiliser:

Dim A As String
La gestion d'un objet est plus lente que la gestion d'une variable typée.

Il faut aussi éviter les liaisons tardives: Une liaison tardive consiste à utiliser une variable Objet. A l'exécution, donc tardivement, on lui assigne un type, une String ou un Objet ListBox par exemple. Dans ce cas, à l'exécution, VB doit analyser de quel type d'objet il s'agit et le traiter, alors que si la variable a été déclarée d'emblée comme une String ou une ListBox, VB a déjà prévu le code nécessaire en fonction du type de variable. Utilisez donc des variables typées.

Utilisez donc des variables le plus typées possible.

Si une variable doit être utilisée pour une assignation de Button, ListBox... plutôt que la déclarer en Objet, il est préférable de la déclarer en System.Windows.Forms.Control

Utilisez donc des variables ByVal plutôt que ByRef. Les types ByVal sont gérés sur la pile, les types ByRef sur 'le tas' c'est plus long.

De manière générale, si le compilateur sait quel type de variable il utilise, il fait des contrôles lors de la compilation; si il ne sait pas, il fait des contrôles lors de l'exécution et cela prend du temps à l'exécution.


XVIII-C-f. Utiliser les bonnes 'Options':
Option Strict On permet de convertir les variables de manière explicite et accélère le code. De plus on est poussé à utiliser le bon type de variable.

Si on affecte une valeur 'par référence' à un objet, le CLR doit créer un objet, transformer la valeur, la mettre dans l'objet et gérer le pointeur. (On nomme cela 'boxing'), c'est très long. L'inverse c'est du 'unboxing'.

Si on utilise Option Strict Off le boxing se fait automatiquement et systématiquement et c'est long.

Si on utilise Option Strict On, on a tendance (ce qui est bien) à moins utiliser des variables de type différent, ce qui diminue le nombre de boxing-unboxing; et cela oblige si on utilise des variables différentes à caster à l'aide d'instructions qui sont plus rapide.

Donc utiliser Option Strict On et choisir des variables du même type dans une routine afin de réduire au minimum les conversions.

Choisir les méthodes de conversion, quand elle sont nécessaire, les plus typées possible:

Pour les conversions en entier par exemple CInt est plus rapide que CType car CInt est dédié aux entiers.

Option Compare Binary accélère les comparaisons et les tris (la comparaison binaire consiste à comparer les codes unicode des chaînes de caractère).


XVIII-C-g. Pour les fichiers utiliser System.IO:
L'utilisation des System.IO classes accélère les opérations sur fichiers (en effet, les autres manières de lire ou d'écrire dans des fichiers comme les FileOpen font appel à System.IO: autant l'appeler directement!!)

Utiliser donc:

  • Path, Directory, et File
  • FileStream pour lire ou écrire
  • BinaryReader and BinaryWriter pour les fichiers binaires.
  • StreamReader and StreamWriter pour les fichiers texte.
Utiliser des buffers entre 8 et 64K


XVIII-C-h. If..Then ou Select Case?
Plutôt qu'un If Then et une longue série de ElseIf, il est préférable d'utiliser un SelectCase qui en Vb est plus rapide (20%)

Dans les Select Case mettre les 'case'fréquent et qui reviennent souvent en premier, ainsi il n'y a pas besoin de traiter tous les Case:

Select Case Variable

Case Valeur1

... Valeur1 revient souvent

Case Valeur2

...

...

Case Valeur25

... Valeur25 survient rarement

End Select

 

XVIII-C-h-1. If..Then
Plutôt qu'un If B= True Then.. il est préférable d'utiliser un If B Then .. cela va 2 fois plus vite en VB (par en C#). B étant une opération booléenne quelconque.


XVIII-C-i. Utiliser les bonnes 'Opérations':
Si possible:

Utiliser :"\"

Pour faire une vraie division on utilise l'opérateur '/'

Si on a seulement besoin du quotient d'une division (et pas du reste ou du résultat fractionnaire) on utilise '\', c'est beaucoup plus rapide.

Utiliser :"+="

A+= 2 est plus rapide que A= A+2

Utiliser :AndAlso et ElseOr

AndAlso et ElseOr sont plus rapide que And et Or.

(puisque la seconde expression n'est évaluée que si nécessaire)

Arrêter le test lorsqu'on connaît la réponse:

if x<3 And y>15 then
Les 2 expressions sont évaluées x<3 et x>15 puis le And est évalué alors que dès que x<3 on pourrait arrêter de tester.

Solution:

if x<3 then

    If y>15 then

..
Réduire les opérations gourmandes:

Remplacer une multiplication par une addition quand c'est possible.

Les fonctions Sinus Cosinus... sont très gourmandes.

(Je me souviens d'un programme , en QuickBasic!! qui affichait de la 3D; plutôt que de calculer plein de sinus , on allait chercher les sinus stockés dans un tableau; cela entraînait un gain de temps phénoménal.)

Calculer des expressions à l'avance:

- Log(2) est très long à calculer surtout s'il est dans une boucle.

For i=1 to 100000

    R=i*P+ Log(2)

next i
utiliser plutôt le résultat calculé à la main

For i=1 to 100000

    R=i*P+ 0.693147

next i
De même si on utilise un membre d'une classe:

For i=1 to 100000

    R=i*P+ Myobjet.MyPropriété

next i
mettre la valeur de la propriété dans une variable simple, c'est plus rapide:

Dim valeur As Integer = Myobjet.MyPropriété

For i=1 to 100000

    R=i*P+ valeur

next i
- L'accès à un élément d'un tableau est lent:

For i=1 to 100000

    R=i*P+ MyTableau (2 ,3 )

next i
mettre la valeur du tableau dans une variable simple, c'est plus rapide si on utilise cette valeur 10000 fois:

Dim valeur As Integer= MyTableau (2 ,3)

For i=1 to 100000

    R=i*P+ valeur

next i
Pour les conversions utilisez DirectCast plutôt que CType:

CType est moins rapide.

Utiliser les conversion typées plutôt que CType:

Faire d=Cdbl(i) plutôt que d= CType(i, Double)

Cdbl est fait pour convertir en Double alors de Ctype qui converti 'tout' en 'tout' doit analyser en quel type il faut convertir puis appeler les routines correspondantes.


XVIII-C-j. Utiliser :With End With
With.. End With accélère le code:

With Form1.TextBox1

    .BackColor= Red

    .Text="BoBo"

    .Visible= True

End With
est plus rapide que

Form1.TextBox1.BackColor= Red

Form1.TextBox1.Text="BoBo"

Form1.TextBox1.Visible= True
car Form1.TextBox1 est 'évalué' 1 fois au lieu de 3 fois.


XVIII-C-k. Optimiser les boucles:
En mettre le moins possible dans les boucles:

Soit un tableau J(100,100) d'entiers:

Soit un calcul répété 100 000 fois sur un élément du tableau, par exemple:

For i=1 to 100000

    R=i*J(1,2)

next i
On va 100000 fois chercher un élément d'un tableau,c'est toujours le même!

Pour accélérer la routine (c'est plus rapide de récupérer la valeur d'une variable simple plutôt d'un élément de tableau), on utilise une variable intermédiaire P:

Dim P as Integer

P=J(1,2)

For i=1 to 100000

    R=i*P

next i
c'est plus rapide.

De la même manière si on utilise une propriété (toujours la même) dans une boucle, on peut stocker sa valeur dans une variable car l'accès à une variable simple est plus rapide que l'accès à une propriété.

Les opérations qui ne sont pas modifiées dans la boucle doivent donc être mises à l'extérieur.

Eviter les On Error dans des grandes boucles, qui ralentissent considérablement; par contre, contrairement à ce qu'on entend, le Try Catch Finally dans une très grande boucle ralentissent très peu.

Dans une boucle tournant 1000000000 fois:

5 s sans gestion d'erreur.

6 s si la boucle contient Try Catch

2 mn si la boucle contient on error resume next!!

Fusionner plusieurs boucles si nécessaire:

Au lieu de faire 2 boucles:


For i=1 to 100000

    P(i)=i

Next i

For i=1 to 100000

    Q(i)=i

Next i

Faire:

For i=1 to 100000

    P(i)=i

    Q(i)=i

Next i
C'est possible quand les 2 boucles ont même valeur initiale et finale.

En cas de boucles imbriquées placer la boucle la plus grande à l'intérieur:

For i=1 to 100    '100 itérations

For j=1 to 10     '100 X 10 itérations

    ...

Next j

Next i

100+(100X10) = 1100 itérations de compteur

 

For j=1 to 10     '10 itérations

For i=1 to 100    '100 X 10 itérations

    ...

Next j

Next i

10+(100X10) = 1010 itérations de compteur
En conclusion:

(1100-1010)/1100 gain 8% d'itérations de compteur en moins (le nombre de boucle restant égal)

Sortir avec exit for dès qu'on a trouvé ou qu'il n'y a plus rien a chercher.

Exemple: rechercher un élément dans un tableau avec une boucle.

Des que l'élément a été trouvé ou que le tableau ne contient plus rien, on quitte la boucle avec un Exit For.


XVIII-C-l. Appel de procédure:
Si on appelle une petite procédure dans une grande boucle, on a parfois intérêts à mettre le contenu de la procédure directement dans la boucle. Cela évite les appels et retour. C'est plus rapide.

Si on a:

 For i=1 to 100000

        resultat= Calcul(i,j)

    Next i

     

    Functin Calcul (i As Integer, j As Integer)

        i=i+3

        Return i*j

    End Sub

    C'est plus rapide d'écrire:

    For i=1 to 100000

        i=i+3

        resultat= i*j

    Next i

     
Si la procédure est longue et complexe et surtout si on a besoin de l'utiliser à différents endroits dans le programme, il est préférable d'utiliser une procédure.


XVIII-C-m. Usage de thread:
Il peut être judicieux d'utiliser des threads, pour accélèrer certaines applications.


XVIII-C-n. Comment accélérer quand on utilise des 'String':
Utiliser & pour la concaténation de chaîne plutôt que +.

Utiliser:

  s &= "mon" & "ami"
plutôt que:

   s += "mon" + "ami"
Utiliser les StringBuilder.

Exemple d'une opération coûteuse en temps:

 Dim s As String = "bonjour"
     

    s += "mon" + "ami"
En réalité le Framework va créer 3 chaînes en mémoire avec toutes les pertes en mémoire et en temps que cela implique.

Pour effectuer des opérations répétées sur les string, le framework dispose donc d'une classe spécialement conçue et optimisée pour ça : System.Text.StringBuilder.

Pour l'utiliser, rien de plus simple

 Dim sb As new System.Text.StringBuilder()

    sb.Append("bonjour")

    sb.Append("mon ami")

    Dim s As String

    s = sb.ToString()
La méthode ToString de la classe StringBuilder renvoi la chaîne qu'utilise en interne l'instance de StringBuilder.

Pour comparer 2 StringBuilder utiliser la méthode Equals plutôt que =.


XVIII-C-o. Comment accélérer l'affichage?:
Formater le plus vite possible le texte:

Pour mettre en forme des nombres et les afficher Format est puissant (Prise en charge de la culture..), mais si on peut utiliser ToString c'est plus rapide (ToString est aussi plus rapide que Cstr).

ChrW utilisé pour afficher un caractère(et AscW) sont plus rapide que Chr et Asc car ils travaillent directement sur les Unicodes.

Précharger les fenêtres et les données.

Quand une fenêtre en ouvre une autre, le temps de chargement est long, l'utilisateur attend!

Solution:

En début de programme pré charger les fenêtres en les rendant invisible. Lors de l'utilisation de ces fenêtres il suffira de les rendre visible, ce qui est plus rapide que de les charger.

Certaines données (liste..)doivent être chargées une fois pour toute, le faire en début de programme, lors de l'affichage de la fenêtre 'Splach' par exemple.

Afficher les modifications en une fois dans un TextBox:

A chaque fois que l'on fait une modification de propriété (couleur, taille..) ou de contenu (texte dans un TextBox) Vb met à jour chaque modification . Si on modifie tout et que l'on re-affiche tout, cela va plus vite.

Pour le cas du TextBox ne pas faire.

TextBox1.Text = TextBox1.Text + "Bonjour"

TextBox1.Text = TextBox1.Text + ""Monsieur"
faire:

Dim T as string

T = "Bonjour"

T &= "Monsieur"

TextBox1.Text = T
Le texte est affiché en une fois, en plus, cela ne 'clignote' pas.

Rendre l'affichage de l'objet inactif, faire toutes les modifications puis réactiver l'affichage.

Cas d'affichage dans une grid (MsFlexGrid).

Afficher en 2 fois dans une ListBox:

A l'inverse pour ne pas faire attendre un affichage très long, afficher le début (l'utilisateur voit apparaître quelque chose à lire) il est occupé un temps, ce qui permet d'afficher le reste.

Exemple : remplir une listBox avec un grand nombre d'éléments: en afficher 5 rapidement puis calculer et afficher les autres. L'utilisateur à l'impression de voir la ListBox se remplir immédiatement.

Pour les images utiliser le DoubleBuffer.

Pour faire patienter l'utilisateur lors d'une routine qui dure longtemps ?(et lui montrer que l'application n'est pas bloquée):

  • Transformer le curseur en sablier en début de routine, remettre un curseur normal en fin de routine.
  • Utiliser une ProgressBar (pour les chargements longs par exemple)

XVIII-C-p. Utiliser les tableaux en mémoire plutôt que la lecture de fichier sur disque:
On a un fichier de 300 noms, plutôt que de lire 300 enregistrements sur disque pour rechercher le bon, charger en mémoire le fichier dans un tableau( en début de programme); la recherche sera ensuite, dans le tableau en mémoire, extrêmement rapide.


XVIII-C-q. Ce qui n'influence pas la rapidité du code:
Les boucles For , Do , While ont toutes une vitesse identique.


XVIII-C-r. Compilation Dll:
Le chargement de dll est gourmant en temps; moins il y en a, plus c'est rapide.

Les dll ne sont chargées qu'une fois.

La compilation en mode Debug fourni un code plus lent.


XVIII-C-s. En conclusion:
Une optimisation sur une ou deux instructions apporte un gain de temps négligeable.

L'optimisation dans les grandes boucles est perceptible.

Le travail en mémoire plutôt que sur disque accélère considérablement.

Les goulots d'étranglement sont les longues boucles et l'accès aux bases de données.


XIX. Allons plus loin


XIX-A. Les bases binaires, hexadécimales, algèbre de Boole.

Mr Georges Boole 1805-1864
Le Bit, poids d'un bit.

Conversion décimal binaire.

L'octet, Kilo, Méga, Téra-Octet

Opération: L'addition, la multiplication binaire, les nombres négatifs.

Table de vérité.

Fonction logique. Or And, Not, Xor...

Notation.

Ordre des évaluations.

Loi de composition.

Déplacement de bit.

Hexadécimale.

Intérêts en Visual Basic.

A notre disposition Boolean, Integer Byte..

Conversion binaire, décimale, hexadécimale.

Cas particulier: If A then

Les masques de bit

Cryptage par Xor

Travail sur les couleurs, graphiques..

Viewer hexadécimal.


XIX-A-1. Introduction.

L'algèbre de Boole est la partie des mathématiques, de la logique de l' électronique et de l'informatique qui s'intéresse aux opérations et aux fonctions sur les variables logiques. En logique propositionnelle, une expression est soit vraie soit fausse. (le vrai (1) et le faux (0)).

Georges Boole (1815-1864), physicien Anglais définit en 1847 un algèbre qui est applicable au raisonnement logique, qui traite des fonctions à variables binaires (deux valeurs). Mais il ne s'applique pas aux systèmes à plus de deux états d'équilibre.

Une variable booléenne, ou logique, ou binaire ne prend que deux valeurs (elle est généralement stockée sous la forme d'un bit).

Vers la fin des années 30, Claude Shannon démontra qu'à l'aide d'interrupteurs fermés pour « vrai » et ouverts pour « faux » il était possible d'effectuer des opérations logiques en associant le nombre 1 pour « vrai » et 0 pour « faux ».

Ce codage de l'information est nommé base binaire. C'est avec ce codage que fonctionnent les ordinateurs. Il consiste à utiliser deux états (représentés par les chiffres 0 et 1) pour coder les informations.

Il permet d'étudier les circuits logiques.


XIX-A-2. Notions théoriques:

Notion de base:

On utilise diverses bases dans la vie courante:

Pour les heures, minutes, secondes on utilise sans le savoir une base 'soixante':

60 secondes= 1 minute

60 minutes = 1 heure

Si je compte : 1 s, 2s, 3s,...59s, 1mn, 1mn+1 s.....1mn+59s, 2 minutes....59 mn+ 59s, 1h...

En base décimale, on a à notre disposition les caractères 1 2 3 4 5 6 7 8 9.

Si on veut représenter le nombre au dessus de 9, comme on n'a plus de caractère, on recommence avec 1 mais en le décalant vers la gauche pour signifier qu'il s'agit d'une dizaine. On obtient '10'. Le nombre suivant est '11' puis "12'.. Idem pour 100, 1000..

En base binaire, on n'a que le caractère 1 (et le zéro), 1 binaire= 1 décimal.

Si on veut écrire en binaire le nombre au dessus de 1, comme on n'a plus de caractère, on procède de même en décalant vers la gauche le 1:

10 binaire= 2 décimal.

Le nombre suivant est 11 binaire (3 en décimal).

Puis 100 (4 en décimal) car il faut de nouveau décaler.

En base hexadécimale, on a à notre disposition les caractères 1 2 3 4 5 6 7 8 9 A B C D E F.

Aussi 10 décimal = A en hexadécimal

...

15 décimal = F en hexadécimal

16 décimal = 10 en hexadécimal

Si on veut représenter le nombre au dessus de 15, comme on n'a plus de caractères, on recommence avec 1 mais en le décalant vers la gauche pour signifier qu'il s'agit d'une 'seizaine'. On obtient '10' hexadécimal qui correspond à 16 décimal . Le nombre suivant est '11' puis "12' jusqu'a 1F puis 100... 1000..

Utilisons l'analogie des allumettes et des paquets d'allumettes:

En décimal on a des paquets de 10 allumettes.

On compte 1 ,2 ,3..9, 1 paquet de 10, puis 1 paquet + 1 allumette...

On a des gros paquets de 100, des énormes paques de 1000 allumettes..

En binaire on a des paquets de 2 allumettes et des gros paquets de 4 allumettes.

On compte 1 , 1 paquet de 2, puis 1 paquet + 1 allumette, puis 1 gros paquet de 4...

Donc pour compter en binaire: Binaire Décimal

1 allumette. 1 1

1 paquet de 2 10 2

1 paquet de 2 + 1 allumette 11 3

1 gros paquet de 4 100 4

1 gros paquet de 4 +1 allumette 101 5

1 gros paquet de 4 +1 paquet de 2 110 6

....

Le nombre d'allumette qu'il y a dans un paquet se nomme le poids.

En hexadécimal, les paquets sont de 16 allumettes:

On compte 1, 2, 3 ..jusqu'a 15 allumettes puis 1 paquet de 16 puis 1 paquet plus une allumette..

Base binaire:

Soyons maintenant un peu plus scientifique:

Le bit:

Le terme bit (b avec une minuscule) signifie « binary digit », c'est-à-dire 0 ou 1 en numérotation binaire. Il s'agit de la plus petite unité d'information manipulable par un ordinateur.

Physiquement cette information binaire correspond à:

* un signal électrique ou magnétique. (pas de signal=0, au-delà d'un certain seuil de +5V, valeur 1).

* des trous ou pas de trous sur un CD.

* l'état de bistables, c'est-à-dire des composants électroniques contenus dans les circuits intégrés qui ont deux états d'équilibre (état 1, état 0).

Avec un bit il est donc possible d'avoir deux états :

soit 1,

soit 0.

Grâce à 2 bits, il est possible d'obtenir quatre états différents (2*2) :

On peut avec 2 bits , avoir les valeurs: 0, 1, 10, 11 soit 0,1, 2, 3 en décimal.

Avec 3 bits, il est possible d'obtenir huit états différents (2*2*2) de 0 à 7 en décimal:

Avec 4 bits, il est possible d'obtenir huit états différents (2*2*2*2) de 0 à 15 en décimal:

Pour un groupe de n bits, il est possible de représenter 2n valeurs ( de 0 à 2n-1 ).

Avec 8 bits =256 valeurs.

Avec 16 bits=65536 valeurs.

Avec 32 bits=4294967296 valeurs.

Avec 64 bits=18446744073709551616 valeurs.

Avec 8 bits (un octet) on peut représenter un nombre qui peut avoir 256 valeurs différentes:

de 0 à 255

Poids des bits:

Chaque bits a un poids, qui dépend de la position du bit en partant de la droite. Comme les dizaines, les centaines et les milliers pour un nombre décimal, le poids d'un bit croît d'une puissance de deux en allant de la droite vers la gauche:

Remarque : cela est valable pour toutes les bases:

Soit un nombre 'mno' en base b

Le premier chiffre à droite a la valeur: o x b1

Le deuxième chiffre à droite a la valeur: n x b2

Le troisième chiffre à droite a la valeur: m x b3

En allant de la droite vers la gauche le poids croît d'un puissance de b.

Le nombre total est la somme de toutes les valeurs:

o x b1 + n x b2 + m x b3

Conversion:

Pour convertir un nombre binaire en nombre décimal:

Il faut multiplier la valeur de chaque bit par son poids, puis d'additionner les résultats.

Ainsi, le mot binaire 10101 vaut en décimal :

24x1 + 23x0 + 22x1 + 21x0 + 20x1

= 16x1 + 8x0 + 4x1 + 2x0 + 1x1

= 21

Pour convertir un nombre décimal en nombre binaire:

-Méthode des poids:

Soit 21 en décimal.

Il faut connaître les poids (puissance de 2): 2, 4, 8, 16 ,32..

Trouver le premier poids (la première puissance de 2) inférieur au nombre décimal 21 :c'est 16

16 donne en binaire 10000

Faire 21-16 =5

Trouver le premier poids inférieur au nombre 5, c'est 4.

4 donne en binaire 100

Faire 5-4= 1

Quand on atteint 1 (ou 0) on s'arrête.

On additionne 10000

+ 100

+ 1

_____

10101

-Méthode des divisions par 2:

21 /2 = 10 reste 1

10 /2 = 5 reste 0

5 /2 = 2 reste 1

2 /2 = 1 reste 0

1 /2 = 0 reste 1

On prend les restes en commençant par la fin: 10101

Y a t-il une solution plus élégante?

La calculette Windows permet les conversions.

1. Dans le menu Affichagede la calculette, cliquez sur Scientifique.

2. Tapez le nombre décimal que vous souhaitez convertir.

3. Cliquez sur le RadioButton 'Bin' .

Octet, Kilo méga Téra Octet.

L'octet (en anglais Byte ou B) est une unité d'information composée de 8 bits ( 256 valeurs possibles). Il permettait par exemple de stocker le code d'un caractère (une lettre ou un chiffre: 65 indiquant 'A' dans le code ASCII). Il y a quelques années les ordinateurs fonctionnaient avec des octets puis ils ont utilisé 16 bits , 32 bits et maintenant 64 bits. On voit que plus l'unité d'information contient de bits, plus elle pourra contenir des grands nombres.

En informatique, si 8 bits correspond à un octet (Byte), 16 bits est généralement appelée mot (en anglais word), 32 bits correspond à un mot double (en anglais double word, d'où l'appellation dword).

En Visual Basic.Net, les entiers (Integer) sont codés sur 32 bits, les Long sur 64 bits. Les valeurs sont signées (positive ou négative), un bit est donc utilisé pour le signe. Par contre UInteger est un entier non signé codé sur 32 bits pouvant donc prendre les valeurs 0 à 4 294 967 295.

Ko, Mo, Go, To ( kB, MB, GB, TB en anglais)

Pour indiquer la capacité d'une mémoire, on utilisait:

* Un kilooctet (Ko) = 210 octets = 1024 octets

* Un Mégaoctet (Mo) = 220 octets = 1024 ko = 1 048 576 octets

* Un Gigaoctet (Go) = 230 octets = 1024 Mo = 1 073 741 824 octets

* Un Téraoctet (To) = 240 octets = 1024 Go = 1 099 511 627 776 octets

Cela correspondait bien à des puissances de 2, de plus c'était en accord avec les circuits intégrés de mémoire qui avaient bien 1024 octets dans un Ko.

Il parait que depuis 1998 l'IEC a décidé:

* Un kilooctet (Ko ou KB) = 1000 octets

* Un Mégaoctet (Mo ou MB) = 1000 Ko = 1 000 000 octets

* Un Gigaoctet (Go ou GB) = 1000 Mo = 1 000 000 000 octets

* Un Téraoctet (To) = 1000 Go = 1 000 000 000 000 octets

Hors de France, on utilise le nom de « byte » plutôt que le terme « octet ». Cela donne les kilobyte, mégabyte, gigabyte et terabyte : (kB, MB, GB, TB avec un B majuscule)

info
Ne pas confondre Byte B (octet) et bit (bit ou binary digit).

Opérations:

Addition binaire:

L'addition en binaire se fait comme en décimale :

0+1 = 1

1+0 = 1

0+0 = 0

1+1 =10

Pour plusieurs digits, on additionne en commençant par les bits de droite. On a des retenues lorsque la somme de deux bits de même poids dépasse la valeur de l'unité la plus grande (dans le cas du binaire : 1), cette retenue est reportée sur le bit de poids plus à gauche...

C'est ce qui se passe avec 1+1= 10

Autre exemple:

0 1 1 0 0

+ 0 1 1 1 0

- - - - - -

1 1 0 1 0

Soustraction binaire:

La soustraction en binaire se fait comme cela :

100

- 010

_____

010

Mais pour les processeurs il est plus facile d'additionner le complément à 2.

Le complément à 1 c'est le fait d'inverser tous les bits du nombre sur toute sa longueur.

010 donne le complément à 1 suivant: 11111101

(si on travaille sur des octets, on inverse les huit bits)

Le complément à 2, c'est le complément à 1 +1: 11111101+1=11111110

Ajoutons 00000100 à 11111110 cela donne bien 00000010

(la dernière retenue tombe dans le vide)

La table de multiplication en binaire est très simple :

* 0x0=0

* 0x1=0

* 1x0=0

* 1x1=1

La multiplication se fait en formant un produit partiel pour chaque digit du multiplicateur (seuls les bits non nuls donneront un résultat non nul). Lorsque le bit du multiplicateur est nul, le produit partiel est nul, lorsqu'il vaut un, le produit partiel est constitué du multiplicande décalé du nombre de positions égal au poids du bit du multiplicateur.

Par exemple :

1 1 0 1 multiplicande

x 0 0 1 0 multiplicateur

- - - - - -

0 0 0 0

1 1 0 1

0 0 0 0

- - - - - -

1 1 0 1 0

On constate que pour multiplier un nombre par 2, il faut le décaler d'un bit à gauche.

10 binaire multiplié par 2 est égal à 100 (2 x 2=4 en décimal)

Nombres négatifs

On peut utiliser des nombres non signés (contenant une valeur absolue), dans un octet il peut y avoir 256 valeurs (0 à 255)

On peut utiliser des nombres signés (positif ou négatif), on 'code' les nombres négatifs en complément à 2:

Le complément à 1 c'est le fait d'inverser tous les bits du nombre sur toute sa longueur.

010 donne le complément à 1 suivant: 11111101 sur un octet

(si on travaille sur des octets, on inverse les huit bits)

Le complément à 2, c'est le complément à 1 +1: 11111101+1=11111110

On se rend compte que le premier bit à gauche est à 1 pour les nombres négatifs. Dans ce cas on ne peut plus coder que 128 valeurs (sur 7 bits) pour un octet signé.

Table de vérité:

Une table de vérité est un tableau permettant de décrire toutes les possibilités de sorties en fonction des entrées. On place donc les variables d'entrées dans les colonnes de gauche en les faisant varier. La colonne (ou les colonnes si la fonction a plusieurs sorties) de droite décrit le résultat.

Exemple de table de vérités de la multiplication.

L'expression logique correspondante est S= A X B

On retrouve bien par exemple: si les 2 entrées sont 1 et 1 la sortie est 1: en d'autres termes 1 X 1 =1

Exemple des tables de vérités des fonctions logiques:

Pour la fonction And par exemple, l'expression logique correspondante est S= A AND B si les 2 entrées sont 1 et 1 la sortie est 1: en d'autres termes 1 And 1 =1

Comment écrire une fonction logique à partir d'une table de vérité:

Il est possible à partir de la table de vérité d'une fonction d'écrire l'expression algébrique de celle-ci.

Exemple 1:Soit la table de vérité suivante:

La sortie vaut 1 lorsque A vaut 1 et B vaut 0, l'expression logique de cette fonction est donc:

S=A AND NOT B

Exemple 2: Soit la table de vérité suivante:

La sortie vaut 1 lorsque A vaut 1 et B vaut 0 ou lorsque A et B sont à 0, l'expression logique de cette fonction est donc:

S=(A And Not B) Or (Not A And Not B)

En conclusion:

On écrit donc les expressions pour chaque sortie à 1 (avec des And), on les combine avec des Or

Fonction logique:

La loi AND, dite conjonction

Elle est définie de la manière suivante : a And b est égal à 1 si et seulement si a est égal à 1 et b est égal à 1.

On peut construire la table.

« l'un et l'autre »

La loi OR, dite disjonction ou disjonction inclusive

Elle est définie de la manière suivante : a Or b est égal à 1 si et seulement si a est égal à 1 ou b est égal à 1. (notons que si a est égal à 1 et que b est égal à 1 aussi, alors a OU b est égal à 1.)

On peut construire la table:

« l'un ou l'autre ou les deux »

Le contraire, dite négation

Le contraire de "a" égal à 1 si et seulement si a est égal à 0. Le contraire de a est noté Not a

La loi XOR, dite disjonction exclusive

Elle est définie de la manière suivante : a Xor b est égal à 1 si et seulement si a est égal à 1 ou b est égal à 1 mais pas les deux. (notons que si a est égal à 1 et que b est égal à 1 aussi, alors a Xor b est égal à 0.)

On peut construire la table:

« l'un ou l'autre mais pas les deux ».

a Xor b équivalent à (a Or b) And Not( a And b)

a Xor b Xor b = a : si on applique sur a 2 fois Xor b, on retrouve a. C'est une propriété très utilisée.

L'opérateur Équivalence

L'équivalence (notée =) est vraie si les deux entrées ont la même valeur et faux sinon. Elle se compose comme suit :

a=b est égal à Not( a Or b) Or ( a And b)

On peut aussi dire que :

a=b est égal à Not (a Xor b)

Notons la notation utilisée dans les traités d'algèbre de Boole:

+ (addition) équivalent à Or

. (produit) équivalent à And

- au dessus (négation) équivalent à Not

Ordre des évaluations:

Les opérations seront soumises aux mêmes règles que les opérations « de tous les jours », la fonction Not est prioritaire par rapport à And qui est prioritaire par rapport à la fonction Or, enfin on trouve Xor ; on peut, pour s'aider, placer des parenthèses dans les opérations pour forcer l'ordre des opérations.

Exemple :

Dim a As Boolean = 0 
    Dim b As Boolean = 1 
    Dim c As Boolean  1
     
    On cherche a And b Or c

    a And b = 0 
    (0 And 1 = 0)
     
    0 Or c = 1
    (O Or 1 = 1)
Le résultat est donc:

a And b Or c = 1 
Les parenthèses modifient l'ordre des opérations: elles sont prioritaires sur tous:

a And (b Or c) = 0
En VB, compte tenu que les opérateurs logiques et de bits ont une priorité inférieure à celle des opérateurs arithmétiques et relationnels, toutes les opérations au niveau du bit doivent être mises entre parenthèses afin de garantir une exécution précise.

Sur un groupe de bit les opérations s'effectuent bit à bit:

Exemples:

15 décimal 00001111

4 décimal 00000100

15 And 4 = 00000100 --->4 décimal

4 décimal 00000100

2 décimal 00000010

4 Or 2 = 00000110 --->6 décimal

Les lois de composition:

Ce sont des règles logiques qui permettent de simplifier l'écriture des expressions algébriques.

Associativité:

* (A And B)And C est équivalent à A And (B And C) et A And B And C

* (A Or B) Or C est équivalent à A Or (B Or C) et A Or B Or C

Absoption:

* A And (A Or B) est équivalent à A

* A Or A And B est équivalent à A

Commutativité:

* A And B est équivalent à B And A L'ordre est sans importance

* A Or B est équivalent à B Or A

Distributivité:

* A Or(B And C) est équivalent à (A Or B) And (A Or C)

* A And (B Or C) est équivalent à A And B Or A And C

Mais aussi:

* A Or A est équivalent à A

* A And A est équivalent à A

Identité:

* 1 And A est équivalent à A

* 0 Or A est équivalent à A

Inversion:

* A And Not A est équivalent à 0 'A ne peut pas être vrai et faux

* A Or Not A est équivalent à 1

Nullité:

* 0 And A est équivalent à 0

* 1 Or A est équivalent à 1

Théorème de De Morgan

Not (a Or b) est équivalent à Not a And Not b

Dans les deux cas, l'expression ne sera égale à 1 que si a et b sont = 0.

Not( a And b)équivalent à Not a Or Not n

Dans les deux cas, l'expression ne sera =1 que si a ou b sont =0.

Les expressions complexes peuvent donc être simplifiées en utilisant des transformations:

Il existe aussi plusieurs autres opérateurs qui n'ont pas d'équivalent en Visual Basic Net:

Ils existaient en VB6!!

Implication

L'implication (notée IMP) qui n'existe pas en VB.Net s'écrit de la manière suivante :

a IMP b peut s'écrire en VB: Not(a) Or b

Cette opération n'est pas commutative a est une condition suffisante pour b, qui, elle, est une condition nécessaire pour a.

Inhibition

L'inhibition (notée INH) n'existe pas en VB.Net, elle se compose comme suit :

a INH b peut s'écrire en VB: a And Not(b)

Cette opération n'est pas commutative.

Déplacement de bit:

Les opérateurs binaires << et >> effectuent des opérations de déplacement de bits.

L'opérateur << décale à gauche les bits du premier opérande du nombre de positions spécifié. Les bits de poids fort situés en dehors de la plage du type de résultat sont éliminés, et les positions libérées par les bits de poids faible sont remplies par des zéros.

L'opérateur >> décale à droite les bits du premier opérande du nombre de positions spécifié. Les bits de poids faible sont éliminés et, si l'opérande de gauche est positif, les positions libérées par les bits de poids fort sont mises à zéro ; s'il est négatif, elles sont mises à un. Si l'opérande de gauche est de type Byte, les bits de poids fort disponibles sont remplis par des zéros.

A quoi cela sert?

Exemple décaler à gauche un Byte revient à faire une multiplication par 2.

3 en décimal= 11

Je décale à gauche, j'obtient 110 , c'est 3*2=6 en décimal.

Revenons sur la base hexadécimale:

En hexadécimal:

On a 16 caractères: 0, 1, 2, 3 ,4 ...8, 9, A, B, C, D, E, F.

Quand on compte et qu'on arrive à F (15 décimal), on passe à 10 (16 décimal) puis 11...

Voyons la correspondant décimale, hexadécimale, binaire:

Pour un nombre hexadécimal à plusieurs chiffres le poids de chaque chiffre est:

1C en base 16 c'est donc 10+C en hexadécimal = en décimal c'est 161 + 12x 160 = 16 + 12 = 28

Le nombre 28 (en base 10) vaut en base 16 : 1*161 + 12*160 = 1*161 + C*160

c'est-à-dire 1C en base 16.

Le nombre FB4 (en base 16) vaut en base 10 : F*162 + B*161 + 4*160 = 3840 + 176 + 4 = 4020

A quoi sert la base hexadécimale?

C'est une représentation plus imagée de la représentation binaire:

Pour convertir un octet en hexadécimale, on le partage en 2 groupes de 4 bits, qui correspondent chacun à un chiffre hexadécimal.

00101010 c'est un octet en binaire; impossible à retenir en binaire (en décimal on ne voit pas du tout ce qu'il représente en bits). Cet octet, on le coupe en 2 , chaque demi-octet représente 4 bits dont la valeur est comprise entre 0 (0000 en binaire) et F (1111 en binaire, 15 en décimal)

00101010 en binaire= 2A en hexadécimal.

Il suffit de se souvenir des nombres de 1 à 15 en binaire pour se représenter rapidement 2A.

Autre exemple:

HFF = 255 décimal

HFFFF=65535 décimal

Notons que pour signifier qu'on a affaire à un nombre hexadécimal, on ajoute H devant.

L'hexadécimal est donc une manière rapide et mnémotechnique de se représenter des nombres binaires.

Les viewers et éditeurs permettant de voir et modifier les octets contenues dans un fichier affichent les octets en hexadécimal. (voir plus bas)


XIX-A-3. Pratique en Visual Basic.

En Visual Basic.Net, on a à notre disposition

Les Boolean qui peuvent prendre les valeurs True ou False..

Les entiers: Byte contient 8 bits (non signé) pouvant prendre les valeurs 0 à 255: il existe aussi en VB 2005, SByte contenant un octet signé dont les valeurs varient de moins 128 à plus 127.

Les Short 16 bits, les Integer sont codés sur 32 bits, les Long sur 64 bits. Ces valeurs sont signées (positives ou négatives), un bit est donc utilisé pour le signe.

Par contre en VB 2005, UInteger est un entier non signé codé sur 32 bits pouvant donc prendre les valeurs 0 à 4 294 967 295. Ushort et ULong existent aussi. (U comme Unsigned)

Il existe aussi les nombres en virgule flottante ou fixe ( Single, Double, Decimal), ceux là, on ne les utilisera pas pour travailler sur les bits.

Littéral

Un littéral est sensé être en base décimal .

Dim A As Integer = 12 (12 est en base décimale)

On peut forcer un littéral a être un hexadécimal ou un octal: Un nombre hexadécimal est noté avec le préfixe &H , exemple :

A=&HFF

(&O pour octal)

Il n'est pas possible de saisir un littéral en binaire.

Bien comprendre que, en interne, les entiers sont codés en binaire: c'est normal, la mémoire de l'ordinateur et les registres des processeurs sont composés d'octets de 8 bits de Dword de 16 bits et maintenant de 32 et 64 bits contenant des bits positionnés à 0 ou 1.

Dim A As Integer = 12

c'est 12 est en base décimale, c'est notre manière de l'utiliser.

mais c'est 0000000000001100 en mémoire physique, représentation binaire.

c'est 000C en hexadécimal, mais dans une autre base plus pratique, "plus imagée".

C'est toujours le même nombre!!

And Or Xor AndAlso, OrElse

En VB, en plus de And, Or, Xor, existent AndAlso et OrElse qui testent la première valeur puis, si nécessaire, la seconde. Si la seconde valeur n'a pas à être évaluée, est ne le sera pas, c'est un gain de temps.

Pourquoi Xor n'a pas d'équivalent?

Car pour évaluer Xor, il faut d'emblée utiliser les 2 valeurs.

Comment réagit VB avec les Booléens, les entiers?

*

Si A et B sont des expressions Booléens (valeur True ou False uniquement):

IF A>=2 And A<=5 Then..

Les expressions booléennes sont évaluées et on a comme résultat True ou False.

* Si A et B sont des nombres entiers (Integer= 32 bits, Long=64 bits, Short=16 bits, Byte=8 bits par exemple):

L'opération est effectuée sur chaque bit de l'équivalent binaire, le résultat binaire est affiché en décimal.

A = 7 'en décimal ( 0111 en binaire)

B = 12 'en décimal( 1100 en binaire)

A And B = 4 'en décimal( 0100 en binaire)

*

Si A et B sont des nombres en virgule flottante (Single, Double par exemple), ils sont codés sous la forme de mantisse plus exposant, une opération logique devrait produire un résultat aberrant. Ils sont convertis en Long avant évaluation si Option Strict= Off:

Dim a As Single = 7

Dim b As Single = 12

Dim c As Boolean = True

MsgBox(a And b) 'affiche '4' car 7 et 12 sont transformés en Long (si Option Strict=Off)

si Option Strict=On Levée d'une exception.

info
Un conseil: utiliser des Booléens quand vous voulez effectuer des opérations logiques, des entiers quand vous travaillez sur les bits.

Conversion Binaire, hexadécimale, décimal:

L'affichage d'un entier se fait en décimal par défaut si on utilise la méthode ToString:

Dim a As Integer =&HFF   Littéral en hexadécimal

MsgBox (a.ToString)      Affiche  '255' décimal
On peut surcharger la méthode et afficher en hexadécimal:

Dim a As Integer = 255

MsgBox(a.ToString("X"))  Affiche 'FF'
On peut afficher en hexadécimal et décider le nombre de digit affiché:

Dim a As Integer = 255

MsgBox(a.ToString("X4")) Affiche '00FF'
En utilisant la classe Convert, on peut même afficher en base binaire, octale, décimal, hexadécimal.

Convert.ToString(Int64, base) Convertit la valeur d'un entier signé 64 bits en sa représentation String équivalente dans une base 'base' spécifiée (base 2, 8, 10, 16).

Dim d As Long = 3

Dim r As String

r= Convert.ToString(d, 2)) 'convertit la valeur Long de "d" en base 2

d= 3 donne r="11" binaire

Si on avait eu une String "3" on l'aurait convertie en Long grâce à CLng(d)

Convert.ToInt64(s, base) 'convertit en type int64(long en base 10) la valeur de la String 's' à partir d'une base 'base'.

Dim d As String = "111"

Dim r As Long

r= Convert.ToInt64(d, 2)) 'convertit d (string représentant un binaire) en Long

cela donne r=7

Enfin dans l'espace Visual Basic l'instruction Hex donne la représentation hexadécimale d'un nombre , ( Oct existe aussi)

str=Hex(456) retourne 1CB

Conversion String en Byte:

Conversion String en Bytes:


    Dim str As String= ".."
    Dim encoding As New System.Text.ASCIIEncoding()
    Dim Bytes() As Byte()= encoding.GetBytes(str)
Conversion Bytes en String:

Dim Bytes As Byte() = ...
Dim str As String
Dim enc As New System.Text.ASCIIEncoding()
str = enc.GetString(Bytes)
Enregistrement d'un tableau de Bytes:

1 - En mémoire: (dans un mémoryStream)

Imports System.IO

...   

        ' Creation d'un tableau de Byte.
        Dim dataArray(1000) As Byte

        ' On le remplit avec des nombres aléatoires.
        Dim randomGenerator As New Random
        randomGenerator.NextBytes(dataArray)
Ecriture

Dim binWriter As New BinaryWriter(New MemoryStream())

      ' Ecrire les données dans la mémoire.
   
       binWriter.Write(dataArray)
Lecture

 ' Créer un reader en utilisant le stream du Writer
        Dim binReader As New BinaryReader(binWriter.BaseStream)

        ' mettre la position au début du stream.
        binReader.BaseStream.Position = 0

        ' Relecture dans verifyArray.
        Dim verifyArray() As Byte = binReader.ReadBytes(dataArray.Length)
       
2 - Dans un fichier:

...

Dim fs As New FileStream(FILE_NAME, FileMode.CreateNew)

Dim w As New BinaryWriter(fs)
w.Write(datArray)

w.Close()
fs.close
Le Framework 2 permet une écriture encore plus simple pour lire écrire les octets d'un fichier:

Lire et mettre dans un tableau les octets d'un fichier? (Framework 2)

Dim myBytes() As Byte =File.ReadAllBytes("c:\monText.txt")

Il existe aussi WriteAllByte.

Précision sur 'If a Then'

Avec des valeurs numériques si

* a=0, a est évalué comme False le programme se poursuit après Then;

* si a est différent de 0 (1, -1, 45,...) a est considéré comme True et le programme se poursuit après Then.

Donc

Dim a As Integer =15

If a  Then..
C'est une mauvaise méthode!! Il vaut mieux écrire

Dim a As Integer =15

If a <>0 Then..
Avec une expression Booléenne par contre, on peut écrire:

Dim a As Boolean= True

    If a = True Then..

    ou

    If a Then..
Exemple:

 If (x=15)=True  Then..

    ou If x=15 Then...
Avec une expression booléenne, et uniquement avec une expression booléenne, il est possible de se passer du = True après un If car de toutes façons , l'expression est évaluée.

Masque de bit:

Or permet d'écrire un bit à 1:

Soit un entier, on veut forcer un des bits à 1 , la solution est de faire un Or avec un entier ayant ce seul bit à 1.

Exemple : Mettre le deuxième bit de 00000100 (4 en décimal) à 1

Il faut faire un Or avec 00000010.

Le poids du deuxième bit est 2, c'est le 'mask bit'.

4 Or 2 = 6

00000100 Or 00000010 = 00000110

En faisant Or 2, on a bien mis le deuxième bit à 1.

Le masque est toujours une puissance de 2.

Or 8 met le quatrième bit à 1

And permet de tester un bit

A And 1 indique si le bit le moins significatif (le plus à droite) est a 1

Exemple: si A = 7 'en décimal ( 0111 en binaire) A And 1 retourne 1

A And 8 indique si le quatrième bit est a 1 (8 est le poids du quatrième bit).

Exemple: si A = 7 'en décimal ( 0111 en binaire) A And 8 retourne 0

8 c'est le 'mask bit' (00001000) du quatrième bit.

A And 8 peut ensuite être évalué comme une expression booléenne:

If A and 8 Then ' Si le quatrième bit de A est à 1 alors,

And permet aussi de forcer à 0 une partie des bits et de ne conserver que la valeur de certains bits:

Soit une couleur codée sur 24 bits; les 8 bits à droite code la composante bleu, Je veux conserver uniquement ces 8 bits de droite (l'octet de droite):

myColor And &HFF conserve le premier octet mais met les 2 autres à 0:

MyColor=0010 0100 1000 0010 0010 0000

And 0000 0000 0000 0000 0000 1111

= 0000 0000 0000 0000 0010 0000

Le masque correspond au bits à conserver.

Xor permet de forcer un bit à 0

Pour mettre le 4eme bit à 0:

Il faut faire un Xor avec 00001000.

Le poids du deuxième bit est 2, c'est le 'mask bit'.

12 Xor 8 = 4

00001100 Or 00001000 = 00000100

Exemple pratique:

Comment stocker plusieurs valeurs dans une variable en utilisant un masque.

Souvent, plutôt que de coder une information par octet, on peut coder une information par bit et ainsi coder 8 informations par octet.

Le paramètre d'une fonction est, par exemple, composé d'un entier ou chaque bit à une signification.

Exemple fictif :

00000001 le premier bit à 1 signifie gras (1 en décimal)

00000010 le deuxième bit à 1 signifie l'italique (2 en décimal)

00000100 le troisième bit à 1 signifie le soulignage. (4 en décimal)

Si je veux envoyer les paramètres gras et souligné, j'enverrais le paramètre 1 Or 4 qui correspond a 00000101. Les bits 1 et 3 sont bien à 1.

On note bien que chaque paramètre doit être une puissance de 2.

C'est plus clair de créer une énumération:

<Flags()> Enum Car

    Normal=0

    Gras= 2

    Italique= 4

    Souligne= 8

End Enum
Si je veux envoyer les paramètres gras et souligné, j'enverrais le paramètre Car.Gras Or Car.Souligne

<Flags()> indique qu'on travaille bien sur des bits.

Souvent les valeurs sont proposées par VB, comme par exemple quand on utilise MsgBox; le deuxième paramètre qui indique le style peut comporter plusieurs indications séparées par des Or:

reponse= MsgBox(msg, MsgBoxStyle.DefaultButton2 Or  MsgBoxStyle.Critical Or MsgBoxStyle.YesNo, Title)
Pour lire un bit en retour d'une fonction, on utilisera And:

Si reponse And Car.Italique =1
c'est que le second bit de reponse est à 1.

Bien que ce soit une opération sur les bits on écrit souvent:

If reponse And Car.Italique Then...
Cryptage simple par Xor

La technique la plus simple est d'appliquer un « OU exclusif » (XOR) entre le texte à chiffrer et la clé.

Pour obtenir le message crypté on effectue Message Xor Cle (si la clé fait x octets on effectue le Xor entre le premier octet du message et le premier de la clé, puis le deuxième.. quand on arrive à x+1 caractère du message, on recommence au premier caractère de la clé).

Comme Message Xor Cle Xor Cle =Message, pour déchiffrer le message codé, il suffit de faire de nouveau un Xor avec la clé.

La clé est donc la même pour coder et décoder, on appelle cela une clé symétrique.

Bien sur, si on utilise un texte comme clé et comme message, c'est le code du caractère qui est utilisé.

Travail sur les couleurs:

Les valeurs RVB (couleurs) sont stockées dans trois octets de 8 bits, conduisant à une couleur à 24 bits, chaque octet correspondant respectivement au rouge, au vert et au bleu.

rrrr rrrr vvvv vvvv bbbb bbbb

Comment récupérer la composante rouge verte ou bleue?

Dim myColor As Integer = 15963245
'Un Integer a 32 bits , les 24 premiers sont utilisés.

Dim R, V, B As Byte
 
Pour le rouge:

R = myColor >> 16
On décale de 16 bits vers la droite: 0000 0000 0000 0000 rrrr rrrr

Pour le vert:

V = (myColor And &HFF00) >> 8
On fait un And &HFF00 ce qui met le premier et le troisième octet à 0 0000 0000 vvvv vvvv 0000 0000

On décale de 8 bits vers la droite: 0000 0000 0000 0000 vvvv vvvv

Pour le bleue:

B = (myColor And &HFF)
On fait un And &HFF ce qui met le premier et le second octet à 0

0000 0000 0000 0000 bbbb bbbb

(En Vb on peut faire plus simple)

Travail sur les graphiques:

Un mode souvent utilisé pour la réalisation d'interfaces est le mode XOR. Ce mode permet d'effacer facilement un cadre de sélection en le redessinant une seconde fois à la même position.

Si l'on a un écran noir et blanc pour lequel 1 = noir et 0 = blanc et que l'on affiche une forme en noir, chaque pixel appartenant à la forme est inversé à l'écran puisque 1 xor p = not p. Donc si l'on dessine la forme deux fois, chaque pixel est inversé deux fois et revient donc dans son état initial.

Par contre, sur un écran couleur, les résultats sont imprévisibles. Si le noir est représenté par la valeur de pixel 1111 et que l'on dessine en xor sur un pixel de valeur 1001, le résultat est un pixel de valeur 1111 xor 1001 = 0110. La couleur résultante est alors imprévisible : on obtient un effet "technicolor".

En VB on a d'autres fonctions sur les graphiques.


XIX-A-4. Viewer Hexadecimal

Comment voir le contenu d'un fichier en hexadécimal?

C'est très simple et VB 2005:

On utilise un composant ByteViewer

Charger la référence System.design.Dll

Puis entrer le code dans Form_Load:

Private Sub Form1_Load() Dim viewer As New System.ComponentModel.Design.ByteViewer()

Dim viewer As New System.ComponentModel.Design.ByteViewer

Me.Controls.Add(viewer)

viewer.Dock = DockStyle.Fill

Dim ofd As New OpenFileDialog 'Choix d'un fichier

If ofd.ShowDialog() = Windows.Forms.DialogResult.OK Then viewer.SetFile(ofd.FileName)

End Sub
Si vous avez déjà un tableau de bytes, utilisez sa méthode SetBytes .

Vous pouvez même choisir son mode d'affichage (Ansi, Unicode, Hexadump ou automatique) avec sa méthode SetDisplayMode.

Second exemple:

Ouvrir un fichier image .jpg le charger dans un tableau de Bytes et l'afficher:

Dim viewer As New System.ComponentModel.Design.ByteViewer

Me.Controls.Add(viewer)

viewer.Dock = DockStyle.Fill

Dim ofd As New OpenFileDialog

ofd.ShowDialog()

Dim img As Image = Image.FromFile(ofd.FileName)

Dim mstImage As IO.MemoryStream = New IO.MemoryStream

img.Save(mstImage, System.Drawing.Imaging.ImageFormat.Jpeg)

Dim bytImage As Byte() = mstImage.GetBuffer

viewer.SetBytes(bytImage)
Fait à partir d'un article de c2i en C#


XIX-A-5. Editeur hexadecimal:

On peut écrire en VB.Net un éditeur hexadécimal de fichier (lecture du fichier, visualisation en hexa et ascii, modification d'un octet:

Voir le lien suivant:


Pour que le source marche , ne pas oublier de générer puis mettre les fichiers vb dans MyProjet et les fichiers ressources dans le répertoire de ressources.


XIX-B. Comprendre le code crée par VB

Comprendre le code crée par VBquand on crée une formulaire ou un contrôle.


XIX-B-1. Code généré automatiquement lors de la création d'un formulaire ou d'un contrôle.

Une application 'Windows Forms' est principalement constituée de formulaires (ou fenêtre), de contrôles et de leurs événements.

Effectivement, pendant la création de l'interface utilisateur de votre application, vous créez généralement une fenêtre contenant des contrôles et des procédures évènements.

Quand vous créer un nouveau projet 'Windows Forms' cela dessine un formulaire, une fenêtre vide et le code correspondant. Ajoutons y un bouton cela donne l'interface utilisateur suivante:

Comme on l'a vu, VB crée le code correspondant et dans ce code une Classe correspondant à la fenêtre

Décortiquons le code:

Vb crée une Class nommé Form1, elle est public (accessible partout)

Public Class Form1

 

End Class
En VB.Net 2003:

L'onglet Form1.vb contient la Class.

Cette Classe hérite des propriétés de la Classe Form (celle ci est fournis par le Framework)

Inherits System.Windows.Forms.Form
(On rappelle que la véritable fenêtre, l'objet sera instancié à partir de cette classe)

Ensuite il y a une région (partie du code que l'on peut 'contracter' et ne pas voir ou 'dérouler'; Cette région contient :" Le Code généré (automatiquement) par le Concepteur Windows Form ", si on le déroule en cliquant sur le '+', on voit:

-Le constructeur de la fenêtre: la routine Sub New

MyBase fait référence à la classe de base,

MyBase.New appelle le constructeur de la classe de base (Form dans notre cas)

-Le destructeur de la fenêtre: la routine Sub Dispose

-Le créateur des contrôles de la fenêtre: la procédure Sub InitializeComponent

Elle est nécessaire pour créer les contrôles et définir les propriétés de ces contrôles:

Exemple : création d'un label Me.Label1= NewSystem.Windows.forms.Label

Modification d'une propriété:Me.Label.Text="Hello"

Elle définie aussi les propriétés du formulaire:

  Me.Name = "Form1"
Exemple d'un formulaire vide nommé Form1

Public Class Form1

Inherits System.Windows.Forms.Form

#Region " Code généré par le Concepteur Windows Form "

Public Sub New()

MyBase.New()

'Cet appel est requis par le Concepteur Windows Form.

InitializeComponent()

'Ajoutez une initialisation quelconque après l'appel InitializeComponent()

End Sub


'La méthode substituée Dispose du formulaire pour nettoyer la liste des composants.

Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

If disposing Then

If Not (components Is Nothing) Then

components.Dispose()

End If

End If

MyBase.Dispose(disposing)

End Sub

'Requis par le Concepteur Windows Form

Private components As System.ComponentModel.IContainer

'REMARQUE : la procédure suivante est requise par le Concepteur Windows Form

'Elle peut être modifiée en utilisant le Concepteur Windows Form.

'Ne la modifiez pas en utilisant l'éditeur de code.

<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

'

'Form1

'

Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)

Me.ClientSize = New System.Drawing.Size(292, 266)

Me.Name = "Form1"

Me.Text = "Form1"

End Sub

#End Region

 

End Class

 
Si dans la fenêtre Design on ajoute un bouton Button1 cela ajoute le code:

Cette ligne contenant WithEvents indique qu'il y a une gestion d'évènement sur les boutons.

Friend WithEvents Button1 As System.Windows.Forms.Button
Puis dans Sub InitializeComponent()

Cette ligne créée le bouton.

Me.Button1 = New System.Windows.Forms.Button
Cette ligne le positionne:

Me.Button1.Location = New System.Drawing.Point(56, 144)
Cette ligne lui donne un nom.

Me.Button1.Name = "Button1"
Cette ligne détermine sa taille

Me.Button1.Size = New System.Drawing.Size(104, 24)
Cette ligne indique ce qui est affiché sur le bouton

Me.Button1.Text = "Button1"
Cela donne:

Private components As System.ComponentModel.IContainer

Friend WithEvents Button1 As System.Windows.Forms.Button

<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

Me.Button1 = New System.Windows.Forms.Button

Me.SuspendLayout()

'

'Button1

'

Me.Button1.Location = New System.Drawing.Point(56, 144)

Me.Button1.Name = "Button1"

Me.Button1.Size = New System.Drawing.Size(104, 24)

Me.Button1.TabIndex = 0

Me.Button1.Text = "Button1"
En VB.Net 2005:

L'onglet Form1.vb contient:

Public Class Form1

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

End Sub

Public Sub New()

' This call is required by the Windows Form Designer.

InitializeComponent()    '<=======Appel d'une routine qui 'initialise les composants de la form

' Add any initialization after the InitializeComponent() call.

End Sub

Protected Overrides Sub Finalize()

MyBase.Finalize()

End Sub

Private Sub Label1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Label1.Click

End Sub

 
Le Code généré par le 'Concepteur Windows Form' est par contre caché, il n'apparaît pas dans la Class Form1, il faut pour y avoir accès, passer par le menu de droite:

Si on clique sur InitializeComponent, l'onglet Form1.Designer.vb apparaît.

On a ainsi accès à InitialiseComponent et à Dispose qui sont dans une classe Partielle de Form1.

(En VB 2005, une Classe peut être 'découpée' en Classes partielles)

C'est ici qu'il est indiqué que la Class hérite de System.Windows.Forms.Form

Exemple du contenu de Dispose et ItinialiseComponent:

Partial Public Class Form1

Inherits System.Windows.Forms.Form

'Form overrides dispose to clean up the component list.

<System.Diagnostics.DebuggerNonUserCode()> _

Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

If disposing AndAlso components IsNot Nothing Then

components.Dispose()

End If

MyBase.Dispose(disposing)

End Sub

'Required by the Windows Form Designer

Private components As System.ComponentModel.IContainer

'NOTE: The following procedure is required by the Windows Form Designer

'It can be modified using the Windows Form Designer.

'Do not modify it using the code editor.

<System.Diagnostics.DebuggerStepThrough()> _

Private Sub InitializeComponent()

Me.Button1 = New System.Windows.Forms.Button

Me.Label1 = New System.Windows.Forms.Label

Me.SuspendLayout()

'

'Button1

'

Me.Button1.FlatStyle = System.Windows.Forms.FlatStyle.System

Me.Button1.Location = New System.Drawing.Point(47, 38)

Me.Button1.Name = "Button1"

Me.Button1.Size = New System.Drawing.Size(177, 42)

Me.Button1.TabIndex = 0

Me.Button1.Text = "Button1"

...

 

 
Pour VB.Net 2003 et 2005:

Les procédures évènements correspondant au formulaire par exemple sont automatiquement créées:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

End Sub
Attention : Form1_Load est un nom de Sub donné par VB, mais cela pourrait être n'importe quoi, ce qui indique l'évènement déclencheur est ce qui est après Handles ( MyBase.Load ici).

Les 2 paramètres sont:

sender l'objet à la source de l'événement (l'objet quia déclenché l'évènement: ici la form)

e un objet EventArgs qui détaille l'événement qui s'est produit et fournissant des informations sur cet évènement.

On constate qu'il y a une liaison entre la fenêtre Design et le code généré; on pourrait modifier dans le code l'interface utilisateur. C'est déconseillé d'aller trafiquer dans cette zone de "Code généré par le Concepteur Windows Form ", il faut mieux faire des modifications dans la partie design et dans la fenêtre de propriété.


XIX-B-2. Substitution de procédures évènement:

Il est possible de substituer une méthode (utiliser sa propre méthode à la place de la méthode normale qui existe normalement dans un contrôle)

Exemple 1 créer un contrôle simple affichant toujours 'Bonjour'

Il faut créer une classe héritant des 'Control', détourner son évènement OnPaint qui dessine le contrôle ( avec Overides) Dans la nouvelle procédure On Paint simplement afficher 'Bonjour'

Public Class ControleAffichantBonjour

Inherits Control

Overrides Protected Sub OnPaint ( e As PaintEventArgs )

    e.Graphics.DrawString ("Bonjour", Font, new SolidBrush(ForeColor)

End Sub

End Class
Cet exemple ne sert strictement à rien!! Pour une fois!!

Il est aussi possible de détourner des évènements.

Dans le chapitre 'Impression' il y a un bel exemple de création de "lien" entre un objet printdocument et la routine évènement PrintPage (imprimer hello avec un printdocument)

Exemple 2 créer un bouton personalisé.

1-Il faut créer une classe qui hérite de Button:

Public Class MonBouton

Inherits System.Windows.Forms.Button

End Class
Le 'Design' devient:

2-Il faut modifier l'aspect graphique du bouton:

Pour cela si vous voulez modifier l'apparence du contrôle, il faut remplacer la méthode OnPaint de Button par la votre(celle-ci dessine le contrôle). Au sein de cette méthode, vous devez appeler la méthode OnPaint de la base (de la classe mère), puis ajouter vos propres fonctions de dessin.

Il faut donc ajouter dans la classe, la procédure:

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)

MyBase.OnPaint(e) 'Appel à la méthode de la classe de base, ce qui dessine le bouton

Dim myPen As New Pen(Color.Purple, 3)

e.Graphics.DrawRectangle(myPen, 3, 3, Me.Width - 6, Me.Height - 6) 'Ajoute un cadre sur le dessin du bouton

End Sub
On rappelle que l'argument e est le graphique du bouton.

Dans le chapitre suivant on va utiliser ces connaissances pour, dans le code, créer soi-même des contrôles et leurs évènements.


XIX-C. Créer des contrôles par code

Dans le code, on peut créer soi-même de toutes pièces, des contrôles et leurs évènements.


XIX-C-1. Créer par code des contrôles.

Dans le code d'une procédure, il est possible de créer de toute pièce un contrôle, mais attention, il faut tout faire!!

Créons le bouton.

Dim Button1 As New Button
Modifions ses propriétés

Me.Button1.Location = New System.Drawing.Point(56, 144)

Me.Button1.Name = "Button1"

Me.Button1.Size = New System.Drawing.Size(104, 24)

Me.Button1.TabIndex = 0

Me.Button1.Text = "Button1"
Le bouton existe mais il faut l'ajouter à la collection Controls de la fenêtre (Cette collection contient tous les contrôles contenus dans la fenêtre):

Me.Controls.Add(Button1)

XIX-C-2. Ajouter des évènements.

Le bouton existe mais pour le moment, il ne gère pas les évènements.

Il faut inscrire le bouton dans une méthode de gestion d'évènements. En d'autres termes, Vb doit savoir quelle procédure évènement doit être déclenchée quand un évènement survient. Pour cela, il y a 2 méthodes:

* Déclarer la variable avec le mot clé WithEvents ce qui permet ensuite d'utiliser le Handles du contrôle dans la déclaration d'une Sub:

Déclaration dans la partie déclaration du module(en haut) (WithEvents n'est pas accepté dans une procédure):

 Private WithEvents Button1 As  New Button
Remarque Button1 est accessible dans la totalité du module .

Puis écrire la sub évènement.

 Sub OnClique ( sender As Object, EvArg As EventArgs) Handles Button1.Click

        End Sub 
Ainsi VB sait que pour l'évènement Button1.Click , il faut déclencher la Sub OnClique.

Il semble que quand on fait:Private WithEvents Button1 As Button (sans New) dans la partie déclaration puis DIM Button1 As New Button dans une procédure, la Sub OnClique ne fonctionne pas!!

C'est un problème de 'visibilité' donc bien faire Private WithEvents Button1 As New Button

Remarque: il pourrait y avoir plusieurs Handles sur une même sub, donc des évènements différents sur des objets différents déclenchant la même procédure.

* Utiliser AddHandler

Déclaration (possible dans une procédure):

 Dim Button1 As New Button

        Puis écrire la gestion de l'évènement.( L'évènement Button1.click doit déclencher la procédure dont l'adresse est BouttonClique)

        AddHandler Button1.Click, AddressOf  BouttonClique

        (ne pas oublier la virgule avant AddressOf)

        Enfin on écrit la sub qui 'récupère ' l'évènement:

        Private Sub BouttonClique (sender As Object, evArgs As EventArgs)

        End Sub 
Ainsi VB sait que pour un évènement du Button1 , il faut déclencher la Sub ButtonClique

Exemple avec AddHandler:

Créons un TextBox nommé TB et une procédure déclenchée par KeyUp de ce TextBox:

Dans une procédure (Button1_Click par exemple): Je crée un TextBox nommé TB, je le positionne, je met dedans le texte 'ici une textbox'. Je l'ajoute aux Contrôles du formulaire.

Grâce à 'AddHandler', je lie l'évènement Keyup de cet objet TB à la sub que j'ai crée :TextboxKeyup.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    Dim TB As New System.Windows.Forms.TextBox

    TB.Location = New System.Drawing.Point(2, 2)

    TB.Text = "ici une textBox"

    Me.Controls.Add(TB)

    AddHandler TB.Keyup, AddressOf TextboxKeyup.

End sub

 

Sub TextboxKeyup.(ByVal sender As Object, ByVal e As KeyEventArgs)

...

End Sub
Si je crée un autre bouton TB2, j'ajoute de la même manière AddHandler TB2.Click, AddressOf TextboxKeyup2, ainsi chaque évènement de chaque contrôle à ses propres routines évènement et en cliquant sur le bouton TB2 on déclenche bien TextboxKeyup2

Attention, la procédure TextboxKeyup doit recevoir impérativement les bons paramètres: un objet et un KeyEventArgs car ce sont les paramètres retournés par un KeyUp.

Autre exemple avec AddHandler mais avec 2 boutons:

Il est possible de créer plusieurs contrôles ayant la même procédure évènement:

Exemple: Créons 2 boutons (BT1 et BT2) déclenchant une seule et même procédures (BoutonClique).

Dans ce cas, comment savoir sur quel bouton l'utilisateur à cliqué ?

En tête du module déclarons les boutons (Ils sont public):

Public BT1 As New System.Windows.Forms.Button

Public BT2 As New System.Windows.Forms.Button
Indiquons dans form_load par exemple la routine évènement commune (BoutonClique) grâce a AddHandler.

Form_Load

    BT1.Location = New System.Drawing.Point(2, 2)

    BT1.Text = "Bouton 1"

    Me.Controls.Add(BT1)

    BT2.Location = New System.Drawing.Point(100, 100)

    BT2.Text = "Bouton 2"

    Me.Controls.Add(BT2)

    AddHandler BT1.Click, AddressOf BoutonClique

    AddHandler BT2.Click, AddressOf BoutonClique

End Sub
Si c'est le bouton 1 qui a été cliqué, afficher "button1" dans une TextBox:

Sub BoutonClique(ByVal sender As Object, ByVal e As EventArgs)

    If sender Is BT1 Then

      TextBox1.Text = "button 1"

    ElseIf sender Is BT2 Then

      TextBox1.Text = "button 2"

    End If

End Sub
La ruse est que déterminer quel objet (quel bouton) à déclenché l'évènement, pour cela on utilise le premier paramètre, le sender;

If sender Is BT1 Then  : Si le sender est le bouton1..
Noter bien:

- le mot clé handles permet d'associer un événement à une procédure au moment de la conception.

Le concepteur sait qu'une procédure doit gérer les événements (il peut y en avoir plusieurs).

- le mot clé addhandler permet d'associer un événement à une procédure au moment de l'exécution.

Ceci est utile dans un cadre producteur-consommateur d'événements. Un objet produit un événement qui doit informer d'autres objets; au cours de l'exécution on crée l'association entre l'évènement et une procédure.

Remarque importante:

Les Handler ne sont en fait libérés qu'au déchargement complet du programme (application.exit) et non à la fermeture de la fenêtre et des objets contenus dans celle-ci... Aussi , si vous ouvrez plusieurs fois un même formulaire possédant AddHandler sur un bouton, cela créera à chaque fois un Handler qui s'ajoute aux précédents et l'évènement se déclenchera plusieurs fois lors de l'appuie du bouton!!

Il faut donc utiliser RemoveHandler pour libérer le Handler. L'instruction s'utilise de la même façon que le AddHandler ! (reprendre les lignes d'ajout du handler et remplacer AddHandler par RemoveHandler) .


XIX-C-3. Les délégués:

Pour la petite histoire, nous créons un délégué à chaque fois que nous créons une procédure gestionnaire d'évènement avec le mot Handles ou avec AddHandler.

En C on utilise des pointeurs de fonction , adresse en mémoire indiquant ou le logiciel doit sauter quand on appelle une fonction ou un évènement. En VB on parle de délégué.


XIX-C-4. Création de menu contextuel par code:

Double-cliquez sur le composant ContextMenu dans la Boîte à outils pour l'ajouter sur le formulaire: Cela crée un ContextMenu1

Par code , on va le vider, puis ajouter des items (lignes) au menu, on indique le texte de l'item mais aussi quelque routine déclencher lorsque l'utilisateur clique sur le menu contextuel:

' Vide le  context menu.
ContextMenu1.MenuItems.Clear()
 

' Ajoute une ligne 'Checked'.
ContextMenu1.MenuItems.Add("Ouvrir", New System.EventHandler(AddressOf Me.Ouvrir_Click))
 

' Ajoute une ligne 'Checked

ContextMenu1.MenuItems.Add("Fermer", New System.EventHandler(AddressOf Me.Fermer_Click))
 

' Test si le contrôle en cours est CheckBox, si oui ajout d'un item "Contrôler".
If ContextMenu1.SourceControl Is CheckBox1 Then
ContextMenu1.MenuItems.Add("Contrôler", New System.EventHandler(AddressOf Me.Controler_Click))
End If
 
Bien sur, il faut écrire les Sub Ouvrir_Click() Fermer_Click Controler_Click.

En fonctionnement, l'utilisateur Clique 'droit' sur un controle, le menu contextuel s'ouvre, il clique sur 'Ouvrir' ce qui exécute la routine Ouvrir_Click.


XIX-D. Les 'régions',la compilation conditionnelle, les 'Attributs'.

Dans le code on peut ajouter des choses qui ne sont pas du code VB, mais plutôt des directives pour l'affichage, le compilateur ou le Runtime:


XIX-D-1. Les Régions.

Pour une meilleur visibilité, il est possible de créer des 'régions' de code. Une région peut être déroulée ou contractée.

Une région peut être déroulée: le code entre #Region et #End Region est visible (pour modifier le code par exemple):

-

#Region "Routine de Tri"

Sub QuickSort(ByVal debut As Integer, ByVal fin As Integer)

Dim pivot, gauche, droite, temp As Integer

Do

...

Loop Until gauche = droite

End Sub

#End Region
Si on clique sur le petit carré (avant #region), cela contracte la région et masque le code, on voit seulement un petit carré avec un plus et le nom de la région.

+

Routine de Tri

Cela permet de masquer une procédure en totalité.

Attention, cela ne permet pas de masquer seulement une partie du code mais la procédure entière.

Exemple:

Dans une Classe de formulaire, il existe une région nommée 'Code généré par le Concepteur Windows Form' qui contient le code créant les contrôles du formulaire. Ce code est habituellement caché.


XIX-D-2. La Compilation conditionnelle.

La compilation conditionnelle contrôle si les séquences de lignes sont traduites en code réel. Certaines lignes peuvent être ignorées pendant le processus de compilation.

Les instructions de compilation conditionnelle sont précédées de #

On utilise:


#if .. then

#else

#end if
Exemple

#const Demo = True    'créer une constante conditionnelle

Class MaClasse
#if Demo then
  Sub F()
#else
  Sub G()
#end if

End Class
La compilation produit le résultat suivant :

Class C
Sub F()
End Class
Il suffit de changer la valeur de la constante pour compiler des parties différentes de code.

Noter que #const Demo crée une constante privée accessible uniquement dans le fichier.

En VB 2005 on peut définir une constante au niveau projet avec /define

/define const Demo=True

XIX-D-3. Les Attributs.

Les attributs peuvent être utilisés pour décrire votre code au runtime (fournir des informations supplémentaires) ou modifier le comportement de l'application au moment de l'exécution. Le Framework fournis de nombreux attributs , mais vous pouvez également créer vos propres attributs personnalisés.

Les attributs sont entre < et > en VisualBasic.

Les attributs peuvent modifier le comportement des propriétés, méthodes, classes, assemblys. Ils couvrent différents aspects comme la compilation, la sécurité, les services Web...

Exemple: <Obsolete > Avec une procédure.

Déclarons une fonction Add comme obsolete, en plus, le compilateur affiche le message: 'Sera enlevé à la prochaine version'.

On utilise donc <Obsolete > ou le nom complet de l'attribut: <System.ObsoleteAttribut>

<Obsolete("Sera enlevé à la prochaine version ")> Function Add(a as Integer, b as Integer) as Integer
Add = a + b - c
End Function
Exemple:<Browsable> avec un composant.

Dans un composant, je crée une Propertie nommée 'Valide', je ne veux pas qu'elle apparaisse dans la fenêtre 'propriétés' du composant; je veux qu'elle soit accessible uniquement par code:


Imports System.ComponentModel    'Classe chargées du comportement des composants.

 

<Browsable(False)> Property Valide() As Integer
Exemple:<ToolBoxBitMap> avec un composant.

Quand on crée un composant, on désire parfois avoir une icône propre à ce composant dans la boite à outils:

<ToolBoxBitMap("C:MonIcone")> Public Class MaClasse
Exemple:<Serializable> avec une Classe.

Quand on crée une classe, on a parfois besoin qu'elle soit sérializable:

<Serializable()> Public Class TestSimpleObject

Public member1 As Integer
Public member2 As String
Public member3 As String
Public member4 As Double

'Un member qui ne doit pas être sérialisé.
<NonSerialized()> Public member5 As String
Il est possible de faire un tas de choses avec les attibuts, mais cela devient vite très complexe.


XIX-E. Multithread.


XIX-E-1. Un Thread c'est quoi?

Le thread représente l'exécution d'un processus en mémoire. Un système multithread tel que Windows offre la capacité d'exécuter en parallèle plusieurs threads et donc plusieurs traitements en simultané.

On peut utiliser la Classe Thread, créer autant de thread que l'on veut, mais il faut gérer un tas de chose et c'est l'horreur.

On peut aussi (Framework 2) utiliser un Thread d'arrière plan (et un seul) qui est très simple d'utilisation. Son intérêts est que lorsqu'on a une tache très longue (très long calcul par exemple), il est possible d'effectuer le calcul long en arrière plan, pendant ce temps, on peut continuer à travailler dans le formulaire (thread principal); quand le thread d'arrière plan est terminé, on affiche les résultats.


XIX-E-2. Comment ajouter un Thread d'arrière plan?

Il faut aller chercher un composant BackgroundWorker dans la boite à outils et le déposer sur le formulaire, il apparaît en dessous et se nomme par défaut BackgroundWorker1.

La propriété WorkerReportsProgress donne à notre BackgroundWorker la possibilité de nous informer ou non de son état d'avancement.

La propriété WorkerSupportsCancellation nous permet d'autoriser l'annulation de la tâche en cours du BackgroundWorker.

Dans le code:

BackGroundWorker1.RunWorkerAsync(Objet) permet de déclencher le thread d'arrière plan.

BackGroundWorker1.DoWork : est l' évènement qui se déclenche lorsque nous faisons appel au BackgroundWorker. C'est cette routine qui tourne en arrière plan.

ProgressChanged : Cet évènement, si la propriété WorkerReportsProgress est activée, se déclenche lorsque nous voulons indiquer que l'état d'avancement du BackgroundWorker change.

RunWorkerCompleted : Une fois le traitement du BackgroundWorker terminé cet événement est déclenché.
Exemple:

Si on clique sur un bouton cela crée un thread d'arrière plan qui effectue un calcul long.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

 'La méthode RunWorkerAsync() du BackgroundWorker déclenche le thread d'arrière plan.

  BackgroundWorker1.RunWorkerAsync()

End Sub

 

'La procédure DoWork contient le code effectué en arrière plan.

Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork

   'mes calculs très long

End Sub

'Quand le code d'arrière plan est terminé la procédure RunWorkerCompleted est exécutée.

Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted

' ici, elle affiche un message indiquant de le thread d'arrière plan est terminé.  

Label1.Text = "terminé"

End Sub
La méthode RunWorkerAsync peut avoir un paramètre qui sera transmis au thread d'arrière plan.

Mais un seul; ce paramètre étant de type objet, vous pouvez passer un tableau d'objets (string, int, etc...) ou même une structure

Ici dans l'exemple, on a un paramètre numérique, utilisé dans le thread d'arrière plan pour faire un calcul.


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

  BackgroundWorker1.RunWorkerAsync(180)

End Sub
Le paramètre , dans DoWork, se retrouve dans e.Argument , comme c'est un Objet, il faut le convertir en Integer pour l'utiliser:

Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork

   a=a + Ctype (e.Argument, Integer)

End Sub
Le thread d'arrière plan peut appeler une Sub.

Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork

   Calcul()

End Sub

Sub Calcul ()

'Mes calculs

End Sub
(Le thread principal peut lui aussi appeler la routine Calcul.)

Les variables sont accessibles dans le thread d'arrière plan:

'MyVar par exemple qui est Public et déclarée en tête de module.

Public  MyVar As Integer = 1

 

Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork

      MyVar=Myvar +1

End Sub
Par contre les objets de l'interface (du thread principal) ne sont pas accessibles dans le thread d'arrière plan:

Cela déclenche une exception si on tente d'y accéder.


XIX-E-3. État d'avancement:

Si la tâche d'arrière plan est très longue, il peut être intéressant de montrer dans l'interface utilisateur, l'état d'avancement de cette tâche.

Mais on rappelle que la tâche de fond ne peut pas intervenir sur l'interface.

Il faut donc:

Mettre la propriété WorkerReportsProgress de notre BackgroundWorker à True.

Dans le thread d'arrière plan, il faut, a chaque que l'on veut indiquer la progression, appeler la méthode ReportProgress en indiquant l'état d'avancement avec un paramètre.

Private Sub BackgroundWorker1_DoWork()

 Dim MyThread As BackgroundWorker = CType(sender, BackgroundWorker)'récupération du thread d'arrière plan

 MyThread.ReportProgress(pourcent)'pourcent est un Integer indiquant l'état d'avancement.

End Sub
Noter que c'est au programmeur de créer la logique calculant d'état d'avancement (et donc la valeur de la variable pourcent)

Enfin dans le thread principal, la Sub BackgroundWorker1_ProgressChanged() s'exécute à chaque fois que le thread d'arrière plan le demande et met à jour un index visuel sur l'interface.


Private Sub BackgroundWorker1_ProgressChanged( _
ByVal sender As Object, _
ByVal e As ProgressChangedEventArgs) _
Handles BackgroundWorker1.ProgressChanged

MyProgressBarr.Value = e.ProgressPercentage
End Sub

XIX-E-4. Arrêter le thread en cours:

Il suffit de faire dans le thread principal:

BackgroundWorker1.CancelAsync()
Dans le thread d'arrière plan, il faut vérifier si l'arrêt à été demandé:

Dans DoWork on récupère le thread d'arrière plan qui est le sender, on regarde si sa propriété CancellationPending est à True, si oui on met e.cancel à True ce qui arrête le thread d'arrière plan.

Dim MyThread As BackgroundWorker = CType(sender, BackgroundWorker)

If MyThread.CancellationPending Then e.Cancel = True  'ce qui arrête le thread d'arrière plan.
Si on veut tester la demande d'arrêt dans une Sub, il faut envoyer en paramètre à cette sub MyThread et e.


XIX-E-5. Résultat retourné par le thread d'arrière plan:

Il peut y avoir plusieurs types de résultat à la fin, on peut le voir dans l'argument e de type RunWorkerCompletedEventArgs retourné par la procédure BackgroundWorker1.RunWorkerCompleted.

:

* Il y a eu une erreur pendant le traitement. Dans ce cas la propriété e.Error est différente de null.

* Le traitement a été annulé. Dans ce cas la propriété e.Canceled est à true.

* Le traitement s'est déroulé normalement. Le résultat se trouve dans la propriété e.Result .(Bien sur ,dans DoWork il faut avoir mis le résultat des calculs dans e.Result)

Exemple de traitement:

Private Sub BackgroundWorker1_RunWorkerCompleted( _
	ByVal sender As Object, _
	ByVal e As RunWorkerCompletedEventArgs) _
	Handles BackgroundWorker1.RunWorkerCompleted

	If Not (e.Error Is Nothing) Then
		lblResult.Text = "Il y a eu une erreur : " + e.Error.Message
	ElseIf e.Cancelled Then
		lblResult.Text = "Opération annulée "
	Else
		lblResult.Text = "Opération Ok  Résultat : " + e.Result.ToString
	End If

End Sub
		

XIX-F. Les délégués, les évènements.

Super complexe? non!!


XIX-F-1. Définition.

Un délégué est une référence (un type référence) qui fait référence à une méthode, qui pointe sur une méthode. L'équivalent le plus proche d'un délégué dans d'autres langages est le pointeur de fonction.

On peut créer directement un délégué avec le mot Delegate et AddressOf.

Dans la gestion des évènements des contrôles on crée aussi des délégués avec Handles et AddHandler.


XIX-F-2. A- Création d'un délégué avec 'Delegate'

Ici on ne parle pas d'évènement

On déclare un délégué (un pointeur):

Delegate Sub D()
on l'instance: on le fait pointer sur une fonction F().

Dim M As New D(AddressOf F)
Quand on utilise l'instance du délégué, cela exécute la fonction.

M() exécute la fonction F()

AddressOf permet de préciser l'adresse de la procédure F(), le pointeur vers la procédure F().

Exemple hyper simple:

Delegate Sub SimpleDelegate() 'On crée un délégué sans paramètres

Module Test
   
   Sub MaSub() 'On crée une Sub
      System.Console.WriteLine("Test")
   End Sub
   
   Sub Main()
      Dim Mondelegue As New SimpleDelegate(AddressOf MaSub) 'le délégué pointe sur la Sub
      Mondelegue()	'On utilise le délégué
   End Sub
End Module 
Il n'est pas d'un grand intérêt d'instancier un délégué pour une méthode et d'appeler ensuite immédiatement la méthode via le délégué, puisqu'il serait plus simple d'appeler directement la méthode, mais c'est un exemple.

Exemple avec une fonction et des paramètres:

Bien sur le délégué peut pointer vers une Sub ou une fonction avec des paramètres:

Dans une Classe MaClasse:

On déclare un delegate en indiquant paramètres envoyés et de retour :

Delegate Function maMethodDelegate(myInt As Integer) As [String]
On déclare une fonction:

Public Shared Function maMethode(myInt As Integer) As [String]

    Return myInt.ToString
End Function
Ici l'exemple est bête: on donne un Integer, cela retourne une String!!

On crée le délégué:

Dim myD As New maMethodDelegate(AddressOf maClasse.maMethode)
myD est maintenant un pointeur sur maClasse.maMethode.

Je peux utiliser myD(2) qui retournera une String "2"

Intérêts d'un délégué par rapport à une fonction?

Un délégué est un type référence qui fait référence à une méthode Shared d'un type ou à une méthode d'instance d'un objet.

Un délégué peut référencer à la fois des méthodes de classe (static) et des méthodes d'instance. Lorsque le délégué référence une méthode d'instance, il stocke non seulement une référence au point d'entrée de la méthode, mais également une référence à l'instance de classe pour laquelle la méthode est appelée. Contrairement aux pointeurs fonction, les délégués sont orientés objet, de type sécurisé et fiables.

Voici un exemple de Microsoft utilisant un délégué avec les 2 types de méthodes.

Imports System

Public Class SamplesDelegate

' Declares un delegate à partir d'une méthode qui accepte un paramètre integer et retourne une String.
Delegate Function myMethodDelegate(myInt As Integer) As [String]

' Definir les méthodes.
Public Class mySampleClass

' Definir une méthode d'instance.
Public Function myStringMethod(myInt As Integer) As [String]
If myInt > 0 Then
Return "positive"
End If
If myInt < 0 Then
Return "negative"
End If
Return "zero"
End Function 'myStringMethod

' Definir une méthode de classe.
Public Shared Function mySignMethod(myInt As Integer) As [String]
If myInt > 0 Then
Return "+"
End If
If myInt < 0 Then
Return "-"
End If
Return ""
End Function 'mySignMethod
End Class 'mySampleClass

'Utilisation du délégué

Public Shared Sub Main()

' Instanciation de délégué pour chaque méthode.
Dim mySC As New mySampleClass()
Dim myD1 As New myMethodDelegate(AddressOf mySC.myStringMethod)
Dim myD2 As New myMethodDelegate(AddressOf mySampleClass.mySignMethod)

'Utilisation des délégués.
Console.WriteLine("{0} is {1}; use the sign ""{2}"".", 5, myD1(5), myD2(5))
Console.WriteLine("{0} is {1}; use the sign ""{2}"".", - 3, myD1(- 3), myD2(- 3))
Console.WriteLine("{0} is {1}; use the sign ""{2}"".", 0, myD1(0), myD2(0))

End Sub 'Main

End Class 'SamplesDelegate


'Le code produit les sorties suivantes:
'
'5 is positive; use the sign "+".
'-3 is negative; use the sign "-".
'0 is zero; use the sign "".
Les membres d'un délégué sont les membres hérités de la classe System.Delegate. Un délégué contient également un ensemble de constructeurs et de méthodes définis par le système.

L'utilité des délégués réside dans leur anonymat. L'exemple suivant illustre une méthode MultiCall qui appelle de façon répétitive une instance SimpleDelegate :

 Sub MultiCall(d As SimpleDelegate, count As Integer)
      Dim i As Integer
      For i = 0 To count - 1
         d()
      Next i
   End Sub
Pour la méthode MultiCall, l'identité de la méthode cible de SimpleDelegate n'a pas d'importance, pas plus que l'accessibilité qu'a cette méthode, ni le fait qu'il s'agisse d'une méthode Shared ou non partagée.

La seule chose qui importe est que la signature de la méthode soit compatible avec SimpleDelegate.


XIX-F-3. B-Délégué et appel asynchrone

Quand une procédure A appelle une autre procédure B, cela se passe de manière synchrone: pendant l'exécution de la procédure B, la procédure A est en attente, elle se poursuit après le retour de la procédure B.

Si vous appelé la procédure B à partir d'un délégué avec BeginInvoke , le fonctionnement sera asynchrone, c'est à dire que les 2 procédures se dérouleront en parallèle.

Si la méthode BeginInvoke est appelée, le Common Language Runtime mettra la demande en file d'attente et le retour à l'appelant sera immédiat. La méthode cible sera appelée sur un autre thread . Le thread d'origine, qui a soumis la demande, est libre de poursuivre en parallèle son exécution. La méthode BeginInvoke est donc utilisée pour établir l'appel asynchrone. Elle possède les mêmes paramètres que la méthode à exécuter de façon asynchrone, plus deux paramètres. Le premier paramètre supplémentaire sert quand l'appel asynchrone se termine (voir plus bas); le second paramètre supplémentaire sert à fournir un objet quelconque.

Delegate Function myDelegate(myInt As Integer) As [String]

Dim ta As New myMethodDelegate(AddressOf MyMethode)

ta.BeginInvoque(2 ,Nothing, Nothing)  'On met les 2 paramètres supplémentaire à Nothing pour le momment.
Ici on a exécuté dans un autre thread, en parallèle, MyMethode.

On reprend l'exemple bête, d'une fonction qui transforme un integer en String.

Public Shared Function myMethode(myInt As Integer) As [String]

    Return myInt.ToString
End Function
Le problème est de savoir quand MyMethode se termine et éventuellement récupérer les résultats de MyMethode.

Là intervient le premier paramètre supplémentaire: il est chargé d'indiquer l'adresse de la procédure à exécuter lorsque l'opération asynchrone se termine.

ta.BeginInvoque(2 ,AdresssOf AfficheResultat, Nothing)
Ici quand ta se termine cela exécute la procédure AfficheResultat.

Il faut donc créer une procédure AfficheResultat avec comme paramètre une variable de type IAsyncResult qui permet de récupérer le résultat.

Sub AfficheResultat (By Val ia As IAsyncResult)

    Dim Resultat As String

    Resultat= ta.EndInvoke(ia)

End Sub
La méthode EndInvoke est utilisée pour obtenir la valeur de retour de la fonction et les paramètres de sortie.

On peut aussi 'surveiller' si ta est terminé et récupérer le résultat:

Il faut déclarer une variable de type IAsyncResult:

Dim ia As IAsyncResult
Quand on instance ta avec BeginInvoke cela retourne un IAsyncResult si on écrit:

ia= ta.BeginInvoque(2 ,Nothing, Nothing)
Il suffit de tester ia avec ia.IsCompleted pour voir si ta est terminé; a titre d'exemple créons un bouton testant si la procédure asynchrone est terminée.

Private Sub Button1_Click(..)

    Dim Resultat As String

    If ia.IsCompleted Then

        Resultat=ta.EndInvoke(ia)

    Else

        MsgBox(" Traitement en cours..")

    End If

End Sub
Il faut cliquer sur le bouton à intervalle régulier pour voir si ta est terminé. (L'exemple est débile car tout cela à de l'intérêt que si la procédure asynchrone est très longue.


XIX-F-4. C-Délégué et évènement:

Les délégués sont utilisés pour lier les événements aux méthodes servant à les gérer. Lorsque l'événement se produit, le délégué appelle la méthode liée.

Délégué crée automatiquement par Visual Basic .NET

Dans le cas d'événements associés à des formulaires ou contrôles, Visual Basic .NET crée automatiquement un gestionnaire d'événements et l'associe à un événement.

Effectivement, en mode design, lorsque vous double-cliquez sur un bouton de commande dans un formulaire, Visual Basic .NET crée automatiquement un gestionnaire d'événements vide et une variable WithEvents pour le bouton de commande, comme dans le code suivant:

Dans la Region " Code généré par le Concepteur Windows Form " il y a:

Friend WithEvents Button1 As System.Windows.Forms.Button
 

Protected Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click


End Sub
WithEvents indique que l'objet Button1 a des évènements.

Le terme Handles provoque l'association d'un événement (Button1.Click situé après Handles) à un gestionnaire d'événements ( la Sub Button1_Click; la Sub pourrait d'ailleurs se nommer différemment, cela n'a pas d'importance).

L'association d'événements aux gestionnaires d'événements se fait au moment de la compilation et ne peut pas être modifiée.

Lorsque vous cliquez sur un Button1 cela déclenche bien la Sub Button1_Click.

Délégué et évènements crées par vous:

On reprend les mêmes concepts que dans le chapitre sur le création de contrôles par code.

Lorsque vous crée par code de toute pièce des contrôles, vous pouvez faire de même avec Handles:

Déclaration dans la partie déclaration du module(en haut):

Private WithEvents Button1 As  New Button

Me.Controls.Add(Button1)

Sub OnClique ( sender As Object, EvArg As EventArgs) Handles Button1.Click

End Sub 
La aussi, l'association d'événements aux gestionnaires d'événements se fait au moment de la compilation et ne peut pas être modifiée. On a bien crée un délégué.

Vous pouvez aussi utiliser la méthode AddHandler:

   Dim TB As New System.Windows.Forms.TextBox

    Me.Controls.Add(TB)

    AddHandler TB.Keyup, AddressOf TextboxKeyup.

 

Sub TextboxKeyup.(ByVal sender As Object, ByVal e As KeyEventArgs)

...

End Sub
AddHandler permet donc d'associer à l'évènement TB.Keyup la Sub TextboxKeyup. On a bien crée un délégué.

le mot clé addhandler permet d'associer un événement à une procédure au moment de l'exécution et peut être annulé par RemoveHandler.


XIX-G. Les génériques VB 2005

Super complexe? non!!


XIX-G-1. Définition.

A partir de VB

Un type générique (generic) permet de créer une Classe, ou une procédure, ayant des Data Types non définis au départ.

En d'autres termes, les paramètres et variables n'ont pas de type: ce ne sont pas des Strings, des Integers.. Ce sont des génériques. Quand on utilise la Classe ou la procédure, on indique le type.

Les génériques nous permettent de définir un comportement ou un algorithme commun sur les types ou un sous ensemble de types .Net. Ils sont un moyen de mutualiser un comportement.

Créons une classe MyClasse; Of permet d'indiquer le generic:

Public Class MyClasse(Of t)
        ' Insérer le code qui utilise le data type t.

	Dim tempItem As t


End Class
Ici t est le 'generic'; t pourra être une entier, une string....

On peut ensuite utiliser cette classe avec des Integer ou des String:

Public UneClass As New MyClasse(Of Integer)
Friend stringClass As New MyClasse(Of String)

XIX-G-2. Exemple de Fonction utilisant un 'generic'

Permettant d'en comprendre l'intérêt:

Créons une sub Swap fonctionnant pour tous les types de données:

Private Sub Swap(Of ItemType) (ByRef v1 As ItemType, ByRef v2 As ItemType)

    Dim temp As ItemType

    temp = v1

    v1 = v2

    v2 = temp

End Sub
Notons que en plus des 2 paramètres V1 et V2 à 'swapper' ,"Of ItemType" indique le type de donnée qui doit être utilisé.

Si on a 2 entiers à swapper, il faut appeler la fonction Swap comme cela:

Swap(Of Integer)(v1, v2)
Si c'est des Strings:

Swap(Of String)(v1, v2)
Le JIT compile la fonction Swap comme si elle avait été écrite pour des Strings.

Sans les génériques j'aurais du écrire plusieurs routines de code pour chaque Type. Or en utilisant les génériques cette redondance peut être évitée.


XIX-G-3. Exemple de Classe utilisant un 'generic'

De la même manière, on peut créer une Classe entièrement générique:

Public Class SomeClass(Of ItemType)

    Private internalVar as ItemType    ' variable generic

        Public Function SomeMethod(ByVal value As ItemType) As ItemType

        'Fonction acceptant un generic comme paramètre

    End Function

End Class

XIX-G-4. Exemple de Collection utilisant un 'generic'

On peut créer une collection générique (System.Collections.Generic) et lui imposer un type.

Exemple: créons une collection de String : List(Of String).

Dim l As New System.Collections.Generic.List(Of String)

l.Add("toto")    'On ajoute une string

Dim S As String = l.Item(0) ' l'item est bien typé : même avec 'Option Strict=on' pas besoin de CType.
Habituellement les collections contiennent des objets; ici c'est une collection de String.

Je ne peux y mettre que des String (sinon cela provoque une erreur)

Comme par définition c'est des string, il n'y a pas de conversion String=>Objet et Objet=>String (pas de boxing/unboxing)

On peut aussi créer des Stack(Of..) Queue(Of..), Dictionnary(Of..) SortedList(Of..)..


XIX-G-5. Intérêts des génériques ?

Pourquoi ne pas utiliser des types 'Object', à la place des génériques?

Les génériques sont fortement typés.

Ils sont plus rapides que l'usage des objets.

S'il y a erreur, elle se produit probablement à la compilation et pas au RunTime.

Cela permet d'utiliser l'intellisense.


XIX-G-6. En VB 2005: il y a des classes permettant l'usage de génériques:

Exemple:

On peut utiliser des méthodes génériques pour travailler sur les tableaux.

Exemple recherche dans un tableau de short nommé monTab l'élément 2

index= Array.indexOf (Of Short)(monTab, 2) est hyper plus rapide que

index= Array.indexOf (monTab, 2) car la première version avec généric est directement optimisée pour les Short.

Il est est de même pour Binarysearch et Sort.

Cela est valable pour les types 'valeur' (peu d'intérêts pour les strings par exemple).


XIX-G-7. En VB 2005:il y a les Collections 'generic' ou 'Specialized'

Collections génériques:

On peut créer une collection générique (System.Collections.Generic) et lui imposer un type.

Exemple: créons une collection de String (List(Of String)): Elle est typée car elle ne peut contenir que des 'String'.

Dim l As New System.Collections.Generic.List(Of String)

Il s'agit d'une List avec Index.

l.Add("toto")    'On ajoute une string

Dim S As String = l.Item(0) ' l'item est bien typé : même avec 'Option Strict=on' pas besoin de CType.
Il y a aussi de nouveaux types de collections génériques

Les Dictionnary(Of..) avec Clé et valeur

Les SortedDictionnary(Of..) avec Clé et valeur trié.

Les LinkedList(Of..) Liste Chaînée, chaque élément comportant une propriété Value, Next et Previous.

Les SortedList(Of..)..

Les Stack(Of..)

Les Queue(Of..)

Collections spécialisées:

L'espace System.Collections.Specialized fournit de nouveau type de collection très spécifiques:

Exemple: ListDictionary avec Clé et Valeur:

Dim l As New System.Collections.Specialized.ListDictionary

l.Add(2, "toto")
On peut aussi créer des collections 'composées'

Dim genericColl As New System.Collections.Generic.Dictionary(Of String, String)

genericColl.Add("PremiereClé", item1)
BitVector32 est un type de collection qui contient des Booléens ou des entiers.

StringCollection est un type de collection String.

Intérêts de ses collections est qu'elle sont fortement typées: Elle n'acceptent que des éléments d'un type: des String dans le dernier exemple.


XX. Bonnes adresses, bibliographie du site.

Ou trouver des informations sur VB.Net?

Mes livres de chevet:

Visual Basic .Net. de Gilles Nicot MicroApplication.

Complet, traite de l'IDE, Windows Forms et Web Forms.

Bien pour ceux qui viennent de VB6.

1092 pages , 31 euros.

Tout sur le code. de Steve McConnell Microsoft Press 2eme édition.

Concevoir un logiciel de qualité dans tous les langages (VB, C, Java..). Ce n'est pas un cours de programmation mais un ouvrage qui aide le programmeur à mieux écrire.

Pavé de 893 pages, un peu cher (56 euros). Le meilleur ouvrage sur la programmation.


XX-A. Sur le Net : trouver des informations.

Comprendre la Plateform NET mémoire de JP Bobier de 2001 très pointu.


XX-A-1. Vb 2003:


Cours très très simple, très court, mais très clair, bien fait. Pour débuter

A lire avant le mien, en français.

http://www.pise.info/vb-net Cours très plaisant, plein d'humour, avec des exemples de code. Il faut déjà avoir des notions de programmation mais les explications sont très claires.


Cours très rigoureux, très bon niveau, bon complément. Sur developpez.com

A lire après le mien, en français. Débutant s'abstenir.


3 pdf , en fait un cours sur vb.net, haut niveau. A lire, en français.

Débutant s'abstenir.


XX-A-1-a. Chez Microsoft


MSDN 1 de Microsoft La bible en français!! VB 2003


QuickStart Tutorial WindowsForms Vb 2003 en français

Le Framework 1 (Cliquez sur .NetFramework dans la liste)Vb 2003 en français


Exemples de petits applications VB 2003 par Microsoft:



XX-A-1-b. VB 2005:


Visual Studio 2005 chez Microsoft en français.

MSDN 2 VB 2005

Le Framework 2 (Cliquez sur .Net development dans la liste)Vb 2005 en anglais

WebCast VB 2005++ avec présentation,exemple de code commenté à vive voix ou filmé.

Exemples de petits applications VB2005 par Microsoft:





il y a un lien ([Developpez.com] Introduction à Vb.net) directement sur le présent site!!!


FAQ



XX-A-2. Sites dédiés au Visual Basic

Developpez.Com le meilleur site de développeur, une mine: Cours didacticiels, forum...





Les articles sont tous bons.


En anglais:





XX-A-3. Convertisseur C# -> VB

Cela énerve, dans certains sites Dot.Net, les exemples sont en C#!!

Convertisseur C#->VB (coller le code C# puis cliquer sur le bouton 'Convert Code')



XX-A-4. SQL

Pour aller plus loin:

Série d'articles sur SQL chez developpez.com:



XX-A-5. Glossaire





            

Valid XHTML 1.1!Valid CSS!

Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.