Une remarque pertinente ?
Une critique impertinente ?
Un lynchage en règle ?
Une invitation sous les tropiques ?

Ecrivez-moi !

Conçu et enseigné tel qu'en lui même, avec pertes, fracas et humour de qualité supérieure            
 par Christophe Darmangeat dans le M2 PISE du Master MECI (Université Paris 7)            


 

 

 

Partie 6

Encore et toujours des contrôles
(des listes de toutes sortes)

Nous pouvons à présent reprendre notre tour d'horizon des différents contrôles proposés par C#. Bon, les Button, c'est fait. Les Label et les Textbox, on les a vues aussi, hmmm... les cases, ça y est... que reste-t-il ? Oh, tiens, ben oui :

1. La classe Listbox

La Listbox est à l'ensemble des classes de listes ce qu'est la 2CV aux automobiles : un prototype ancien et basique, mais solide, rustique, et qu'on a toujours plaisir à voir en service :

 La Listbox, par définition :

  • graphiquement, se présente toujours sous une forme « développée » (ce n'est pas une liste déroulante).
  • impose un choix parmi les items proposés (ce n'est pas une liste modifiable, où l'on peut entrer une valeur qui n'est pas proposée dans la liste)
  • possède ou non une barre de défilement verticale (voire horizontale), selon le nombre d'éléments présents dans la liste et la place disponible pour les afficher (l'apparition et la disparition des barres de défilement sont gérées de manière automatique par C#, même si on peut toujours bidouiller cela via certaines propriétés).

Les Listbox, nous offrent plusieurs propriétés concernant le mode d'affichage, dont entre autres :

  • Sorted : propriété booléenne qui indique si la liste est automatiquement triée ou non.
  • Multicolumn : propriété booléenne qui permet d'afficher les items sur plusieurs colonnes.

Et une propriété fondamentale pour son comportement :

  • SelectionMode : qui  indique si l'on autorise ou non la multisélection des items de la liste.

En ce qui concerne la gestion des éléments contenus dans la ListBox, il faut avoir à l'esprit une chose, de laquelle se déduisent toutes les autres : un objet de cette classe contient exclusivement des éléments de type String. Ces éléments sont les membres d'une collection appelée Items .

Théorème :
Un item d'une Listbox est une chaîne de caractères, membre de la collection définie par la Listbox.

Par conséquent, ce que nous avons appris au chapitre précédent sur les collections s'applique de plein droit aux items des Listbox. Comme quoi, on dira ce qu'on voudra, mais au niveau de l'articulation pédagogique, on sent bien que ce cours est drôlement bien goupillé et qu'on a pas affaire à un amateur. Enfin, moi, je dis ça, je dis rien.

1.1 Gérer la ListBox comme une collection

Pour balayer les éléments d'une Listbox du premier au dernier, nous pourrons donc utiliser, au choix, leurs numéros d'indice (avec une boucle classique for), ou nous en passer (en utilisant foreach).

Attention toutefois, la collection définie par une Listbox n'est pas désignée par Controls. C'est tout à fait logique : une ListBox ne contient pas des contrôles, mais des éléments (chaînes de caractères) : la collection est donc définie par sa propriété Items. Ainsi, pour ajouter un tiret devant tous les éléments de notre ListBox, on pourra écrire :

int i;
for (i = 0; i < listBox1.Items.Count; i++)
{
   listBox1.Items[i] = "- " + listBox1.Items[i];
}

On pourra également utiliser la boucle foreach... à condition de ne pas oublier que dans une telle boucle, les éléments désignés par la variable sont en lecture seule. Pas question donc de pouvoir les modifier. On pourra en revanche (même si c'est idiot, ce n'est pas la question) les faire afficher un par un dans une boîte à messages :

foreach (string toto in listBox1.Items)
{
   MessageBox.Show(toto);
}

Et, quitte à enfoncer une porte ouverte, je rappelle qu'on peut, comme dans n'importe quelle collection, ajouter un élément dans une liste via la méthode Add, en supprimer grâce aux méthodes Remove (qui demandera de fournir en argument l'élément lui-même) et RemoveAt, où il faudra spécifier son indice, voire supprimer d'un coup tous les éléments par la méthode Clear.

1.2 Propriétés gérant la sélection

1.2.1 Sélection simple

Le but d'une liste, c'est de permettre à l'utilisateur d'en sélectionner un ou plusieurs éléments. Or, la sélection d'un élément par l'utilisateur affectera deux propriétés à la fois :

  • SelectedItem : qui désigne sous forme de chaîne de caractères l'élément actuellement sélectionné. Si aucun élément n'est sélectionné, cette propriété contient une chaîne vide.
  • SelectedIndex : qui désigne l'indice de l'élément actuellement sélectionné. Si aucun élément n'est sélectionné, cette propriété vaut -1.

Pour connaître (ou, beaucoup plus rarement, pour définir) l'élément actuellement sélectionné dans une liste, on n'a donc que l'embarras du choix : par son texte ou par son indice, comme on dit, c'est vous qui voyez !

1.2.2 Sélection multiple

Toujours plus vite, toujours plus haut, toujours plus fort : il est possible d'autoriser l'utilisateur à sélectionner plusieurs éléments à la fois. Il suffit pour cela de passer la propriété SelectionMode à l'une des deux valeurs suivantes :

  • MultiSimple : la sélection multiple se fera automatiquent, sur simples clics.
  • MultiExtended) : la sélection multiple se fera en cas de combinaison du clic avec la touche Control ou Shift – c'est a priori le réglage standard sous Windows.

Le truc, eut dit M. de Lapalisse, c'est qu'une fois qu'on a autorisé la sélection multiple, l'utilisateur va pouvoir sélectionner... plusieurs éléments. Plus question donc de récupérer son choix par les propriétés SelectedItem et SelectedIndex, qui ne contiennent par définition qu'une seule valeur. En fait, la solution est parfaitement logique : dans ce cas, l'ensemble des éléments sélectionnés vont faire partie d'une collection. Et même de deux pour le prix d'une, puisqu'on aura à disposition :

  • SelectedItems (attention au « s » final) qui contiendra l'ensemble des éléments sélectionnés, sous forme de chaînes de caractères
  • SelectedIndices qui, comme son nom l'indique, contiendra ces mêmes éléments mais sous la forme d'indices

En fait, c'est tout ballot : SelectedItems est en quelque sorte le pluriel de SelectedItem, et SelectedIndices le pluriel de SelectedIndex.

1.3 Évènement(s)

En ce qui concerne les événements, on peut bien sûr associer une Listbox à l'action Click. Mais ça n'est pas très malin, parce qu'on peut tout à fait changer une sélection avec son clavier plutôt qu'avec sa souris... Un événement spécifique est donc disponible, qui se déclenche en cas de changement de l'item sélectionné, quelle que soit la manière dont cela se produit. Il s'agit de SelectedIndexChanged. Cet événement  est à la fois plus restrictif et plus large que le Click. Plus restrictif, car il ne se déclenche pas en cas de clic sur un item déjà sélectionné. Plus large, car il détectera un changement de sélection survenant y compris suite à une manoeuvre au clavier.

Bon, c'est pas tout ça, mais on va pouvoir utiliser notre science toute neuve :

Cet exercice n'est pas spécialement facile. Afin de graduer la difficulté, on pourra commencer par réaliser une première version, qui ne se préoccupe pas de la multisélection. Une fois que c'est au point, on introduira la case à cocher, et on modifiera le code là où c'est nécessaire.

Exercice

Exécutable

Sources

Inventaire

2. La classe Combobox

Il s'agit d'une classe-fille à la fois de la classe Listbox et de la classe Textbox. Elle en hérite donc les principales propriétés. En gros, on peut considérer qu'une ComboBox, c'est une liste modifiable et/ou déroulante :

L'aspect de la ComboBox dépend de la valeur de la propriété DropDownStyle :

  • Dropdown : signifie que la zone est modifiable et déroulante
  • DropDownList : la liste est déroulante, mais non modifiable
  • Simple : la liste est modifiable, mais non déroulante

Rappel : le caractère déroulant d'une Combobox n'influence que son aspect, alors que son caractère modifiable influence son comportement (peut-on ou non y entrer autre chose qu'un item de la liste).

3. La classe CheckedListBox

Cette classe est une espèce de croisement entre la Listbox et la Checkbox. De la première, elle hérite toutes les propriétés hormis celles liées à la multisélection. Cette classe affiche une liste dans laquelle chaque élément est représenté par une case à cocher :

 Remarque « Ne pas rater le coche »
Il arrive que les éléments de la liste se comportent étrangement et refusent obstinément de se cocher, même avec les clics les plus déterminés. La plupart du temps, c'est dû à la mauvaise valeur de la propriété CheckOnClic, qui est bêtement à False au lieu de True.

Le fait qu'il s'agisse d'une Listbox (presque) ordinaire fait que, malgré les apparences, on peut la traiter comme telle. Les éléments qui se trouvent à l'intérieur, contrairement aux apparences, ne sont pas des CheckBox mais de simples Item. Ca, c'est la bonne nouvelle. La moins bonne, c'est que ces Item ne constituent pas des objets différents (ils sont de simples String au sein d'une propriété d'un objet unique de la classe CheckListBox. Moralité, si on peut identifier un Item par son indice (au sein de la collection des Items, oude la collection plus restreinte des seuls Items cochés), on ne peut pas savoir, par exemple, quel Item vient d'être coché ou décoché via le paramètre sender. Ce n'est généralement pas vraiment gênant : il suffit de savoir ce qui est possible ou non, et de choisir sa stratégie en conséquence.

Un autre truc bon à savoir : contrairement à ce qui se passe avec de vraies CheckBox, les Items ne possèdent pas de propriété Checked qui permettrait de connaître leur état. Rien n'ets perdu pour autant, puisqu'il existe deux moyens alternatifs de récupérer cette information :

  • On peut passer par la méthode GetItemCheckState de la CheckListBox, en passant en argument l'indice de l'Item souhaité. La méthode renvoie un membre de l'énumération CheckState.
  • On peut aussi balayer la collection CheckedItems ou sa petite soeur, CheckedIndices définies par la CheckListBox, et qui contiennent respectivement l'ensemble des éléments et celle des indices des Items actuellement cochés.

Tant qu'on y est, à noter aussi que :

  • la propriété ThreeDCheckBoxes indique si ces cases sont en relief
  • l'événement ItemCheck est provoqué par le changement d'état (cochage ou décochage) d'un élément
  • la méthode SetItemCheckState permet de modifier par du code l'état d'un élément dont on spécifie l'indice.

Comme ça, ça a peut-être l'air compliqué, mais c'est loin d'être vraiment méchant.

4. La classe ImageList

J'en profite pour faire une petite visite à ce contrôle, qui rend des services collectifs inestimables. Son rôle consiste à être un tableau d'images, destiné à permettre à d'autres contrôles de venir puiser dedans. Il s'agit d'un contrôle invisible. Ce n'est pas le seul, mais c'est le premier que nous rencontrons. Lorsqu'on le sélectionne et qu'on tente de le poser sur la Form, dans la boîte à outils, on voit tout de suite qu'il ne se pose pas sur la Form elle-même, mais à côté.

Pour utiliser ce contrôle, on le remplit via sa propriété Images qui désigne une collection ( et à laquelle s'appliquent donc les méthodes Add et Remove, si on veut en manipuler le contenu par du code). La propriété ColorDepth permet de régler la qualité de codage des images en question, et roule Raoul : on accède ensuite aux images que contient ImageList par la propriété ImageIndex.

Et tiens, si on s'en servait ?

Cet exercice fait fonctionner trois contrôles les uns avec les autres : la liste de cases à cocher pilote la liste déroulante, qui elle-même provoque l'affichage des images. Pour afficher celles-ci, vous aurez besoin du conteneur à images ; celui-ci s'appelle un PictureBox, et la seule propriété qui nous intéresse est celle qui désigne son contenu, en l'occurrence Image. Une dernière chose : il vous faut les 26 images des jetons de scrable. Vous les trouverez dans cette archive.
Une dernière chose, avant de vous lancer dans un code compliqué comme une usine réelle à gaz virtuel, si on prend les choses par le bon bout, le tout tient en une douzaine de lignes simples comme bonjour (ou presque).

Exercice

Exécutable

Sources

Diaporama littéraire