Teaching - 2i013

Enseignants


2i013 - Groupe 5 : Course de voiture

TME 3 bis : première interface SWING pour les étudiants en avance

Ce nouveau TME est destiné à ceux qui sont en avancent, c'est à dire: ceux qui ont déjà fait une voiture opérationnelle avec un radar fonctionnel capable de courir (au moins) les deux premières courses.

Votre simulation est fonctionnelle.

Les évènements sont bien gérés entre la Simulation et votre interface image.

Normalement, la fin de votre main ressemble à ça:

		Simulation simu = new Simulation(track, v, strategy);
		Controleur ihm = new Controleur(track);
		ihm.add(new VoitureObserveur(v));
		simu.add(ihm);		
		simu.play();
		ImageIO.write(ihm.getImage(), "png", new File("result.png"));

Introduction à Swing

Pour bien débuter avec SWING, vous pouvez regarder le guide officiel qui est très bien fait à l'adresse suivante: http://download.oracle.com/javase/tutorial/uiswing/

NB: l'exercice suivant ne nécessite pas de lire ces sources

Nouveaux observeurs

Les Observeurs sont remplacés par des ObserveurSWING. Au lieu d'écrire dans une image, les nouveaux observeurs écrivent dans un objet Graphics.

  public void print(Graphics g);

Pour l'instant, vous allez créer l'interface abstraite. Dans la suite nous allons créer les observeurs de Voiture et de Circuit.

Dessiner une voiture revient à dessiner un rectangle à la place de la voiture. Pour dessiner un rectangle 2x2, la syntaxe est la suivante:

  g.setColor(color);
  g.drawRect((int) voiture.getPosition().getX(), 
    (int) voiture.getPosition().getY(), 2, 2);

Pour dessiner une image, vous utiliser la syntaxe:

  g.drawImage(im, 0, 0, null); // avec im: BufferedImage

Remplacement du Controleur

Le controleur est remplacé par:

		JFrame fen = new JFrame();
		IHMSwing ihm = new IHMSwing();

JFrame désigne une fenêtre: on ouvre donc une fenêtre... IHMSwing désigne un JPanel, c'est à dire une zone vierge de "dessin" que l'on va utiliser pour dessiner la course.

IMHSwing remplace notre Controleur... Il doit donc répondre au même cahier des charges. Les Observeurs sont remplacés par des ObserveurSWING dont la spécification est donnée dans la question précédente.

  public class IHMSwing extends JPanel implements UpdateEventListener
  • public void manageUpdate()
  • public void add(ObserveurSWING obj)

Le processus de dessin est le suivant: lorsque le système décide de mettre à jour l'affichage, il fait appel à la méthode void paint(Graphics g). Vous allez redéfinir cette méthode, faire défiler tous les observeurs et appeler leurs méthodes de dessin.

Pour lancer le réaffichage lorsque la simulation fait appel à manageUpdate(), il faut appeler repaint(). C'est une méthode standard du JPanel qui met à jour l'affichage.

APRES avoir ajouter les observeurs et AVANT de lancer la méthode play() de la simulation, faire les appels suivants:

  ihm.setPreferredSize(new Dimension(768, 1024)); // regler la taille de la fenetre
  fen.setContentPane(ihm); // ajouter le JPanel dans la fenetre
  fen.setVisible(true); // rendre la fenetre visible
  fen.pack(); // rendre la fenetre affichable

Résolution des courses "trop rapides"

Certaines courses vont trop vite... Et on ne voit pas assez ce qui se passe. Les vraies solutions sont assez difficiles à comprendre et à mettre en oeuvre. Je vous propose la solution suivante:

Ralentir la simulation en ajoutant le code:

  try { Thread.sleep(10);
  } catch (InterruptedException e) {
	e.printStackTrace();
  }

dans la boucle play()

Observeur de radar

Une fois que le programme est fonctionnel, construire un obseveur de radar, afin de visualiser le comportement de l'algorithme en temps réel. Dans la méthode void print(Graphics g):

  1. Récupérer toutes les distances à l'aide de distancesInPixels(); et tous les angles à l'aide de thetas();
  2. Parcourir tous les faisceaux et calculer pour chaque faisceau le point de départ (la voiture) et le point d'arrivée (voiture (position et direction)+distance+angle)
  3. Afficher la ligne représentant le faisceau à l'aide de :
  g.drawLine((int) voiture.getPosition().getX(), 
             (int) voiture.getPosition().getY(), 
             (int) arrivee.getX(),(int) arrivee.getY());

Il est possible d'afficher de couleur différente le meilleur faisceau à l'aide de :

  g.setColor(Color.cyan); // par exemple

Observeur de trajectoire

Dans ce formalisme, on ne voit plus la trajectoire... Il suffit d'ajouter un observeur qui mémorise les positions successives de la voiture.