PushZone

PushXXXX sont des classes de boutons poussoirs, genre bouton de sonnette. Lorsque l'on appuie dessus "le courant passe" et "s'arrête" si on relâche. Pour cette bibliothèque, lorsqu'on appuie dessus un événement onSelect est généré et il devient actif. Lorsque l'on relâche l'appui, ou si l'appui sort de la zone d'action, un événement onUnselect est généré et le bouton devient inactif. Bon nombre d'applications n'utilisent que l'événement onSelect.

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.

PushZone est donc une classe de boutons poussoirs sans dessin prédéfini.

 

Exemples d'utilisation

PushZone bouton(0,0,LARGEUR,HAUTEUR); // Crée bouton sur toute la surface de l'écran
PushZone bouton(150,100,170,120); // Crée bouton au centre en mode PAYSAGE 320x240
PushZone bouton = new PushZone(100,100,120,120); // Crée une instance dynamique bouton
new PushZone(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 l'appui
bouton.onUnselectFunction = &action; // Appel la fonction void action(void) lors du relâchement

if (bouton.isSelect())... // Si on est en train d'appuyer sur le bouton

 

Référence

class PushZone
 public:
  PushZone(int x1, int y1, int x2, int y2);
  byte demiX1, demiY1, demiX2, demiY2;
  word buttonColor;
  void (*onSelectFunction)(void);
  void (*onUnselectFunction)(void);
  PushZone *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

PushZone(): 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 (utile pour les descendants)

*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. N'a aucun intérêt pour ce bouton, mais pas pour des descendants. Le bouton est automatiquement activé lorsque l'on appuie dessus

unselect(): : Désactive ce bouton N'a aucun intérêt pour ce bouton, mais pas pour des descendants. Le bouton est automatiquement déactivé lorsque l'on le relâche

isSelected(): : Informe de l'état du bouton. Pour ce bouton, il est actif tant qu'on appuie dessus

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.

 

Voir aussi

- scanEvent(); Moteur de la gestion des événements
- pourBoutonTexte(); Aide pour dessiner des boutons textes
- PushCoche; Bouton poussoir case à cocher
- PushCircle; Bouton poussoir rond
- CheckZone; Bouton bistable (va vient) sans dessin
- 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.

Si on définit: Nombres pairs retenus: Zones actives:
PushZone bouton1(100,100,120,120); (100,100,120,120); (100,100,120,119);
PushZone bouton2(100,121,120,140); (100,120,120,140); (100,120,120,139);
PushZone bouton3(100,141,120,160); (100,140,120,160); (100,140,120,160);
La définition la plus simple pour l'exemple ci dessus est:
PushZone bouton1(100,100,120,120);
PushZone bouton2(100,120,120,140);
PushZone bouton3(100,140,120,160);

 

Exemples

Dans les exemples qui suivent trois boutons sont placées à droite de l'écran. Comme ce sont des boutons invisibles, un rectangle vert indique leur zone d'action. Leur activité est montré par un disque blanc (si le bouton est actif) ou sans rien (si le bouton est inactif). Les carrés sont dessinés d'un côté et les boutons PushZone ayant les mêmes coordonnées récupère l'information de l'appui. C'est un exemple typique du dessin et du bouton séparé. Il y a plusieurs implantations possibles, la plus simple est la première version, que l'on utilisera le plus souvent. Pour ce bouton, je donne toutes les possibilités, mais pour les autres contrôles, je ne le ferai pas systématiquement. Toutes les possibilités sont aussi donné pour Clock.

Quand on appuie sur le bouton, soit la fonction pointée par onSelectFunction est appelée, soit onSelect() qui est surchargée fait le travail.

Premier exemple: déclaration statique

C'est la façon la plus simple d'utiliser un bouton. L'instance est statique.

PecheuxGraph_ILI9341_8bits.zip\PecheuxGraph_ILI9341_8bits\examples\Documentation\Exemple-901-PushZone-Statique-onSelectFunction\Exemple-901-PushZone-Statique-onSelectFunction.ino (dans votre fichier téléchargé):

// Mise en place de 3 boutons de type PushZone (poussoir sur une zone, 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

#
  $menu = ":PG";
  include <PecheuxGraph_ILI9341_8bits.h> // Appel de la bibliothèque 


// Déclaration statique de l'instance, doit se faire en dehors du setup
// Dans ce cas le bouton est accessible partout
PushZone boutonHaut(190, 90, 230, 130); // Bouton en haut
PushZone boutonCentre(190, 140, 230, 180); // Bouton au centre
PushZone 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
// Je passe par les pointeurs exceptionnellement pour s'affranchir des noms des
// boutons. Cela permet aussi de montrer l'utilité du pointeur premierControle.
// Si cela vous pose problème, laissez de côté la compréhension de cette fonction
void Action() // Action à faire quand on appuie sur un bouton
{
  PushZone *pointeur = premierControle;
  int ordonnee = 210; // Ligne ou se trouve le contrôle. On commence par celui du bas, c'est le dernier défini
  while (pointeur != NULL) // tant qu'on a pas fait toute la liste
  {
    if (pointeur->isSelected()) fillCircle(30, ordonnee, 20, WHITE); // Disque blanc si il est sélectionné
    else fillCircle(30, ordonnee, 20, BLACK);

    pointeur = pointeur->controleSuivant; // Mise à jour pour le bouton suivant
    ordonnee -= 50;
  }
}


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 = &Action; // Fonction appelée si on active le bouton du haut de l'écran
  boutonCentre.onSelectFunction = &Action; // Fonction appelée si on active le bouton au milieu de l'écran
  boutonBas.onSelectFunction = &Action; // Fonction appelée si on active le bouton en bas de l'écran
  boutonHaut.onUnselectFunction = &Action; // Fonction appelée si on désactive le bouton du haut de l'écran
  boutonCentre.onUnselectFunction = &Action; // Fonction appelée si on désactive le bouton au milieu de l'écran
  boutonBas.onUnselectFunction = &Action; // 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: déclaration dynamique avant le setup.

Quand on déclare l'instance, on obtient un pointeur sur bouton. Ce pointeur va nous permettre de modifier ses caractéristiques, notamment le pointeur onSelectFunction.

La déclaration est faite ici avant le setup

PecheuxGraph_ILI9341_8bits.zip\PecheuxGraph_ILI9341_8bits\examples\Documentation\Exemple-902-PushZone-Dynamique-onSelectFunction\Exemple-902-PushZone-Dynamique-onSelectFunction.ino (dans votre fichier téléchargé):

// Mise en place de 3 boutons de type PushZone (poussoir sur une zone, 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 dynamique avant le setup()
// - Utilise onSelectFunction pour exécuter l'action à faire

#
  $menu = ":PG";
  include <PecheuxGraph_ILI9341_8bits.h> // Appel de la bibliothèque 


// Déclaration dynamique de l'instance, peut se faire en dehors du setup
// Dans ce cas bouton est accessible partout
PushZone *boutonHaut = new PushZone(190, 90, 230, 130); // Bouton en haut
PushZone *boutonCentre = new PushZone(190, 140, 230, 180); // Bouton au centre
PushZone *boutonBas = new PushZone(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
// Je passe par les pointeurs exceptionnellement pour s'affranchir des noms des
// boutons. Cela permet aussi de montrer l'utilité du pointeur premierControle.
// Si cela vous pose problème, laissez de côté la compréhension de cette fonction
void Action() // Action à faire quand on appuie sur un bouton
{
  PushZone *pointeur = premierControle;
  int ordonnee = 210; // Ligne ou se trouve le contrôle. On commence par celui du bas, c'est dle dernier défini
  while (pointeur != NULL) // Tant qu'on a pas fait toute la liste
  {
    if (pointeur->isSelected()) fillCircle(30, ordonnee, 20, WHITE); // Disque blanc si il est sélectionné
    else fillCircle(30, ordonnee, 20, BLACK);

    pointeur = pointeur->controleSuivant; // Mise à jour pour le bouton suivant
    ordonnee -= 50;
  }
}


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é"));

  // Association de la fonction qui va faire le travail avec le bouton
  // Attention, il y a un caractère "&" avant le nom de la fonction.
  // Cette ligne veut dire: bouton a une propriété onSelectFunction et on va
  // affecter cette propriété avec l'adresse (présence du "&") de onSelectAction
  boutonHaut->onSelectFunction = &Action; // Fonction appelée si on active le bouton du haut de l'écran
  boutonCentre->onSelectFunction = &Action; // Fonction appelée si on active le bouton au milieu de l'écran
  boutonBas->onSelectFunction = &Action; // Fonction appelée si on active le bouton en bas de l'écran
  boutonHaut->onUnselectFunction = &Action; // Fonction appelée si on désactive le bouton du haut de l'écran
  boutonCentre->onUnselectFunction = &Action; // Fonction appelée si on désactive le bouton au milieu de l'écran
  boutonBas->onUnselectFunction = &Action; // 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: déclaration dynamique dans le setup.

C'est pratiquement la même chose que dans l'exemple précédent, mais l'instance est déclarée dans le setup. Dans ce cas, l'instance est dans la pile et est accessible tout le temps, mais seul le pointeur est détruit au sortir du setup. Ou pourrait aussi sur le même principe déclarer l'instance dans une fonction.

Même si le pointeur est détruit au sortir de la fonction, pendant qu'il existe, on peut accéder à l'objet. Cela permet en particulier d'utiliser une boucle pour définir plusieurs objets semblables dans le style:

PushZone *bouton;
for (byte numero=0; numero<10; numero++)
{
  bouton = new PushZone(100, 20*numero, 120, 20*numero+20); // Déclaration d'un bouton
  bouton->onSelectFunction=&onSelectAction; // Fonction à appeler
}

Ceci créerait 10 boutons les uns en dessous des autres, avec une même action. onSelectAction peut agir en fonction du bouton par exemple en regardant ou est le stylet grâce à getTouchY().

PecheuxGraph_ILI9341_8bits.zip\PecheuxGraph_ILI9341_8bits\examples\Documentation\Exemple-903-PushZone-Dynamique-setup-onSelectFunction\Exemple-903-PushZone-Dynamique-setup-onSelectFunction.ino (dans votre fichier téléchargé):

// Mise en place de 3 boutons de type PushZone (poussoir sur une zone, 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 dynamique dans le setup()
// - Utilise onSelectFunction pour exécuter l'action à faire

#
  $menu = ":PG";
  include <PecheuxGraph_ILI9341_8bits.h> // Appel de la bibliothèque 


// 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
// Je passe par les pointeurs exceptionnellement pour s'affranchir des noms des
// boutons. Cela permet aussi de montrer l'utilité du pointeur premierControle.
// Si cela vous pose problème, laissez de côté la compréhension de cette fonction
void Action() // Action à faire quand on appuie sur un bouton
{
  PushZone *pointeur = premierControle;
  int ordonnee = 210; // Ligne ou se trouve le contrôle. On commence par celui du bas, c'est dle dernier défini
  while (pointeur != NULL) // Tant qu'on a pas fait toute la liste
  {
    if (pointeur->isSelected()) fillCircle(30, ordonnee, 20, WHITE); // Disque blanc si il est sélectionné
    else fillCircle(30, ordonnee, 20, BLACK);

    pointeur = pointeur->controleSuivant; // Mise à jour pour le bouton suivant
    ordonnee -= 50;
  }
}


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é"));

  // Déclaration dynamique de l'instance, faite dans une fonction
  // Dans ce cas l'instance est accessible partout, mais le pointeur
  // boutonX sera détruit en sortant de la fonction (ici du setup())
  PushZone *boutonHaut = new PushZone(190, 90, 230, 130); // Bouton en haut
  PushZone *boutonCentre = new PushZone(190, 140, 230, 180); // Bouton au centre
  PushZone *boutonBas = new PushZone(190, 190, 230, 230); // Bouton en bas

  // Association de la fonction qui va faire le travail avec le bouton
  // Attention, il y a un caractère "&" avant le nom de la fonction.
  // Cette ligne veut dire: bouton a une propriété onSelectFunction et on va
  // affecter cette propriété avec l'adresse (présence du "&") de onSelectAction
  boutonHaut->onSelectFunction = &Action; // Fonction appelée si on active le bouton du haut de l'écran
  boutonCentre->onSelectFunction = &Action; // Fonction appelée si on active le bouton au milieu de l'écran
  boutonBas->onSelectFunction = &Action; // Fonction appelée si on active le bouton en bas de l'écran
  boutonHaut->onUnselectFunction = &Action; // Fonction appelée si on désactive le bouton du haut de l'écran
  boutonCentre->onUnselectFunction = &Action; // Fonction appelée si on désactive le bouton au milieu de l'écran
  boutonBas->onUnselectFunction = &Action; // 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: Surcharge de onSelect, déclaration statique.

Si on a besoin de plusieurs boutons ayant des comportements identiques, on a vu qu'on peut écrire une fonction externe pour gérer l'appui. Pour chaque bouton, il faudra alors lui associer cette fonction externe. En définissant une classe fille de PushZone et en surchargeant onSelect(), on aura plus qu'a déclarer l'instance, la fonction étant dedans. C'est un peu plus lourd, mais le code peut être plus clair.

Notez que l'on n'a pas besoin d'accéder au bouton un fois défini, le nom de la variable ne nous sert à rien

PecheuxGraph_ILI9341_8bits.zip\PecheuxGraph_ILI9341_8bits\examples\Documentation\Exemple-904-PushZone-Statique-Classe\Exemple-904-PushZone-Statique-Classe.ino (dans votre fichier téléchargé):

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

// Version 4:
// - On définir une classe Bouton, dérivée de PushZone, avec le bon comportement
// - Les boutons ont une définition statique

#
  $menu = ":PG";
  include <PecheuxGraph_ILI9341_8bits.h> // Appel de la bibliothèque 


class Bouton: public PushZone // Nouvelle classe pour redéfinir onSelect
{
  public:
    Bouton(int x1, int y1, int x2, int y2): PushZone(x1, y1, x2, y2) {} // constructeur, on copie la classe mère
    virtual void onSelect() // Nouveau comportement si on le sélectionne
    {
      fillCircle(100, demiY1 * 2 + 20, 20, WHITE);
    }
    virtual void onUnselect() // Nouveau comportement si on le désélectionne
    {
      fillCircle(100, demiY1 * 2 + 20, 20, BLACK);
    }
}; // Ne pas oublier le ; à la fin de la déclaration d'une classe


// Déclaration statique des instances, doit se faire en dehors du setup
// Si on la définissait dans le setup elle serait détruite au sortir du setup et
// en pariculier lorsque l'on en a besoin (dans le loop).
Bouton boutonHaut(190, 90, 230, 130); // Bouton en haut
Bouton boutonCentre(190, 140, 230, 180); // Bouton au centre
Bouton 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, 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.

 

Cinquième exemple: Surcharge de onSelect, déclaration dynamique.

Si l'on crée une nouvelle classe, il est aussi possible de définir des insances avec des pointeurs.

PecheuxGraph_ILI9341_8bits.zip\PecheuxGraph_ILI9341_8bits\examples\Documentation\Exemple-905-PushZone-Dynamique-Classe\Exemple-905-PushZone-Dynamique-Classe.ino (dans votre fichier téléchargé):

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

// Version 5:
// - On définir une classe Bouton, dérivée de PushZone, avec le bon comportement
// - Les boutons ont une définition dynamique

#
  $menu = ":PG";
  include <PecheuxGraph_ILI9341_8bits.h> // Appel de la bibliothèque 


class Bouton: public PushZone // Nouvelle classe pour redéfinir onSelect
{
  public:
    Bouton(int x1, int y1, int x2, int y2): PushZone(x1, y1, x2, y2) {} // constructeur, on copie la classe mère
    virtual void onSelect() // Nouveau comportement si on le sélectionne
    {
      fillCircle(100, demiY1 * 2 + 20, 20, WHITE);
    }
    virtual void onUnselect() // Nouveau comportement si on le désélectionne
    {
      fillCircle(100, demiY1 * 2 + 20, 20, BLACK);
    }
}; // Ne pas oublier le ; à la fin de la déclaration d'une classe


// Déclaration dynamique de l'instance, peut se faire en dehors du setup
// Dans ce cas bouton est accessible partout
Bouton *boutonHaut = new Bouton(190, 90, 230, 130); // Bouton en haut
Bouton *boutonCentre = new Bouton(190, 140, 230, 180); // Bouton au centre
Bouton *boutonBas = new Bouton(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, 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.

 

Sixième exemple: Surcharge de onSelect, déclaration dynamique dans une fonction.

Comme cela a été fait plus haut, que l'on dérive une nouvelle classe ou pas, on peut créer l'instance bouton dans une fonction. Comme tout à l'heure, l'instance existe partout, mais le pointeur bouton n'est accessible que dans la fonction qui l'a définie.

PecheuxGraph_ILI9341_8bits.zip\PecheuxGraph_ILI9341_8bits\examples\Documentation\Exemple-906-PushZone-Dynamique-setup-Classe\Exemple-906-PushZone-Dynamique-setup-Classe.ino (dans votre fichier téléchargé):

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

// Version 6:
// - On définir une classe Bouton, dérivée de PushZone, avec le bon comportement
// - Les boutons ont une définition dynamique dans une fonction

#
  $menu = ":PG";
  include <PecheuxGraph_ILI9341_8bits.h> // Appel de la bibliothèque 


class Bouton: public PushZone // Nouvelle classe pour redéfinir onSelect
{
  public:
    Bouton(int x1, int y1, int x2, int y2): PushZone(x1, y1, x2, y2) {} // constructeur, on copie la classe mère
    virtual void onSelect() // Nouveau comportement si on le sélectionne
    {
      fillCircle(100, demiY1 * 2 + 20, 20, WHITE);
    }
    virtual void onUnselect() // Nouveau comportement si on le désélectionne
    {
      fillCircle(100, demiY1 * 2 + 20, 20, BLACK);
    }
}; // Ne pas oublier le ; à la fin de la déclaration d'une classe


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é"));

  // Déclaration dynamique de l'instance, peut se faire dans une fonction
  // Dans ce cas l'instance est accessible partout, mais le pointeur
  // bouton sera détruit en sortant de la fonction (ici du setup())
  Bouton *boutonHaut = new Bouton(190, 90, 230, 130); // Bouton en haut
  Bouton *boutonCentre = new Bouton(190, 140, 230, 180); // Bouton au centre
  Bouton *boutonBas = new Bouton(190, 190, 230, 230); // Bouton en bas
}


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.

 

Septième exemple: Surcharge de onSelect, déclaration dynamique dans une fonction, sans pointeur.

Dans la dernière version, on voit que l'on n'a pas besoin du pointeur. Dans ce cas, ce n'est pas la peine d'en avoir un.

PecheuxGraph_ILI9341_8bits.zip\PecheuxGraph_ILI9341_8bits\examples\Documentation\Exemple-907-PushZone-SansPointeur-Classe\Exemple-907-PushZone-SansPointeur-Classe.ino (dans votre fichier téléchargé):

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

// Version 7:
// - On définir une classe Bouton, dérivée de PushZone, avec le bon comportement
// - Les boutons ont une définition dynamique sans pointeur

#
  $menu = ":PG";
  include <PecheuxGraph_ILI9341_8bits.h> // Appel de la bibliothèque 


class Bouton: public PushZone // Nouvelle classe pour redéfinir onSelect
{
  public:
    Bouton(int x1, int y1, int x2, int y2): PushZone(x1, y1, x2, y2) {} // constructeur, on copie la classe mère
    virtual void onSelect() // Nouveau comportement si on le sélectionne
    {
      fillCircle(100, demiY1 * 2 + 20, 20, WHITE);
    }
    virtual void onUnselect() // Nouveau comportement si on le désélectionne
    {
      fillCircle(100, demiY1 * 2 + 20, 20, BLACK);
    }
}; // Ne pas oublier le ; à la fin de la déclaration d'une classe


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é"));

  // Déclaration dynamique de l'instance, mais on n'a pas besoin du pointeur
  // On peut donc créer une instance sans avoir une référence. 
  new Bouton(190, 90, 230, 130); // Bouton en haut
  new Bouton(190, 140, 230, 180); // Bouton au centre
  new Bouton(190, 190, 230, 230); // Bouton en bas
}


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.

 

Côté technique

En fait PushZone ne fait pas grand chose, car c'est le gestionnaire scanEvent() qui vient demander les propriétés de PushZone 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 PushZone 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.