Outils de développement des interfaces Graphiques La toolkit de JAVA 1 Plan • Introduction Mountaz Hascoët, Univ. Montpellier II, LIRMM – X/Motif, TCL-TK, Java-AWT, ... • La toolkit de Java : de jdk1.0 à jdk 1.2,1.3,1.4 en passant par Swing – – – – – – Evolution et différences Aperçu des composants swing Caractéristiques communes Placement Gestion d ’événements La forme générale d ’un programme • Conclusion 2 1 Outils de développement • Systèmes graphiques et systèmes de fenêtrage Mountaz Hascoët, Univ. Montpellier II, LIRMM – gestion des périphériques d ’entrée sortie – apporte le concept de fenêtre aux applications – ex: Windows, X, Next, etc. Í Boites à outils – utilisées pour construire la plupart des applications actuelles – repose sur la notion de widget – ex: Motif, Tk, AWT-Swing, IlogViews, etc • Générateur d ’interface – permet de construire une interface en la « dessinant » – ex: VisualBasic, VisualCafe (symantex), VisualJ++ (ms), VisualAge(IBM) 3 La toolkit JAVA De AWT 1.0 à AWT 1.2 en passant par SWING 4 2 AWT = Abstract Windowing Toolkit – Plusieurs versions radicalement différentes Mountaz Hascoët, Univ. Montpellier II, LIRMM • AWT 1.0 [~95] – Une librairie avec des composants de base et un modèle de gestion des événements primitifs • AWT 1.1 [~ 97] – Nouveau modèle de gestion des évènements • AWT 1.1 + swing ou AWT 1.2 [ 98] » Nouveaux types de composants légers (intégration de Swing) » Swing fait partie du Java Foundation Class (JFC) • Depuis les modifications sont plus « légères » pour la base de la toolkit 5 – par contre évolution vers des extensions java2D, java3D Les composants Swing Mountaz Hascoët, Univ. Montpellier II, LIRMM • Composants légers – composants écrits en Java au dessus de AWT – utilise AWT pour la création de fenêtre – portabilité immédiate – Comparaison avec AWT 1.0 et 1.1 • composants écrits en code C natif. • implémentation différente sur chaque plate forme • problème portabilité • Look and feel interchangeable – Quel look and feel faut-il donner aux composants légers? – Look and feel, séparé du composant • Jbutton : composant • ButtonUI : look and feel du composant • Orientation MVC NB: Composant = widget ~ fenêtre dotée d ’un comportement ~ objet 6 interactif 3 Evolution des composants de Java 1.0 à Java 1.2 (Swing) Mountaz Hascoët, Univ. Montpellier II, LIRMM • Hiérarchie des composants prédéfinis dans AWT 1.0 et 1.1 • Hiérarchie des composants prédéfinis dans AWT 1.2 – Tous ceux de AWT1.1 + ceux de Swing AWT1.0 AWT1.2 7 Démos 8 4 Les composants TOP-LEVEL AWT 1.2 - Swing • Les fenêtres de base (ou top-level) – Les seules fenêtres qui peuvent se dessiner seules Mountaz Hascoët, Univ. Montpellier II, LIRMM • JFrame, JDialog et JApplet – Ces fenêtres de bases contiennent implicitement un composant JRootPane • composant qui gère le contenu du toplevel • indirections supplémentaires par rapport à awt1.1 • possibilité de gérer des fenêtres internes et des layers – tous les autres composants ont besoin d’être rattachés à une fenêtre de base (via le contentPane du rootPane) pour s’afficher JMenuBar ContentPane JLayeredPane JRootPane JFrame 9 Les composants - CONTAINER AWT 1.2 - Swing Mountaz Hascoët, Univ. Montpellier II, LIRMM • Les containers intermédiaires – Utiles pour regrouper des composants dans un panneau de contrôle – Panneau (Jpanel), Box, Panneau multi-couche (JLayeredPane),Panneau Divisable (JSplitPane), Onglet (JTabbedPane), Panneau déroulant (ScrollPane), etc 10 5 Autres composants AWT 1.2 - Swing • Les viewer – barre de progression, bulles d ’aide, label • Les contrôles Mountaz Hascoët, Univ. Montpellier II, LIRMM – boutons, combo box, listes, menus, slider, champs textuels, palette d ’outils • Les éditeurs – table, texte, sélecteur de fichier, sélecteur de couleur, arbre 11 Caractéristiques communes des composants Swing (1) • Caractéristiques définies dans la classe Jcomponent – Bordures, Tailles par défauts, Bulles d ’aide,Rendu lent pour debugger, Défilement automatique, Double-buffer, Raccourcis clavier, Icones, Actions Mountaz Hascoët, Univ. Montpellier II, LIRMM • Bordures – Bordure visible du composant • ex: ligne qui fait le tour d ’un bouton – Utilisation/motivation • structuration visuelle de l'IHM (regrouper les widgets qui vont ensemble) • création d ’une bordure (class Border) et affection de cette bordure (setBorder) à un composant – Bordures prédéfinies • EmptyBorder blanc • LineBorder: ligne en couleur • BevelBorder : Bordure 3D 12 6 • Tailles Caractéristiques communes des composants Swing (2) Mountaz Hascoët, Univ. Montpellier II, LIRMM – la classe Jcomponent définit trois tailles pour un composant • minimum, maximum, preferred • utilisées lors du re-dimensionnement de la fenêtre – pour redéfinir les tailles par défaut on utilise les méthodes de Jcomponent: public Dimension getMinimumSize (); public Dimension getMaximumSize (); public Dimension getPreferredSize (); • Bulles d ’aide – Tout composant a une bulle d ’aide associée – Pour redéfinir le texte de cette bulle d’aide: public void setToolTipText (String txt); 13 Caractéristiques communes des composants Swing (3) • Rendu ralenti pour debugger Mountaz Hascoët, Univ. Montpellier II, LIRMM – Pour optimiser le code • Un composant peut flasher dans une couleur particulière chaque fois qu ’ il se redessine • Défilement automatique – auto-scrolling • pour les composants qui se trouvent dans une zone partiellement visible public void setAutoscrolls(boolean trueFalse); – défilement d ’une zone rectangulaire • rendre visible une zone particulière du composant public void scrollRectToVisible(Rectangle AVoir); 14 7 • Icones Caractéristiques communes des composants Swing (4) Mountaz Hascoët, Univ. Montpellier II, LIRMM – Tout graphique supporté par la plateforme Java, peut faire office d ’icone – Tout composant peut utiliser un icone • => boutons avec icone (impossible dans AWT1.1) – Swing définit une interface et une classe ImageIcon icon = new ImageIcon("images/truc.gif") • Double Buffer – Eviter le scintillement lors du rendu • tous les composants peuvent se dessiner dans un buffer hors écran qui est ensuite copié à l ’écran. – Utilisation optimisée des buffers • prise en compte de la hiérarchie des composants et partage de buffers entre 15 parents et enfants Caractéristiques communes des composants Swing (5) • Raccourcis clavier – Tout composant peut définir des raccourcis clavier Mountaz Hascoët, Univ. Montpellier II, LIRMM public void registerKeyboardAction(ActionListener a,KeyStroke k,int condition) • Actions – Une action représente une fonction spécifique d ’un programme partagée par différents widgets • Exemple – copier/coller qui est accessible par un menu et par une palette • Les actions peuvent être « enabled » ou « disabled » • Les actions implémentent l ’interface ActionListener – Swing définit une interface et une classe • Action et AbstractAction 16 8 Organisation des composants • Gestionnaire de placement (gp) – Objet qui gère l ’organisation des composants au sein d ’un container – avec AWT Mountaz Hascoët, Univ. Montpellier II, LIRMM • gestionnaires de placement de base • Des plus simples – FlowLayout, GridLayout • Un peu plus sophistiqués – BorderLayout, CardLayout • Pour les panneaux de contrôle plus compliqués – GridBagLayout – avec swing • gp spécifiques • Borders : composant servant à regrouper d ’autres composants 17 • Box: pour placer des composants horizontalement ou verticalement FlowLayout • Caractéristiques – mise en page par défaut des JPanel – ligne par ligne, de gauche à droite, centrage vertical – respect de la taille "préférée" des composants Mountaz Hascoët, Univ. Montpellier II, LIRMM • Construteurs – public FlowLayout() – public FlowLayout(int alignment) fi FlowLayout.LEFT, FlowLayout.CENTER, or FlowLayout.RIGHT – public FlowLayout(int alignment,int horizontalGap, int verticalGap) horizontalGap et verticalGap : espacement en pixel entre les éléments (par défaut 5) • Exemple … this.setLayout(new FlowLayout()); add(new Button("Button 1")); add(new Button("2")); add(new Button("Button 3")); add(new Button("Long-Named Button 4")); add(new Button("Button 5")); 18 9 BorderLayout Mountaz Hascoët, Univ. Montpellier II, LIRMM • Caractéristiques – – – – mise en page par défaut des classes JFrame, JOptionPane, JDialog découpe l ’espace en 5 régions en utilisant les points cardinaux placement au centre par défaut taille des items variable. L ’espace gagné est alloué au centre en priorité, les autres espaces dépendent de la taille « préférée » des composants qui s ’y trouvent – Spécification des contraintes de placement lors de l ’ajout des éléments • Constructeur – public BorderLayout(int horizontalGap, int verticalGap) setLayout(new BorderLayout()); • Exemple add("North", new Button("North")); add("South", new Button("South")); add("East", new Button("East")); add("West", new Button("West")); add("Center", new Button("Center")); 19 GridLayout Mountaz Hascoët, Univ. Montpellier II, LIRMM • Caractéristiques – crée une grille avec une nb lignes nb colonnes spécifiés dans le constructeur – valeur 0 pour nb ligne(ou colonne) libre – taille des items variable • Constructeurs public GridLayout(int rows, int columns) public GridLayout(int rows, int columns, int horizontalGap, int verticalGap) • Exemple … setLayout(new GridLayout(0,2)); add(new Button("Button 1")); add(new Button("2")); add(new Button("Button 3")); add(new Button("Long-Named Button 4")); add(new Button("Button 5")); 20 10 CardLayout • Exemple JPanel cards; final static String BUTTONPANEL = "boutons"; final static String TEXTPANEL = "texte"; Mountaz Hascoët, Univ. Montpellier II, LIRMM • Caractéristiques – utile pour avoir des fenêtres alternatives – généralement contrôlé par une ComboBox (JComboBox) //Initialisation du container et du gp cards = new JPanel(); cards.setLayout(new CardLayout()); … //création d'un panel p1 avec des boutons … //création d'un panel p2 avec du texte //Ajout de p1 et p2 dans le panneau principal cards cards.add(BUTTONPANEL, p1); cards.add(TEXTPANEL, p2); //Lorsque l'item de la combo change, le gp réagit public void itemStateChanged(ItemEvent evt) { CardLayout cl = 21 (CardLayout)(cards.getLayout()); cl.show(cards, (String)evt.getItem()); } GridBagLayout Mountaz Hascoët, Univ. Montpellier II, LIRMM • Caractéristiques – Gère un ensemble de composants qui ont tous un placement propre – Définition de contraintes pour chacun des composants – Calcul automatique du placement après résolution des contraintes – Tend à être remplacé par BoxLayout • Exemple 22 11 Modèles de gestion des entrées • Modèle par échantillonage (polling) – le dispositif d’entrée mémorise son état courant – l ’application consulte l ’état courant du dispositif à intervalles réguliers – inconvénient: : attente active Mountaz Hascoët, Univ. Montpellier II, LIRMM Ì Modèle à événements – concept commun à tous les toolkits • message émis par le « système » à chaque action de l ’utilisateur – Un événement décrit les changements d ’état d’un dispositif – L ’application a accès à une file d ’événements remplie par les pilotes des dispositifs d ’entrée. • caractérisé par un type (qui correspond à l ’action de l ’utilisateur) – structure de données pré-définie qui permet de représenter des infos complémentaires (ex: la position (x,y) de la souris) – exemple: type MotionNotify pour les mouvement de la souris – mais avec des différences • Des types d ’événements différents selon les toolkits • Des modèles de gestion d ’évènements différents 23 Les types d ’évènements de AWT 1.0 Mountaz Hascoët, Univ. Montpellier II, LIRMM • La classe Event –Tous les évènements sont représentés par la classe Event –Le champs id représente le type de l ’événement –Le champs target représente l ’objet qui a engendré l ’évènement ou qui est le composant sur lequel l ’évènement s ’est produit –Les autres champs peuvent ou non être renseignés selon le type de l ’évènement • Les différents types ( i.e valeurs possibles pour event.id) – – – – – – – – – – – – – Event.ACTION_EVENT Event.MOUSE_ENTER Event.MOUSE_EXIT Event.MOUSE_MOVE Event.MOUSE_DOWN Event.MOUSE_DRAG Event.MOUSE_UP Event.KEY_PRESS Event.KEY_ACTION Event.KEY_RELEASE Event.KEY_ACTION_RELEASE Event.GOT_FOCUS Event.LOST_FOCUS 24 12 Les types d ’évènements de AWT 1.1 et SWING Mountaz Hascoët, Univ. Montpellier II, LIRMM • Hiérarchie de classes pour représenter les différents types – Une classe prédéfinie par type d ’évènement – EventObject racine de la hiérarchie – définie avec 1.1, enrichie avec Swing • Tout événement a un objet source (~target pour 1.0 ) • Les id demeurent – pour les classes qui encapsulent plusieurs types d ’évènements – par ex FocusEvent FocusEvent.FOCUS_.GAINED Focus Event.FOCUS_LOST 25 Mountaz Hascoët, Univ. Montpellier II, LIRMM Les classes d ’évènements de AWT 1.1 et SWING Evt de haut niveau (enfoncer un bouton, taper return) ActionEvent Chgt d ’une valeur (émis par les modèles) Entrée ou sortie du curseur dans le composant ChangeEvent Super classe de MouseEvent et KeyboardEvent Chgt de la selection FocusEvent InputEvent ItemEvent (pour les composants permettant une sélection simple ou multiple) Touche enfoncée ou relachée Chgt dans le contenu d ’une liste Chgt de sélection dans une liste Sélection d ’un menu ou annulation Interaction avec la souris Chgt état fenêtre (iconification, fermeture, etc.) KeyEvent ListDataEvent ListSelectionEvent MenuEvent MouseEvent WindowEvent 26 13 Modèle de gestion des évènements dans AWT 1.0 • Principe Mountaz Hascoët, Univ. Montpellier II, LIRMM – C ’est le composant qui gère les évènements – A chaque action de l ’utilisateur, un événement est créé et complètement renseigné (voir class Event) • • • • • • target - l ’objet qui a provoqué l ’évènement. when - le moment auquel l ’événement s ’est produit. id - le type d ’ événement. x, y key - la touche tapée (pour les événements KeyPress). modifiers - l ’état des touches modifier (SHIFT, CTRL,etc). – L ’événement est ensuite propagé à toute la hiérarchie de composition • l e composant directement concerné puis tous ceux qui le contiennent – Gestion de l’événement par les composants • via la méthode handleEvent de chaque composant • méthode héritée de la classe Component appelée pour traiter tout événement 27 La méthode handleEvent dans AWT 1.0 • Fonctionnement par défaut de la méthode handleEvent Mountaz Hascoët, Univ. Montpellier II, LIRMM – utilise des sous méthodes selon le type de l ’événement – On peut la redéfinir mais attention aux effets de bord… • mieux vaut redéfinir les méthodes appelées pour chaque type d ’événement • Ne pas oublier de retourner true • Appeler la méthode de même nom de la classe mère – Les « sous-méthodes » de handleEvent • Redéfinir le comportement d ’un composant – Deux solutions • redéfinir la méthode handleEvent (ou une sous-méthode) de chaque composant – inefficace car il faut créer une nouvelle classe par bouton par exemple. • Redéfinir la méthode handleEvent (ou une sous-méthode) au niveau d ’un composant « container » et sélectionner le type d ’action en fonction du « target » 28 – pas satisfaisant non plus … d ’où le modèle de l ’awt1.1 14 Modèle d’événements • Dans AWT1.1 et Swing Mountaz Hascoët, Univ. Montpellier II, LIRMM – Modèle de gestion d ’événements par délégation • Ce n ’est pas le composant qui traite l ’événement mais un gestionnaire d’événement (GE aussi appelé EventListener) – Le composant reçoit l ’événement et notifie le GE • Les GE héritent des interfaces xxxListener Evt (2) Diffuser Composant (3) Notifier (1) Enregistrer GE 29 Mountaz Hascoët, Univ. Montpellier II, LIRMM Les Gestionnaires d ’événements • Les gestionnaires d ’évènements sont représentés par des interfaces et des classes qui implémentent ces interfaces par défaut • Rappels: Interfaces – Une interface est une spécification formelle de classe • elle ne peut être instanciée • toutes les méthodes sont abstraites • tous les attributs sont static final – final: ne peut pas être redéfini (attribut constant) – static : partagé par toutes les instances (attribut partagé) – l'appel n'est pas possible sur une instance particulière , il doit se faire sur la classe » <nomClasse>.methode 30 15 Rappels: Héritage, interface et classe Mountaz Hascoët, Univ. Montpellier II, LIRMM • Héritage simple: class A extends B – la sous classe hérite des attributs et méthodes de sa classe mère. – redéfinition possible • Héritage d'interface: class A implements B – il faut définir toutes les méthodes déclarées dans l'interface B dont hérite la classe A – s'il reste des méthodes non définies, la classe A est une classe abstraite et ne sera pas instanciable. • Héritage multiple – possible avec les interfaces – interdit avec les classes 31 Les Gestionnaires d ’événements • Listener – les gestionnaires d’événements sont prédéfinis dans AWT1.1 • par les interfaces xxxListerner Mountaz Hascoët, Univ. Montpellier II, LIRMM – Pour écrire un gestionnaire d ’évènement on peut • directement écrire une classe qui implémente l ’interface • utiliser une classe adapter • Adapter – Pour chaque interface xxxlistener il existe une classe xxxAdapter – xxxAdapter: implémentation par défaut de ces interfaces • Fonctions d ’enregistrement – Pour utiliser un GE, les composants doivent les enregistrer • addxxxListener 32 16 Les Gestionnaires d ’événements • Les différents listeners Mountaz Hascoët, Univ. Montpellier II, LIRMM – Toute classe xxxListener hérite de EventListener – Adapters associés et méthodes à implémenter ListenerInterface ActionListener AdjustmentListener ComponentListener AdapterClass none none ComponentAdapter ContainerListener FocusListener ItemListener KeyListener MouseListener ContainerAdapter FocusAdapter none KeyAdapter MouseAdapter MouseMotionListener TextListener WindowListener MouseMotionAdapter none WindowAdapter Methods actionPerformed adjustmentValueChanged componentHidden, componentMoved, componentResized, componentShown componentAdded, componentRemoved focusGained, focusLost itemStateChanged keyPressed, keyReleased, keyTyped mouseClicked, mouseEntered, mouseExited, mousePressed, mouseReleased mouseDragged, mouseMoved textValueChanged windowActivated, windowClosed, windowClosing, windowDeactivated, windowDeiconified, windowIconified, windowOpened 33 Gestion d ’événements typique 1. Créer un gestionnaire d ’événement – en héritant d ’une interface (xxxlistener) • public class MonControleur implement ActionListener – en héritant d ’une classe qui implémente une interface (xxxAdapter) • public class MonControleur extends ActionAdapter Mountaz Hascoët, Univ. Montpellier II, LIRMM 2. Implémenter (ou redéfinir) les méthodes du gestionnaire d ’événement – Dans la classe MonControleur public void actionPerformed(ActionEvent e) {...} 3. Enregistrer le gestionnaire d’événement auprès d ’un widget « source » – – button.addActionListener(instanceDeMonControleur) myWidget.addxxxListener(instanceDeMonControleur) NB : dans de nombreux exemples de code, il n'y a pas ou peu de séparation entre composant et listener 34 17 Mountaz Hascoët, Univ. Montpellier II, LIRMM Structure d ’un programme en AWT-Swing • "Structure" générale du programme – Définition de la hiérarchie de composants • Fenêtre principale (top-level) • Définition des fonctions de dessins des composants – Définition de la gestion des événements • Gestionnaires d'évènements + association aux composants – Appeler la méthode pack() sur le top-level • calcule la disposition des composants (récursivement) – Appeler la méthode setVisible() sur le top-level • affiche les composants de l'interface (récursivement) • Exemple 35 Petit exemple (version 1) import import import import import java.util.*; java.awt.*; java.awt.event.*; javax.swing.*; javax.swing.text.*; Mountaz Hascoët, Univ. Montpellier II, LIRMM public class Exemple extends JFrame implements ActionListener { JTextField textField; JTextArea textArea; String newline; public Exemple(){ JMenuBar bar = new JMenuBar(); JMenu menu = new JMenu("Fichier"); JMenuItem tmp; newline = System.getProperty("line.separator"); /* creation du menu quitter et ajout du gestionnaire d'evenement*/ tmp = new JMenuItem("Quitter"); tmp.addActionListener(this); tmp.setActionCommand("Quitter"); menu.add(tmp); bar.add(menu); this.setJMenuBar(bar); /* creation des zones de texte */ textField = new JTextField(20); textArea = new JTextArea(5,20); getContentPane().add(textField,"North"); getContentPane().add(textArea,"Center"); /* ajout d'un gestionnaire d'evenements sur le textField */ textField.addActionListener(this); addWindowListener(new ExitWindow()); } /* gestion des evenements sur le TextField */ public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); if (cmd.equals("Quitter")) { ImageIcon icone = new ImageIcon("adieu.gif"); JOptionPane.showMessageDialog(this," Adieu Monde Cruel !! ", "Quitter", JOptionPane.PLAIN_MESSAGE,icone); setVisible(false); dispose(); System.exit(0); } else { String text = textField.getText(); textArea.append(text + newline); textField.selectAll(); } } public static void main(String s[]){ ExempleGE frame = new ExempleGE(); frame.setForeground(Color.black); frame.setBackground(Color.lightGray); frame.pack(); frame.setVisible(true); } 36 } 18 Petit exemple (version 2 - avec classe interne) import import import import import java.util.*; java.awt.*; java.awt.event.*; javax.swing.*; javax.swing.text.*; /* ajout d'un gestionnaire d'evenements sur le textField */ textField.addActionListener(new GEText()); addWindowListener(new ExitWindow()); } Mountaz Hascoët, Univ. Montpellier II, LIRMM public class ExempleGE extends JFrame implements ActionListener { JTextField textField; JTextArea textArea; String newline; public ExempleGE(){ JMenuBar bar = new JMenuBar(); JMenu menu = new JMenu("Fichier"); JMenuItem tmp; newline = System.getProperty("line.separator"); /* creation du menu quitter et ajout du gestionnaire d'evenement*/ tmp = new JMenuItem("Quitter"); tmp.addActionListener(this); tmp.setActionCommand("Quitter"); menu.add(tmp); bar.add(menu); this.setJMenuBar(bar); /* creation des zones de texte */ textField = new JTextField(20); textArea = new JTextArea(5,20); getContentPane().add(textField,"North"); getContentPane().add(textArea,"Center"); /* classe interne pour evts textfield*/ class GEText implements ActionListener { public void actionPerformed(ActionEvent e) { String text = textField.getText(); textArea.append(text + newline); textField.selectAll(); } /* gestion des evenements du menu*/ public void actionPerformed(ActionEvent e) { ImageIcon icone = new ImageIcon("adieu.gif"); JOptionPane.showMessageDialog(this," Adieu Monde Cruel !! ", "Quitter", JOptionPane.PLAIN_MESSAGE,icone); setVisible(false); dispose(); System.exit(0); } public static void main(String s[]){ Exemple frame = new Exemple(); frame.setForeground(Color.black); frame.setBackground(Color.lightGray); frame.pack(); frame.setVisible(true); } 37 } Pour en savoir plus • Bibliographie – Java in a nutshell, Flanagan, O'reilly, second edition , 1997. – Programming with JFC, Weiner et Asbury, Wiley Ed., 1998. Mountaz Hascoët, Univ. Montpellier II, LIRMM • Sites HTTP – Le site SUN • http ://java.sun.com – nouveautés, faq, exemples – Le tutorial [oct 2003] • http://java.sun.com/docs/books/tutorial (contient des liens vers la doc. complète de swing et awt) • http ://java.sun.com/jfc/tsc/ – infos sur swing – http://www.developer.com/java/ • des centaines d'applets et d'applications JAVA classées par thèmes 38 19