lundi 1 septembre 2008

Saisie au clavier et affichage

Voici donc l'une des façons dont on pourrait capturer les saisies au clavier :

PFont font; // instanciation de la fonte
String entree = ""; // on déclare la chaîne "entree" et on la vide

void setup() {
size(400,200); // définition de la surface de travail
font = loadFont("LucidaSans-24.vlw"); // chargement de la police
textFont(font); // déclaration de la police active
frameRate(10); // taux de traitement par seconde
}


void draw() {
text(entree,10,30); // on affiche le contenu de 'entree' aux coordonnées 10,30
if (keyPressed == true) { // si une touche a été pressée
entree = entree + key; // on ajoute sa valeur à la chaîne 'entree'
}
}

Le code est assez explicite. Vous aurez compris que :
text("un mot",10,30) affiche "un mot" (ou une chaîne) à 10 pixels du bord en abscisses et 30 pixels en ordonnées
keyPressed est une instruction réservée qui permet de tester une saisie au clavier
key est une variable réservée qui contient le dernier caractère saisi
une égalité se teste avec == comme en PHP

Une chose intéressante : frameRate() détermine le nombre d'images par seconde (rappelez vous que Processing est orienté graphique). Partant de là, cette fonction influe directement sur la précision de ce que le script "capte" au clavier.
Avec un frameRate(100), même la pression la plus brève renverra de nombreux caractères. En fait, autant de caractères que de centièmes de secondes durant lesquels la touche aura été enfoncée. Si en revanche vous diminuez le paramètre à 10 ou 5, il vous faudra exercer une pression plus longue pour que le script en tienne compte.

mardi 26 août 2008

L'affichage graphique part 3

Deuxième fonction, draw(). Comme son nom l'indique, cette fonction dessine...

Elle doit obligatoirement être placée immédiatement après setup(), exécute en permanence les lignes de code qu'elle contient. Elle n'est arrêtée que par la fin du programme en lui même, ou un appel à l'instruction noLoop() en fin de la fonction setup().
Aucun appel direct ne peut être fait à cette fonction. L'exécution en est contrôlée par :
redraw(), qui relance l'exécution du code pour une seule itération.
loop(), qui rend l'exécution à nouveau continue

Il ne peut y avoir qu'une seule fonction draw() par script, et sa présence est nécessaire si vous attendez un événement comme un clic de souris. Dans ce cas, l'appel à la fonction peut être "vide".

samedi 23 août 2008

L'affichage graphique part 2

Dans le post précédent, on a abordé un point assez capital sur lequel on va s'attarder un peu : il s'agit des deux fonctions setup et draw.

Comme son nom le laisse supposer, setup installe quelquechose. En l'occurrence, elle définit l'environnement graphique dans lequel s'exécutera le script : dimensions, couleur ou image de fond etc. Dans la pratique ça donne ceci, avec l'appel à la police (oui, bon).

void setup() {
size(400,200);
font = loadFont("ACaslonPro-Italic-16.vlw");
textFont(font);
background(0);
fill(102);
frameRate(10);
}

Size parle de lui-même : c'est la dimension de la zone exprimée en pixels.
loadFont et textFont, je n'y reviens pas.

Background définit la couleur du fond, de plusieurs façons (notez au passage que fill() prend les mêmes paramètres). Les valeurs passées en paramètres peuvent représenter principalement :
  • une nuance de couleur (0 = noir, 250 = blanc, 300 = bleu marine etc. Je n'ai pas cherché à définir l'univers colorimétrique)
  • une nuance rvb ou hsv selon le mode colorimétrique (par défaut colorMode(RGB) ou colorMode(HSB), nous y reviendrons) exemple : background (128,128,250);
  • une nuance "web" en utilisant la notation hexadécimale : background(#FFFF66);
  • Dans tous cas, il est possible de rajouter un paramètre supplémentaire de transparence (alpha). Pour l'instant, je vous avoue que je ne vois pas trop l'intérêt de rendre un fond transparent.
  • Enfin, la doc officielle nous apprend qu'on peut utiliser une image comme fond, comme ceci :
    PImage b;
    b = loadImage("\images\laDefense.jpg");
    background(b);
...Il faut bien sur que l'image soit dans l'arborescence du dossier du script. Il n'est pas nécessaire de la placer dans un sous-répertoire comme ici.

lundi 18 août 2008

Un grand pas en avant - L'affichage graphique

Non, non, ce blog n'est pas abandonné ! Je tiens à rassurer les deux lecteurs qui se sont perdus sur ces pages. A vrai dire, pour pouvoir vous faire part de mes découvertes, il faut que j'en fasse... Et parfois, ça prend du temps.

Alors pour me faire pardonner, je vous propose de gagner du temps et d'accélérer la cadence. Avec ce projet dingue de réaliser ici notre première application. Comme ça. Paf ! A froid.
Mais bon, quand on parle d'application, entendons-nous bien : on ne va pas réécrire Word tout de suite.

Ce qu'on va faire, c'est écrire un petit programme très à la mode de l'époque où j'alignais mes toutes premières lignes de code. Ca remonte à... Pfffff ! Pour vous situer, en ce temps là, Steve Jobs commandait pour Apple des petits logiciels à un jeune du nom de Bill Gates.
Ce programme va consister à calculer un prix TTC à partir du montant HT. Oui, je sais, ça a l'air tarte, mais ça n'est pas si simple. Vous allez voir ça tout de suite.

Commençons par distinguer les différentes étapes de notre programme :

  1. Saise du montant HT
  2. Contrôle de la saisie (il doit s'agir d'un nombre positif)
  3. Calcul
  4. Affichage du résultat
Le tout, évidemment, de façon un peu élégante.

Seulement, il n'existe pas en Processing d'instruction équivalente au input() ou raw_input() du Python, par exemple. C'est probablement dû à sa parenté avec Java, qui n'en dispose pas non plus. Ne faisons pas de mystères, cela revient à dire que Processing ne sait pas attendre gentiment que vous saisissiez quelque chose au clavier. Du coup, il ne vous autorise pas non plus à contrôler et modifier ce que vous tapez.
Ce qui signifie que notre programme a besoin de quelques étapes supplémentaires, pour devenir :
  1. Définition de la zone d'affichage
  2. Capture des éventuels événements clavier
  3. Interprétation de la saisie "non-alphanumérique" = touches de fonction, flèches etc.
  4. Affichage de la saisie capturée
  5. Modification de la saisie en cas de correction
  6. Validation de la saisie
  7. Contrôle de la saisie (il doit s'agir d'un nombre positif)
  8. Affichage du résultat

A la taille de cette liste, vous aurez compris que Processing a besoin qu'on lui précise bien des choses. A priori, ça peut paraître pénible mais ça aurait été pareil dans d'autres langages. En Python par exemple la déclaration d'une zone d'affichage aurait eu lieu plus loin dans le script.

Pour vous imprégner au mieux de la logique Processing, pensez que vous développez une applet destinée à être intégrée à une page web. D'où, premier souci, définir les dimensions "physiques" de la chose. Deuxième souci, d'ordre graphique également : quels sont les éléments d'affichage mobilisés. En l'occurrence, c'est du texte, il faut donc définir les polices utilisées. Enfin, puisque le langage a une vocation graphique/animation, déterminons le taux de rafraîchissement.

PFont font;
String entree = ""; -> on définit quelques variables et chaînes utiles pour plus tard
int i;

void setup() {
size(400,200); -> la dimension en pixels de notre zone de travail
font = loadFont("ACaslonPro-Italic-16.vlw"); -> choix de la police utilisée
textFont(font); -> utilisation de la police pour le texte
frameRate(10); -> taux de rafraîchissement
}

Evidemment, en rose, ce sont des commentaires qui n'ont rien à voir avec le script. Notez au passage que j'utiliserai désormais de véritables commentaires pour, euh... Ben pour commenter ! C'est à dire qu'une note dans le script sera indiquée par // si elle tient en une ligne et délimitée par /* et */ si elle tient en plusieurs.

PFont est la classe de gestion des fontes. On commence par en créer une instance qui recevra la fonte choisie.
Pour pouvoir utiliser une police de caractères, il faut faire appel au menu de votre IDE : menu "Tools", "Create font...". Là, vous choisirez la police et son corps en pixels. Elle sera convertie au format bitmap .vlw et placée dans un sous-répertoire du dossier où sera sauvegardé votre script. Dans mon cas, ça donne : Processing/caspratique/data/ACaslonPro-Italic-16.vlw .

Dans le script, on "chargera" la police au moyen de loadFont et on la rendra active par textFont(). Et pour l'utiliser véritablement, on ne fera plus appel à print mais à text(), utilisée ainsi :
text("chaîne à afficher", coordonnées x, coordonnées y);

Sachant que la "chaîne à afficher" peut être une variable et que x et y sont indiqués en pixels.

mardi 5 août 2008

Il est l'heure du Hello World !

C'est super de programmer des trucs et des machins, mais c'est encore mieux quand on en voit le résultat. Comme vous l'aurez constaté en utilisant l'interface de développement (dans le jargon, on appelle ça l'IDE, vous avouerez que ça fait quand même très pro), il y a en bas de la fenêtre d'icelle (de l'IDE, donc) une zone d'affichage qui pourrait être celle de la console des autres langages de programmation.
En clair, tout ce que Processing à a vous dire, il vous le dira dans la partie noire, en bas de la fenêtre de l'application.

Mais nous aussi, si on veut, on peut écrire dans cette zone. Ce qui est surtout utile lorsque, en cours de développement d'un script, on veut surveiller une variable. Et pour ça, on dispose de deux instructions : print() et println(). La différence ? LN, justement, deux lettres qui seront familières à tous ceux qui se sont un jour pris la tête pour aligner une imprimante matricielle. Plus sérieusement, la différence tient au fait que le println insère un saut de ligne.

Pour le reste, les deux instructions permettent d'afficher des variables comme des chaines alphanumériques en les plaçant entre guillemets. Les opérations de concaténation de chaîne sont possibles. Sur ce, entrons dans le vif du sujet.

String a = "Hello";
println(a+" world !");
print(a);
print(" world ! (en deux fois)");

...ce qui affichera bien

Hello world !
Hello world ! (en deux fois)

Alors que

D'un type à l'autre

Si les variables et chaînes sont typées, comme on vient de le voir juste au-dessous, là, on peut quand même effectuer des conversions d’un type à l’autre.
Attention tout de même, si vous convertissez une variable vers une autre, la variable “récepteur” doit posséder le type de destination. Vous me suivez ? J’illustre :

c = 'A';
f = float(c); // f = 65.0
i = int(f * 1.4); // i = 91
b = byte(c / 2);

Ces exemples sont sortis de la doc officielle. Ce que je vous disais plus haut c’est que, par exemple, la variable f qui reçoit c converti en décimal doit elle-même être définie comme un décimal. D’où la nécessité d’un float f; au préalable.

Et puis, cela ne vous aura pas échappé, il y a une finesse : c vaut la lettre ‘A’. Or, on vient de convertir c en décimal. En d’autres termes, un chiffre en lettre (mes amitiés à Armand Jammot. Armand, si tu nous regardes…). Vous aurez compris que 65, soit la valeur de c, est le code ASCII de A.

Les grands classiques : variables et chaînes

Dans tous les guides de langages de programmation que j’ai pu lire, le premier chapitre parlait des variables. Toujours. Et quel que soit le langage. Alors je ne vais pas jouer au plus malin, et faire pareil. En plus, c’est assez logique comme démarche, finalement. Bref, commençons.

En processing, une variable, ça se déclare. S’il s’agit d’un entier, on la déclarera par :

int a = 12;

S’il s’agit d’une variable à virgule flottante, ce sera

float b = 0.0;

On peut aussi utiliser un type booléen. Je vous dirai franchement que je vois pas trop l’intérêt, même pour faire des flags. Mais s’il existe, c’est qu’il doit y avoir une bonne raison

boolean z = true;

qui permettra de faire des tests du style :

if (!z) { ...

Et pour finir, il y a le type byte qui, comme son nom l’indique (byte = octet), peut prendre les valeurs de -128 à 128.

byte b = 32;

(oui, on peut définir une variable et lui donner une valeur dans la foulée.)

Pour ce qui est des chaînes, rien d’affolant :

String chaine="une jolie chaîne de caractères";

…Rien d’affolant, sauf que String prend une majuscule, probablement parce qu’il le vaut bien.
Les chaînes d’un seul caractère, destinées à stocker des symboles typographiques, sont définies par :

char c;
c = 'P';