JAVA Interface Graphique SWING Historique sur les interfaces graphiques Java Java fournit les deux paquetages principaux pour les interfaces graphiques : java.awt (Abstract Window Toolkit) : Utilise les composants graphiques natifs de la plate-forme Peut avoir un comportement différent suivant la plate-forme Limité aux caractéristiques communes à toutes les plates-formes cibles Exécution assez rapide. javax.swing, initialement JFC (Java Foundation Classes) : Bibliothèque écrite en 100% pure Java ; Bibliothèque très riche proposant des composants évolués (arbres, tables,...) Construite au dessus de la partie portable de AWT ; Look & Feel modifiable (application du patron MVC) ; Exécution assez lente. SWING Méthode de construction : Une plaque de base: Jframe, Jwindow, Jdialog, Objets JApplet On ajoute des briques prédéfinies par dessus :composants ou contrôle boutons, textfield,etc. Le sous système graphique est objet chaque composant s'affiche chaque composant provoque l'affichage des composants qu'il contient JFrame La fenêtre top level JFrame s'affiche Le contentpane affiche un fond opaque Le JPanel s'affiche (par dessus le précédent) : • • le fond (paintComponent()) les bordures(paintBorder()) getContentPane() Il demande à son contenu de s'afficher(paintChildren()) • • Le JButton "Mon bouton" s'affiche par paintComponent() – le fond – le texte Le Jlabel "Du texte" s'affiche par paintComponent() JPanel – le texte Pour provoquer l'affichage, utiliser repaint() : affiche tout le composant repaint(int,int,int,int) : affiche le rectangle JButton Jlabel Mon Bouton Du Texte Construire une IG en pratique : patron MVC Définir le Modèle de données de l’application Définir l’ergonomie de l’IG : la Vue Construire une fenetre de base (JFrame, JDialog, JApplet…) Construire un composant intermédiaire : Jpanel, JScrollPane, JSplitPane,… Ajouter des objets graphiques ou d’autres composants intermédiaires dans le composant intermédiaire : methode add du composant intermédiaire Ajouter le composant intermédiaire à la fenetre de base : methode add de la fenetre principale Positionner et dimensionner les composants methode pack() de la fenetre principale Visualiser la fenetre de base : methode setVisible(true) de la fenetre principale Définir la réaction aux actions de l’utilisateur sur les éléments de l’ IG : le Contrôleur Swing : composants de base Swing : composants de haut niveau Swing : les composants intermédiaires Les Gestionnaires de Placement Principe : Associé à un Container, un gestionnaire de placement (LayoutManager) est chargé de positionner ses composants suivant une politique prédéfinie FlowLayout Les uns à la suite des autres BorderLayout Au centre ou à un des quatre coins cardinaux BoxLayout Sur une même ligne ou sur une même colonne GridLayout Sur un tableau à 2 dimensions (les composants ont tous la même taille) GridBagLayout Dans une grille mais les composants peuvent être de tailles différentes en occupant plusieurs lignes et/ou colonnes CardLayout seulement un seul composant est affiché Exemples de Gestionnaires de Placement Créer un nouveau composant pour dessiner • La classe Graphics est une classe abstraite – – – permettant de dessiner des formes simples et des chaines de caractères D’etre indépendant du support réel :carte graphique, imprimante, image en mémoire contient des informations sur : • • • Les couleurs d’affichage, de fond, le type d’opération de dessin (xor) Le composant abstrait dans lequel on dessine Pour dessiner dans une fenetre: – On crée un nouveau composant d’affichage dérivant de JPanel et on redéfinit les méthodes • • PaintComponent(Graphics g) pour l’affichage PaintBorder pour les bordures public void paintComponent(Graphics g) { super.paintComponent(g); //Le fond g.drawRect(10, 20, 99, 199); g.setColor(Color.yellow); // Dessine un rectangle jaune g.fillRect(10+1, 20 + 1,98,198); } Image • AWT : getImage, drawImage myImage = Toolkit.getDefaultToolkit().getImage(filenameOrURL); g.drawImage(myImage, 0, 0, this); • SWING : une image est simplement affichée dans un JPanel, un JButton – interface icons – Classe ImageIcon : implemente icons, lit du GIF ou JPEG, mais aussi des BufferedImage (!= Image) – la fonction paintIcon(Component,Graphics,int,int) personnalise l'affichage d'une image Afficher une image dans un composant (1) class AfficheImage extends JLabel { private ImageIcon icon=null; public AfficheImage(String im) { updateImage(im); } public void updateImage(String im) { icon=new ImageIcon(im); setIcon(icon);} // Creation et affichage de l’image } class AppliAffiche extends JFrame { private AfficheImage affiche =null; public AppliAffiche(String im) { getContentPane().add(affiche=new AfficheImage(im)); pack(); setVisible(true); } public void suite(String im) { affiche.updateImage(im); pack(); } } public class Ex40 { public static void main (String []arg) { Scanner clavier = new Scanner(System.in); if (arg==null) {System.out.println("Usage : java Ex40 im1 im2 ...."); } else { AppliAffiche p = new AppliAffiche(arg[0]); System.out.println("Photo suivante"); clavier.nextLine(); for (int i=1; i<arg.length; i++) { p.suite(arg[i]); System.out.println("Photo suivante"); clavier.nextLine(); } } } } Afficher une image dans un composant (2) class AfficheImage extends JPanel{ private BufferedImage img = null; public AfficheImage(BufferedImage i) { img=i;} public void updateImage(BufferedImage i) { img=i; repaint();} public void paintComponent(Graphics g) { g.drawImage(img, 0, 0, null); } public Dimension getPreferredSize() { return (img==null) ? new Dimension(100,100): new Dimension(img.getWidth(null), img.getHeight(null)); } } class AppliAffiche extends JFrame { private AfficheImage affiche =null; public AppliAffiche(BufferedImage im) { getContentPane().add(affiche=new AfficheImage(im)); pack(); setVisible(true); } public void suite(BufferedImage im) { affiche.updateImage(im); pack(); } } public class Ex40b { public static void main(String [] arg) {Scanner clavier = new Scanner(System.in); BufferedImage img = null; if (arg==null) {System.out.println("Usage : java Ex40 im1 im2 ...."); } else { try { img = ImageIO.read(new File(arg[0])); } catch (IOException e) {} AppliAffiche p = new AppliAffiche(img); System.out.println("Photo suivante"); clavier.nextLine(); for (int i=1; i<arg.length; i++) { try { img = ImageIO.read(new File(arg[i])); } catch (IOException e) {} p.suite(img); System.out.println("Photo suivante"); clavier.nextLine(); } System.exit(0); } } } Swing : exemple Exemple de réalisation ergonomie JAVA Gestion des évènements en SWING Gestion des évenements Objet Ecouteur3 Evenement : clic sur le moins EDT : file des évènements gérée par un thread Contient la méthode à executer public void actionPerformed(ActionEvent event) Envoi à tous les objets qui ont le droit d’écouter le bouton « moins » cette information Objet Ecouteur1 Objet Ecouteur2 Contient la méthode à executer public void actionPerformed(ActionEvent event) Mettre a jour le compteur Contient la méthode à executer public void actionPerformed(ActionEvent event) Ecouter un bouton Il faut créer l’interface graphique (IG) : une fenetre de base Trois boutons : moins, plus, reset Une zone de texte : resultat Deux possibilités pour définir un écouteur : La classe principale (la Vue) réalise ActionListener Définition d’une classe spécifique pour chaque écouteur qui réalise ActionListener La classe qui réalise l’interface ActionListener permet de gérer les clics sur un bouton, les sélections de menu On définit dans cette classe la méthode actionPerformed(…) qui explicite ce qui doit être fait quand on clique sur un bouton public void actionPerformed(ActionEvent event) { TODO } Le bouton moins autorise l’objetEcoutant à traiter les evenements en provenance de lui même (le moins), i.e. on enregistre objetEcoutant aupres du bouton par la méthode addActionListener, moins.addActionListener(objetEcoutant); Ecouter un bouton Exemple de l’IG compteur : Patron Modèle-Vue-Contrôleur (MVC) • Modèle de l’application = la classe compteur (les données) • Vue = « Ergonomie » de l’IG • Contrôleur = Réaction aux actions de l’utilisateur sur les éléments de l’IG Graphique Fermer la fenetre Il faut créer une classe (ici MonEcouteurFenetre) qui implémente l’interface windowListener qui permet de gérer les fenetres Il faut définir 7 méthodes, meme si elles sont vides void windowOpened(WindowEvent e) : ouverture de la fenetre void windowClosed(WindowEvent e) : apres la fermeture de la fenetre void windowClosing(WindowEvent e) : au moment de la fermeture de la fenetre void windowIconified(WindowEvent e) : iconifier la fenetre void windowDeiconified(WindowEvent e) : deiconifier de la fenetre void windowActivated(WindowEvent e) : focus dans la fenetre; Utiliser de préférence windowGainedFocus de WindowFocusListener void windowDeactivated(WindowEvent e) : perte du focus de la fenetre. Utiliser de préférence windowLostFocus de WindowFocusListener On crée et enregistre cet objet aupres de la fenetre par la méthode addWindowListener Les adapteurs : Fermer la fenetre Gérer les événements par adaptateur une interface listener toutes les méthodes doivent être écrites, même vides exemple : windowsListener : 7 méthodes à redéfinir windowActivated, windowClosed, windowClosing, WindowDeactivated, windowDeiconified, windowIconified, windowOpened Un adaptateur : une classe contient déjà une version vide on ne surcharge que les fonctionnalités dont on a besoin Attention : la classe écouteur HERITE de la classe Adapter au lieu de IMPLEMENTE une interface ComponentAdapter ContainerAdapter FocusAdapter KeyAdapter MouseAdapter MouseMotionAdapter WindowAdapter Quel écouteur définir pour quelle action ? Interface ActionListener Utilisée par les clics bouton, choix de menu, et les CR dans un zone de texte (JTextField, JTextArea) Méthodes à définir void actionPerformed(ActionEvent e) : que faire lors de l'apparition d’un des évènements Interface MouseListener ou classe MouseAdapter Utilisée pour les actions souris entrant et sortant dans la fenetre, les clics dans la fenetre Méthodes à définir void void void void void mouseClicked(MouseEvent e) : clic dans la fenetre mouseEntered(MouseEvent e) : souris entrant dans la fenetre mouseExited(MouseEvent e) : souris sortant de la fenetre mousePressed(MouseEvent e) : touche souris appuyée dans la fenetre mouseRealised(MouseEvent e) : touche souris relachée dans la fenetre Principales méthodes de la classe MouseEvent boolean isAltDown(), boolean isControlDown(), boolean isMetaDown(), boolean isShiftDown() int getModifiers(), int getX(), int getY() Méthodes utiles boolean isLeftMouseButton(MouseEvent e) : vrai si e concerne le bouton gauche de la souris boolean isMiddleMouseButton(MouseEvent e) : vrai si e concerne le bouton milieu de la souris boolean isRightMouseButton(MouseEvent e) : vrai si e concerne le bouton droit de la souris Interface MouseMotionListener ou classe MouseMotionAdapter Utilisée pour les déplacement souris dans la fenetre Méthodes à définir void mouseDragged(MouseEvent e) : clic dans la fenetre void mouseMovedMouseEvent e) : déplacement souris dans la fenetre Quel écouteur définir pour quelle action (2) ? Interface WindowListener ou classe WindowAdapter Utilisée pour les actions sur les fenetres : ouverture, fermeture, iconification, quitter Méthodes à définir void windowOpened(WindowEvent e) : ouverture de la fenetre void windowClosed(WindowEvent e) : apres la fermeture de la fenetre void windowClosing(WindowEvent e) : au moment de la fermeture de la fenetre void windowIconified(WindowEvent e) : iconifier la fenetre void windowDeiconified(WindowEvent e) : deiconifier de la fenetre void windowActivated(WindowEvent e) : focus dans la fenetre; Utiliser de préférence windowGainedFocus de WindowFocusListener void windowDeactivated(WindowEvent e) : perte du focus de la fenetre. Utiliser de préférence windowLostFocus de WindowFocusListener La principale action à redéfinir est celle de la fermeture d’une application. Pour cela, il faudrait Soit vos applications graphiques implémentent l’interface WindowListener avec ses 7 methodes redéfinir systématiquement la fonction windowClosed Ecrire un corps de fonction vide pour les autres Soit vos applications graphiques héritent de WindowAdapter avec ses 7 methodes redéfinir systématiquement la fonction windowClosed Mais votre application ne peut plus hérité d’une autre classe Solution : la méthode définit la sortie propre sans redéfinir le listener ou l’adapter setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Exercice Programmer une Interface Graphique en Java / Swing pour le Zoo2D