Powershell : création d'interfaces graphiques - première partie

Après quelques semaines de développement de ma Lightweight ActiveDirectory Toolbox, je vais commencer à faire une petite série d'articles afin d'expliquer comment développer une interface graphique avec Powershell, en utilisant Windows Forms. Cela est bien plus simple qu'il n'y paraît car nous allons écrire "beaucoup" de code ; une fois la logique acquise tout se fait très vite. J'ai la chance d'avoir fait quelques développements durant mes études et mon temps personnel il y a quelques années en VB.NET et C# avec WinForms, ce qui m'a facilité la tâche pour m'y remettre.

Dans cette première partie, nous allons aborder :

  • La conception d'une fenêtre ;
  • L'ajout de contrôles simples sur une fenêtre : label, button, textbox ;
  • L'ajout de EventsHandlers sur ces contrôles.
Si au début je développais avec Powershell ISE qui est intégré à Windows, j'ai fini par le remettre au placard suite à des freezes incessants et visiblement son incapacité à gérer des scripts qui ont quelques centaines de lignes. Sous Windows, je vous conseille l'excellent Notepad++ qui fera parfaitement le travail une fois le langage Powershell sélectionné en édition.
Quelques explications avant de se lancer, que vous pouvez passer si vous êtes déjà familiers avec WinForms ou le développement .NET en général :
  • Un contrôle est un élément visible de l'interface graphique. Il peut s'agir d'un bouton, d'une étiquette, d'un champ à remplir, etc.
  • Un EventHandler est une procédure qui sera déclenchée en fonction d'une action sur un contrôle : un clic, le passage de la souris, une modification de valeur, etc.
  • Une classe permet de définir un objet. Nous allons faire référence à des classes dans le code, à partir desquelles nous allons créer des objets. Par exemple, la classe Bouton va nous permettre de créer des boutons. Pour simplifier, la classe est le modèle et l'objet ce que nous modifions directement (taille, couleur, effet souhaité, etc.)
  • Il est important de bien nommer les variables : si cela ne pose pas de soucis d'avoir Bouton1, Bouton2 pour quelques lignes, un script ayant 40 ou 50 contrôles deviendra une plaie à écrire si l'on ne sait plus quel contrôle fait référence à Label4.
  • La documentation de Microsoft concernant WinForms est très riche et doit être le premier point de recherche en cas de doute.

Conception de la fenêtre de base

Tout d'abord, il faut savoir que Powershell tout seul ne sait pas créer d'interfaces graphiques avec WinForms. Il faut lui spécifier que nous allons appeler des classes propres à WinForms. En tout début de code, nous ajoutons ceci :

Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()

Puis nous pouvons définir notre toute première fenêtre :

$Form = New-Object System.Windows.Forms.Form

Voilà, notre fenêtre existe. Mais elle n'a ni taille, ni titre, ni propriété aucune... Et elle ne s'affiche même pas ! Corrigeons cela :

$Form.ClientSize = '300,300'
$Form.Text = "Mon UI en PS"
$Form.ShowDialog()

A l'exécution, nous obtenons donc ceci :
Une belle fenêtre - vide - avec ses contrôles habituels pour la redimensionner, l'agrandir, la fermer, etc.

Ajout de contrôles supplémentaires

On va l'agrémenter d'un bouton et d'un label (élément de texte non modifiable par l'utilisateur). On reprend donc les mêmes idées que pour notre Form principale, c'est à dire création d'un objet de la classe Button et Label.

$Bouton = New-Object System.Windows.Forms.Button

Mais ceci ne suffira pas. Il nous faut au moins lui indiquer une taille, le texte apposé dessus et surtout... l'endroit où on veut le placer ! Pour définir l'emplacement d'un contrôle, il faut créer un objet avec les coordonnées. Windows dessinera alors le contrôle en partant des paramètres données. Ici, nous souhaitons donc dessiner le bouton à partir de 30 pixels du côté gauche de la fenêtre et 50 pixels du côté haut.

$Bouton.Location = New-Object System.Drawing.Point(30,50)

Et plus simplement, il ne reste plus qu'à lui donner ses attributs : une largeur, une hauteur et le texte écrit dessus.

$Bouton.Width = 80
$Bouton.Height = 40
$Bouton.Text = "Cliquez moi!"

Si vous exécutez maintenant le script, vous ne verrez pas votre bouton. En effet, comment Powershell peut-il savoir que le bouton que vous avez créé doit être affiché sur la Form ? Si vous ne lui dites pas, il peut pas. On va donc gentiment lui indiquer :

$Form.controls.Add($Bouton)

Ce qui va nous donner ceci :

Ajoutons une TextBox qui va servir à saisir du texte, puis une Label.

$TextBox = New-Object System.Windows.Forms.TextBox
$TextBox.Location = New-Object System.Drawing.Point(30,110)
$TextBox.Width = 70
$Label = New-Object System.Windows.Forms.Label
$Label.Location = New-Object System.Drawing.Point(30,150)
$Label.Text = "bonjour"

Etant donné que nous avons plusieurs contrôles désormais sur notre Form, plutôt que d'ajouter un contrôle par instruction, nous allons utiliser la variante AddRange et non Add de $Form.controls.

Ainsi, nous remplaçons $Form.controls.Add($Bouton) par :

$Form.controls.AddRange(@($Bouton,$Label,$Textbox))

Et à l'exécution, tout apparaît :

Attention à bien renseigner les coordonnées des contrôles car si ils se chevauchent, ils peuvent ne plus être visibles et vous faire chercher à comprendre pourquoi ce satané Label ne s'affiche pas alors qu'il est "coincé" sous le bouton...

Tout cela est bien beau, mais n'offre aucune interactivité. Nous allons faire en sorte qu'un clic sur le bouton affiche sur le Label le texte saisi dans notre TextBox.

Ajout d'EventHandlers

C'est ici que le véritable développement Powershell se fait. C'est sur ces EventHandlers que l'on place le code qui est traité par le script. Chaque objet possède ses propres EventHandlers mais pas mal sont communs entre eux, dont le Add_Click que je vais présenter. Celui-ci permet de réagir lorsque l'utilisateur clique sur le contrôle. Nous allons donc écrire un EventHandler sur le bouton :

$Bouton.Add_Click({ })

Et glisser le code entre les accolades. Dans cet exemple, je veux prendre le contenu de la TextBox et l'affiche sur le label. J'obtiens donc simplement ceci :

$Bouton.Add_Click({
Label.Text = TextBox.Text
})

Il est important de toujours garder en dernière ligne l'ouverture de la Form car le script se met en pause de déroulement lorsque la fenêtre est activée (en attente d'un EventHandler, justement). Afin que tout soit bien interprété, on placera nos EventHandler avant.
Sur un clic du bouton, le Label prend le texte indiqué dans la TextBox. Réalisons un deuxième bouton qui viendra écrire la date du jour dans le label lors du clic.

$Bouton2 = New-Object System.Windows.Forms.Button
$Bouton2.Location = New-Object System.Drawing.Point(150,50)
$Bouton2.Width = 80
$Bouton2.Height = 40
$Bouton2.Text = "date du jour, bonjour!"

On ne manquera pas d'ajouter $Bouton2 dans le $Form.Controls.AddRange afin qu'il apparaisse sur la Form. Puis, on écrit son EventHandler :

$Bouton2.Add_Click({
$Label.Text = Get-Date
})

Ce qui nous donne ceci :
Voici donc pour cette première partie qui illustre les bases de la création d'une interface graphique en Powershell grâce à Windows Forms.

Liens

Télécharger le script de l'article
Développement d'une UI en Powershell : deuxième partie - troisième partie
Documentation et référence des classes : Form - Button - Label - TextBox
Lien pour marque-pages : Permaliens.

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.