Comment créer une application de dessin avec Processing
Vue de l'application de dessin programmée avec Processing |
Processing (processing.org), à la fois logiciel et langage de programmation,
permet de réaliser des applications graphiques et interactives sur la base du langage Java. Pour illustrer ces usages, voyons comment programmer une
application de dessin qui permettra de sélectionner la couleur et
l'épaisseur de trait et d'enregistrer le travail sous forme d'une
image PNG ou JPEG selon le choix du programmeur (sous réserve que
l'enregistrement comprend aussi des éléments d'interface : on
enregistre tout ce qui s'affiche dans la fenêtre de notre
programme).
Pour débuter, comme pour tout
programme dans Processing, tout se passe autour du setup(),
qui se joue une fois pour fixer les paramètres de l'application, et
une boucle draw() qui tourne en continu pendant tout le
temps que se joue le programme. Commençons donc par créer une
fenêtre de 900 pixels de large et 700 pixels de hauteur. La page de
dessin sera concrètement d'une largeur de 800 pixels et prendra
toute la hauteur de la fenêtre. Le menu viendra, sur toute la
hauteur, dans un rectangle de 100 pixels de largeur collé au bord.
void
setup() {
size(900,
700);
smooth();
background(0);
//
définition de la surface de dessin
noStroke();
fill(255);
rect(100,
0, width-100, height);
}
void
draw() {
}
🚩:
Pour tester un programme à chaque étape, il suffit de cliquer sur
le bouton lecture de Processing (▶).
Interagir avec la souris
Testons les grands principes
d’interactivité dans Processing. Pour repérer la position du
pointeur de la souris, ce qui nous permettra de définir où se situe
la pointe du crayon dans la fenêtre, nous devons connaître ses
coordonnées selon les axes X et Y. Nous allons utiliser mouseX
et mouseY, ces paramètres déterminent en temps réel
la position de la souris. Pour le visualiser, dessinons un cercle
jaune de 5 pixels de rayon autour du pointeur.
void
draw() {
fill(255,
255, 0);
ellipse(mouseX,
mouseY, 10, 10);
}
Avec ce code, le programme dessine un
cercle de 10 pixels de diamètre autour du pointeur de la souris à
chaque fois que l'écran se rafraîchit.
Pour notre programme, il faudrait tracer une ligne continue pendant tout le temps où l'on maintient enfoncé le bouton de la souris. Pour ce faire, il nous faut repérer la position de la
souris par rapport à son ancienne position et dessiner alors un
trait entre les deux étapes. Nous pouvons appeler pmouseX
et pmouseY pour cela. Le programme connaîtra alors les
coordonnées X et Y précédentes.
void
draw() {
noFill();
stroke(255,
255, 0);
strokeWeight(2);
line(pmouseX,
pmouseY, mouseX, mouseY);
}
La position par défaut du pointeur est
dans le coin haut gauche de la fenêtre, le dessin commence donc de
cette position et relie le trait à la souris à chaque changement de
position. Pour un programme de dessin, il nous faudra préciser que
le dessin ne se fait que lorsque le bouton de la souris est enfoncé,
dans le cadre de dessin blanc, pas sur le menu. Ces fonctionnalités
se jouent en émettant une condition : mousePressed,
et une autre condition : on dessine au delà de 100 pixels à
partir de la gauche.
void
draw() {
if
(mousePressed && mouseX > 100 && pmouseX > 100)
{
noFill();
stroke(255,
255, 0);
strokeWeight(2);
line(pmouseX,
pmouseY, mouseX, mouseY);
}
}
Nous avons maintenant quasiment élaboré
les principes de l'application. Le programme permet déjà de
réaliser un dessin dans la fenêtre créée.
Pour obtenir un vrai programme de
dessin, il faut avoir accès à certaines fonctionnalités qui
permettent de paramétrer le crayon (épaisseur du trait, couleur) et
d'agir à partir du menu (nouveau dessin, enregistrement).
Occupons-nous maintenant du menu à gauche.
Le menu s'affiche à gauche, dans un
cadre de couleur noire de 100 pixels sur la hauteur. Le menu sera
dessiné dans la boucle draw() du programme pour pouvoir
afficher les modifications de paramètres à chaque fois.
Épaisseur du crayon
L'épaisseur du crayon se déterminera
à l'aide de deux flèches (des triangles blancs) encadrant le
chiffre correspondant à l'épaisseur en pixels du trait (limitée
entre 1 et 10). Créons une variable globale epaisseur (un
entier) définie à 4 par défaut.
int
epaisseur;
void
setup() {
...
epaisseur
= 4;
textAlign(CENTER);
textSize(20);
...
}
void
draw() {
//
dessin du menu
noStroke();
fill(0);
rect(0,
0, 100, height);
fill(255);
triangle(50,
580, 80, 610, 20, 610);
text(epaisseur,
50, 635);
triangle(20,
650, 80, 650, 50, 680);
//
dessin des traits de crayon
if
(mousePressed && mouseX > 100 && pmouseX > 100)
{
noFill();
stroke(255,
255, 0);
strokeWeight(epaisseur);
line(pmouseX,
pmouseY, mouseX, mouseY);
}
}
L'interactivité du menu se passera
dans une nouvelle boucle mousePressed() qui prend en
charge chaque action de la souris. Il faut définir la zone
correspondant au bouton d'action et l'action provoquée par un clic :
void
mousePressed() {
//
flèche vers le haut
if(mouseX
> 20 && mouseX < 80 && mouseY > 580 &&
mouseY < 610) epaisseur = epaisseur + 1;
//
flèche vers le bas
if(mouseX
> 20 && mouseX < 80 && mouseY > 650 &&
mouseY < 680) epaisseur = epaisseur - 1;
//
contraintes de l'épaisseur
if(epaisseur
< 1) epaisseur = 1;
if(epaisseur
> 10) epaisseur = 10;
}
Sélecteur de couleurs
Les couleurs d'un programme Processing
sont, par défaut, déterminées en mode RVB (rouge, vert, bleu en
256 niveaux de 0 à 255). Nous allons donc faire un sélecteur de
couleurs avec 3 boutons à glisser pour faire varier la valeur de 0 à
255 du rouge, du vert et du bleu. Nous pouvons créer trois variables
globales (définies ici à 100 pour un niveau de gris) au début du
code :
int
rouge, vert, bleu;
void
setup() {
...
rouge
= 100;
vert
= 100;
bleu
= 100;
…
}
Pour afficher les sélecteurs de
couleur, nous allons créer trois objets (étant donné que les
éléments sont quasiment identiques). Nous créons une classe*
« Selecteur » avec deux variables définissant le
sélecteur.
* Pour la
construction d'un objet, voir article Programmation Orientée Objets dans Processing.
Le sélecteur comprend une ligne
servant de guide pour voir où on en est du niveau de couleur, le
niveau de rouge, vert ou bleu s'affiche dans un rectangle qui sert de
manette. La couleur de chaque rectangle est obtenue à partir des
variables correspondantes combinées avec des valeurs nulles pour les
deux autres nuances du mode RVB.
La création de l'objet peut se placer
à la fin du code, ou même dans un nouvel onglet (Ctrl + Maj +
N) :
class
Selecteur {
int
positionX, niveau;
Selecteur(int
tempX, int tempNiveau) {
positionX
= tempX;
niveau
= tempNiveau;
}
void
display() {
stroke(200);
strokeWeight(2);
line(positionX, 500,
positionX, 240);
if
(positionX == 30) {
fill(rouge,
0, 0);
niveau
= rouge;
}
else if (positionX == 50) {
fill(0,
vert, 0);
niveau
= vert;
}
else {
fill(0,
0, bleu);
niveau
= bleu;
}
rectMode(CENTER);
rect(positionX, 500 - niveau,
10, 10);
}
}
Pour afficher les sélecteurs, nous
créons les instances de l'objet dans la partie setup()
où l'on défini les paramètres, et on affiche les objets dans la
boucle draw(). Au dessous des sélecteurs, nous
affichons la couleur en cours. Nous ajoutons cette forme juste après
la description de la partie interactive du tracé de crayon :
void
setup() {
...
//
création des boutons du sélecteur de couleur
for
(int i = 0; i < niveaux.length; i++) {
niveaux[i]
= new Selecteur(30+i*20, 50);
}
}
void
draw() {
…
//
dessin des traits de crayon
if
(mousePressed && mouseX > 100 && pmouseX > 100)
{
noFill();
stroke(rouge,
vert, bleu);
strokeWeight(epaisseur);
line(pmouseX,
pmouseY, mouseX, mouseY);
}
//
affichage de la couleur en cours
stroke(255);
strokeWeight(2);
fill(rouge,
vert, bleu);
rect(30,
520, 40, 40);
line(20,
200, 80, 200);
//
affichage des sélecteurs de couleur
for
(int i = 0; i < niveaux.length; i++) {
niveaux[i].display();
}
}
La partie interactive du sélecteur de
couleurs ne sera pas positionnée dans la boucle mousePressed(),
qui permet de sélectionner une action selon l'endroit où l'on
clique, mais dans une boucle mouseDragged() qui offre
l'avantage de suivre, tant que le bouton de la souris est enfoncé,
la position du pointeur de la souris et d'agir de manière plus
naturelle, comme avec une manette de réglage. Ajoutez et testez ce code
pour agir avec les sélecteurs de couleurs :
void
mouseDragged() {
if
(mouseY > 244 && mouseY < 501) {
if
(mouseX > 24 && mouseX < 36) rouge = 500 - mouseY;
if
(mouseX > 44 && mouseX < 56) vert = 500 - mouseY;
if
(mouseX > 64 && mouseX < 76) bleu = 500 - mouseY;
}
}
Effacer et recommencer
Maintenant que nous avons une
application fonctionnelle, nous pouvons dessiner. Mais le besoin se
fera certainement ressentir de faire un nouveau dessin sans devoir fermer et
rouvrir l'application à chaque fois. C'est ici qu'entrent en jeu des
éléments d'interface : un bouton « nouveau document »
et un autre bouton pour enregistrer.
Pour effacer le dessin en cours et en
faire un nouveau, nous allons créer un bouton qui, lorsque l'on
clique dessus, dessine un rectangle blanc pour recouvrir la surface
de dessin et ouvrir ainsi un nouvel espace libre.
Dessinons une forme libre sous le
sélecteur de couleurs. Dans la boucle draw(),
traçons une forme (Shape) où chaque point de la figure géométrique
est décrit par un vertex(coordonnéeX, coordonnéeY). Les deux
lignes figurent le coin de la page replié.
void draw() {
…
// forme du bouton "Nouveau"
fill(255);
beginShape();
vertex(30, 40);
vertex(60, 40);
vertex(70, 50);
vertex(70, 90);
vertex(30, 90);
endShape(CLOSE);
stroke(50);
line(60, 40, 60, 50);
line(60, 50, 70, 50);
}
Pour
que ce bouton ait une fonction, ajoutons de l'interactivité dans la
boucle mousePressed() :
void
mousePressed() {
…
//
bouton "Nouveau" : nouvelle surface de dessin
if(mouseX
> 29 && mouseX < 71
&&
mouseY > 39 && mouseY < 91) {
fill(255);
noStroke();
rectMode(CORNER);
rect(100,
0, width-100, height);
}
}
Nous avons défini la zone du bouton
« Nouveau », et quand l'utilisateur clique dans cette
zone, le programme dessine une nouvelle zone de dessin vierge.
Se souvenir des belles choses
On peut, en tant qu'utilisateur d'un
programme de création graphique, avoir envie de sauvegarder ses
créations. Pour offrir cette possibilité, créons notre bouton
d'enregistrement sous la forme d'un disquette simplifiée, comme
encore utilisé dans beaucoup d'applications.
Pour obtenir des coins arrondis sur
notre disquette, indiquons le paramètre « ROUND »
(arrondi) dans le descriptif de la jonction des lignes (strokeJoin).
Le reste est du code de dessin classique :
void
draw() {
…
//
forme du Bouton "Enregistrer"
rectMode(CORNER);
stroke(255);
strokeJoin(ROUND);
strokeWeight(5);
rect(32,
120, 36, 40);
fill(50);
stroke(50);
rect(40,
145, 20, 10);
fill(100);
noStroke();
rect(42,
118, 16, 10);
rect(45,
143, 10, 5);
}
Une fois la disquette dessinée,
ajoutons-lui la fonction dont nous avons besoin. Pour enregistrer la
fenêtre de l'application en cours dans Processing, il existe une
fonction simple : save(), qui prend pour paramètre
le nom du fichier dans lequel nous souhaitons enregistrer l'image :
void
mousePressed() {
…
//
fonction d'enregistrement
if(mouseX
> 29 && mouseX < 71
&&
mouseY > 119 && mouseY < 161)
save("mesdessins/dessin.png");
}
L'enregistrement se fera donc dans le
dossier de l'application, à l'intérieur d'un sous-dossier « mes
dessins » que le programme se chargera de créer s'il n'existe
pas encore. Si le fichier existe déjà, la nouvelle image écrasera
la précédente ; il faudra prévoir de renommer chaque nouveau
dessin avant d'en commencer un autre. Vous pouvez maintenant exporter
l'application (Fichier / Exporter ou Ctrl + Maj + E)
pour diffuser votre programme sur différents ordinateurs.
Voici le code complet :
int
epaisseur;
int
rouge, vert, bleu;
Selecteur
niveaux[] = new Selecteur[3];
void
setup() {
size(900,
700);
smooth();
background(0);
epaisseur
= 4;
rouge
= 100;
vert
= 100;
bleu
= 100;
textAlign(CENTER);
textSize(20);
//
définition de la surface de dessin
noStroke();
fill(255);
rect(100,
0, width-100, height);
//
création des boutons du sélecteur de couleur
for
(int i = 0; i < niveaux.length; i++) {
niveaux[i]
= new Selecteur(30+i*20, 50);
}
}
void
draw() {
//
dessin du menu
rectMode(CORNER);
noStroke();
fill(0);
rect(0,
0, 100, height);
fill(255);
triangle(50,
580, 80, 610, 20, 610);
text(epaisseur,
50, 635);
triangle(20,
650, 80, 650, 50, 680);
//
dessin des traits de crayon
if
(mousePressed && mouseX > 100 && pmouseX > 100)
{
noFill();
stroke(rouge,
vert, bleu);
strokeWeight(epaisseur);
line(pmouseX,
pmouseY, mouseX, mouseY);
}
//
affichage de la couleur en cours
stroke(255);
strokeWeight(2);
fill(rouge,
vert, bleu);
rect(30,
520, 40, 40);
line(20,
200, 80, 200);
//
affichage des sélecteurs de couleur
for
(int i = 0; i < niveaux.length; i++) {
niveaux[i].display();
}
//
forme du bouton "Nouveau"
fill(255);
beginShape();
vertex(30,
40);
vertex(60,
40);
vertex(70,
50);
vertex(70,
90);
vertex(30,
90);
endShape(CLOSE);
stroke(50);
line(60,
40, 60, 50);
line(60,
50, 70, 50);
//
forme du Bouton "Enregistrer"
rectMode(CORNER);
stroke(255);
strokeJoin(ROUND);
strokeWeight(5);
rect(32,
120, 36, 40);
fill(50);
stroke(50);
rect(40,
145, 20, 10);
fill(100);
noStroke();
rect(42,
118, 16, 10);
rect(45,
143, 10, 5);
}
void
mousePressed() {
//
flèche vers le haut
if
(mouseX > 20 && mouseX < 80 && mouseY > 580
&& mouseY < 610) epaisseur = epaisseur + 1;
//
flèche vers le bas
if
(mouseX > 20 && mouseX < 80 && mouseY > 650
&& mouseY < 680) epaisseur = epaisseur - 1;
//
contraintes de l'épaisseur
if
(epaisseur < 1) epaisseur = 1;
if
(epaisseur > 10) epaisseur = 10;
//
bouton "Nouveau" : nouvelle surface de dessin
if(mouseX
> 29 && mouseX < 71
&&
mouseY > 39 && mouseY < 91) {
fill(255);
noStroke();
rectMode(CORNER);
rect(100,
0, width-100, height);
}
//
fonction d'enregistrement
if(mouseX
> 29 && mouseX < 71
&&
mouseY > 119 && mouseY < 161)
save("mesdessins/dessin.png");
}
void
mouseDragged() {
if
(mouseY > 244 && mouseY < 501) {
if
(mouseX > 24 && mouseX < 36) rouge = 500 - mouseY;
if
(mouseX > 44 && mouseX < 56) vert = 500 - mouseY;
if
(mouseX > 64 && mouseX < 76) bleu = 500 - mouseY;
}
}
class
Selecteur {
int
positionX, niveau;
Selecteur(int
tempX, int tempNiveau) {
positionX
= tempX;
niveau
= tempNiveau;
}
void
display() {
stroke(200);
strokeWeight(2);
line(positionX, 500,
positionX, 240);
if
(positionX == 30) {
fill(rouge,
0, 0);
niveau
= rouge;
}
else if (positionX == 50) {
fill(0,
vert, 0);
niveau
= vert;
}
else {
fill(0,
0, bleu);
niveau
= bleu;
}
rectMode(CENTER);
rect(positionX, 500 - niveau,
10, 10);
}
}
Commentaires
Enregistrer un commentaire