Une animation                  

Une animation

     

alt : l'applet n'est pas visible par votre navigateur ; pour voir l'application, vous devez télécharger le code, le compiler et l'exécuter
Il s'agit, dans ce paragraphe, de faire une animation simple où, à intervalles de temps réguliers, on redessine tout le contenu de la fenêtre de façon à obtenir une animation. L'animation correspond à ce qu'on peut sans doute voir sur l'applet, les anneaux donnant l'impression de grandir tout en se reformant par l'intérieur. L'animation peut être arrêtée ou reprise avec les boutons correspondants.

Le plus simple est d'utiliser un timer, instance de la classe javax.swing.Timer. Un timer sert à provoquer des actions à intervalles réguliers. Ces actions sont provoquées par l'intermédiaire d'instances de la classe ActionEvent engendrées par le timer. Il faut associer au timer un ou plusieurs listeners de type ActionListener qui ont pour tâche d'effectuer les actions à la réception des ActionEvent ; on fournit aussi au timer le délai qui doit séparer deux actions successives. Les actions sont traitées par le gestionnaire d'événements (event-dispatching thread). On doit démarrer le timer avec la méthode start ; on peut choisir le temps écoulé avant le premier appel du timer par la méthode setInitialDelay(int t); on peut choisir que le timer ne fasse qu'un seul appel par la méthode setRepeats(boolean b) ; on peut arrêter le timer avec la méthode stop. On peut faire repartir le timer avec la méthode restart.

Du fait que les actions demandées par le timer sont prises en charge par le gestionnaire d'événements, il ne serait pas judicieux, dans une interface graphique un peu complexe, de faire par l'intermédiaire du timer des actions consommatrices de beaucoup de temps car cela empêcherait la gestion correcte des autres événements. Pour une action « lourde », il faut envisager de définir un nouveau thread pour exécuter celle-ci.

Dans notre programme, on peut remarquer que nous avons ajouté deux ActionListener à chacun des boutons ; l'un (défini par la classe Ardoise) s'occupe de gérer, selon le cas, l'arrêt ou le redémarrage de l'animation, l'autre (défini par la classe Anneaux) s'occupe de rendre les boutons disponibles ou non.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

class Ardoise extends JPanel implements ActionListener {
	
	private static final long serialVersionUID = 1L;
	private int dep = 0;
        private Timer declencheur;
	private int largeur = 200, hauteur = 200;

	Ardoise() {
		setPreferredSize(new Dimension(largeur, hauteur));
		setBackground(Color.WHITE);
		declencheur = new Timer(100, this);
		declencheur.start();
	}

	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == declencheur) {
			repaint();
			dep = (dep - 1) % 10;
		}
		else {
			String commande = e.getActionCommand();
			if (commande.equals("arreter"))
 				declencheur.stop();
			else if(commande.equals("reprendre"))
				declencheur.restart();
		}
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		for (int i = dep - 5; i < largeur/2; i += 10) {
			for (int j = i; j < i + 5; j++)
				if (j > 0) g.drawOval(j, j, largeur - 2*j, hauteur - 2*j);
		}
	}
}
 
class IHMAnneaux extends JPanel implements ActionListener {
	private static final long serialVersionUID = 1L;
	
	Ardoise ardoise = new Ardoise();
	JButton arret = new JButton("arret");
	JButton reprise = new JButton("reprendre");

	IHMAnneaux() {
		arret.setActionCommand("arreter");
		arret.addActionListener(ardoise);
		arret.addActionListener(this);

		reprise.setActionCommand("reprendre");
		reprise.addActionListener(ardoise);
		reprise.addActionListener(this);
		reprise.setEnabled(false);

		JPanel boutons = new JPanel();
		boutons.setBackground(Color.WHITE);
		boutons.add(arret);
		boutons.add(reprise);

		setLayout(new BorderLayout());
		add(boutons, BorderLayout.NORTH);
		add(ardoise, BorderLayout.CENTER);
		setBackground(Color.WHITE); 
	}

	public void actionPerformed(ActionEvent e) {
		String commande = e.getActionCommand();
		if (commande.equals("arreter")) {
			arret.setEnabled(false);
			reprise.setEnabled(true);
		}
 		else if (commande.equals("reprendre")){
			arret.setEnabled(true);
			reprise.setEnabled(false);
		}
	}
}

class Anneaux {
	public static void main(String[] arg) {
		JFrame fenetre = new JFrame();
		fenetre.setContentPane(new IHMAnneaux());
		fenetre.pack();
		fenetre.setLocation(100, 100);
		fenetre.setVisible(true);
		fenetre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
}

declencheur = new Timer(100, this); : l'appel à la méthode actionPerformed de l'ActionListener indiqué par le second argument (ici this) se fera toutes les 100 millisecondes.
declencheur.start(); : cette instruction fait démarrer le timer ; pour notre exemple, le premier appel à actionPerformed se fera après 100 millisecondes.
dep = (dep - 1) % 10; : c'est de cette instruction que dépend l'élargissement des anneaux.
declencheur.stop(); : cette instruction interrompt le timer mais cela ne l'empêche pas d'être redémarré.
declencheur.restart(); : redémarre le timer ; s'il n'avait pas été démarré, cette instruction le ferait démarrer. Le délai pour le premier appel est le délai initial du timer.

© Irène Charon, Télécom ParisTech 2011