CheckZone

CheckXXXX sont des classes de cases à cocher, genre "j'ai lu les conditions de vente". Comme bouton, c'est comme un bouton de lumière avec télérupteur. Lorsque l'on appuie dessus il change d'état. Pour cette bibliothèque, lorsqu'on appuie dessus, si il n'est pas actif, il le devient, et un événement onSelect est généré. Si il était déjà actif, il se désactive et un événement onUnselect est généré. Lorsque l'on relâche l'appui, ou si l'appui sort de la zone d'action, il ne se passe rien.

XXXXZone sont des classes de boutons sans dessin prédéfini. En principe, on affiche une image de fond qui va servir de zone visible pour les boutons de cette classe.

CheckZone est donc une classe de cases à cocher sans dessin prédéfini.

 

Exemples d'utilisation

CheckZone bouton(0,0,LARGEUR,HAUTEUR); // Crée bouton sur toute la surface de l'écran
CheckZone bouton(150,100,170,120); // Crée bouton au centre en mode PAYSAGE 320x240
CheckZone bouton = new CheckZone(100,100,120,120); // Crée une instance dynamique bouton
new CheckZone(100,100,120,120); // Crée une instance dynamique bouton sans pointeur dessus

circle(bouton.demiX1+bouton.demiX2, bouton.demiY1+bouton.demiY2, 10); // Cercle centré sur le bouton

bouton.onSelectFunction = &action; // Appel la fonction void action(void) lors de lors de la sélection
bouton.onUnselectFunction = &action; // Appel la fonction void action(void) lors de la désélection

if (bouton.isSelect())... // Si la case est cochée ...

 

Référence

class CheckZone
 public:
  CheckZone(int x1, int y1, int x2, int y2);
  byte demiX1, demiY1, demiX2, demiY2;
  word buttonColor;
  void (*onSelectFunction)(void);
  void (*onUnselectFunction)(void);
  CheckZone *controleSuivant;
  void select(void);
  void unselect(void);
  boolean isSelected(void);
  virtual void onSelect(void);
  virtual void onUnselect(void)
  virtual void drawButton(void);

Attributs et méthodes

CheckZone(): Constructeur, s'insère dans la liste des contrôles gérées. x1, y1, x2, y2: zone d'action

demiX1, demiY1, demiX2, demiY2: Occupation de l'espace dans l'écran, coordonnés absolues DIVISEES par 2

buttonColor: Couleur du fond des boutons de la classe

*onSelectFunction: : Pointeur sur la fonction à appeler lorsque le bouton est sélectionné

*onUnselectFunction: : Pointeur sur la fonction à appeler lorsque le bouton est désélectionné

*controleSuivant: Pointeur sur le contrôle suivant dans la liste des contrôles

select(): : Active un bouton.

unselect(): : Désactive ce bouton

isSelected(): : Informe de l'état du bouton.

onSelect(): : Fonction appelée lors de la sélection. On peut surcharger cette fonction, par défaut elle est vide

onUnselect(): : Fonction appelée lors de la désélection. On peut surcharger cette fonction, par défaut elle est vide

drawButton(): : Fonction appelée lors de l'activation, la désactivation, à l'initialisation de la librairie ou sur appel de la fonction drawControles(). On peut surcharger cette fonction, par défaut elle est vide pour les boutons XXXXZone, et fait ce qu'il faut pour les autres. On peut surcharger cette méthode, mais si on veut garder le dessin par défaut, il faut appeler la méthode drawButton() de la classe mère.

 

Voir aussi

- scanEvent(); Moteur de la gestion des événements
- PushZone; Bouton poussoir sans dessin
- CheckCoche; Bouton bistable (va vient) case à cocher
- CheckCircle; Bouton bistable (va vient) rond
- RadioZone; Bouton radio (un seul bouton actif parmi plusieurs) sans dessin

 

Notes

Pour définir un bouton, il faut donner sa zone d'action. Pour des raisons de stockage mémoire et de précision, n'est enregistré que les nombres pairs des valeurs passées. Les nombres impairs sont arrondis au nombre pair inférieur. Ainsi la zone (100,100,201,201) est équivalente à (100,100,200,200).

Si on a plusieurs boutons dont les zones d'actions ont une partie commune, comme les boutons sont analysés dans l'ordre inverse de leur déclaration, la zone commune devient propriété du bouton défini en dernier. Cela évite les conflits. Cela permet aussi d'avoir un bouton dont la zone n'est pas rectangulaire, il peut manquer un coin.

 

Exemples

Dans les exemples qui suivent trois boutons sont placées à droite de l'écran. Leur définition est statique, on peut aussi les passer en dynamique, cela ne change rien. Il y a plusieurs implantations possibles pour lire l'état des boutons et l'afficher. J'en montre ici 5, il y en a d'autres, par exemple par la lecture de la liste des contrôles. Le programme affiche l'état des boutons.

Premier exemple: 3 fonctions externes

PecheuxGraph_ILI9341_8bits.zip\PecheuxGraph_ILI9341_8bits\examples\Documentation\Exemple-920-CheckZone-3-onSelectFunction\Exemple-920-CheckZone-3-onSelectFunction.ino (dans votre fichier téléchargé):

// Mise en place de 3 boutons de type CheckZone (zone à cocher, pas de dessin
// dans le bouton). Quand on appuie sur un bouton, un disque blanc montre son
// activité

// Version 1:
// - Les boutons ont une définition statique
// - Utilise onSelectFunction pour exécuter l'action à faire
// - Une action différente pour chaque bouton

#include <PecheuxGraph_ILI9341_8bits.h> // Appel de la bibliothèque 


// Déclaration statique des instances, doit se faire en dehors du setup
// Dans ce cas les boutons sont accessibles partout
CheckZone boutonHaut(190, 90, 230, 130); // Bouton en haut
CheckZone boutonCentre(190, 140, 230, 180); // Bouton au centre
CheckZone boutonBas(190, 190, 230, 230); // Bouton en bas


// Déclaration de 3 fonctions, une par bouton, qui feront ce qu'il faut
// faire à chaque changement
// Ces fonctions ne doivent pas avoir de paramètres et ne doit rien retourner
// Les noms peuvent être quelconques
void onSelectActionHaut() // Action à faire quand on appuie sur le bouton du haut
{
  if (boutonHaut.isSelected()) fillCircle(30, 110, 20, WHITE);
  else fillCircle(30, 110, 20, BLACK);
}


void onSelectActionCentre() // Action à faire quand on appuie sur le bouton du centre
{
  if (boutonCentre.isSelected()) fillCircle(30, 160, 20, WHITE);
  else fillCircle(30, 160, 20, BLACK);
}


void onSelectActionBas() // Action à faire quand on appuie sur le bouton du bas
{
  if (boutonBas.isSelected()) fillCircle(30, 210, 20, WHITE);
  else fillCircle(30, 210, 20, BLACK);
}


void setup()
{
  setGraphMode(PAYSAGE); // Initialisation de la carte
  rect(190, 90, 230, 130,GREEN); // Carré du haut
  rect(190, 140, 230, 180); // Carré au centre de l'écran
  rect(190, 190, 230, 230); // Carré du bas
  text(F("Appuyez sur un carré"));
  
  boutonHaut.onSelectFunction=&onSelectActionHaut; // Fonction appelée si on active le bouton du haut de l'écran
  boutonCentre.onSelectFunction=&onSelectActionCentre; // Fonction appelée si on active le bouton au milieu de l'écran
  boutonBas.onSelectFunction=&onSelectActionBas; // Fonction appelée si on active le bouton en bas de l'écran
  boutonHaut.onUnselectFunction=&onSelectActionHaut; // Fonction appelée si on désactive le bouton du haut de l'écran
  boutonCentre.onUnselectFunction=&onSelectActionCentre; // Fonction appelée si on désactive le bouton au milieu de l'écran
  boutonBas.onUnselectFunction=&onSelectActionBas; // Fonction appelée si on désactive le bouton en bas de l'écran
}


void loop() 
{
  scanEvent(); // Gestion des boutons et des horloges, le plus souvent seul dans le loop
}

Résultat:

 

Deuxième exemple: 1 fonction externe indifférenciée

PecheuxGraph_ILI9341_8bits.zip\PecheuxGraph_ILI9341_8bits\examples\Documentation\Exemple-921-CheckZone-1-onSelectFunction\Exemple-921-CheckZone-1-onSelectFunction.ino (dans votre fichier téléchargé):

// Mise en place de 3 boutons de type CheckZone (zone à cocher, pas de dessin
// dans le bouton). Quand on appuie sur un bouton, un disque blanc montre son
// activité

// Version 2:
// - Les boutons ont une définition statique
// - Utilise onSelectFunction pour exécuter l'action à faire
// - Une seule action pour les trois boutons, qui ne fait pas de différence entre les boutons

#include <PecheuxGraph_ILI9341_8bits.h> // Appel de la bibliothèque 


// Déclaration statique des instances, doit se faire en dehors du setup
// Dans ce cas les boutons sont accessibles partout
CheckZone boutonHaut(190, 90, 230, 130); // Bouton en haut
CheckZone boutonCentre(190, 140, 230, 180); // Bouton au centre
CheckZone boutonBas(190, 190, 230, 230); // Bouton en bas


// Déclaration d'une fonction qui fera ce qu'il faut faire à chaque changement
// Cette fonction ne doit pas avoir de paramètres et ne doit rien retourner
// Le nom peut être quelconque
void onSelectAction() // Action à faire quand on appuie sur un bouton
{
  if (boutonHaut.isSelected()) fillCircle(30, 110, 20, WHITE); // On s'occupe du premier bouton
    else fillCircle(30, 110, 20, BLACK);
  if (boutonCentre.isSelected()) fillCircle(30, 160, 20, WHITE); // Puis du deuxième
    else fillCircle(30, 160, 20, BLACK);
  if (boutonBas.isSelected()) fillCircle(30, 210, 20, WHITE); // Puis du troisième
    else fillCircle(30, 210, 20, BLACK);
}


void setup()
{
  setGraphMode(PAYSAGE); // Initialisation de la carte
  rect(190, 90, 230, 130,GREEN); // Carré du haut
  rect(190, 140, 230, 180); // Carré au centre de l'écran
  rect(190, 190, 230, 230); // Carré du bas
  text(F("Appuyez sur un carré"));
  
  // Ici j'utilise pour l'exemple la triple affectation. Au lieu d'écrire a=1; b=1; c=1; on peut
  // écrire a=b=c=1 Cela doit se lire j'affecte 1 à c, cette affectation prned la valeur 1 et c'est
  // cette valeur que j'affecte à b. Cette nouvelle affectation retourne 1 que j'affecte à a.
  boutonHaut.onSelectFunction= // Fonction appelée si on active le bouton du haut de l'écran
  boutonCentre.onSelectFunction= // Fonction appelée si on active le bouton au milieu de l'écran
  boutonBas.onSelectFunction=&onSelectAction; // Fonction appelée si on active le bouton en bas de l'écran
  boutonHaut.onUnselectFunction= // Fonction appelée si on désactive le bouton du haut de l'écran
  boutonCentre.onUnselectFunction= // Fonction appelée si on désactive le bouton au milieu de l'écran
  boutonBas.onUnselectFunction=&onSelectAction; // Fonction appelée si on désactive le bouton en bas de l'écran
}


void loop() 
{
  scanEvent(); // Gestion des boutons et des horloges, le plus souvent seul dans le loop
}

Résultat:

Le fonctionnement est exactement le même que pour le premier exemple. C'est juste une histoire d'implantation.

 

Troisième exemple: 1 fonction tri sur l'ordonnée

PecheuxGraph_ILI9341_8bits.zip\PecheuxGraph_ILI9341_8bits\examples\Documentation\Exemple-922-CheckZone-Suivant-ordonnee\Exemple-922-CheckZone-Suivant-ordonnee.ino (dans votre fichier téléchargé):

// Mise en place de 3 boutons de type CheckZone (zone à cocher, pas de dessin
// dans le bouton). Quand on appuie sur un bouton, un disque blanc montre son
// activité

// Version 3:
// - Les boutons ont une définition statique
// - Utilise onSelectFunction pour exécuter l'action à faire
// - Une seule action pour les trois boutons, différence faites sur les coordonnées

#include <PecheuxGraph_ILI9341_8bits.h> // Appel de la bibliothèque 


// Déclaration statique des instances, doit se faire en dehors du setup
// Dans ce cas les boutons sont accessibles partout
CheckZone boutonHaut(190, 90, 230, 130); // Bouton en haut
CheckZone boutonCentre(190, 140, 230, 180); // Bouton au centre
CheckZone boutonBas(190, 190, 230, 230); // Bouton en bas


// Déclaration d'une fonction qui fera ce qu'il faut faire à chaque changement
// Cette fonction ne doit pas avoir de paramètres et ne doit rien retourner
// Le nom peut être quelconque
void onSelectAction() // Action à faire quand on appuie sur un bouton
{
  int y=getTouchY();
  if (y<90) // On a touché sur le bouton du haut
  {
    if (boutonHaut.isSelected()) fillCircle(30, 110, 20, WHITE); // On s'occupe du premier bouton
    else fillCircle(30, 110, 20, BLACK);
  }
  else if (y>150) // On a touché sur le bouton du bas
  {
    if (boutonBas.isSelected()) fillCircle(30, 210, 20, WHITE); // Puis du troisième
    else fillCircle(30, 210, 20, BLACK);
  }
  else // on a donc forcément touché sur le bouton du milieu
  { // (Accolades inutiles pour le dernier cas)
    if (boutonCentre.isSelected()) fillCircle(30, 160, 20, WHITE); // Puis du deuxième
    else fillCircle(30, 160, 20, BLACK);
  }  
}


void setup()
{
  setGraphMode(PAYSAGE); // Initialisation de la carte
  rect(190, 90, 230, 130,GREEN); // Carré du haut
  rect(190, 140, 230, 180); // Carré au centre de l'écran
  rect(190, 190, 230, 230); // Carré du bas
  text(F("Appuyez sur un carré"));
  
  boutonHaut.onSelectFunction=  // Fonction appelée si on active le bouton du haut de l'écran
  boutonCentre.onSelectFunction= // Fonction appelée si on active le bouton au milieu de l'écran
  boutonBas.onSelectFunction= // Fonction appelée si on active le bouton en bas de l'écran
  boutonHaut.onUnselectFunction= // Fonction appelée si on désactive le bouton du haut de l'écran
  boutonCentre.onUnselectFunction= // Fonction appelée si on désactive le bouton au milieu de l'écran
  boutonBas.onUnselectFunction=&onSelectAction; // Fonction appelée si on désactive le bouton en bas de l'écran
}


void loop() 
{
  scanEvent(); // Gestion des boutons et des horloges, le plus souvent seul dans le loop
}

Résultat:

Le fonctionnement est exactement le même que pour le premier exemple. C'est juste une histoire d'implantation.

 

Quatrième exemple: 3 boutons, loop() fait le travail

PecheuxGraph_ILI9341_8bits.zip\PecheuxGraph_ILI9341_8bits\examples\Documentation\Exemple-923-CheckZone-loop\Exemple-923-CheckZone-loop.ino (dans votre fichier téléchargé):

// Mise en place de 3 boutons de type CheckZone (zone à cocher, pas de dessin
// dans le bouton). Quand on appuie sur un bouton, un disque blanc montre son
// activité

// Version 4:
// - Les boutons ont une définition statique
// - Teste dans le loop sans utiliser onSelectFunction

#include <PecheuxGraph_ILI9341_8bits.h> // Appel de la bibliothèque 


// Déclaration statique des instances, doit se faire en dehors du setup
// Dans ce cas les boutons sont accessibles partout
CheckZone boutonHaut(190, 90, 230, 130); // Bouton en haut
CheckZone boutonCentre(190, 140, 230, 180); // Bouton au centre
CheckZone boutonBas(190, 190, 230, 230); // Bouton en bas


void setup()
{
  setGraphMode(PAYSAGE); // Initialisation de la carte
  rect(190, 90, 230, 130,GREEN); // Carré du haut
  rect(190, 140, 230, 180); // Carré au centre de l'écran
  rect(190, 190, 230, 230); // Carré du bas
  text(F("Appuyez sur un carré"));
  }


void loop() 
{
  scanEvent(); // Gestion des boutons et des horloges, d'habitude seul dans le loop


  // On va tester systématiquement l'état des boutons. Dans la vraie vie, on ne ferait le
  // test que si on en a besoin. Si c'est pour faire le test systématique, autant passer
  // par onSelectFunction. Ici c'est pour montrer que cela est possible.
  // Ici on surcharge beaucoup la boucle loop(), le dessin est fait systématiquement.
  // On manque des informations rapides sur les boutons
  if (boutonHaut.isSelected()) fillCircle(30, 110, 20, WHITE); // On s'occupe du premier bouton
    else fillCircle(30, 110, 20, BLACK);
  
  if (boutonBas.isSelected()) fillCircle(30, 210, 20, WHITE); // Puis du troisième
    else fillCircle(30, 210, 20, BLACK);
  
  if (boutonCentre.isSelected()) fillCircle(30, 160, 20, WHITE); // Puis du deuxième
    else fillCircle(30, 160, 20, BLACK);
}

Résultat:

Le fonctionnement est exactement le même que pour le premier exemple. C'est juste une histoire d'implantation.

 

Cinquième exemple: 3 boutons, loop() fait le travail, avec mémorisation

PecheuxGraph_ILI9341_8bits.zip\PecheuxGraph_ILI9341_8bits\examples\Documentation\Exemple-924-CheckZone-Memoire\Exemple-924-CheckZone-Memoire.ino (dans votre fichier téléchargé):

// Mise en place de 3 boutons de type CheckZone (zone à cocher, pas de dessin
// dans le bouton). Quand on appuie sur un bouton, un disque blanc montre son
// activité

// Version 5:
// - Les boutons ont une définition statique
// - Teste dans le loop sans utiliser onSelectFunction
// - On mémorise les actions faites pour ne pas surcharger loop()

#include <PecheuxGraph_ILI9341_8bits.h> // Appel de la bibliothèque 


// Déclaration statique des instances, doit se faire en dehors du setup
// Dans ce cas les boutons sont accessibles partout
CheckZone boutonHaut(190, 90, 230, 130); // Bouton en haut
CheckZone boutonCentre(190, 140, 230, 180); // Bouton au centre
CheckZone boutonBas(190, 190, 230, 230); // Bouton en bas


// Pour mémoriser les actions faites, on a recours à trois variables
// qui vont permettre de savoir si un bouton a changé
boolean ancienEtatBoutonHaut; // ancien état du bouton du haut
boolean ancienEtatBoutonCentre; // ancien état du bouton du centre
boolean ancienEtatBoutonBas; // ancien état du bouton du bas


void setup()
{
  setGraphMode(PAYSAGE); // Initialisation de la carte
  rect(190, 90, 230, 130,GREEN); // Carré du haut
  rect(190, 140, 230, 180); // Carré au centre de l'écran
  rect(190, 190, 230, 230); // Carré du bas
  text(F("Appuyez sur un carré"));
  }


void loop() 
{
  scanEvent(); // Gestion des boutons et des horloges, d'habitude seul dans le loop

  // On va tester systématiquement l'état des boutons pour savoir si l'un d'eux a changé.
  // Si c'est le cas, on agit.
  // Ici on surcharge peu la boucle loop(), le dessin est fait que si nécessaire.
  if (boutonHaut.isSelected()!=ancienEtatBoutonHaut)
  { // Le bouton haut a changé d'état, on le redessine
    if (boutonHaut.isSelected()) fillCircle(30, 110, 20, WHITE); // On s'occupe du premier bouton
    else fillCircle(30, 110, 20, BLACK);
    ancienEtatBoutonHaut=boutonHaut.isSelected(); // Et on met à jour la mémoire
  }
  
  if (boutonCentre.isSelected()!=ancienEtatBoutonCentre)
  { // Le bouton du centre a changé d'état, on le redessine
    if (boutonCentre.isSelected()) fillCircle(30, 160, 20, WHITE); // Puis du troisième
    else fillCircle(30, 160, 20, BLACK);
    ancienEtatBoutonCentre=boutonCentre.isSelected(); // Et on met à jour la mémoire
  }
  
  if (boutonBas.isSelected()!=ancienEtatBoutonBas)
  { // Le bouton bas a changé d'état, on le redessine
    if (boutonBas.isSelected()) fillCircle(30, 210, 20, WHITE); // Puis du deuxième
    else fillCircle(30, 210, 20, BLACK);
    ancienEtatBoutonBas=boutonBas.isSelected(); // Et on met à jour la mémoire
  }
}

Résultat:

Le fonctionnement est exactement le même que pour le premier exemple. C'est juste une histoire d'implantation.

 

Sixième exemple: 3 boutons, 3 fonctions externes

PecheuxGraph_ILI9341_8bits.zip\PecheuxGraph_ILI9341_8bits\examples\Documentation\Exemple-925-Maison-CheckZone\Exemple-925-Maison-CheckZone.ino (dans votre fichier téléchargé):

// L'intérieur d'une maison est dessinée. Deux boutons de type CheckZone 
// permettent d'allumer la lumière. Ce sont des va et vient (boutons à 2
// positions comme les cases à cocher)

#include <PecheuxGraph_ILI9341_8bits.h>

// Déclaration statique des instances, doit se faire en dehors du setup
// Dans ce cas les boutons sont accessibles partout
CheckZone bouton1(186, 124, 212, 152); // Définit une zone cliquable à droite
CheckZone bouton2(8, 124, 34, 152); // Définit une zone cliquable à droite

// Déclaration d'une fonction qui fait ce qu'il faut faire à chaque changement
// Cette fonction ne doit pas avoir de paramètres et ne doit rien retourner
// Le nom peut être quelconque
// Cette fonction allume ou éteint la lampe. Elle est allumée si un seul des
// deux boutons est actif. C'est pour cela qu'on utilise le ou-exclusif ^
void lampe()
{
  fill(160, 30+1, bouton1.isSelected() ^ bouton2.isSelected() ? YELLOW : BLACK); // La lampe copie l'état des boutons
}


void setup()
{
  bouton1.onSelectFunction = &lampe; // Change l'état de la lampe si on active le bouton de droite
  bouton2.onSelectFunction = &lampe; // Change l'état de la lampe si on active le bouton de gauche
  bouton1.onUnselectFunction = &lampe; // Change l'état de la lampe si on désactive le bouton de droite
  bouton2.onUnselectFunction = &lampe; // Change l'état de la lampe si on désactive le bouton de gauche

  setGraphMode(PAYSAGE); // Initialisation

  // Consigne
  setTextCursor(10, 200);
  text(F("Appuyez sur un bouton de\n  chaque côté de la fenêtre"));

  maison(1,1); // avec 2 boutons
}

void loop()
{
  scanEvent(); // Gestion des boutons et des horloges, le plus souvent seul dans le loop
}

Résultat:

 

Côté technique

En fait CheckZone ne fait pas grand chose, car c'est le gestionnaire scanEvent() qui vient demander les propriétés de CheckZone et qui calcule si il est sélectionné ou pas. C'est aussi le gestionnaire qui appelle onSelect() et onSelectFunction si le contrôle vient d'être choisi ou onClac() et onClacFunction si le contrôle vient d'être relâché. Le rôle de CheckZone se borne à initialiser les valeurs lors de sa déclaration, et à répondre aux événements clic ou clac.

On ne stocke pas les coordonnées complètes car il faut un entier pour le stockage. La moité de la valeur tient dans un byte, et au niveau de la précision cela suffit. Ainsi chaque bouton économise 4 octets, et les tests de limites portent sur des octets, ce qui est mieux.

 

PushCircle()   <<     >>   CheckCoche()