1. Faire ses propres composants 2. Programmer l`interaction

publicité
1. Faire ses propres composants
Faire une interface graphique avec Java2d
et Swing (suite et fin)
Définir le rendu graphique d’un composant
2. Programmer l’interaction
Définir le rendu graphique d’un composant
•
• Le rendu graphique des composants est assuré par le thread awt
(cf. cours suivant). Pour assurer la fluidité, Java2D utilise un
mécanisme de double-buffering.
• Le thread awt se charge d’appeler repaint() sur les composants
quand cela est nécessaire : le composant devient visible, il est
redimensionné…repaint() appelle paint() dès que c’est possible.
On ne force pas un appel à paint(), on appelle repaint().
• Pour les composants standard, le rendu déjà défini par Swing, on
le redéfinit pas en général.
• Pour définir le rendu graphique d’un composant, on fait
généralement une sous-classe de JComponent ou JPanel dans
laquelle on redéfinit la méthode paint.
•
La méthode paint(Graphics g) permet de
récupérer un contexte graphique dans
lequel dessiner
Il faut caster en Graphics2D pour disposer
de toutes les fonctionnalités de la librairie
Java2D
public class MyComponent extends JPanel {
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
…
}
}
Dessiner des primitives graphiques Java2D
public class MyComponent extends JPanel {
Image logo;
public MyComponent() {
super();
Toolkit tk = Toolkit.getDefaultToolkit();
logo = tk.getImage("UPS11-logo.jpg");
try {
MediaTracker tracker = new MediaTracker(this);
tracker.addImage(logo, 0);
tracker.waitForID(0);
} catch(Exception e) { e.printStackTrace(); }
}
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.fillOval(150, 250, 200, 100);
g2d.drawRect(200, 40, 100, 200);
g2d.drawString("Hello", 30, 300);
g2d.drawImage(logo, 0, 0, this);
}
(0, 0)
Le contexte du graphics2D
Le contexte graphique est défini par :
• des attributs de style :
- java.awt.Paint (ex: java.awt.Color…)
- java.awt.Stroke (ex:
java.awt.BasicStroke…)
- java.awt.Font
• des attributs géométriques :
- java.awt.geom.AffineTransform
• des attributs définissant la qualité :
- java.awt.RenderingHints
}
Le contexte du graphics2D
Des primitives plus évoluées
interface java.awt.Shape
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.RED);
g2d.fillOval(150, 250, 200, 100);
g2d.setStroke(new BasicStroke(4));
g2d.drawRect(200, 40, 100, 200);
Ex : Ellipse, Rectangle, Segments, Polylignes…
g2d.setColor(Color.BLACK);
g2d.setFont(new Font("verdana", Font.ITALIC, 24));
g2d.drawString("Hello", 30, 300);
AffineTransform transf = new AffineTransform();
transf.translate(10, 20);
transf.rotate(Math.PI/4);
g2d.setTransform(transf);
g2d.drawImage(logo, 0, 0, this);
}
GeneralPath gp = new GeneralPath();
gp.moveTo(60, 30);
gp.lineTo(90, 60);
gp.lineTo(30, 60);
gp.closePath();
g2d.fill(gp);
Les évènements
1. Faire ses propres composants
2. Programmer l’interaction
Comment capturer les actions de
l’utilisateur (souris, clavier…) et
exécuter les traitements
correspondants?
Programmation évènementielle en
utilisant des objets écoutant les
évènements arrivant sur un
composant graphique.
Ecouteur
Composant graphique
écoute
AWT vs. Glut
• Glut :
Une fonction de rappel (callback) par type
d’événement pour toute la fenêtre
AWT vs. Glut
• Glut : "approche callback"
abcgudiew
• AWT :
Une fonction de rappel (callback) par
écouteur et par type d’événement.
Plusieurs écouteurs peuvent être attachés
à un même composant. Un écouteur peut
être attaché sur plusieurs composants
graphiques.
En cas de clic:
selectObjet
Callback de touche clavier
Si c’est la touche suppr :
Si je suis dans la partie haute:
effacer forme sélectionnée
Si je suis dans la partie basse:
effacer la dernière lettre
• AWT : "approche événements"
Ecouteur1 de touche clavier
écoute
En cas de touche suppr:
effacer forme sélectionnée
Ecouteur2 de touche clavier
abcgudiew
écoute
En cas de touche suppr:
effacer la dernière lettre
Les écouteurs en Java
• Ce sont des instances de classes implémentant
les interfaces XListener :
– Les évènements bas niveau (souris, clavier)
Ex : MouseListener, MouseMotionListener,
MouseWheelListener, KeyListener
– Les évènements haut niveau (bouton logiciel enclenché,
case à cocher sélectionnée..)
Ex : ActionListener, ItemListener…
Les écouteurs bas niveau
• MouseListener
–
–
–
–
–
Press : appui d’un bouton
Release : relâchement d’un bouton
Click : appui+relâchement d’un même bouton
Enter : entrée du curseur dans un composant graphique
Leave : sortie du curseur d’un composant graphique
• MouseMotionListener
– Move : mouvement de souris sans bouton appuyé
– Drag : mouvement de souris avec bouton appuyé
• MouseWheelListener
– Wheel : roulement de la roulette de la souris
• KeyListener
• …que l’on attache à des composants graphiques :
composant.addMouseListener(ecouteur)
– Press : appui sur une touche de clavier
– Release : relâchement d’une touche de clavier
– Type : caractère tapé
Remarque : Avec Glut, nous n’avions que les événements de bas niveau
Exemple simple
Exemple simple
class MyListener implements MouseListener {
public void mouseClicked(MouseEvent evt) {
System.out.println("clic en ("+evt.getX()+","+evt.getY()+")");
}
public void mousePressed(MouseEvent evt) { }
public void mouseReleased(MouseEvent evt) { }
public void mouseEntered(MouseEvent evt) { }
public void mouseLeaved(MouseEvent evt) { }
}
class MyListener implements MouseListener {
public void mouseClicked(MouseEvent evt) {
System.out.println("clic en ("+evt.getX()+","+evt.getY()+")");
}
public void mousePressed(MouseEvent evt) { }
public void mouseReleased(MouseEvent evt) { }
public void mouseEntered(MouseEvent evt) { }
public void mouseLeaved(MouseEvent evt) { }
}
public class Application {
public static void main(String[] args) {
JFrame frame = new JFrame("Example");
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(400, 400));
panel.addMouseListener(new MyListener());
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
public class Application {
public static void main(String[] args) {
JFrame frame = new JFrame("Example");
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(400, 400));
panel.addMouseListener(new MyListener());
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
On peut éviter
d’écrire ces
lignes
XListener / XAdapter
Pour la plupart des interfaces XListener, il existe des classes
abstraites XAdapter. Xadapter est une classe abstraite
implémentant les méthodes de XListener avec des corps vides. Il
suffit de sous-classer et de redéfinir les méthodes qui ont de
l’intérêt.
Un paradigme de programmation souvent utilisé
Fusionner le composant graphique et
l’écouteur
class MyListener implements MouseListener {
public void mouseClicked(MouseEvent evt) {
System.out.println("clic en ("+evt.getX()+","+evt.getY()+")");
}
public void mousePressed(MouseEvent evt) { }
public void mouseReleased(MouseEvent evt) { }
public void mouseEntered(MouseEvent evt) { }
public void mouseLeaved(MouseEvent evt) { }
}
écoute
En cas de clic:
selectObjet
DEVIENT
class MyListener extends MouseAdapter {
public void mouseClicked(MouseEvent evt) {
System.out.println("clic en ("+evt.getX()+","+evt.getY()+")");
}
}
Exemple
class MyPanel extends JPanel implements MouseListener {
public MyPanel() {
On ne peut pas utiliser
super();
la classe abstraite
addMouseListener(this);
MouseAdapter
}
public void mouseClicked(MouseEvent evt) {
System.out.println("clic en ("+evt.getX()+","+evt.getY()+")");
}
public void mousePressed(MouseEvent evt) { }
public void mouseReleased(MouseEvent evt) { }
public void mouseEntered(MouseEvent evt) { }
public void mouseLeaved(MouseEvent evt) { }
}
public class Application {
public static void main(String[] args) {
JFrame frame = new JFrame("Example");
JPanel panel = new MyPanel();
panel.setPreferredSize(new Dimension(400, 400));
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
Classes anonymes
On a souvent besoin que d’une instance d’un écouteur.
On n’a pas besoin de nommer une nouvelle classe, on
utilise le mécanisme de classe anonyme.
a est l’unique instance de A’
A a = new A() {
public void methodA() {
…
}
Sous-classe de A = A’
};
Exemple
Un formalisme pour décrire l’interaction: les machines à états
• Forme graphique
public class Application {
public static void main(String[] args) {
JFrame frame = new JFrame("Example");
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(400, 400));
panel.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
System.out.println(
"clic en ("+evt.getX()+","+evt.getY()+")");
}
});
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
Les machines à états : définition
Les machines à états sont une façon simple de décrire précisément
l'interaction. Elles sont basées sur les automates à états finis.
Une machine est constituée d'un ensemble d'états (cercles), dont un
état initial qui est l'état de départ. Le passage d'un état à un autre
est décrit par des transitions (flèches), qui sont déclenchées par
l'arrivée d'évènements tels que le déplacement de la souris,
l'appui sur un bouton...
A chaque transition peuvent être associées :
- une garde = une condition qui, si elle n’est pas vraie, empêche la
transition d’être déclenchée.
- une action = du code exécuté lorsque la transition est déclenchée.
A chaque état peuvent être associées :
- une action d'entrée = du code exécuté lorsque l'état devient l’état
courant.
une action de sortie = du code exécuté lorsque l'état cesse d’être
l'état courant.
Click()
CreateEllipse()
PressOn(ellipse)
Select(ellipse)
drag
START
Drag()
Move(ellipse)
Release()
Deselect(ellipse)
• Forme textuelle
Etat start {
Transition
Transition
}
Etat drag {
Transition
Transition
}
PressOn(ellipse) => drag {Select(ellipse)}
Click => start {CreateEllipse()}
Move => drag {Move(ellipse)}
Release => start {Deselect(ellipse)}
Du bas niveau au haut niveau
JButton button = new JButton("Ok");
button.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me1){
System.out.println("OK");
MouseReleased
}
Invoke
});
START
MouseEntered
invokable
MousePre
ssed
Mo
use
En
Mo
use
Lea
ved
in
MouseReleased
Cancel
tere
d
Le bouton est déclenché
out
par une séquence d’événements
de bas niveau plus complexe qu’un simple
clic et qui se produit sur un certain type de composant
graphique (un bouton logiciel).
Évènements de Haut Niveau
Exemple du JButton
• Quand un bouton est invoqué
JButton button = new JButton("Ok");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt){
System.out.println("bouton "+evt.getSource()+"invoqué");
}
});
• Quand une case est cochée
• Quand un item de menu est sélectionné
•…
Exemple du JCheckbox
Renvoie l’objet source de l’événement
"
getComponent() renvoie le composant
graphique sur lequel l’événement a eu lieu
(Sur cet exemple, getSource et getComponent renvoie la même résultat
car c’est le composant graphique lui-même qui émet l’évènement
Ecouteurs de fenêtre
Remarque : Le programme Java ne
termine pas quand on ferme la fenêtre.
JCheckBox checkBox = new JCheckBox("Select");
button.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt){
if (evt.getStateChange() == ItemEvent.DESELECTED)
System.out.println("déselectionné");
else
System.out.println("selectionné");
}
});
On peut écouter les évènements de la
fenêtre (WindowListener) et quitter le
programme quand la fenêtre se ferme.
!Un raccourci syntaxique utile
frame.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE);
Questions diverses
Téléchargement