Page de garde Les librairies AWT et Swing ESSI2, Septembre
Introduction Les GUI en Java Le JDK comporte de nombreuses classes permettant la construction de Graphical User Interfaces (interfaces homme/machine) très évoluées De nombreux composants simples (étiquettes, boutons, cases à cocher, zones de texte, …) ou très évolués (arbres, tables, éditeur de texte formatté, …) sont disponibles
Introduction \ Deux packages Deux packages java.awt Abstract Window Toolkit Utilise les composant graphiques natifs (peers) Comportements différents selon les plate-formes Exécution assez rapide javax.swing 100% pure Java Librairie complètement écrite en Java Construite au-dessus dun sous-ensemble fiable (portable) de lAWT Librairie très puissante, composants très évolués (arbres, tables, …) Séparation modèle-représentation, apparence modifiable (pluggable look-and-feels) Exécution assez lente
Principes de base Un composant graphique dérive de : java.awt.Component ou javax.swing.JComponent Les composant graphiques sont contenus par des java.awt.Container Les composants sajoutent par : Container.add( Component ) (placement non contraint) Container.add( Component, Object ) (placement contraint) Le placement des composants est géré par des java.awt.LayoutManager Les containers ont chacun un Layout Manager par défaut Le Layout Manager se modifie par setLayout( LayoutManager ) Théoriquement : pas de placement absolu Les containers sont des composants ! Possibilité d'emboîter récursivement des containers
"Structures" à connaître java.awt.Point, utilisée notamment pour les positions : class java.awt.Point { public int x; public int y; … } java.awt.Dimension : class java.awt.Dimension { public int width; public int height; … }
"Structures" à connaître java.awt.Rectangle, utilisée notamment pour les bounding boxes : class java.awt.Rectangle { public int x; public int y; public int width; public int height; … } java.awt.Insets indique les espaces que les composants doivent laisser sur les côtés : class java.awt.Insets { public int top; public int left; public int bottom; public int right; … }
Première fenêtre
javax.swing.JFrame est la fenêtre de base Swing Le container principal de javax.swing.JFrame s'obtient par : getContentPane() javax.swing.JLabel est une étiquette affichant du texte et/ou une icône Une fois les composants ajoutés, pack() réalise la fenêtre La fenêtre est rendue visible par setVisible( true ) Enfin, la fenêtre est détruite par dispose()
Première fenêtre \ 1 ère méthode Première fenêtre 1 ère méthode (instanciation directe) : JFrame frame= new JFrame( "Première fenêtre" ); Container content_pane= frame.getContentPane(); Content_pane.add( new JLabel( "Hello World !", SwingConstants.CENTER ) ); frame.pack(); frame.setVisible( true ); ··· frame.dispose();
Première fenêtre \ 2 ème méthode Première fenêtre 2 ème méthode (spécialisation) : public class Fenetre extends javax.swing.JFrame { public Fenetre( String title ) { super( title ); Container content_pane= getContentPane(); content_pane.add( new JLabel( "Hello World !", SwingConstants.CENTER ) ); pack(); setVisible( true ); } new Fenetre( "Première fenêtre" );
Créer son composant Créer un objet dérivant de java.awt.Component ou javax.swing.JComponent L'objet indique sa dimension préférée par la méthode : java.awt.Dimension getPreferredSize() L'objet se dessine dans les méthodes : void paint( java.awt.Graphics g ) ( Component ) void paintComponent( java.awt.Graphics g ) ( JComponent ) g, le contexte graphique reçu, permet le dessin, l'affichage de texte, … Pour les JComponent s, il faut généralement commencer par appeler la méthode paintComponent(…) de la classe mère : super.paintComponent( g )
Créer son composant Exemple
Créer son composant Exemple public class DiagonalComponent extends javax.swing.JComponent { public DiagonalComponent() { } public Dimension getPreferredSize() { return new Dimension( 300, 240 ); } public void paintComponent( Graphics g ) { g.drawLine( 0, 0, getWidth(), getHeight() ); g.drawLine( getWidth(), 0, 0, getHeight() ); }
java.awt.Graphics java.awt.Graphics, le contexte graphique Le contexte graphique, java.awt.Graphics, permet : De dessiner des figures simples et complexes vides : drawLine(…), drawRect(…), drawOval(…), drawPolygon(…) De dessiner des figures simples et complexes pleines : fillRect(…), fillOval(…), fillPolygon(…) D'afficher du texte : drawString(…) De changer la couleur, la fonte, le mode : setColor(…), setFont(…), setPaintMode()/setXORMode(…) D'afficher des images …
L'affichage de texte en Java Graphics.drawString(…) utilise la fonte préalablement définie par : setFont( java.awt.Font ) Les fontes sont généralement créées par le constructeur : Font( String name, int style, int size ) name : nom logique ("Monospaced", "SansSerif", …) ou nom de fonte style : PLAIN, BOLD, ITALIC ou BOLD|ITALIC size : taille en points Les métriques de fontes s'obtiennent notamment par : getFontMetrics() dans java.awt.Graphics Les métriques de chaînes de caractères s'obtiennent notamment par : getLineMetrics(…) dans java.awt.Font
L'affichage de texte en Java \ Métriques de fontes Métriques de fontes Une fonte est caractérisée par sa métrique : java.awt.FontMetrics et java.awt.font.LineMetrics Une métrique indique notamment les informations suivantes :
Containers et Layout Managers \ Les principaux containers Les principaux containers Les plus simples : java.awt.Panel, javax.swing.JComponent javax.swing.Box java.awt.ScrollPane et javax.swing.JScrollPane javax.swing.JSplitPane javax.swing.JTabbedPane javax.swing.JDesktopPane et javax.swing.JInternalFrame · · ·
Containers et Layout Managers \ Les Layout Managers Les Layout Managers Responsables : Du placement relatif des composants dans un container Du calcul des dimensions minimales et préférées des containers … Deux interfaces : java.awt.LayoutManager (placements simples) java.awt.LayoutManager2 (placements contraints)
Containers et Layout Managers \ java.awt.FlowLayout java.awt.FlowLayout Positionnement à la suite, "passage à la ligne automatique" Alignements : centré, à gauche, à droite Les composants ont des tailles quelconques Surtout utilisé pour les boutons
Containers et Layout Managers \ java.awt.GridLayout java.awt.GridLayout Disposition matricielle GridLayout( int rows, int columns ) add( new JLabel( "Label n°1", SwingConstants.CENTER ) ); add( new JLabel( "Label n°2", SwingConstants.CENTER ) ); · · · Les composants ont tous la même largeur et la même hauteur
Containers et Layout Managers \ java.awt.BorderLayout java.awt.BorderLayout Positionnement sur les quatre côtés dun container ou au centre : add( new JLabel( "NORTH", SwingConstants.CENTER ), BorderLayout.NORTH ); · · ·
Containers et Layout Managers \ java.awt.GridBagLayout java.awt.GridBagLayout Le plus puissant de tous ! Mais aussi le plus complexe… Le plan est découpée en lignes et colonnes Chaque composant occupe une ou plusieurs cellules (en largeur comme en hauteur) Suite aux retaillements : La taille des cellules évolue proportionnellement à la demande Les composants peuvent s'étendre dans les deux directions, une seule ou pas du tout Les composants se positionnent dans leurs cellules à l'un des 8 points cardinaux ou au centre Les contraintes de placements sont transmises par la "structure" : java.awt.GridBagConstraints
Containers et Layout Managers \ java.awt.GridBagLayout java.awt.GridBagLayout Exemple : Trois panneaux (listes déroulantes, cases à cocher, boutons) gérés respectivement par deux GridBagLayout et un FlowLayout Ces trois panneaux sont gérés par un troisième GridBagLayout
Containers et Layout Managers \ java.awt.GridBagLayout java.awt.GridBagLayout La "structure" java.awt.GridBagConstraints : int gridx, int gridy Coordonnées de la première cellule occupée par le composant RELATIVE (défaut) pour une incrémentation automatique int gridwidth, int gridheight Nombre de cellules occupées par le composant REMAINDER indique que le composant utilise le reste de la ligne/colonne int fill (NONE, HORIZONTAL, VERTICAL, BOTH) Détermine si le composant s'étend si la dimension de ses cellules augmente int anchor (CENTER (défaut), NORTH, NORTHEAST, …) Emplacement du composant dans ses cellules s'il ne s'étend pas complètement double weightx, double weighty Facteurs de distribution de l'espace entre colonnes/lignes
Les boîtes de dialogue javax.swing.JDialog Très similaires aux fenêtres standard javax.swing.JFrame s : Peuvent être modales (i.e. conserver le focus) Sont généralement attachées à une autre JDialog ou JFrame
Les boîtes de dialogue communes javax.swing.JOptionPane : Affichage de messages Questions simples (Oui/Non, Ok/Annuler, …) Saisie de valeur unique
Les boîtes de dialogue communes javax.swing.JFileChooser : Sélection de fichier(s) (ouvrir, enregistrer sous, …)
Les boîtes de dialogue communes javax.swing.JColorChooser :
Les bordures Les JComponents peuvent se voir attribuer une bordure par : setBorder( border ) Les bordures peuvent être composées
Les bordures Les bordures sont des objets implémentants l'interface : javax.swing.border.Border Dans le package : javax.swing.border Dans le but de partager les bordures identiques, on ne construit pas les bordures à partir des constructeurs des classes, mais via la Factory : javax.swing.BorderFactory : static Border createLoweredBevelBorder() static Border createEtchedBorder() … Les bordures affectent les Insets des composants qui en ont : Pensez-y dans vos méthodes paintComponent( Graphics ) !
Composants \ Etiquettes Les étiquettes javax.swing.JLabel Affiche une icône, du texte, ou les deux Peut-être grisée Peut-être associé à un composant et un mnémonique Alignement vertical et horizontal (gauche/haut, centré, droite/bas) …
Composants \ Boutons de commandes Les boutons de commandes javax.swing.JButton Affiche une icône, du texte, ou les deux
Composants \ Cases à cocher Les cases à cocher javax.swing.JCheckBox
Composants \ Boutons radio Les boutons radios javax.swing.JRadioButton
Composants \ Boutons radio \ Exclusions entre boutons Exclusions entre boutons javax.swing.JButtonGroup Permet la gestion d'exclusion mutuelles entre boutons Généralement : JRadioButton, JRadioButtonMenuItem
Composants \ Boutons bascules Les boutons bascules javax.swing.JToggleButton
Composants \ Champs de texte Les champs de texte javax.swing.JTextField
Composants \ Zones de texte Les zones de texte javax.swing.JTextArea
Composants \ Listes Les listes javax.swing.JList
Composants \ Combos Les combos javax.swing.JComboBox
Composants \ Barres de progression Les barres de progression javax.swing.JProgressBar
Composants \ Glissières Les glissières javax.swing.JSlider
Composants \ Menus déroulants Les menus déroulants javax.swing.JMenu
Composants \ Menus flottants Les menus flottants javax.swing.JPopupMenu
Composants \ Barres d'outils Les barres d'outils javax.swing.JToolBar
Composants \ Info-bulles Les info-bulles javax.swing.JToolTip
Composants \ Arbres Les arbres javax.swing.JTree
Composants \ Tables Les tables javax.swing.JTable
Composants \ Editeurs de texte Les éditeurs de texte javax.swing.JTextComponent
Multiple Document Interface Le JDesktopPane est un conteneur spécialisé pour des classes dérivées de JInternalFrame
Séparation données/composant Le composant agit comme interface entre lutilisateur et les données : celles-ci sont gérées par des modèles Le composant : Interroge le modèle pour déterminer son état Interroge le modèle pour afficher les données Transmet au modèle les modifications à apporter aux données Les modèles sont des interfaces ; des implémentations courantes sont fournies Ex.: une JTable fait appel aux méthode suivante de TableModel : public int getColumnCount() public int getRowCount() public Object getValueAt( int row, int col)
Communication entre composants La classe AFrame, dérivant de JFrame, utilise un JButton : AFrame connait JButton AFrame communique avec le JButton en lui appliquant ses méthodes JButton ne connaît (théoriquement) pas AFrame Comment JButton communique avec AFrame ? AFrame va se mettre à lécoute du JButton
Communication entre composants \ Les Listeners Les Listeners De nombreux composants comportent des méthodes : addXXXListener( XXXListener ) removeXXXListener( XXXListener ) XXXListener étant une interface déclarant un petit nombre de méthodes Ces méthodes sont appelées lorsque lobjet a quelque chose à signaler à ses Listeners Exemple : public interface ActionListener extends java.util.EventListener { public void actionPerformed( ActionEvent event ); } event permet de connaître la source de lévénement, le type daction, … Utilisable avec JButton : button.addActionListener( ActionListener )
Communication entre composants \ Mise en œuvre des Listeners Mise en œuvre des Listeners 1 ère méthode implémentation directe de linterface ActionListener public class AFrame extends javax.swing.JFrame implements java.awt.event.ActionListener { JButton button1, button2,...; ··· button1.addActionListener( this ); button2.addActionListener( this ); ··· public void actionPerformed( ActionEvent event ) { if (event.getSource() == button1) ··· else if (event.getSource() == button2) ···... } ··· }
Communication entre composants \ Mise en œuvre des Listeners Mise en œuvre des Listeners 1 ère méthode implémentation directe de linterface ActionListener Deux inconvénients majeurs : La classe AFrame déclare publiquement "être" un ActionListener, alors quaucune autre classe quelle-même nest capable de sen servir comme ActionListener Lidentification de la source de laction ( button1, button2, …) impose une recherche linéaire parmi les sources potentielles
Communication entre composants \ Mise en œuvre des Listeners Mise en œuvre des Listeners 2 ère méthode création dun objet implémentant linterface ActionListener public class AFrame extends javax.swing.JFrame { JButton button1, button2,...; ··· button1.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent event ) { ··· } } ); ··· button2.addActionListener( new ActionListener()... }
Communication entre composants \ Les Adapters Les Adapters Lorsque les interfaces XXXListener comportent de nombreuses méthodes : Il existe une classe XXXAdapter correspondante, implémentant XXXListener Toutes les méthodes déclarées par linterface ont un corps vide Lorsquon nutilisera quune petite partie des méthodes, on spécialisera donc lAdapter
Communication entre composants \ Générer des événements Générer des événements Utiliser une interface existante ou définir le Listener (et éventuellement lAdapter) La classe JComponent déclare la variable protected EventListenerList listenerList EventListenerList maintient des paires (Classe de Listener, instance de Listener) EventListenerList définit notamment les méthodes suivantes : public void add( Class une_class, EventListener listener ) public void remove( Class une_class, EventListener listener ) public Object[] getListenerList() getListenerList renvoie un tableau t à 2n éléments où, pour tout n : t[n] est un objet Class t[n+1] est linstance de Listener correspondante
Communication entre composants \ Générer des événements Générer des événements Définir les méthodes suivantes, qui délèguent le travail à EventListenerList : public void addListener( XXXListener listener ) public void removeListener( XXXListener listener ) Définir des méthodes fireYYY : ··· YYYEvent yyy_event= new YYYEvent( this ); ··· protected void fireYYY() { Object[] listeners= listenerList.getListenerList(); for ( int i= listeners.length–2 ; i >= 0 ; i-= 2 ) { if (listeners[i] == XXXListener.class) ((FooListener)listeners[i+1]).yyy( yyy_event ); }
Communication entre composants \ Listeners courants \ ActionListener Listeners courants actions java.awt.event.ActionListener : void actionPerformed( java.awt.ActionEvent ) Enregistré par addActionListener(…) auprès de : javax.swing.JButton javax.swing.JMenuItem javax.swing.JToggleButton … javax.swing.AbstractButton
Communication entre composants \ Listeners courants \ ItemListener Listeners courants changements détat java.awt.event.ItemListener : void itemStateChanged( java.awt.event.ItemEvent ) Enregistré par addItemListener(…) auprès de : javax.swing.JButton javax.swing.JMenuItem javax.swing.JToggleButton javax.swing.JComboBox … javax.swing.AbstractButton
Communication entre composants \ Listeners courants \ KeyListener Listeners courants événements clavier java.awt.event.KeyListener : void keyPressed( java.awt.event.KeyEvent ) void keyReleased( java.awt.event.KeyEvent ) void keyTyped( java.awt.event.KeyEvent ) Enregistré par addKeyListener(…) auprès de : javax.swing.JComponent (en fait : java.awt.Component ) …
Communication entre composants \ Listeners courants \ MouseListener Listeners courants événements souris de base java.awt.event.MouseListener : void mouseClicked( java.awt.event.MouseEvent ) void mouseEntered( java.awt.event.MouseEvent ) void mouseExited( java.awt.event.MouseEvent ) void mousePressed( java.awt.event.MouseEvent ) void mouseReleased( java.awt.event.MouseEvent ) Enregistré par addMouseListener(…) auprès de : javax.swing.JComponent (en fait : java.awt.Component ) …
Communication entre composants \ Listeners courants \ MouseMotionListener Listeners courants événements mouvements de souris java.awt.event.MouseMotionListener : void mouseDragged( java.awt.event.MouseEvent ) void mouseMoved( java.awt.event.MouseEvent ) Enregistré par addMouseMotionListener(…) auprès de : javax.swing.JComponent (en fait : java.awt.Component ) …
Communication entre composants \ Listeners courants \ FocusListener Listeners courants focus java.awt.event.FocusListener : void focusGained( java.awt.event.FocusEvent ) void focusLost( java.awt.event.FocusEvent ) Enregistré par addFocusListener(…) auprès de : javax.swing.JComponent (en fait : java.awt.Component ) …
Communication entre composants \ Listeners courants \ WindowListener Listeners courants événements liés aux fenêtres java.awt.event.WindowListener : void windowActivated( java.awt.event.WindowEvent ) void windowClosed( java.awt.event.WindowEvent ) void windowClosing( java.awt.event.WindowEvent ) void windowDeactivated( java.awt.event.WindowEvent ) void windowDeiconified( java.awt.event.WindowEvent ) void windowIconified( java.awt.event.WindowEvent ) void windowOpened( java.awt.event.WindowEvent ) Enregistré par addMouseListener(…) auprès de : javax.swing.JFrame javax.swing.JDialog … java.awt.Window
Communication entre composants \ Listeners courants \ ComponentListener Listeners courants événements liés aux composants java.awt.event.ComponentListener : void componentHidden( java.awt.event.ComponentEvent ) void componentMoved( java.awt.event.ComponentEvent ) void componentResized( java.awt.event.ComponentEvent ) void componentShown( java.awt.event.ComponentEvent ) Enregistré par addComponentListener(…) auprès de : javax.swing.JComponent (en fait : java.awt.Component ) …
Communication entre composants \ Gestion interne des événements Gestion interne des événements L'OS notifie la VM d'événements : Déplacements et clicks souris, frappes clavier (événements d'inputs) Perte, gain du focus Portions d'écran à mettre à jour … La VM insère ces événements, ainsi que ceux générés par le programme, sous forme d'objets dans une queue (file) :
Communication entre composants \ Gestion interne des événements Gestion interne des événements Ces événements sont analysés par le dispatching thread Thread : unité d'exécution qui s'exécute en parallèle d'autres, au sein d'un programme Les événements d'inputs et de focus sont transmis aux composants, qui en informent leurs listeners Les mises à jour de l'affichage sont transmises au RepaintManager, qui appelle les mé- thodes paint(…) des composants concernés, qui appellent enfin paintComponent(…) Les événements de mise à jour de l'affichage ont la plus faible priorité…
Le RepaintManager javax.swing.RepaintManager Responsable de : La gestion des dirty regions de l'écran, à mettre à jour La gestion du double-buffering … Une seule instance par application, renvoyée par : RepaintManager.currentManager( null ) Optimisation possible de la mise à jour d'un composant complexe en : 1°/ Obtenant sa dirty region (un java.awt.Rectangle ) par : Rectangle RepaintManager.getDirtyRegion( JComponent ) 2°/Ne redessinant que ce qui doit l'être en contrôlant les intersections entre les bounding boxes et la dirty region avec : boolean intersects( Rectangle )
Le RepaintManager javax.swing.RepaintManager Pour les descendants de JComponent, les appels de méthodes lors de la mise à jour de l'affi- chage sont : paint( Graphics ) paintComponent( Graphics ) paintBorder( Graphics ) paintChildren( Graphics )
La clipping area Synonyme de dirty region pour un composant : Zone en dehors de laquelle les ordres graphiques n'ont pas d'effet S'obtient par le contexte graphique : Rectangle getClipBounds()
Pluggable Look & Feel L'AWT délégait l'affichage et le comportement à des composants pairs du système Swing délégue l'affichage et le comportement à des composants Java pluggables javax.swing.UIManager propose de nombreuses méthodes pour gérer les L&F : Obtenir le L&F courant : LookAndFeel getLookAndFeel() Obtenir la classe du L&F implémentant le L&F de la plate-forme d'exécution : String getSystemLookAndFeelClassName() Obtenir la classe du L&F cross-platform : String getCrossPlatformLookAndFeelClassName() Lister les L&F installés : UIManager.LookAndFeelInfo[] getInstalledLookAndFeels()
Pluggable Look & Feel Modifier le Look & Feel Les JComponent s exhibent une méthode : void setUI( ComponentUI new_ui ) Généralement, on change le L&F général : UIManager.setLookAndFeel( new_LF_class_name ); Puis on lance une mise à jour de l'arbre des composants : SwingUtilities.updateComponentTreeUI( component ); component devrait être un composant "racine" : Component SwingUtilities.getRoot( Component component )
Les Applets Une applet est une petite application en Java, destinée à être intégrée dans une page HTML Une application standalone : N'a pas d'exigence en terme de type (elle étend au minimum java.lang.Object ) N'a qu'un seul point d'entrée : public static main( String[] ) Une applet : Doit au moins étendre java.applet.Applet ou javax.swing.JApplet N'a pas de point d'entrée exigé Graphe d'héritage : java.lang.Object java.awt.Component java.awt.Container java.awt.Panel java.applet.Applet javax.swing.JApplet
Les Applets \ Etat des applets Etat des applets Une applet peut être dans 4 états : A chaque transition d'état une des méthodes suivante est invoquée : public void init() public void start() public void stop() public void destroy()
Les Applets \ Arguments des applets Arguments des applets Une application standalone reçoit les paramètres de la ligne de commande en argument de la méthode statique main sous forme de liste de valeurs de type String Une applet reçoit les paramètres jouxtant le tag HTML sous forme d'ensemble de paires de type String, lisibles par la méthode : public String getParameter( String parameter_name )
Les Applets \ Le tag Le tag Le tag, fonctionnant si la version de la JVM du navigateur est correcte : <APPLET [CODEBASE= codebaseURL] CODE= appletFile [ALT= alternateText] [NAME= appletInstanceName] WIDTH= pixels HEIGHT= pixels [ALIGN= alignment] [VSPACE= pixels] [HSPACE= pixels]> [ ]... [alternateHTML]
Les Applets \ Les plugins Java Les plugins Java Les navigateurs étant souvent en retard de plusieurs versions de JVM (+ M$ qui ne met volontairement pas à jour la JVM dIE), Sun a développé une technique de plugins Java : Les navigateurs n'exécutent plus l'applet, mais un plugin qui exécute lui-même l'applet Le plugin peut-être téléchargé à la volée Internet Explorer utilise le tag, Netscape Navigator le tag … Il faut donc faire trois versions de tags…
Les Applets \ Le tag Le tag (Internet Explorer) <OBJECT classid="clsid:8AD9C E-11D1-B3E F499D93" WIDTH= pixels HEIGHT= pixels CODEBASE= " jinstall-1_2_2-win.cab#Version=1,2,2,0"> [CODEBASE= codebaseURL] <PARAM NAME= "type" VALUE= "application/x-java-applet;version=1.2.2"> [ ]... [ alternateHTML]
Les Applets \ Le tag Le tag (Netscape Navigator) <EMBED type= "application/x-java-applet;version=1.2.2" CODE= appletFile WIDTH= pixels HEIGHT= pixels pluginspage= " plugin-install.html"> scriptable= false [ ]... [ alternateHTML ]