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 10

Les graphismes

Des graphismes avec C#, il y aurait évidemment beaucoup à dire, et cela dépasserait largement le cadre de ce cours. Mais il y a tout de même quelques éléments de base à savoir, auxquels je voudrais consacrer ce chapitre... haut en couleurs, comme il se doit.

1. Couleurs et Propriétés

Même si jusqu'ici nous ne nous sommes pas particulièrement arrêtés sur cette question, votre proverbial sens de l'observation vous aura sans doute indiqué que la quasi-totalité des contrôles possèdent des propriétés désignant leur(s) couleur(s). Ainsi, Backcolor et ForeColor permettent de modifier respectivement la couleur d'arrière-plan et d'avant-plan des contrôles ‐ 99 fois sur 100, « la couleur », c'est la couleur d'arrière-plan, soit Backcolor.

Mais comment spécifie-t-on une couleur ? Il existe pour cela deux grands moyens : soit on va piocher dans l'une des nombreuses couleurs prédéfinies, soit on compose entièrement sa couleur soi-même. Finalement, il se passe avec le code exactement la même chose qu'avec l'interface, lorsqu'on va modifier une couleur en allant trifouiller dans la fenêtre des propriétés.

1.1 Les palettes prédéfinies

Il en existe deux :

  • La palette web : System.Drawing.Color. Cette structure (de son petit nom : Color tout court) est celle qui contient un certain nombre de couleurs prédéfinies, dites couleur « web », sous forme d'une énumération : on choisit la couleur par son nom, et derrière, le compilateur traduit ce nom en une série d'entiers qui fixeront les valeurs nécessaires pour sa fabrication. Outre la clarté qu'elle permet au niveau du code, cette manière de procéder introduit une incontestable touche poétique da,s les programmes, puisqu'on aura accès à des couleurs aussi évocatrices que LightCoral, Orchid ou SeaShell. À noter que ces couleurs s'afficheront de la même manière sur toutes les machines où sera installée l'application. Pourquoi je dis ça ? Ben parce que ...
  • La palette système : System.Drawing.Systemcolors, autrement dit Systemcolors. Cette palette fonctionne différemment de la précédente : elle propose en effet une énumération des couleurs « ace;système ace;», c'est-à-dire des couleurs des éléments de Windows tel que chaque utilisateur peut les personnaliser. Ainsi, si l'on dit qu'un élément doit posséder la couleur Systemcolors.Control, l'élément aura la couleur par défaut des contrôles sur la machine cliente, quelle que soit cette couleur.

Rien de vraiment compliqué, donc.

1.2 Définir une couleur personnalisée

Il est également possible de définir, par le code, des couleurs entièrement personnalisées. Ceci est possible grâce à la méthode FromArgb, qui demandera quatre paramètres entiers entre 0 et 255 : l'alpha (autrement dit, l'opacité, puis les valeurs de rouge, de vert et de bleu). Ainsi, pour colorier un bouton en bleu (pétoire), on écrira :

Button1.BackColor = Color.FromArgb(255, 0, 0, 255)

Remarque : il est également possible d'appeler la méthode FromArgb uniquement avec trois paramètres. Dans ce cas, ceux-ci désignent les couleurs et par défaut, l'opacité est considérée comme maximale. Cette possibilité d'appeler certaines méthodes avec un nombre variable de paramètres est une des beautés de la programmation objet ; elle porte le joli nom de surcharge. Mais laissons ces considérations aux cours de Java, et concentrons-nous sur notre sujet.

Voilà un exercice pas très difficile, mais où certains éléments de code ne s'improvisent pas. La boucle permettant de récupérer l'ensemble des couleurs, en particulier, est impossible à écrire par le seul raisonnement. Il faut donc fouiller sur le net pour trouver un exemple de code, le comprendre et l'adapter... ce qui fait partie des compétences vitales pour se dépatouiller en programmation !
Exercice

Exécutable

Sources

Home cinema

2. Images et Contrôles

Il n'aura pas échappé à vos yeux de lynx qu'en mode design, un certain nombre de contrôles acceptent volontiers que leur fond soit constitué d'une image. C'est entre autres le cas pour les Form et les Buttons, avec la propriété BackgroundImage.

J'aborderai dans un instant la manière dont on peut affecter cette propriété par du code. En attendant, je dois dire quelques mots des contrôles dont le rôle spécifique est de contenir des images.

2.1 La classe ImageList (rappel)

Il y a tout d'abord l'ImageList, dont nous avons déjà fait la connaissance. Je rappelle que ce contrôle :

  • est un véritable tableau d'images, qui peut donc en contenir autant qu'on le souhaite.
  • reste invisible lors de l'exécution, ainsi que toutes les images qu'il contient.

Il ne peut donc servir que de « réservoir à images » pour les autres contrôles, qui iront y puiser les images nécessaires au fur et à mesure de leurs besoins, durant l'exécution de l'application.

2.2 La classe PictureBox

Si l'on veut qu'à un endroit de la Form, se trouve telle ou telle image, alors il faut utiliser le contrôle adéquat, à savoir PictureBox. Celui-ci possède une propriété Image, qui indiquera son contenu. Le contrôle PictureBox prend en charge les principaux formats d'image : JPEG, GIF, Bitmap, métafichiers (WMF), icônes... Il ne gère pas, en revanche, les vidéos.

Une propriété notable des PictureBox est SizeMode. Celle-ci peut prendre quatre valeurs, qui modifieront les propriétés du contrôle et/ou de l'image dans le cas où ceux-ci ne possèdent pas les mêmes dimensions :

  • aucun : ni le contrôle ni l'image ne changent de taille. Cela peut signifier que l'image sera rognée, et/ou que le contrôle débordera de l'image. L'image est alignée en haut à gauche du contrôle.
  • 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 automatiquement adaptée à celle de l'image qu'il contient.
  • centerimage : les tailles de l'image et du contrôle ne sont pas modifiées, mais l'image est centrée par rapport au contrôle.

3. Gérer intelligemment les images

On en vient à présent à la manière de gérer les images dans une application. Il y a deux stratégies, possédant chacune leurs avantages et leurs inconvénients, qu'il vaut mieux connaître avant de faire des choix discutables et pénalisants.

Le premier mouvement, lorsqu'on veut utiliser des images, c'est évidemment de les intégrer aux contrôles (PictureBox, ImageList, Form, etc.) en mode design, donc en tant que propriétés par défaut de ces contrôles. C'est la manière la plus simple de procéder, qui va avoir une double conséquence : d'une part, les fichiers images vont être considérés par C# comme fasiant partie intégrante de la Form. À l'enregistrement de celle-ci, les informations qu'ils contiennent seront recopiées dans un fichier annexe du fichier *.cs, portant le même nom et l'extension *.resx. Par conséquent, les fichiers image seront directement incorporés à l'exécutable. L'avantage, c'est que celui-ci n'aura jamais de problème pour les trouver. Mais l'inconvénient, c'est que l'exécutable peut s'en trouver considérablement – et inutilement ‐ alourdi, au point de devenir éventuellement un monstre incapable de tourner sur certaines machines à la puissance limitée.

Voilà pourquoi cette technique, si elle a l'avantage de la facilité, est à réserver aux petites images, et qu'elle doit être proscrite dès qu'on a affaire à des images volumineuses et/ou trop nombreuses.

Pour celles-ci, comment faire ? Pour s'y retrouver, il va falloir en quelque sorte raisonner à rebrousse-poil, en partant du but à atteindre pour remonter vers les moyens à mettre en œuvre. C'est parti :

Au final, que voulons-nous ? Que le(s) fichier(s) image(s) dont l'exécutable va avoir besoin soient stockés indépendamment de cet exécutable, afin de conserver à celui-ci la sveltesse qui fait toute son élégance.

Pour cela, il faut que l'exécutable contienne une ou plusieurs instructions donnant l'ordre de charger tel ou tel fichier image dans tel ou tel contrôle. Cette instruction est la méthode FromFile, qui appartient à la classe Image. On écrira ainsi :

PictureBox1.Image = Image.FromFile(nom du fichier)

C'est là qu'arrive un petit souci. Le nom du fichier, cela sous-entend de devoir préciser le répertoire dans lequel il se trouve. Dans le cas contraire, cette instruction serait incapable de fonctionner et provoquerait une erreur. Il faut donc absolument :

  • spécifier correctement, lors de l'emploi de la méthode FromFile, le nom du fichier image, y compris, naturellement, le chemin des répertoires qui y mène.
  • faire en sorte que lors de l'installation de cette application sur différentes machines, et ce, quel que soit le répertoire où s'effectuera l'installation, le fichier image se trouvera bel et bien dans le chemin voulu.

Le premier point ne pose guère de problème. On a le choix entre positionner les fichiers image de manière absolue (« à la racine de D: »), soit, et c'est l'option la plus fréquente, de manière relative (« dans le sous-répertoire Images »). Il faut alors s'assurer que le sous-répertoire concerné soit bel et bien présent au bon endroit par rapport à l'exécutable... en se souvenant que Visual Studio place l'exécutable obtenu par simple débogage dans le répertoire Bin/Debug des sources, et celui obtenu par la commande Générer la solution dans le répertoire Bin/Release.

Quant au second point (le fait que répertoires et fichiers soient bien positionnés sur toute machine à laquelle on distribuera le programme), il est à relier aux questions liées à l'installation des applications. Or, la version gratuite de Visual Studio, dite Express, ne comporte pas de module installateur. Je passerai donc cet aspect sous silence, même si dans le cadre d'une « vraie » application, se poserait la question de son déploiement (mais soyons justes, ce n'est tout de même pas la plus compliquée).

Terminons par un enfonçage de porte ouverte : cette technique ne se limite pas aux grosses images ; elle s'appliquera avec de menues variantes à tous les fichiers annexes dont une application pourra avoir besoin : données, vidéos, sons, etc.

4. Deux mots sur les méthodes graphiques

Mais alors juste deux mots, parce que le sujet ne peut intéresser que des programmeurs d'applications d'un type peu spécialisé. Sachez donc que C# donne facilement accès aux classes et aux méthodes de Windows qui permettent de tracer directement des points et des formes à l'écran.

On peut ainsi par du code tracer aussi bien des graphismes en mode Bitmap (c'est à dire en faisant du point par point) qu'en mode vectoriel (en raisonnant sur des formes). Et on peut dessiner aussi bien à l'écran (sur un contrôle), qu'à l'imprimante (sur un objet PrintDocument) ou en mémoire (le résultat restant ensuite disponible pour n'importe quel usage, y compris être enregistré dans un fichier).

En mode Bitmap, on peut positionner des points, des rectangles, des ellipses, tracer des traits paramétrables avec un crayon ou un pinceau virtuel, faire des dégradés. En mode vectoriel, il sera possible de tracer des lignes, des polygones, des cercles, des ellipses, des courbes de Bézier...

Bon, bref, on peut faire à peu près tout ce qu'on veut tant que ce n'est pas une reproductiopn de la Joconde (ou alors, il faut être très doué et très patient). Et comme j'avais dit que je ne serais pas long sur le sujet, je vais tenir parole.