Cours:Idees OOP : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
m (Travail à réaliser)
m (Travail à réaliser)
 
Ligne 851 : Ligne 851 :
 
# Tester avec des [https://processing.org/reference/print_.html print]  et/ou des [https://processing.org/reference/println_.html println]  
 
# Tester avec des [https://processing.org/reference/print_.html print]  et/ou des [https://processing.org/reference/println_.html println]  
 
# Gérer la liaison série ([https://processing.org/reference/libraries/serial/Serial.html Serial]) en lieu et place de l'affichage dans la console processing.
 
# Gérer la liaison série ([https://processing.org/reference/libraries/serial/Serial.html Serial]) en lieu et place de l'affichage dans la console processing.
 +
===Correction partielle sans liaison série===
 +
 +
<source lang=Java>
 +
class ClassPianoKey
 +
{
 +
  int _note;
 +
  int _type; // type d la touche
 +
  int couleurOff, couleurOn; // noir, blanc ou  gris
 +
  int offsetX;
 +
  int clickAreaPosX,clickAreaPosY,clickAreaDX,clickAreaDY;
 +
 
 +
ClassPianoKey(int deltaX,int type,int note) {
 +
    _note = note;
 +
    _type = type;
 +
    offsetX = deltaX;
 +
    if (type < 4) { // touche blanche
 +
      couleurOff = 255;
 +
      couleurOn = 200;
 +
      clickAreaPosX=offsetX;
 +
      clickAreaPosY = 250;
 +
      clickAreaDX= 50;
 +
      clickAreaDY = 150;
 +
    } else {
 +
      couleurOff = 0;
 +
      couleurOn = 50;
 +
      clickAreaPosX=offsetX;
 +
      clickAreaPosY = 0;
 +
      clickAreaDX= 30;
 +
      clickAreaDY = 250;
 +
    }
 +
   
 +
  }
 +
 +
  void showOff() {
 +
    if (_type == 1) {
 +
      fill(couleurOff);
 +
      stroke(couleurOff);
 +
      rect(0+offsetX,0,35,250);
 +
      rect(0+offsetX,250,50,150);
 +
      // black
 +
      stroke(0);
 +
      line(0+offsetX,0,0+offsetX,400);
 +
      line(0+offsetX+50,0+250,0+offsetX+50,400);
 +
    }
 +
    if (_type == 2) {
 +
      fill(couleurOff);
 +
      stroke(couleurOff);
 +
      rect(0+offsetX+15,0,35,250);
 +
      rect(0+offsetX,250,50,150);
 +
      stroke(0);
 +
      line(0+offsetX,0+250,0+offsetX,400);
 +
      line(0+offsetX+50,0,0+offsetX+50,400);
 +
    }
 +
    if (_type == 3) {
 +
      fill(couleurOff);
 +
      stroke(couleurOff);
 +
      rect(0+offsetX+15,0,20,250);
 +
      rect(0+offsetX,250,50,150);
 +
      stroke(0);
 +
      line(0+offsetX,0+250,0+offsetX,400);
 +
      line(0+offsetX+50,0+250,0+offsetX+50,400);
 +
    }
 +
    if (_type == 4) {
 +
      fill(couleurOff);
 +
      stroke(couleurOff);
 +
      rect(0+offsetX,0,30,250);     
 +
    }
 +
   
 +
  }
 +
 +
  void showOn() {
 +
    if (_type == 1) {
 +
      fill(couleurOn);
 +
      stroke(couleurOn);
 +
      rect(0+offsetX,0,35,250);
 +
      rect(0+offsetX,250,50,150);
 +
      // black
 +
      stroke(0);
 +
      line(0+offsetX,0,0+offsetX,400);
 +
      line(0+offsetX+50,0+250,0+offsetX+50,400);
 +
    }
 +
    if (_type == 2) {
 +
      fill(couleurOn);
 +
      stroke(couleurOn);
 +
      rect(0+offsetX+15,0,35,250);
 +
      rect(0+offsetX,250,50,150);
 +
      stroke(0);
 +
      line(0+offsetX,0+250,0+offsetX,400);
 +
      line(0+offsetX+50,0,0+offsetX+50,400);
 +
    }
 +
    if (_type == 3) {
 +
      fill(couleurOn);
 +
      stroke(couleurOn);
 +
      rect(0+offsetX+15,0,20,250);
 +
      rect(0+offsetX,250,50,150);
 +
      stroke(0);
 +
      line(0+offsetX,0+250,0+offsetX,400);
 +
      line(0+offsetX+50,0+250,0+offsetX+50,400);
 +
    }
 +
    if (_type == 4) {
 +
      fill(couleurOn);
 +
      stroke(couleurOn);
 +
      rect(0+offsetX,0,30,250);     
 +
    }
 +
   
 +
  }
 +
 
 +
  Boolean mouseIn() {
 +
    if ((mouseX>clickAreaPosX) && (mouseX < clickAreaPosX+clickAreaDX)
 +
      && (mouseY>clickAreaPosY) && (mouseY < clickAreaPosY+clickAreaDY))
 +
        return true;
 +
    else return false;
 +
  }
 +
 
 +
}
 +
</source>
 +
 +
Et enfin le programme principal :
 +
 +
<source lang=Java>
 +
ClassPianoKey[] pianokeys = new ClassPianoKey[15];
 +
 +
void setup() {
 +
  size(400,400);
 +
  frameRate(1);
 +
  pianokeys[0]= new ClassPianoKey(0,1,1);  //do
 +
  pianokeys[1]= new ClassPianoKey(35,4,2);  //do#
 +
  pianokeys[2]= new ClassPianoKey(50,3,3);  //re
 +
  pianokeys[3]= new ClassPianoKey(85,4,4);
 +
  pianokeys[4]= new ClassPianoKey(100,2,5);
 +
  pianokeys[5]= new ClassPianoKey(150,1,6);
 +
  pianokeys[6]= new ClassPianoKey(185,4,7);
 +
  pianokeys[7]= new ClassPianoKey(200,3,8);
 +
  pianokeys[8]= new ClassPianoKey(235,4,9);
 +
  pianokeys[9]= new ClassPianoKey(250,3,10);
 +
  pianokeys[10]= new ClassPianoKey(235,4,11);
 +
  pianokeys[11]= new ClassPianoKey(250,3,12);
 +
  pianokeys[12]= new ClassPianoKey(285,4,13);
 +
  pianokeys[13]= new ClassPianoKey(300,2,14);
 +
  pianokeys[14]= new ClassPianoKey(350,1,15);
 +
  for (int i=0;i<15;i++) {
 +
    pianokeys[i].showOff();
 +
  }
 +
}
 +
 +
void draw() {
 +
 
 +
}
 +
 +
void mousePressed() {
 +
  for (int i=0;i<15;i++) {
 +
    if (pianokeys[i].mouseIn())
 +
      pianokeys[i].showOn();
 +
  } 
 +
}
 +
 +
void mouseReleased() {
 +
  for (int i=0;i<15;i++) {
 +
    if (pianokeys[i].mouseIn())
 +
      pianokeys[i].showOff();
 +
  } 
 +
}
 +
</source>
 +
 +
Malheureusement  l'ensemble est un peu lent pour être utilisé pour réaliser de la musique !!!
  
 
==Voir aussi==
 
==Voir aussi==

Version actuelle datée du 13 juin 2019 à 09:54

Introduction aux objets avec Processing

Programmation orientée-objet (version sympathique) peut être lue en guise de cours.

Exercice 1

Refaire les exemples développés dans la Playlist Youtube de Daniel Shiffman. On commencera par la classe Bubble développée dans le troisième cours.

Préparation à l'exercice suivant

Processing : Les Objets peut être consulté pour un rappel sur les objets. Nous allons continuer avec les tableaux ou listes.

Les listes (ou tableaux) vous propose des tableaux sur types simples (ou presque).

Pour aller plus loin, les listes d'objets sont abordées avec « Programmation orientée-objet (version sympathique) » en y cherchant la section Liste d'objets.

Array Objects montre une autre syntaxe pour les boucles for.

Exercice 2

1°) Transformer le code ci-dessous en une classe Processing pour utilisation.

Indications : on vous donne le code permettant un affichage d'un seul digit

int[] val={63,6,91,79,102,109,125,7,127,111,119,124,57,94,121,113};

void segment() {
  beginShape();
  vertex(0,10);
  vertex(10,0);
  vertex(50,0);
  vertex(60,10);
  vertex(50,20);
  vertex(10,20);
 endShape(CLOSE); 
}

void affiche7segs(int val,int rouge,int vert, int bleu) {
  pushMatrix(); // on désire laisser le repère inchangé
  noStroke();
  translate(40,0);
  if ((val & 1) == 1) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment a
  translate(-10,70);
  if ((val & 64) == 64) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment g
  translate(-10,70);
  if ((val & 8) == 8) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment d
  translate(15,-53);
  rotate(radians(100));
  if ((val & 16) == 16) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment e
  translate(-70,0);
  if ((val & 32) == 32) fill(rouge,vert,bleu); else fill(200);
  segment(); // segtment f
  translate(-12,-68);
  if ((val & 2) == 2) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment b
  translate(72,0);
  if ((val & 4) == 4) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment c
  popMatrix(); // on récupère le repère initial
}

2°) Faire fonctionner la correction de l'exercice 1. Puis réaliser l'affichage du compteur binaire de la correction sur deux digits

3°) Réaliser un affichage de 4 digits destiné à afficher l'heure et les minutes d'un réveil.

4°) Modifier la classe pour pouvoir changer la taille de chaque digit (!!! ANNULE !!!)

5°) Réaliser une classe "HHMMClass" de 2x2 digits séparés par deux points.

Indication : voici le début de la classe. Il ne vous reste qu'à positionner les ':' et probablement être capable de positionner cet ensemble de digits si vous voulez un jour afficher l'heure courante et l'heure réveil.

class HHMMClass {
  int posX,posY;
  int hh_mm;
  Digit[] digits = new Digit[4];
  HHMMClass() {
    posX=posY=0;
    hh_mm = 0x2340;
    for(int i=0;i<4;i++)
      digits[i]=new Digit(100*i,50);
  }
  void affiche() {
    for(int i=0;i<4;i++) {
      digits[3-i].put(hh_mm >> (4*i) & 0xF);
      digits[3-i].affiche7segs(255,0,0);
    }
  }
  void incrementHHMM() {
      (hh_mm)++;
      if ((hh_mm & 0x000F) > 0x0009)
        hh_mm += 0x0006;
      if ((hh_mm & 0x00F0) > 0x0050)
        hh_mm += 0x00A0;
      if ((hh_mm & 0x0F00) > 0x0900)
        hh_mm += 0x0600;
      if ((hh_mm & 0xFF00) > 0x2300)
        hh_mm = 0x0000;
  }
  void decrementHHMM() {
      (hh_mm)--;
      if ((hh_mm & 0x000F) == 0x000F)
      hh_mm -= 0x0006;
      if ((hh_mm & 0x00F0) == 0x00F0)
      hh_mm -= 0x00A0;
      if ((hh_mm & 0x0F00) == 0x0F00)
      hh_mm -= 0x0600;
      if ((hh_mm & 0xFFFF) > 0x2359)
      hh_mm = 0x2359;
  }
}

Faire vos propres essais avant de passer à la question suivante. L'utilisation de cette classe nécessite l'utilisation de la classe digit avec laquelle elle possède un lien fort.

6°) Utiliser cette classe pour afficher l'heure courante. On utilisera

Le code d'une horloge à aiguilles est disponible sur Internet.


7°) Modifier la classe HHMMClass pour pouvoir afficher les heures et les minutes à un endroit précis. Cela devrait ainsi vous permettre d'afficher à la fois l'heure courante et l'heure de réveil.


8°) Vous réaliserez ensuite un mécanisme de mise à jour de l'heure réveil. On pourra utiliser pour cela les fonctions souris :

et réaliser deux boutons UP et DOWN avec des rectangles.

Indications : La gestion des boutons serait mieux réalisée avec une classe Bouton. Nous vous en proposons une (assez simplifiée) :

class Bouton
{
  int etat;
  String label;
  int couleur; // en gris
  //int r,v,b; // couleur allumé
  int posX,posY,dX,dY;

  Bouton() {
    couleur = 84;
    posX=0; posY=0; dX=40; dY=40;
  }

  Bouton(int posx,int posy,String txt) {
    couleur = 84;
    posX=posx; posY=posy; dX=40; dY=40;
    label = txt;
  }

  void showOff() {
    fill(couleur);
    rect(posX,posY,dX,dY);
    textSize(24);
    fill(0,255,0);
    text(label,posX,posY+dY+24);
  }

  void showOn() {
    fill(couleur);
    rect(posX,posY,dX,dY);
    fill(0,192,0);
    ellipseMode(CORNER);
    ellipse(posX,posY,dX,dY);
    fill(0,255,0);
    ellipse(posX+5,posY+5,dX-10,dY-10);   
  }
  
  Boolean mouseIn() {
    if ((mouseX>posX) && (mouseX < posX+dX)
      && (mouseY>posY) && (mouseY < posY+dY)) 
         return true;
    else return false;
  }
  
}

9°) Pour finir, il ne vous reste qu'à faire le mécanisme qui fait sonner le réveil quand l'heure courante est égale à l'heure réveil. Vous pourrez vous inspirer de la correction trouvée dans la Wikiversité.

Indications :

  • Le bouton d'armement est un peu particulier puisqu'il mémorise son état. Il faut donc spécialiser la classe bouton de la question précédente.
  • Il existe une classe Sound pour processing, mais vous devez vérifier si elle est installée ou pas.


10°) Utiliser l'héritage pour fabriquer un bouton de type switch.

Indications :

  • Cours Association et héritage appliqué à notre problématique. Il y a la réponse dans l'exercice 6 de ce cours.
  • Et le code ressource :
    • La classe BoutonSuper
class BoutonSuper {
  String label;
  int couleur; // en gris
  int posX,posY,dX,dY;
  BoutonSuper() {
    couleur = 84;
    posX=0; posY=0; dX=40; dY=40;
  }
  BoutonSuper(int posx,int posy,String txt) {
    couleur = 84;
    posX=posx; posY=posy; dX=40; dY=40;
    label = txt;
  }
  void showOff() {
    fill(couleur);
    rect(posX,posY,dX,dY);
    strokeWeight(2);
    stroke(0);
    line(posX,posY+dY,posX+dX,posY+dY);
    line(posX+dX,posY,posX+dX,posY+dY);
    stroke(255);
    line(posX,posY,posX+dX,posY);
    line(posX,posY,posX+dX,posY);
    strokeWeight(1);
    noStroke();
    textSize(24);
    fill(0,255,0);
    text(label,posX,posY+dY+24);
  }
  void showOn() {    
  }
  Boolean mouseIn() {
    if ((mouseX>posX) && (mouseX < posX+dX)
      && (mouseY>posY) && (mouseY < posY+dY)) 
         return true;
    else return false;
  }
}
    • La classe Bouton
class Bouton extends BoutonSuper
{
    Bouton(int posx,int posy,String txt) {
    couleur = 84;
    posX=posx; posY=posy; dX=40; dY=40;
    label = txt;
  }
  void showOn() {
    fill(couleur);
    rect(posX,posY,dX,dY);
    fill(0,192,0);
    ellipseMode(CORNER);
    ellipse(posX,posY,dX,dY);
    fill(0,255,0);
    ellipse(posX+5,posY+5,dX-10,dY-10);
  }
}
    • La classe Switch
class Switch extends BoutonSuper
{ 
  int etat;
  Switch(int posx,int posy,String txt) {
    couleur = 84;
    posX=posx; posY=posy; dX=30; dY=40;
    label = txt;
    etat=0;
  }
  void showOff() {
    fill(couleur);
    rect(posX,posY,dX,dY);
    strokeWeight(2);
    stroke(0);
    line(posX,posY+dY,posX+dX,posY+dY);
    line(posX+dX,posY,posX+dX,posY+dY);
    stroke(255);
    line(posX,posY,posX+dX,posY);
    line(posX,posY,posX+dX,posY);
    strokeWeight(1);
    noStroke();
    textSize(24);
    fill(0,255,0);
    text(label,posX,posY+dY+24);
  }
  void switchEtat() {
    etat ^= 1;
  }
  void showOn() {
    fill(couleur);
    rect(posX,posY,dX,dY);
    fill(0,192,0);
    ellipseMode(CORNER);
    ellipse(posX,posY,dX,dY);
    fill(0,255,0);
    ellipse(posX+5,posY+5,dX-10,dY-10);
  }
  void show() {
    if (etat == 0) showOff(); else showOn();
  }
}
    • et un exemple d'utilisation :
Bouton bouton1 = new Bouton(50,50,"UP");
Switch switch1 = new Switch(150,50,"SW0");
void setup() {
  size(300,300);
  frameRate(10);
}
void draw() {
    bouton1.showOff();
    switch1.show();
}
void mousePressed() {
  if (bouton1.mouseIn()) {
      bouton1.showOn();
    } else if (switch1.mouseIn()) {
      switch1.switchEtat();
    }
}

Poursuivez avec l'exercice 7 du cours ci-dessus qui change seulement l'apparence du bouton.



Réponse à la question 1 (Exercice 2)

Voici la définition de classe qui est un peu différente de celle présentée en cours.

 
class Digit {
   private int[] val={63,6,91,79,102,109,125,7,127,111,119,124,57,94,121,113};
   int nb1digit;
   int x,y;
   Digit(){
     nb1digit = val[0];
     x=0;y=0;
   }
   Digit(int nb){
     x=0;y=0;
     if (nb < 16)
       nb1digit = val[nb];
     else
       nb1digit=64; // affichage tiret en cas d'erreur
   }
   
   Digit(int xd, int yd){
     nb1digit = val[0];
     x=xd;y=yd;
   }
   
   void put(int nb) {
     if (nb < 16)
       nb1digit = val[nb];
     else
       nb1digit=64; // affichage tiret en cas d'erreur
   }

  private void segment() {
    beginShape();
    vertex(0,10);
    vertex(10,0);
    vertex(50,0);
    vertex(60,10);
    vertex(50,20);
    vertex(10,20);
   endShape(CLOSE); 
  }

void affiche7segs(int rouge,int vert, int bleu) {
  pushMatrix(); // on désire laisser le repère inchangé
  noStroke();
  translate(40+x,0+y);
  if ((nb1digit & 1) == 1) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment a
  translate(-10,70);
  if ((nb1digit & 64) == 64) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment g
  translate(-10,70);
  if ((nb1digit & 8) == 8) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment d
  translate(15,-53);
  rotate(radians(100));
  if ((nb1digit & 16) == 16) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment e
  translate(-70,0);
  if ((nb1digit & 32) == 32) fill(rouge,vert,bleu); else fill(200);
  segment(); // segtment f
  translate(-12,-68);
  if ((nb1digit & 2) == 2) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment b
  translate(72,0);
  if ((nb1digit & 4) == 4) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment c
  popMatrix(); // on récupère le repère initial
}

}

Et voici maintenant un exemple de programme d'utilisation :

Digit digitpoids0;

void setup() {  
  digitpoids0 = new Digit(50,50);
  frameRate(1); 
  size(480, 400);
}

int i=0;

void draw() {  
  i = (++i %16);
  digitpoids0.put(i);
  digitpoids0.affiche7segs(255,0,0);
}

Réponse à la question 6 (Exercice 2)

Voici la nouvelle classe HHMMClass :

class HHMMClass {
  int posX,posY;
  int hh_mm;
  Digit[] digits = new Digit[4];
  HHMMClass() {
    posX=posY=0;
    hh_mm = 0x950;
    for(int i=0;i<4;i++) {
      if (i < 2)
        digits[i]=new Digit(100*i,50);
      else
        digits[i]=new Digit(100*(i+1),50);
    }
  }
  void affiche() {
    for(int i=0;i<4;i++) {
      digits[3-i].put(hh_mm >> (4*i) & 0xF);
      digits[3-i].affiche7segs(255,0,0);
    }
    if ((second() % 2) == 1)
      fill(255,0,0);
    else 
      fill(200);
      
    ellipse(260,100,20,20);
    ellipse(255,150,20,20);
  }
  
  void updateHHMM() {
    int temp;
    temp = hour();
    hh_mm = ((temp/10) << 12)+((temp%10)<<8);
    temp = minute();
    hh_mm += ((temp/10) << 4)+(temp%10);
  }
  void incrementHHMM() {
      (hh_mm)++;
      if ((hh_mm & 0x000F) > 0x0009)
        hh_mm += 0x0006;
      if ((hh_mm & 0x00F0) > 0x0050)
        hh_mm += 0x00A0;
      if ((hh_mm & 0x0F00) > 0x0900)
        hh_mm += 0x0600;
      if ((hh_mm & 0xFF00) > 0x2300)
        hh_mm = 0x0000;
  }
  void decrementHHMM() {
      (hh_mm)--;
      if ((hh_mm & 0x000F) == 0x000F)
      hh_mm -= 0x0006;
      if ((hh_mm & 0x00F0) == 0x00F0)
      hh_mm -= 0x00A0;
      if ((hh_mm & 0x0F00) == 0x0F00)
      hh_mm -= 0x0600;
      if ((hh_mm & 0xFFFF) > 0x2359)
      hh_mm = 0x2359;
  }
}

Il serait bon de modifier la méthode affiche() pour qu'elle puisse changer la couleur d'affichage.

La classe Digit n'a pas changée.

Et voici maintenant le programme principal :

HHMMClass heureC;
void setup() {
  heureC = new HHMMClass();
  frameRate(10);
  size(520,400);
}

void draw() {
  heureC.updateHHMM();
  heureC.affiche();
}

Réponse à la question 7 (Exercice 2)

Nous avons ajouté une possibilité de zoom en plus d'un placement défini. Voici donc la classe HHMM complète correspondante :

class HHMMClass {
  int posX,posY;
  int hh_mm;
  float zoom;
  Digit[] digits = new Digit[4];
  
  HHMMClass() {
    posX=posY=0;
    zoom=1.0;
    hh_mm = 0x950;
    for(int i=0;i<4;i++) {
      if (i < 2)
        digits[i]=new Digit(100*i,50,zoom);
      else
        digits[i]=new Digit(100*(i+1),50,zoom);
    }
  }
  
  HHMMClass(int posx,int posy,float grossissement) {
    zoom = grossissement;
    posX=posx; posY=posy;
    hh_mm = 0x950;
    for(int i=0;i<4;i++) {
      if (i < 2)
        digits[i]=new Digit(int(100*i+posX),int(50+posY),zoom);
      else
        digits[i]=new Digit(int(100*(i+1)+posX),int(50+posY),zoom);
    }
  }
  
  void affiche(int red,int green,int blue) {
    for(int i=0;i<4;i++) {
      digits[3-i].put(hh_mm >> (4*i) & 0xF);
      digits[3-i].affiche7segs(red,green,blue);
    }
    if ((second() & 1) == 1)
      fill(red,green,blue);
    else 
      fill(200);
      
    ellipse(int((260+posX)*zoom),int((100+posY)*zoom),20*zoom,20*zoom);
    ellipse(int((255+posX)*zoom),int((150+posY)*zoom),20*zoom,20*zoom);
  }
  
  void updateHHMM() {
    int temp;
    temp = hour();
    hh_mm = ((temp/10) << 12)+((temp%10)<<8);
    temp = minute();
    hh_mm += ((temp/10) << 4)+(temp%10);
  }
  void incrementHHMM() {
      (hh_mm)++;
      if ((hh_mm & 0x000F) > 0x0009)
        hh_mm += 0x0006;
      if ((hh_mm & 0x00F0) > 0x0050)
        hh_mm += 0x00A0;
      if ((hh_mm & 0x0F00) > 0x0900)
        hh_mm += 0x0600;
      if ((hh_mm & 0xFF00) > 0x2300)
        hh_mm = 0x0000;
  }
  void decrementHHMM() {
      (hh_mm)--;
      if ((hh_mm & 0x000F) == 0x000F)
      hh_mm -= 0x0006;
      if ((hh_mm & 0x00F0) == 0x00F0)
      hh_mm -= 0x00A0;
      if ((hh_mm & 0x0F00) == 0x0F00)
      hh_mm -= 0x0600;
      if ((hh_mm & 0xFFFF) > 0x2359)
      hh_mm = 0x2359;
  }
}

Cette classe possède un défaut : le facteur de zoom intervient sur le déplacement !

On vous donne de plus la nouvelle classe Digit :

class Digit {
   private int[] val={63,6,91,79,102,109,125,7,127,111,119,124,57,94,121,113};
   int nb1digit;
   int x,y;
   float zoom;
   Digit(){
     nb1digit = val[0];
     zoom = 1.0;
     x=0;y=0;
   }
   Digit(int nb){
     x=0;y=0;
     zoom = 1.0;
     if (nb < 16)
       nb1digit = val[nb];
     else
       nb1digit=64; // affichage tiret en cas d'erreur
   }
   
   Digit(int xd, int yd,float dilatation){
     nb1digit = val[0];
     zoom = dilatation;
     x=xd;y=yd;
   }
   
   void put(int nb) {
     if (nb < 16)
       nb1digit = val[nb];
     else
       nb1digit=64; // affichage tiret en cas d'erreur
   }

  private void segment() {
    beginShape();
    vertex(0*zoom,10*zoom);
    vertex(10*zoom,0*zoom);
    vertex(50*zoom,0*zoom);
    vertex(60*zoom,10*zoom);
    vertex(50*zoom,20*zoom);
    vertex(10*zoom,20*zoom);
   endShape(CLOSE); 
  }

void affiche7segs(int rouge,int vert, int bleu) {
  pushMatrix(); // on désire laisser le repère inchangé
  noStroke();
  translate((40+x)*zoom,(0+y)*zoom);
  if ((nb1digit & 1) == 1) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment a
  translate(-10*zoom,70*zoom);
  if ((nb1digit & 64) == 64) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment g
  translate(-10*zoom,70*zoom);
  if ((nb1digit & 8) == 8) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment d
  translate(15*zoom,-53*zoom);
  rotate(radians(100));
  if ((nb1digit & 16) == 16) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment e
  translate(-70*zoom,0*zoom);
  if ((nb1digit & 32) == 32) fill(rouge,vert,bleu); else fill(200);
  segment(); // segtment f
  translate(-12*zoom,-68*zoom);
  if ((nb1digit & 2) == 2) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment b
  translate(72*zoom,0*zoom);
  if ((nb1digit & 4) == 4) fill(rouge,vert,bleu); else fill(200);
  segment(); // segment c
  popMatrix(); // on récupère le repère initial
}

}

Réponse à la question 10 (Exercice 2)

Correction complète

Exercice3

Caractères matriciel et affichage LCD.

TP programmation Objet

L'objectif de ce TP sur deux séances de trois heures est de réaliser un clavier de Piano capable de d'envoyer les changements d'états de ses touches par une liaison série. Les changements d'états des touches seront réalisés par la souris. Vous devrez donc être capable de gérer les deux événement souris "mousePressed()" et "mouseReleased()". Nous aurons en bout de la liaison série, un Arduino Leonardo qui lui-même sera relié à un amplificateur sonore

Code de départ

Pour vous aider, quelques ressources vous sont fournies.

Un clavier piano fonctionnel sur une octave

Un code de départ vous est fourni pour vous éviter de chercher les tailles et la façon de représenter votre clavier. Ce code n'envoie absolument rien sur la liaison série mais affiche dans le moniteur de Processing la touche appuyée ou relachée.

int spazio = 50;
int value;

void setup(){
size(400,400);
  //minim = new Minim(this); 
}

void draw(){
background(0);
stroke(0);
for (int x = 0; x <= width; x = x + spazio ){
  fill(255); // white
  rect(x - 50,0,x,height);
}
fill(0); // black
rect(35, 0, 30, 250);
rect(85, 0, 30, 250);
rect(185, 0, 30, 250);
rect(235, 0, 30, 250);
rect(285, 0, 30, 250);
rect(385, 0, 30, 250);
}

void mouseReleased() {
    value = 0;
    println(value);
}

void mousePressed(){
  value=0;
 //do 
if (mouseX < 35 && mouseY < 250 || mouseX < 50 && mouseY > 250){
  //song = minim.loadFile("Do1.mp3");
  //song.play();
  value = 1;
  //println(value);
} 
//re
if (mouseX > 65 && mouseX < 85 && mouseY < 250){
  //song = minim.loadFile("Re1.mp3");
  //song.play();
  value = 3;
  //println(value);
} 
if (mouseY > 250 && mouseX > 50 && mouseX < 100 || value == 3){
  //song = minim.loadFile("Re1.mp3");
  //song.play();
  value = 3;
  //println(value);
} 
//mi
if (mouseX > 115 && mouseX < 150 && mouseY < 250){
  //song = minim.loadFile("Mi1.mp3");
  //song.play();
  value = 5;
  //println(value);
} 
if ( mouseY > 250 && mouseX > 100 && mouseX < 150 || value == 5){
  //song = minim.loadFile("Mi1.mp3");
  //song.play();
  value = 5;
  //println(value);
} 
//fa
if (mouseX > 150 && mouseX < 185 && mouseY < 250){
  //song = minim.loadFile("Fa1.mp3");
  //song.play();
  value = 6;
  //println(value);
} 
if (mouseY > 250 && mouseX > 150 && mouseX < 200 || value == 6){
  //song = minim.loadFile("Fa1.mp3");
  //song.play();
  value = 6;
  //println(value);
} 
//sol
if (mouseX > 215 && mouseX < 235 && mouseY < 250){
  //song = minim.loadFile("Sol1.mp3");
  //song.play();
  value = 8;
  //println(value);
} 
if (mouseY > 250 && mouseX > 200 && mouseX < 250 || value == 8){
  //song = minim.loadFile("Sol1.mp3");
  //song.play();
  value = 8;
  //println(value);
} 

//la
if (mouseX > 265 && mouseX < 285 && mouseY < 250){
  //song = minim.loadFile("La1.mp3");
  //song.play();
  value = 10;
  //println(value);
} 
if (mouseY > 250 && mouseX > 250 && mouseX < 300 || value == 10){
  //song = minim.loadFile("La1.mp3");
  //song.play();
  value = 10;
  //println(value);
} else


//si 
if (mouseX > 315 && mouseX < 350 && mouseY < 250){
  //song = minim.loadFile("Si1.mp3");
  //song.play();
  value = 12;
  //println(value);
} 
if (mouseY > 250 && mouseX > 300 && mouseX < 350 || value == 12){
  //song = minim.loadFile("Si1.mp3");
  //song.play();
  value = 12;
  //println(value);
} 

//do2
if (mouseX > 350 && mouseX < 385 && mouseY < 250){
//  song = minim.loadFile("Do2.mp3");
  //song.play();
  value = 13;
  //println(value);
} 
if (mouseY > 250 && mouseX > 350 && mouseX < 400 || value == 13){
  //song = minim.loadFile("Do2.mp3");
  //song.play();
  value = 13;
  //println(value);
} 

// I bemolli
//do#
if ( mouseX > 35 && mouseX < 65 && mouseY < 250){
  //song = minim.loadFile("Do#1.mp3");
  //song.play();
  value = 2;
} 
//re#

if ( mouseX > 85 && mouseX < 115 && mouseY < 250){
  //song = minim.loadFile("Re#1.mp3");
  //song.play();
  value = 4;
} 
// fa#
if ( mouseX > 185 && mouseX < 215 && mouseY < 250){
  //song = minim.loadFile("Fa#1.mp3");
  //song.play();
  value = 7;
} 
// sol#
if ( mouseX > 235 && mouseX < 265 && mouseY < 250){
  //song = minim.loadFile("Sol#1.mp3");
  //song.play();
  value = 9;
} 
//la#
if ( mouseX > 285 && mouseX < 315 && mouseY < 250){
  //song = minim.loadFile("La#1.mp3");
  //song.play();
  value = 11;
}
  println(value);
}

Ce code est un bon point de départ mais il comporte plusieurs défauts :

  1. si le graphisme n'est pas trop mal, son principe est de dessiner d'abord les touches blanches puis, par dessus, les touches noires.
  2. les touches ne sont pas des objets et donc il est difficile de gérer une couleur appuyée et une couleur relachée

La classe Bouton

La question 8 de l'exercice 2 introduit la notion de classe pour un bouton et vous seriez bien inspiré de relire le code correspondant.

Travail à réaliser

  1. Pour éviter de travailler avec de l'héritage, vous allez définir 4 types de touches : 3 blanches et 1 noire. Par défaut ces touches seront considérées comme dessinées en coordonnée (0,0) en haut à gauche. Le constructeur devra contenir la définition du type de touche qui déterminera complètement le graphisme de la touche. Pévoir aussi une couleur pour touche non appuyée (blanc ou noir) et une couleur pour touche appuyée.
  2. Décomposer chacune des touches blanches en deux rectangles dont on déterminera les coordonnées à partir de l'exemple donné. Évidemment, au moment du dessin il ne faudra pas dessiner de bords aux rectangles sauf sur le côté gauche et le côté droit (line et le stroke associé).
  3. Traiter le cas des touches noires
  4. Décider de la taille et de la forme la zone dans laquelle il faudra appuyer pour considérer un appui de touche. La mise en place de cette zone sera faite par le constructeur en fonction du type de touche.
  5. A jouter une possibilité de transfert vers la droite pour chacun des types de touche
  6. Gérer la mise de l'ensemble des touches dans un tableau (Les listes (ou tableaux))
  7. Tester avec des print et/ou des println
  8. Gérer la liaison série (Serial) en lieu et place de l'affichage dans la console processing.

Correction partielle sans liaison série

class ClassPianoKey
{
  int _note;
  int _type; // type d la touche
  int couleurOff, couleurOn; // noir, blanc ou  gris
  int offsetX;
  int clickAreaPosX,clickAreaPosY,clickAreaDX,clickAreaDY;
  
 ClassPianoKey(int deltaX,int type,int note) {
    _note = note;
    _type = type;
    offsetX = deltaX;
    if (type < 4) { // touche blanche
      couleurOff = 255;
      couleurOn = 200;
      clickAreaPosX=offsetX;
      clickAreaPosY = 250; 
      clickAreaDX= 50;
      clickAreaDY = 150;
    } else {
      couleurOff = 0;
      couleurOn = 50;
      clickAreaPosX=offsetX;
      clickAreaPosY = 0; 
      clickAreaDX= 30;
      clickAreaDY = 250;
    }
    
  }

  void showOff() {
    if (_type == 1) {
      fill(couleurOff);
      stroke(couleurOff);
      rect(0+offsetX,0,35,250);
      rect(0+offsetX,250,50,150);
      // black
      stroke(0);
      line(0+offsetX,0,0+offsetX,400);
      line(0+offsetX+50,0+250,0+offsetX+50,400);
    }
    if (_type == 2) {
      fill(couleurOff);
      stroke(couleurOff);
      rect(0+offsetX+15,0,35,250);
      rect(0+offsetX,250,50,150);
      stroke(0);
      line(0+offsetX,0+250,0+offsetX,400);
      line(0+offsetX+50,0,0+offsetX+50,400);
    }
    if (_type == 3) {
      fill(couleurOff);
      stroke(couleurOff);
      rect(0+offsetX+15,0,20,250);
      rect(0+offsetX,250,50,150);
      stroke(0);
      line(0+offsetX,0+250,0+offsetX,400);
      line(0+offsetX+50,0+250,0+offsetX+50,400);
    }
    if (_type == 4) {
      fill(couleurOff);
      stroke(couleurOff);
      rect(0+offsetX,0,30,250);      
    }
    
  }

  void showOn() {
    if (_type == 1) {
      fill(couleurOn);
      stroke(couleurOn);
      rect(0+offsetX,0,35,250);
      rect(0+offsetX,250,50,150);
      // black
      stroke(0);
      line(0+offsetX,0,0+offsetX,400);
      line(0+offsetX+50,0+250,0+offsetX+50,400);
    }
    if (_type == 2) {
      fill(couleurOn);
      stroke(couleurOn);
      rect(0+offsetX+15,0,35,250);
      rect(0+offsetX,250,50,150);
      stroke(0);
      line(0+offsetX,0+250,0+offsetX,400);
      line(0+offsetX+50,0,0+offsetX+50,400);
    }
    if (_type == 3) {
      fill(couleurOn);
      stroke(couleurOn);
      rect(0+offsetX+15,0,20,250);
      rect(0+offsetX,250,50,150);
      stroke(0);
      line(0+offsetX,0+250,0+offsetX,400);
      line(0+offsetX+50,0+250,0+offsetX+50,400);
    }
    if (_type == 4) {
      fill(couleurOn);
      stroke(couleurOn);
      rect(0+offsetX,0,30,250);      
    }
    
  }
  
  Boolean mouseIn() {
    if ((mouseX>clickAreaPosX) && (mouseX < clickAreaPosX+clickAreaDX)
      && (mouseY>clickAreaPosY) && (mouseY < clickAreaPosY+clickAreaDY)) 
         return true;
    else return false;
  }
  
}

Et enfin le programme principal :

ClassPianoKey[] pianokeys = new ClassPianoKey[15];

void setup() {
  size(400,400);
  frameRate(1); 
  pianokeys[0]= new ClassPianoKey(0,1,1);  //do
  pianokeys[1]= new ClassPianoKey(35,4,2);  //do#
  pianokeys[2]= new ClassPianoKey(50,3,3);  //re
  pianokeys[3]= new ClassPianoKey(85,4,4);
  pianokeys[4]= new ClassPianoKey(100,2,5);
  pianokeys[5]= new ClassPianoKey(150,1,6);
  pianokeys[6]= new ClassPianoKey(185,4,7);
  pianokeys[7]= new ClassPianoKey(200,3,8);
  pianokeys[8]= new ClassPianoKey(235,4,9);
  pianokeys[9]= new ClassPianoKey(250,3,10);
  pianokeys[10]= new ClassPianoKey(235,4,11);
  pianokeys[11]= new ClassPianoKey(250,3,12);
  pianokeys[12]= new ClassPianoKey(285,4,13);
  pianokeys[13]= new ClassPianoKey(300,2,14);
  pianokeys[14]= new ClassPianoKey(350,1,15);
  for (int i=0;i<15;i++) {
    pianokeys[i].showOff();
  }
}

void draw() {
  
}

void mousePressed() {
  for (int i=0;i<15;i++) {
    if (pianokeys[i].mouseIn())
      pianokeys[i].showOn();
  }  
}

void mouseReleased() {
  for (int i=0;i<15;i++) {
    if (pianokeys[i].mouseIn())
      pianokeys[i].showOff();
  }  
}

Malheureusement l'ensemble est un peu lent pour être utilisé pour réaliser de la musique !!!

Voir aussi