Interface Graphique IFT1025 – Programmation 2 Jian-Yun Nie Concepts • Construire une fenêtre graphique – Objets graphiques – Composition, affichage • Programmation par événement – Comment faire pour que le programme réagisse? – Principe MVC – Modèle-Vue-Contrôle • Package Swing Généralité Programme Interface Utilisateur Rôles d’une interface utilisateur: • montrer le résultat de l’exécution • permettre à l’utilisateur d’interagir • (1) Montrer – (2) Réagir Exemple simple (Montrer) Importer le package import javax.swing.*; public class DisplayFrame { Créer un objet public static void main (String[] args) { graphique JFrame f = new JFrame("FrameDemo"); //… components are added to its content frame. f.setSize(300,200); Définir la taille f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); } } afficher Afficher une interface • Importer le package (les classes) – Les classes sont regroupées en package – Importer un package = importer toutes les classes du package – import javax.swing.*; • • • • Créer une fenêtre graphique (JFrame, …) Définir les paramètres (taille, …) Afficher Différence: – import java.awt.*; les classes dans awt – import java.awt.event.*; les classes dans event – import javax.swing.*; awt: Abstract Windows Toolkit Hiérarchie de package java … awt event javax swing [classes] … import java.awt.*; N’importe pas event.* [classes] … import java.awt.event.*; Les objets graphiques • 3 niveaux – Haut niveau • Définir une fenêtre • JApplet, JDialog, JFrame, JWindow – Niveau intermédiaire • Pour composer la fenêtre • JPanel, JScrollPane, JSplitPane, … – Niveau inférieur • Les éléments de base • JButton, JCheckBox, JTextField, JTextArea, … Insérer des éléments dans la fenêtre • Composition d’une fenêtre JFrame Jframe internal structure Ajouter des composants dans une fenêtre import javax.swing.*; public class DisplayFrame { Haut niveau public static void main (String[] args) { JFrame f = new JFrame("FrameDemo"); Composante JLabel label = new JLabel("Hello World"); de base JPanel p = (JPanel)f.getContentPane(); Niveau p.add(label); intermédiaire f.setSize(300,200); //alternative: f.pack(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); } } Composer une fenêtre • Créer une fenêtre (1) • Créer un ou des composants intermédiaires (2) – Pour JFrame, un JPanel est associé implicitement (ContentPane) • Créer des composants de base (3) • Insérer (3) dans (2) • Insérer (2) dans (1) (s’ils ne sont pas déjà associés) • Afficher Composant de base (pour obtenir des données) • • • • JButton JCheckBox a toggled on/off button displaying state to user. JRadioButton a toggled on/off button displaying its state to user. JComboBox a drop-down list with optional editable text field. • • • • Jlist allows a user to select one or more items from a list. Jmenu popup list of items from which the user can select. Jslider lets user select a value by sliding a knob. JTextField area for entering a single line of input. user can key in a value or select a value from drop-down list. The Composants de base pour afficher l’information • Jlabel contains text string, an image, or both. • JProgressBar communicates progress of some work. • JToolTip describes purpose of another component. • Jtree a component that displays hierarchical data in outline form. • Jtable a component user to edit and display data in a two-dimensional grid. • JTextArea, JTextPane, JEditorPane – define multi-line areas for displaying, entering, and editing text. Swing components: Illustration Composants intermédiaires • Utilisés pour organiser ou positionner d’autres composants (de base) – JPanel utilisé pour regrouper d’autres composants – JScrollPane fournir une vue avec scroll bars – JSplitPane divise en 2 composants – … Exemple d’organisation des composants Ajouter 2 boutons dans un Panel JPanel p = new JPanel(); p.add(new JButton("on")); p.add(new JButton("off")); • Ce Panel contient maintenant 2 boutons Construire GUI: Méthode générale • Utiliser JPanel comme décomposition de fenêtre un outil de – Une technique standard – Permet plus de flexibilités – JPanel peut être ajouté à d’autres structures pour modifier ou étendre l’application • Construire une vue de l’application dans un JPanel, et ajouter JPanel à ContentPane de JFrame Hiérarchie des classes pour composants graphiques • AWT (Abstract Windowing Toolkit) Object Component MenuComponent Layout Event Peer • Utilisé dans JDK1.0 et JDK1.1 • JDK2 utilise plutôt Swing (mais continue à supporter AWT) Hiérarchie des composants graphiques: AWT Hiérarchie des composants graphiques: AWT Hiérarchie des composants graphiques: Swing Hiérarchie des composants graphiques: Swing Container de haut niveau • N’est pas contenu dans d’autre Container • Fournir une fenêtre dans laquelle les autres composants peuvent s’afficher – JApplet, JDialog, JFrame, JWindow Haut niveau (1): JFrame • It’s a window with title, border, (optional) menu bar and user-specified components. • It can be moved, resized, iconified. • It is not a subclass of JComponent. • Delegates responsibility of managing userspecified components to a content pane, an instance of JPanel. – getContentPane() Insérer des éléments dans la fenêtre • Composition d’une fenêtre JFrame Jframe internal structure JFrame: Composer • Ajouter un composant dans Content Pane de JFrame JFrame f = new JFrame("A Frame"); JButton b = new JButton("Press"); JPanel cp = (JPanel)f.getContentPane(); cp.add(b) ou JFrame f = new JFrame("A Frame"); JButton b = new JButton("Press"); f.getContentPane().add(b) ou JFrame f = new JFrame("A Frame"); JButton b = new JButton("Press"); f.add(b) Définir ses propres classes paintComponent: méthode pour affichage (overriding) Graphics g: la surface à dessin de JComponent 01: import java.awt.Graphics; 02: import java.awt.Graphics2D; 03: import java.awt.Rectangle; 04: import javax.swing.JPanel; 05: import javax.swing.JComponent; 06: 07: /** 08: A component that draws two rectangles. 09: */ 10: public class RectangleComponent extends JComponent 11: { 12: public void paintComponent (Graphics g) 13: { 14: // Recover Graphics2D 15: Graphics2D g2 = (Graphics2D) g; 16: 17: // Construct a rectangle and draw it 18: Rectangle box = new Rectangle(5, 10, 20, 30); 19: g2.draw(box); 20: 21: // Move rectangle 15 units to the right and 25 units down 22: box.translate(15, 25); 23: 24: // Draw moved rectangle 25: g2.draw(box); 26: } 27: } Créer et voir l’objet 01: import javax.swing.JFrame; 02: 03: public class RectangleViewer 04: { 05: public static void main(String[] args) 06: { 07: JFrame frame = new JFrame(); 08: 09: final int FRAME_WIDTH = 300; 10: final int FRAME_HEIGHT = 400; 11: 12: frame.setSize(FRAME_WIDTH, FRAME_HEIGHT); 13: frame.setTitle("Two rectangles"); 14: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 15: 16: RectangleComponent component = new RectangleComponent(); 17: frame.add(component); 18: 19: frame.setVisible(true); 20: } 21: } Haut Niveau (2): JApplet • Applet = une fenêtre dans un navigateur • Permet à n’importe quel utilisateur de lancer une application • Plus de contrainte de sécurité (pas d’écriture) • Programme englobé dans une page Web Lancer un Applet À partir d’une page Web: <html> <head> <title>Two rectangles</title> </head> <body> <p>Here is my <i>first applet</i>:</p> <applet code="RectangleApplet.class" width="300" height="400"> </applet> </body> </html> Afficher deux Rectangles 01: import java.awt.Graphics; 02: import java.awt.Graphics2D; 03: import java.awt.Rectangle; 04: import javax.swing.JApplet; 05: 06: /** 07: An applet that draws two rectangles. 08: */ 09: public class RectangleApplet extends JApplet 10: { 11: public void paint (Graphics g) 12: { 13: // Prepare for extended graphics 14: Graphics2D g2 = (Graphics2D) g; 15: 16: // Construct a rectangle and draw it 17: Rectangle box = new Rectangle(5, 10, 20, 30); 18: g2.draw(box); 19: 20: // Move rectangle 15 units to the right and 25 units down 21: box.translate(15, 25); 22: 23: // Draw moved rectangle 24: g2.draw(box); 25: } 26: } 27: paint:méthode d’affichage dans JApplet Graphics g: surface Différence JApplet: quelques détails public void public void public void public void public void public void init () start () stop () destroy () paint (Graphics) repaint() public void update (Graphics) public void showStatus(String) public String getParameter(String) JApplet: détails • init() est la première méthode exécutée – init() est la place idéale pour initialiser les variables – init() est la meilleure place pour définir la configuration de GUI – Presque chaque Applet a une méthode init( ) JApplet: détails • public void start() est appelée: – Juste après init( ) – Chaque fois quand la page est chargée ou rafraichie • public void stop( ) est appelée: – Quand le navigateur quitte la page – Juste avant destroy( ) • public void destroy( ) est appelée après stop( ) – Utiliser destroy() pour relâcher les ressources – Les ressources sont relâchées automatiquement JApplet: détails • Pour dessiner ou paindre • Tout ce qu’on veut paindre doit être fait ici • Ne pas appeler paint(Graphics), mais repaint( ), qui appele paint. Graphics • Every component has a graphics context. • The Graphics object has methods for drawing text, images, and geometrical figures on components. – drawLine, – drawImage, – drawRect, – drawString, – fillRect, etc. Graphics g.drawString(“Hello”, 20, 20); g.drawRect(x, y, width, height); g.fillRect(x, y, width, height); g.drawOval(x, y, width, height); g.setColor(Color.red); Hello Drawing a triangle • A JPanel can be used as a canvas to draw on. • JPanel defines an integer coordinate system with coordinates ranging from (0,0) in the upper left to (width-1, height-1) in the lower right. • Units are pixels. • To draw on a JPanel, we override the method paintComponent. Drawing a triangle class TrianglePanel extends JPanel { … public void paintComponent (Graphics g) { super.paintComponent(g); g.drawLine(10,10,10,80); g.drawLine(10,80,110,80); g.drawLine(110,80,10,10); } } paintComponent est la méthode exécutée à la création, quand on l’appelle ou quand on appelle repaint(). Événement et composants • • • • Événement sont des objets Sous-classes de la class abstraite java.awt.AWTEvent. Les composants génèrent des événements Événements: chaque interaction de l’utilisateur sur un composant génère un événement – – – – Bouger la souris Cliquer sur un bouton Fermer une fenêtre … • Un événement contient des informations: source, type d’événement, … public Object getSource(); – Utile pour détecter d’où provient l’événement Propagation et traitement des événements Composant a: Génère un événement e du type T • • e Objet b qui capte l’événement de l’objet a, du type T: Traitement de e Les événements sont générés et propagés Certains autres objets sont capables de capter des événements des types spécifiés, provenant de ces composants – b écoute les événements du type T venant de a – b est un listener de a • On peut activer le traitement suite à la capture d’un événement – Le traitement lancé par l’objet b • Programmation par événement – Le programme réagit aux événements Listener et Event handler: donner la capacité d’entendre un événement • Listener: Un objet est intéressé à écouter l’événement produit (être signalé quand il y a un événement) • Listener doit implanter l’interface event listener interface associée à chaque type d’événement. • Event Handler: le programme qui lance un traitement suite à un événement Type d’événement écouté • Exemple classe public class Capteur implements ActionListener { public void actionPerformed(ActionEvent e) { … } } Action déclenchée Donner la capacité d’écoute class <class_name> implements <EventListener> { <attributes / methods of the class> <implementation of all the required methods> } La classe est capable de capter les événements du type <EventListener> Exemple public class Capteur implements ActionListener { public void actionPerformed(ActionEvent e) { … } } import java.awt.*; import javax.swing.*; import java.awt.event.*; public class JAppletExample extends JApplet implements ActionListener { private JButton rouge, bleu; private Color couleur = Color.BLACK; public void init() { rouge = new JButton("Rouge"); bleu = new JButton("Bleu"); // Liens d'ecoute rouge.addActionListener(this); bleu.addActionListener(this); } // affichage public void paint(Graphics g) { super.paint(g); g.setColor(couleur); g.drawString("Choisir une couleur.", 100, 100); } // methode qui reagit aux evenements public void actionPerformed (ActionEvent e) { if (e.getSource() == rouge) couleur=Color.RED; else if (e.getSource() == bleu) couleur = Color.BLUE; repaint(); //appeler paint(...) pour repaindre } Container content = getContentPane(); content.setLayout(new FlowLayout()); content.add(rouge); content.add(bleu); } Mode de fonctionnement Fenêtre: Composants graphique rouge ActionEvent bleu Liens d’écoute: addAcionListener Réactions: actionPerformed redéfinir la couleur, réafficher Un autre exemple public PlayBalloon() { setTitle("Balloon"); setLayout(new FlowLayout()); import java.awt.*; import java.awt.event.*; public class PlayBalloon extends Frame implements ActionListener, WindowListener { private Button grow, shrink, exit; private Balloon myBalloon; public static void main(String[] args) { PlayBalloon f = new PlayBalloon(); f.setSize(300, 300); f.setVisible(true); } grow = new Button("Grow"); add(grow); grow.addActionListener(this); shrink = new Button("Shrink"); add(shrink); shrink.addActionListener(this); exit = new Button("Exit"); add(exit); exit.addActionListener(this); myBalloon = new Balloon(20, 50, 50); this.addWindowListener(this); } // fin constructeur PlayBalloon Réactions public void actionPerformed(ActionEvent event) { if (event.getSource() == grow) myBalloon.changeSize(10); if (event.getSource() == shrink) myBalloon.changeSize(-10); repaint(); if (event.getSource() == exit) System.exit(0); } public void windowClosing(WindowEvent event) { System.exit(0); } public void windowIconified(WindowEvent event) {} public void windowOpened(WindowEvent event) {} public void windowClosed(WindowEvent event) {} public void windowDeiconified(WindowEvent event) {} public void windowActivated(WindowEvent event) {} public void windowDeactivated(WindowEvent event) {} public void paint (Graphics g) { myBalloon.display(g); } } Ballon class Balloon { private int diameter; private int xCoord, yCoord; Balloon (int initialDiameter, int initialX, int initialY) { diameter = initialDiameter; xCoord = initialX; yCoord = initialY; } public void changeSize (int change) { diameter = diameter+change; } public void display (Graphics g) { g.drawOval (xCoord, yCoord, diameter, diameter); } } Types d’événement et écouteur • ActionEvent, ActionListener: – Button, List, TextField, MenuItem, JButton, … – public void actionPerformed(ActionEvent) • AdjustmentEvent, AdjustmentListener – Scrollbar, ScrollPane, … – public void adjustmentValueChanged(AdjustmentEvent) • ItemEvent, ItemListener – Checkbox, CheckboxMenuItem, Choice, List – public void itemStateChanged(ItemEvent) Types d’événement et écouteur • MouseEvent, – Souris – MouseListener • public void mouseDragged(MouseEvent) • public void mouseMoved(MouseEvent) – MouseMotionListener • • • • • public void mousePressed(MouseEvent) public void mouseReleased(MouseEvent) public void mouseEntered(MouseEvent) public void mouseExited(MouseEvent) public void mouseClicked(MouseEvent) • TextEvent, TextListener – TextComponent et ses sous-classes – public void textValueChanged(TextEvent) Embellir l’affichage • Pour les composants dans une fenêtre: – Position – Taille – (Autres aspects visuels) • LayoutManager LayoutManager • Chaque container est associé avec un LayoutManager. • Spécifier un LayoutManager pour un Container (JPanel est une sous classe de Container): public LayoutManager getLayout(); public void setLayout (LayoutManager manager); e.g. JButton b = new JButton("Press"); JLabel label = new JLabel("Hello World"); JPanel p = new JPanel(); p.setLayout(new BorderLayout()); p.add(label, BorderLayout.NORTH); p.add(b, BorderLayout.SOUTH); LayoutManager classes • FlowLayout gauch à droite, de haut en bas • BorderLayout 5 potitions: SOUTH, NORTH, CENTER, EAST, WEST • GridLayout • CardLayout Grille de 2 dimention comme une carte Default layout managers • JPanel: FlowLayout. • content pane de JFrame : BorderLayout. • GridLayout import java.awt.*; import java.applet.Applet; public class ButtonGrid extends Applet { public void init() { setLayout(new GridLayout(3,2)); add(new Button("1")); add(new Button("2")); add(new Button("3")); add(new Button("4")); add(new Button("5")); add(new Button("6")); } } Variante: new GridLayout(3,2,5,5): les marges entre les cases: 5 et 5 pixels Component layout figures Un exemple non MVC – valable pour une application simple • Regrouper M, V et C dans une même classe: – Affichage – Contrôle – Modèle - Affichage -Modele -Controle Rouge Bleu Choisir une couleur. – Problème: changer la couleur d’affichage Schéma général main: -Créer les instances de Vue, Modèle et Controle -Établir les liens d’écoute Vue: - Définir une fenêtre et les composants - Créer un objet de Modèle et de Contrôle Modèle: - Les attributs et méthodes spécifique à une application - Produire un résultat à afficher à la Vue Contrôle: - Un objet capable d’écouter les événements - Traitements selon chaque événement capté (appeler la méthode appropriée de Vue pour le traiter) Exemple MVC • Problème: compteur – Deux boutons: ++ pour incrémenter et RAZ pour remettre à 0; – Quand on clique sur un bouton, la valeur affichée doit changer – Utiliser JApplet ++ Valeur=0 RAZ Modules Vue extends JApplet - Init: - Création des boutons - Création d’un Modèle, et d’un Contrôle - Lien d’écoute - affichage Demande d’affichage Modèle - attributs: valeur - Méthodes - bump:ajouter 1 - Raz: remet valeur à 0 Propagation des événements Requête de traitement Contrôle - Définir 2 classes internes pour capter les événements des boutons - Définir les méthodes de réaction Exemple: Vue public class CompteurVue extends JApplet{ private CompteurModele modele; private CompteurControle controle; private JButton bumpButton,razButton; private String message = "Valeur=0"; init(): méthode exécutée quand Applet est lancée public void init(){ // configurer l'interface; Container content = getContentPane(); content.setLayout(new FlowLayout()); bumpButton = new JButton("++"); razButton = new JButton("RAZ"); content.add(bumpButton); content.add(razButton); Création // creer un modele et un controle; modele = new CompteurModele(this); controle = new CompteurControle(modele); // lien d'ecoute; bumpButton.addActionListener(controle.new Bump()); razButton.addActionListener(controle.new RAZ()); } // methode pour afficher une valeur; public void display(int valeur) { message = "Valeur="+valeur; repaint(); } Préparer le message et l’afficher public void paint(Graphics g) { super.paint(g); // pour repaindre les boutons; g.drawString(message,20,50); // ensuite afficher le message; } } Lien d’écoute Méthode pour afficher aussi exécutée par repaint() Exemple: Contrôle Classe de Contrôle class CompteurControle { private CompteurModele modele; Attributs public CompteurControle(CompteurModele modele) { constructeur this.modele = modele; } public class Bump implements ActionListener Type { public void actionPerformed(ActionEvent event) { modele.bump(); } Classes internes avec } Méthodes qui réagissent public class RAZ implements ActionListener { public void actionPerformed(ActionEvent event) { modele.raz(); } } } Exemple: Modèle class CompteurModele { private int valeur = 0; private CompteurVue vue; CompteurModele(CompteurVue vue) { this.vue = vue; } // bump incremente valeur de 1; public void bump() { valeur++; vue.display(valeur); } // raz remet valeur a 0; public void raz() { valeur=0; vue.display(valeur); } } Haut Niveau (3): Dialog • A window to present information or gather input from user. • For standard dialogs use: JOptionPane, JFileChooser, and JColorChooser • For custom dialogs use JDialog. Dialog • Every dialog – Has owner, a frame. – It’s destroyed if owner is destroyed, – disappears from the screen while owner is iconified. • Two kinds of dialogs – modal : User input to all other windows is blocked when a modal dialog is visible. – non-modal : dialogs for which you must use JDialog. JOptionPane Method Name • showConfirmDialog – Asks a confirming question, like yes/no/cancel. • showInputDialog – Prompt for some input. • showMessageDialog – Tell the user about something that has happened. • showOptionDialog – The Grand Unification of the above three. JOptionPane.showMessageDialog • Used to create simple, standard dialogues. public static void showMessageDialog ( Frame owner Component parentComponent, Object message, String title, int messageType, String message to be displayed Window’s title int value indicating style of message Icon icon); icon to be displayed in dialog JOptionPane.showInputDialog Used to get input from the user. It gets a String from the user, using either a text field or a combo box. The parameters are the same as in showMessageDialog. A simpler variants of method is specified as public static String showInputDialog ( Component parentComponent, Object message) • When user presses “OK” button, – contents of text field is returned or null if user presses “Cancel” or closes window. – Contents is String. Requesting a number from user, you must validate and convert String to appropriate type of value. JOptionPane.showInputDialog String response = JOptionPane.showInputDialog(frame, “Message Type”); int value = convertToInt(response); JOptionPane.showConfirmDialog • The showConfirmDialog generates a two or three button window. • The two button provides “Yes” and “No” or ‘OK” and “Cancel” buttons. • The three button, “Yes,” “No,” and “Cancel” buttons. • The method returns an int indicating the user’s response. Possible return values include JOptionPane.YES_OPTION, JOptionPane.OK_OPTION, JOptionPane.NO_OPTION, JOptionPane.CANCEL_OPTION, and if user closes window, JOptionPane.CLOSED_OPTION. Show confirm dialog int response = JOptionPane.showConfirmDialog(frame, “Take over the world?”, “The Brain”, JOptionPane.YES_NO_OPTION); if (response == YES_OPTION) … FileChooser and JColorChooser dialogs • JFileChooser : a simple mechanism for a user to select a file. JFileChooser directory = new JFileChooser(); directory.setCurrentDirectory(new File(“.”)); directory.showOpenDialog(this); //open dialog File file = directory.getSelectedFile(); JDialog • Used to create custom dialog windows. • A JDialog – a top-level window. – has an owner, generally a frame. – It delegates component management to a content pane, to which components are added. – It’s displayed by invoking its setVisible method with an argument of true, and is hidden by invoking its setVisible method with an argument of false JDialog • A typical constructor is specified as follows: public JDialog (Frame owner, String title, boolean modal) Provides an object to create custom views to get or present data.