f.pack();
 f.setVisible(true);
Les cycles des feux sur les trois voies pour les temps par défaut sont résumés dans le tableau ci-dessous :
Qualité de l'affichage du composant.
Le dessin circulaire du composant montre un crénelage causé par le tracé pixel par pixel.
Il est possible d'améliorer l'affichage en utilisant l'antialiasing, en modifiant légèrement le code.
Tout d'abord, il faut définir les propriétés de rendu dans un dictionnaire utilisant des clés de la classe codice_15.
La partie de code ci-dessous est à ajouter dans la classe codice_16, et montre les clés modifiables.
Celles sur l'affichage du texte (KEY_TEXT_ANTIALIASING, KEY_FRACTIONALMETRICS) ne sont pas nécessaires pour cette classe mais illustrent les possibilités.
protected static final HashMap<Key, Object> QUALITY_HINTS =
 new HashMap<RenderingHints.Key, Object>();
static
 QUALITY_HINTS.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// QUALITY_HINTS.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
 QUALITY_HINTS.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
 QUALITY_HINTS.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
 QUALITY_HINTS.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
 QUALITY_HINTS.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
 QUALITY_HINTS.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
 QUALITY_HINTS.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
On peut aussi améliorer le tracé en utilisant une plus grande épaisseur de trait.
Les paramètres de trait sont gérés par la classe abstraite codice_17, dont la classe codice_18 est une implémentation.
private Stroke STYLE_TRAIT = new BasicStroke(2); // Épaisseur : 2 pixels
Il ne reste plus qu'à utiliser ces éléments dans la méthode codice_19.
Cependant ils ne sont utilisables qu'avec une instance de la classe codice_20, qui est la classe réelle de l'objet codice_21 passé à la méthode.
Il faut donc convertir l'objet pour définir les options de rendu et le style des traits.
@Override
protected void paintComponent(Graphics graphics)
 Graphics2D g = (Graphics2D)graphics;
 Dimension d = getSize();
 g.addRenderingHints(QUALITY_HINTS);
 g.setStroke(STYLE_TRAIT);
// ... la suite reste inchangée, identique à la version précédente.
Préservation du contexte graphique.
La méthode codice_8 étant implémentée par appels à d'autres méthodes, elle leur passe le même contexte graphique de classe codice_20.
Cela signifie que le dernier changement de paramètre (couleur, police de caractère, style de trait, région clip, ...) est celui par défaut pour la méthode appelée après.
Il est donc recommandé de restaurer les valeurs d'origine avant de terminer.
Cependant, cela implique de lire la valeur au début de la méthode pour la restaurer à la fin, ce qui complique le codage vu le nombre possible de paramètres auquel cela s'applique.
La solution est de créer un contexte dérivé de celui passé en paramètre, et de ne plus utiliser l'original ensuite.
Il faudra cependant libérer les ressources prises par le nouveau contexte en appelant sa méthode codice_24 à la fin.
@Override
protected void paintComponent(Graphics graphics)
 Graphics2D g = (Graphics2D)graphics.create();
 try
 Dimension d = getSize();
 g.addRenderingHints(QUALITY_HINTS);
 g.setStroke(STYLE_TRAIT);
 // ... la suite reste inchangée, identique à la version précédente, indentée d'un cran.
 finally
 g.dispose();
Orientation du composant.
Le feu tricolore utilisé dans une simulation de circulation réaliste avec vue de dessus d'un carrefour devrait pouvoir être positionné horizontalement de haut en bas et inversement, ou verticalement de droite à gauche et inversement.
Génération d'évènements spécifiques.
Dans une utilisation réaliste du composant, le feu tricolore utilisé pour simuler la circulation devrait être capable de notifier ses changements d'états aux automobilistes pour qu'ils puissent s'arrêter ou redémarrer.

Programmation Java Swing/Gestion des évènements

Un composant peut recevoir divers évènements issus de l'interaction avec l'utilisateur :
Il peut aussi en générer :
Principes de gestion des évènements.
De manière générale, la gestion des évènements en Java se fait de la manière suivante :
L'exemple ci-dessous illustre comment recevoir un évènement d'action sur un bouton, qui se déclenche au clic avec la souris, ou au clavier quand le bouton a le focus.
JButton b_ok = new JButton("OK");
b_ok.addActionListener(new ActionListener()
 @Override
 public void actionPerformed(ActionEvent e)
 // ... Action du bouton OK ici
 System.out.println("Clic du bouton OK");
});
La convention de gestion des évènements est basée sur celle des JavaBeans.
Pour un évènement de type "type" (MouseWheel, Key, Mouse, ...) :
Les différents types d'évènements.
Il existe un grand nombre de types d'évènements représentés par des classes dérivant de la classe codice_1.
Cette section ne citera que les principaux types parmi ceux concernant les interfaces graphiques avec Swing.
La hiérarchie des types d'évènements contient un certain nombre de classes, chacune pouvant ajouter une ou plusieurs informations sur l'évènement.
Les sous-classes de la classe codice_10 ont un attribut (ID) qui identifie une notification particulière d'un évènement, chacune correspondant à une méthode de l'interface d'écoute de l'évènement.
Par exemple, pour les évènements provenant de la souris, les méthodes de l'interface codice_11 sont appelées avec un objet évènement de classe codice_12 dont la valeur de l'identificateur (ID) correspond à celles-ci :
public void mouseReleased(MouseEvent e); // e.getID() == MouseEvent.MOUSE_RELEASED
public void mousePressed(MouseEvent e); // e.getID() == MouseEvent.MOUSE_PRESSED
public void mouseExited(MouseEvent e); // e.getID() == MouseEvent.MOUSE_EXITED
public void mouseEntered(MouseEvent e); // e.getID() == MouseEvent.MOUSE_ENTERED
public void mouseClicked(MouseEvent e); // e.getID() == MouseEvent.MOUSE_CLICKED
Même principe pour les méthodes de l'interface codice_13 pour intercepter les évènements de mouvement de la souris :
public void mouseMoved(MouseEvent e); // e.getID() == MouseEvent.MOUSE_MOVED (Souris déplacée sans bouton enfoncé)
public void mouseDragged(MouseEvent e); // e.getID() == MouseEvent.MOUSE_DRAGGED (Souris déplacée avec bouton enfoncé)
Cela s'applique aussi aux interfaces qui n'ont qu'une seule méthode, comme l'interface codice_14 pour la notification de rotation de molette de la souris :
public void mouseWheelMoved(MouseWheelEvent e); // e.getID() == MouseEvent.MOUSE_WHEEL
Cette redondance apparente d'identification du type d'évènement (par la méthode appelée et par la valeur de l'attribut ID) facilite la réutilisation d'une même méthode pour traiter plusieurs évènements de façon similaire.
Implémentation partielle.
Les interfaces d'écoute définissant au moins deux méthodes possèdent une classe dont le nom est celui de l'interface où l'on remplace le suffixe codice_15 par codice_16.
Cette classe définit des méthodes vides et permet aux applications de la surcharger pour ne définir que certaines méthodes de l'interface.
Exemple :
addWindowListener(new WindowAdapter()
 @Override
 public void windowClosing(WindowEvent e)
 fermerFenetre();
});

Programmation Java Swing/Créer une case à cocher à trois états