Site:  Cours VB.net  
8.3 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.

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)

 

 

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é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.

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) .

 

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é.

 

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.