Gestion des événements Exercice: "Paint" Disposition des vues * Préparer deux zones * Haut: barre d'outils * Bas: espace où dessiner * Zone de dessin * Type: FrameLayout * Identifiant: "scene" * Barre d'outils * Type: LinearLayout (horizontal) * Ajouter des boutons * Une classe représentant le dessin sera développée * Classe "Dessin" qui hérite de "FrameLayout" * Un objet de cette classe sera ajouté dans la vue "scene" Dessiner sur une vue (1/2) * Deux objets sont nécessaires pour tracer sur une vue * Pinceau: "outil" de dessin (objet de la classe "Paint") * A créer, possibilité d'en avoir plusieurs * Paint pinceau = new Paint(); * Style de tracé * Forme pleine: pinceau.setStyle(Paint.Style.FILL); * Contour uniquement: pinceau.setStyle(Paint.Style.STROKE); * Couleur du tracé: pinceau.setColor(0xFF00FF00); * Code ARGB: Aliasing + Rouge + Vert + Bleu * Epaisseur du trait: pinceau.setStrokeWidth(4); * Toile: "réceptable" du dessin (objet de la classe "Canvas") * Elle est fournie automatiquement par le système * Utiliser un pinceau pour tracer * Ligne: toile.drawLine(x1,y1,x2,y2,pinceau); * Rectangle: toile.drawRect(x1,y1,x2,y2,pinceau); Dessiner sur une vue (2/2) * On n'appelle jamais directement le code qui dessine * Appel automatique du système à la méthode "onDraw" de la vue * Uniquement quand le rafraîchissement du dessin est nécessaire * La toile est alors fournie à cette méthode * Placer le code du dessin dans la méthode "onDraw" de la vue protected void onDraw(Canvas toile) { super.onDraw(toile); // Tracé du dessin } * Indiquer au système qu'il doit appeler votre code * Dans le constructeur: setWillNotDraw(false); * Possibilité de demander le rafraîchissement de la vue * A tout moment, en appelant sa méthode "invalidate" Classe "Dessin" (1/2) * Héritage d'une classe de vues existante public class Dessin extends FrameLayout { private Paint pinceau_; // Attribut public Dessin(Context contexte) { [...] } protected void onDraw(Canvas toile) { [...] } } * Constructeur * Une vue est construite à partir d'un contexte * public Dessin(Context contexte) { super(contexte); // Initialisation de la vue } Classe "Dessin" (2/2) * Initialisation de la vue * Couleur de fond * setBackgroundColor(0xFFEEEEEE); * Dimensions (par exemple, adaptation au parent) * setLayoutParams(new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); * Forcer l'appel à "onDraw" * setWillNotDraw(false); * Au démarrage de l'activité * Récupérer la zone de dessin (identifiant "scene") * FrameLayout scene = findViewById(R.id.scene); * Créer un objet dessin * Dessin dessin = new Dessin(this); * Ajouter le dessin dans la zone * scene.addView(dessin); Mécanisme des écouteurs * Possibilité de surveiller de nombreux événements sur une vue * Les événements sont organisés par type * OnClick: détection "clic" (appui + relâchement) avec le doigt * OnTouch: détection appui, relâchement, déplacement du doigt * ... * Surveillance d'un type d'événement sur une vue ==> écouteur * Ecouteur = objet alerté quand l'événement se produit sur la vue * Exemple: vue.setOnTouchListener(ecouteur); * Au démarrage de l'activité * Créer un objet écouteur (dont la classe devra être développée) * Ecouteur ecouteur = new Ecouteur(); * Associer l'écouteur aux événements sur la vue "dessin" * dessin.setOnTouchListener(ecouteur); Classe "Ecouteur" (1/2) * Héritage de l'interface correspondant au type d'événement * Interface ~ classe sans implémentation * public class Ecouteur implements OnTouchListener { public boolean onTouch(View vue, MotionEvent evnt) { [...] } } * Lorsqu'un événement "OnTouch" se produit ==> appel de la méthode "onTouch" de l'écouteur * C'est de cette manière que l'écouteur est informé * Il reçoit la vue qui a subi l'événement (ici, notre dessin) * Au besoin, il faut la convertir * Dessin dessin = (Dessin)vue; * Et un objet contenant des renseignements sur l'événement: evnt Classe "Ecouteur" (2/2) * Redéfinition de la méthode "onTouch" public boolean onTouch(View vue,MotionEvent evnt) { int action = evnt.getAction(); // Type d'action du doigt int x = (int)evnt.getX(); // Position X du doigt int y = (int)evnt.getY(); // Position Y du doigt if (action == MotionEvent.ACTION_DOWN) System.out.println("Doigt posé au point " + x + ";" + y); else if (action == MotionEvent.ACTION_UP) System.out.println("Doigt levé au point " + x + ";" + y); else if (action == MotionEvent.ACTION_MOVE) System.out.println("Doigt déplacé au point " + x + ";" + y); return true; // Indique que l'événement a été traité } Classe "Courbe" (1/2) * Courbe = liste de points * Classe "Point" existe * Utilisation du conteneur "ArrayList" * Equivalent à un tableau dont la taille s'adapte automatiquement * ArrayList<Point> = liste de points * Classe "Courbe" agrège une liste de points public class Courbe { private ArrayList<Point> points_; public Courbe() { [...] } public void ajouter(Point point) { points_.add(point); } public void dessiner(Paint pinceau,Canvas toile) { [...] } } Classe "Courbe" (2/2) * Dessiner la courbe public void dessiner(Paint pinceau,Canvas toile) { // Réglage du pinceau for (int i = 1; i < points_.size(); ++i) { int x1 = points_.get(i-1).x; int x2 = points_.get(i).x; int y1 = points_.get(i-1).y; int y2 = points_.get(i).y; // Tracé d'une ligne (x1;y1) ? (x2;y2) sur la toile } } * Dans la classe "Dessin" * Mémoriser la liste des courbes ==> attribut "courbes_" * Méthode pour ajouter une courbe dans la liste ==> void ajouter(Courbe courbe) * Méthode "onDraw" à modifier pour qu'elle affiche les courbes mémorisées * Faire un test en créant des courbes dans le constructeur Création interactive d'une courbe * Dans la classe "Ecouteur" * Doigt posé ==> nouvelle courbe (position = 1er point) * Doigt en mouvement ==> ajout point dans la courbe * Doigt levé ==> courbe terminée * Mémoriser la courbe en cours de tracé * Attribut "courbe_", initialisé à "null" dans le constructeur * Modifier la méthode "OnTouch" if (action == MotionEvent.ACTION_DOWN) { /* Nouvelle courbe (ajouter à la liste) */ } else if (action == MotionEvent.ACTION_UP) { /* Courbe terminée */ } else if (action == MotionEvent.ACTION_MOVE) { /* Ajout point dans la courbe */ } dessin.invalidate(); // Demande rafraîchissement Classe "Ligne" public class Ligne { private Point origine_; private Point destination_; public void setOrigine(Point point) { [...] } public void setDestination(Point point) { [...] } public Ligne(Point origine,Point destination) { [...] } public void dessiner(Paint pinceau,Canvas toile) { // Réglage du pinceau // Tracé de la ligne } } Affichage des lignes * Dans la classe "Dessin"... * Mémoriser la liste des lignes ==> attribut "lignes_" * Mémoriser la ligne en cours de tracé * Attribut "ligneCourante_" * Initialisé à "null" dans le constructeur * Méthode pour ajouter une ligne dans la liste * void ajouter(Ligne ligne) * Méthode pour définir la ligne en cours de tracé * void setLigneCourante(Ligne ligne) * Compléter la méthode d'affichage "onDraw" * Pour les lignes fixées, tracé d'une certaine couleur * Pour la ligne en cours (si elle existe), tracé d'une autre couleur Création interactive d'une ligne * Dans la classe "Ecouteur" * Doigt posé ==> nouvelle ligne courante (position = origine de la ligne) * Doigt en mouvement ==> modification destination de la ligne * Doigt levé ==> ligne fixée * Mémoriser la ligne en cours de tracé * Attribut "ligne_", initialisé à "null" dans le constructeur * Modifier la méthode "OnTouch" if (action == MotionEvent.ACTION_DOWN) { /* Nouvelle ligne courante */ } else if (action == MotionEvent.ACTION_UP) { /* Ligne fixée (ajouter à la liste) */ } else if (action == MotionEvent.ACTION_MOVE) { /* Modification destination de la ligne */ } dessin.invalidate(); // Demande rafraîchissement Gestion des outils * Dans la classe "Ecouteur" * Mémoriser le choix de l'outil ==> attribut "outil_" * Exemple: 1 = courbe, 2 = ligne... * Méthode pour changer d'outil: void setOutil(int outil) * Modifier la méthode "onTouch" * Afin d'effectuer le travail correspondant à l'outil sélectionné * Dans la classe de l'activité * L'objet écouteur devient un attribut de la classe * Afin d'être accessible à partir d'autres méthodes * Créer une méthode (déclenchée par un bouton) pour activer chaque outil * void selectionnerCourbe(View vue) * void selectionnerLigne(View vue) * ... * Associer chaque méthode au clic du bouton correspondant * Attribut "onClick" |