Gestione di eventi ed interfacce utente grafiche Eventi Ogni volta che l’utente esegue un’azione un clic del mouse la pressione di un tasto sulla tastiera la modifica di una finestra la selezione di un elemento da un menu… viene generato un evento 2 Gestione degli eventi Per gestire gli eventi bisogna distinguere tra Sorgente dell’evento (source) la componente dell’interfaccia utente che ha generato l’evento Pulsanti, voci di menu, barre di scorrimento, etc. Ricevitore dell’evento (listener) la classe che intercetta l’evento e definisce le azioni intraprese a seguito del verificarsi di particolari eventi 3 Package java.awt.event Ogni evento è descritto da una appropriata classe Il package java.awt.event contiene Le classi per i diversi tipi di eventi Le interfacce relative ai ricevitori di eventi, i Listener Le classi degli adattatori, gli Adapter, che implementano le interfacce Listener 4 Tipi di evento MouseEvent: eventi del mouse ActionEvent: eventi di azione AdjustmentEvent: eventi di modifica FocusEvent: eventi di selezione ItemEvent: eventi di elemento KeyEvent: eventi di tastiera WindowEvent: eventi di finestra etc… 5 Interfacce Listener Sono i ricevitori di eventi Esiste una interfaccia Listener per ciascun tipo di evento Definiscono i metodi che devono essere implementati da ogni oggetto che desidera essere informato dell’accadere di un particolare tipo di evento 6 Interfacce Listener MouseListener: eventi del mouse ActionListener: eventi di azione AdjustmentListener: eventi di modifica FocusListener: eventi di selezione ItemListener: eventi di elemento KeyListener: eventi di tastiera WindowListener: eventi di finestra etc… 7 MouseEvent Si verificano in seguito ad azioni che riguardano il mouse Tali azioni possono essere eseguite dall’utente in un punto qualsiasi dell’interfaccia grafica Una classe deve implementare l’interfaccia MouseListener per essere in grado di avvertire e gestire eventi di questo tipo 8 MouseEvent: metodi addMouseListener() associa l’ascoltatore di eventi a ciascun componente in grado di generare eventi di questo tipo getX() e getY() restituiscono le coordinate del punto in cui l’evento relativo al mouse è accaduto 9 MouseListener L’interfaccia MouseListener ha cinque metodi: mousePressed(MouseEvent event) mouseReleased(MouseEvent event) mouseClicked(MouseEvent event) mouseEntered(MouseEvent event) mouseExited(MouseEvent event) 10 MouseListener public interface MouseListener { void mousePressed(MouseEvent event); void mouseReleased(MouseEvent event); void mouseClicked(MouseEvent event); void mouseEntered(MouseEvent event); void mouseExited(MouseEvent event); } 11 Spiare gli eventi del mouse Scriviamo un programma che spia gli eventi del mouse e li stampa man mano che si verificano Scriviamo una classe MouseSpy (ricevitore) che implementa MouseListener Scriviamo un applet MouseSpyApplet (sorgente degli eventi) ed installiamo il ricevitore 12 File MouseSpy.java import java.awt.event.MouseEvent; import java.awt.event.MouseListener; class MouseSpy implements MouseListener { public void mousePressed(MouseEvent event) { System.out.println ("Mouse pressed. x=" + event.getX() + " y=" + event.getY()); } public void mouseReleased(MouseEvent event) { System.out.println ("Mouse released. x=" + event.getX() + " y=" + event.getY()); } 13 public void mouseClicked(MouseEvent event) { System.out.println ("Mouse clicked. x=" + event.getX() + " y=" + event.getY()); } public void mouseEntered(MouseEvent event) { System.out.println ("Mouse entered. x=" + event.getX() + " y=" + event.getY()); } 14 public void mouseExited(MouseEvent event) { System.out.println ("Mouse exited. x=" + event.getX() + " y=" + event.getY()); } } 15 File MouseSpyApplet.java import java.applet.Applet; public class MouseSpyApplet extends Applet { public MouseSpyApplet() { MouseSpy listener = new MouseSpy(); addMouseListener(listener); } } 16 Spiare gli eventi del mouse 17 Elaborare gli eventi del mouse Scriviamo un programma che disegna un rettangolo sullo schermo in seguito alla pressione di un tasto del mouse, sposta l’angolo superiore sinistro nella posizione del puntatore del mouse 18 File MouseApplet.java import import import import import import java.applet.Applet; java.awt.Graphics; java.awt.Graphics2D; java.awt.Rectangle; java.awt.event.MouseListener; java.awt.event.MouseEvent; public class MouseApplet extends Applet { public MouseApplet() { // il rettangolo disegnato dal metodo paint box = new Rectangle(BOX_X, BOX_Y, BOX_WIDTH, BOX_HEIGHT); 19 class MousePressListener implements MouseListener { public void mousePressed(MouseEvent event) { int x = event.getX(); int y = event.getY(); box.setLocation(x, y); repaint(); } public public public public void void void void mouseReleased(MouseEvent event) {} mouseClicked(MouseEvent event) {} mouseEntered(MouseEvent event) {} mouseExited(MouseEvent event) {} } MouseListener listener = new MousePressListener(); addMouseListener(listener); } } 20 public void paint(Graphics g) { Graphics2D g2 = (Graphics2D)g; g2.draw(box); } private private private private private Rectangle box; static final int static final int static final int static final int BOX_X = 100; BOX_Y = 100; BOX_WIDTH = 20; BOX_HEIGHT = 30; } 21 MouseApplet Il ricevitore listener è definito come classe interna della classe MouseApplet mousePressed può accedere alla variabile istanza box definita nel costruttore In seguito ad una pressione del mouse viene chiamato il metodo setLocation(x,y) sul rettangolo box L’oggetto che memorizza il rettangolo viene aggiornato Per visualizzare la nuova posizione dobbiamo ridisegnare lo schermo con repaint() 22 Esecuzione di MouseApplet 23 Adattatori di eventi Nella classe MousePressListener eravamo interessati solo alla pressione dei tasti del mouse… …ma abbiamo dovuto riscrivere tutti I metodi di MouseListener! Possiamo usare la classe MouseAdapter, che implementa tutti i metodi di MouseListener come metodi vuoti sovrascriviamo solo i metodi che ci interessano! 24 Adattatori di eventi class MousePressListener extends MouseAdapter { public void mousePressed(MouseEvent event) { int x = event.getX(); int y = event.getY(); box.setLocation(x,y); repaint(); } } 25 ActionEvent Si verificano quando l’utente compie un’azione utilizzando uno dei componenti dell’interfaccia utente Una classe deve implementare l’interfaccia ActionListener per essere in grado di avvertire e gestire eventi di questo tipo 26 ActionEvent: metodi addActionListener() associa l’ascoltatore di eventi a ciascun componente in grado di generare eventi di questo tipo getSource() determina il componente che ha provocato l’evento 27 ActionListener L’interfaccia ActionListener ha un solo metodo: actionPerformed(ActionEvent event) public interface ActionListener { void actionPerformed(ActionEvent event); } Non ha senso avere un adattatore di eventi per ActionListener 28 Interfaccia utente In Java esistono due modi per gestirla: Swing (package javax.swing) Estensione delle prime versioni di Java, componente standard di Java 2 Esempi di classi: JTextField, JLabel, JButton, JRadioButton, JCheckbox, JFrame, JPanel, JScrollPane, … Abstract Windowing Toolkit (package java.awt) Ormai obsoleto Esempi di classi: TextField, Label, Button, RadioButton, ChechBox, Frame, Panel, ScrollBar, 29 Interfaccia utente Tre elementi fondamentali Componenti: elementi di base dell’interfaccia Contenitori: elementi che contengono componenti Gestori del Layout: elementi che controllano la disposizione delle componenti all’interno di un contenitore 30 Componenti Etichette Caselle di testo Aree di testo Barre di scorrimento Bottoni Bottoni radio Caselle di controllo Caselle combinate 31 Etichette I più semplici elementi di un’interfaccia utente Stringhe di testo impiegate per identificare la funzione di altre componenti aggiungere spiegazioni destinate all’utente Per creare un’etichetta si usa la classe JLabel JLabel xLabel = new JLabel (“x=’’); 32 Caselle di testo Aree in cui l’utente può digitare del testo Bisogna specificare la dimensione della casella di testo Per creare una casella di testo si usa la classe JTextField JTextField xField = new JTextField(5); 33 Aree di testo Aree in cui l’utente può digitare del testo su più righe Per creare un’area di testo si usa la classe JTextArea JTextArea textarea = new JTextArea(10,30); 34 Aree di testo Alcuni metodi append aggiunge testo alla fine dell’area di testo setText imposta il testo getText legge il contenuto dell’area setEditable(false) impedisce la modifica dell’area setFont imposta il font 35 Barre di scorrimento Possono essere aggiunte ad un’area di testo Per creare una barra di scorrimento si usa la classe JScrollPane JTextArea textarea = new JTextArea(10,30); JScrollPane scrollPane = new JScrollPane(textArea); 36 Bottoni Pulsanti dell’interfaccia che reagiscono al clic del mouse Per creare un bottone si usa la classe JButton JButton moveButton = new JButton(“Move”); JButton moveButton = new JButton(new ImageIcon(“hand.gif”)); JButton moveButton = new JButton(“Move”,new ImageIcon(“hand.gif”)); 37 Bottoni Quando un bottone viene premuto, invia un evento di azione Per riceverlo, è necessario installare un ricevitore di azioni (classe che implementa l’interfaccia ActionListener) class MoveButtonListener implements ActionListener { public void actionPerformed(ActionEvent event) { … } } ActionListener listener = new MoveButtonListener(); moveButton.addActionListener(listener); 38 Bottoni radio Consentono all’utente di fare una sola scelta tra più opzioni 39 Bottoni radio Per creare bottoni radio si usa la classe JRadioButton JRadioButton paperButton = new JRadioButton(“Paperino”); JRadioButton pippoButton = new JRadioButton(“Pippo”); Poi si crea un oggetto di tipo ButtonGroup e si aggiungono i singoli pulsanti ButtonGroup fumettiGroup = new ButtonGroup(); fumettiGroup.add(paperButton); fumettiGroup.add(pippoButton); 40 Bottoni radio Alcuni metodi isSelected() stabilisce se un pulsante è selezionato setSelected(true) imposta la selezione per uno dei pulsanti del gruppo 41 Bottoni radio Quando un bottone radio viene selezionato, invia un evento di azione Per riceverlo, è necessario installare un ricevitore di azioni (classe che implementa l’interfaccia ActionListener) class RadioButtonListener implements ActionListener { public void actionPerformed(ActionEvent event) { … } } ActionListener listener = new RadioButtonListener(); paperButton.addActionListener(listener); 42 Caselle di controllo Consentono all’utente di fare varie scelte che non si escludono a vicenda 43 Caselle di controllo Per creare una casella di controllo si usa la classe JCheckbox JCheckBox paperCheckBox = new JCheckBox(“Paperino”); Non è necessario creare un gruppo di pulsanti, come per i bottoni radio 44 Caselle di controllo Quando una casella di controllo viene selezionata, invia un evento di azione Per riceverlo, è necessario installare un ricevitore di azioni (classe che implementa l’interfaccia ActionListener) class CheckBoxListener implements ActionListener { public void actionPerformed(ActionEvent event) { … } } ActionListener listener = new CheckBoxListener(); paperCheckBox.addActionListener(listener); 45 Caselle combinate Consentono all’utente di fare una sola scelta tra più opzioni attraverso un elenco a discesa 46 Caselle combinate Per creare una casella combinata si usa la classe JComboBox JComboBox fumettiCombo = new JComboBox(); Poi si aggiungono le voci con il metodo addItem fumettiCombo.addItem(“Paperino”); fumettiCombo.addItem(“Pippo”); fumettiCombo.addItem(“Pluto”); fumettiCombo.addItem(“Topolino”); 47 Caselle combinate Alcuni metodi setEditable() rende la casella modificabile getSelectedItem() restituisce l’elemento (di tipo Object) scelto dall’utente setSelectedItem() imposta la voce iniziale da visualizzare nella casella 48 Caselle combinate Quando una casella combinata viene selezionata, invia un evento di azione Per riceverlo, è necessario installare un ricevitore di azioni (classe che implementa l’interfaccia ActionListener) class ComboBoxListener implements ActionListener { public void actionPerformed(ActionEvent event) { … } } ActionListener listener = new ComboBoxListener(); fumettiCombo.addActionListener(listener); 49 Interfaccia utente Tre elementi fondamentali Componenti: elementi di base dell’interfaccia Contenitori: elementi che contengono componenti Gestori del Layout: elementi che controllano la disposizione delle componenti all’interno di un contenitore 50 Contenitori Negli applet visti finora l’esecuzione avveniva all’interno della finestra del browser Per creare una maggiore interazione con l’utente è possibile creare diversi contenitori per i componenti dell’interfaccia utente panelli finestre menu 51 Pannelli Contenitori per i componenti dell’interfaccia utente Per creare un pannello si usa la classe JPanel JPanel panel = new JPanel(); Dopo aver creato il pannello, si aggiungono i componenti mediante il metodo add Panel.add(xLabel); Panel.add(xField); Panel.add(yLabel); Panel.add(yField); Panel.add(moveButton); 52 Frame Un frame è una finestra indipendente dotata di barra del titolo pulsanti di ridimensionamento e chiusura Per creare un frame si usa la classe JFrame JFrame frame = new JFrame(); 53 Frame 54 Frame Il metodo pack() assegna le dimensioni al frame in modo che possa contenere tutti i suoi componenti frame.pack(); Il metodo show() mostra la finestra sullo schermo (inizialmente è invisibile) frame.show(); 55 Barra dei menu Una barra dei menu è costituita da un gruppo di menu lungo il margine superiore di una finestra 56 Barra dei menu Per creare una barra dei menu si usa la classe JMenuBar JMenuBar menuBar = new JMenuBar(); La barra dei menu deve essere associata a un oggetto di tipo Frame con il metodo setJmenuBar() frame.setJMenuBar(menuBar); 57 Menu Per creare un menu si usa la classe JMenu JMenu fileMenu = new JMenu(“File”); I menu vengono aggiunti alla barra dei menu mediante il metodo add() menuBar.add(fileMenu); 58 Menu All’interno dei menu si aggiungono le voci di menu Per creare una voce di menu si usa la classe JMenuItem JMenuItem fileNewMenuItem = new JMenuItem(“New”); filemenu.add(fileNewMenuItem); 59 Menu Quando una voce di menu viene selezionata, invia un evento di azione Per riceverlo, è necessario installare un ricevitore di azioni (classe che implementa l’interfaccia ActionListener) class MenuItemListener implements ActionListener { public void actionPerformed(ActionEvent event) { … } } ActionListener listener = new menuItemListener(); fileNewMenuItem.addActionListener(listener); 60 Interfaccia utente Tre elementi fondamentali Componenti: elementi di base dell’interfaccia Contenitori: elementi che contengono componenti Gestori del Layout: elementi che controllano la disposizione delle componenti all’interno di un contenitore 61 Gestori di layout Determinano la disposizione (layout) componenti all’interno di un contenitore delle Alcuni gestori comunemente usati: FlowLayout (a scorrimento) Borderlayout (a bordi) GridLayout (a griglia) GridBagLayout 62 Gestori di layout Bisogna innanzitutto creare un contenitore Poi si utilizza il metodo setLayout() per definire un gestore di layout In seguito si aggiungono i componenti contenitore con il metodo add() al 63 FlowLayout Gestore di default Posiziona le componenti da sinistra verso destra finchè c’è spazio e poi procede alla riga successiva 64 FlowLayout 65 BorderLayout Suddivide un contenitore in cinque settori Alto (NORTH) Basso (SOUTH) Sinistra (WEST) Destra (EAST) Centro (CENTER) I settori relativi ai bordi occupano lo spazio di cui hanno bisogno, e tutto lo spazio restante viene usato dal settore centrale 66 BorderLayout 67 BorderLayout Impostiamo il gestore in un pannello: panel.setLayout(new BorderLayout()); Aggiungiamo un componente al contenitore, specificandone la posizione: panel.add(label, BorderLayout.CENTER); 68 BorderLayout Possiamo usare il pannello dei contenuti predefinito di un frame, ottenuto dal metodo getContentPane(): frame.getContentPane().add(label, BorderLayout.CENTER); 69 GridLayout Dispone i componenti in base ad una griglia con un certo numero di righe e colonne L’aggiunta dei componenti avviene a partire dalla riga superiore, da sinistra a destra La dimensione delle componenti cambia in seguito a ridimensionamenti del contenitore 70 GridLayout 71 GridLayout Impostiamo il gestore in un pannello: panel.setLayout(new GridLayout(4,3)); Aggiungiamo i componenti al contenitore: panel.add(button7); panel.add(button8); panel.add(button9); panel.add(button4); 72 GridBagLayout Consente la creazione di griglie avanzate le proporzioni tra righe e colonne all’interno della griglia non sono necessariamente uguali i componenti possono essere disposti in modo arbitrario e occupare più celle Noi non lo utilizzeremo 73 E adesso? Dopo aver descritto i componenti dell’interfaccia utente, vogliamo gestire gli eventi di azione Una classe deve implementare l’interfaccia ActionListener per essere in grado di avvertire e gestire eventi di questo tipo 74 Esempio Scriviamo un applet che consente all’utente di muovere un rettangolo specificando le coordinate dell’angolo superiore sinistro 75 File ButtonApplet.java import import import import import import import import import import import import java.applet.Applet; java.awt.Graphics; java.awt.Graphics2D; java.awt.Rectangle; java.awt.event.ActionEvent; java.awt.event.ActionListener; javax.swing.ImageIcon; javax.swing.JButton; javax.swing.JFrame; javax.swing.JLabel; javax.swing.JPanel; javax.swing.JTextField; /** Questo applet consente all’utente di muovere un rettangolo specificando le coordinate dell’angolo superiore sinistro */ 76 public class ButtonApplet extends Applet { public ButtonApplet() { // il rettangolo disegnato dal metodo paint box = new Rectangle(BOX_X, BOX_Y, BOX_WIDTH, BOX_HEIGHT); // i campi di testo per inserire le coordinate final JTextField xField = new JTextField(5); final JTextField yField = new JTextField(5);; // il bottone per muovere il rettangolo JButton moveButton = new JButton("Move", new ImageIcon("hand.gif")); 77 class MoveButtonListener implements ActionListener { public void actionPerformed(ActionEvent event) { int x = Integer.parseInt(xField.getText()); int y = Integer.parseInt(yField.getText()); box.setLocation(x, y); repaint(); } } ActionListener listener = new MoveButtonListener(); moveButton.addActionListener(listener); 78 // le etichette per i campi di testo JLabel xLabel = new JLabel("x = "); JLabel yLabel = new JLabel("y = "); // il pannello che contiene i componenti JPanel panel = new JPanel(); panel.add(xLabel); panel.add(xField); panel.add(yLabel); panel.add(yField); panel.add(moveButton); // il frame che contiene il pannello JFrame frame = new JFrame(); frame.setContentPane(panel); frame.pack(); frame.show(); } 79 public void paint(Graphics g) { Graphics2D g2 = (Graphics2D)g; g2.draw(box); } private private private private private Rectangle box; static final int static final int static final int static final int BOX_X = 100; BOX_Y = 100; BOX_WIDTH = 20; BOX_HEIGHT = 30; } 80 Più pulsanti con comportamento simile JButton leftButton = new JButton(“Left”); class LeftButtonListener implements ActionListener { public void actionPerformed(ActionEvent event) { box.translate(-BOX_WIDTH, 0); repaint(); } } LeftButtonListener leftListener = new LeftButtonListener(); leftButton.addActionListener(leftListener); 81 Più pulsanti con comportamento simile JButton rightButton = new JButton(“Right”); class RightButtonListener implements ActionListener { public void actionPerformed(ActionEvent event) { box.translate(BOX_WIDTH, 0); repaint(); } } RightButtonListener rightListener = new RightButtonListener(); rightButton.addActionListener(rightListener); 82 Più pulsanti con comportamento simile Evitiamo di scrivere codice ripetitivo per pulsanti con lo stesso comportamento! Rimedio: isoliamo il codice comune e scriviamo un nuovo metodo makeButton Ad ogni invocazione del metodo viene creato un bottone e un oggetto ricevitore di tipo ButtonListener 83 Più pulsanti con comportamento simile public JButton makeButton(String label, final int dx, final int dy) { JButton button = new JButton(label); class ButtonListener implements ActionListener { public void actionPerformed(ActionEvent event) { box.translate(dx, dy); repaint(); } } ButtonListener listener = new ButtonListener(); button.addActionListener(listener); return button; } 84 Più pulsanti con comportamento simile • Invochiamo il metodo quattro volte: panel.add(makeButton("Left",-BOX_WIDTH,0)); panel.add(makeButton("Right",BOX_WIDTH,0)); panel.add(makeButton("Up",0,-BOX_HEIGHT)); panel.add(makeButton("Down",0,BOX_HEIGHT)); 85 File ButtonApplet.java import import import import import import import import import java.applet.Applet; java.awt.Graphics; java.awt.Graphics2D; java.awt.Rectangle; java.awt.event.ActionEvent; java.awt.event.ActionListener; javax.swing.JButton; javax.swing.JFrame; javax.swing.JPanel; /** Questo applet permette all’utente di spostare un rettangolo premendo quattro pulsanti con etichette "Left", "Right", "Up", and "Down". */ 86 public class ButtonApplet extends Applet { public ButtonApplet() { // il rettangolo disegnato dal metodo paint box = new Rectangle(BOX_X, BOX_Y, BOX_WIDTH, BOX_HEIGHT); // il pannello che contiene i componenti JPanel panel = new JPanel(); panel.add(makeButton("Left", -BOX_WIDTH, 0)); panel.add(makeButton("Right", BOX_WIDTH, 0)); panel.add(makeButton("Up", 0, -BOX_HEIGHT)); panel.add(makeButton("Down", 0, BOX_HEIGHT)); // il frame che contiene il pannello JFrame frame = new JFrame(); frame.setContentPane(panel); frame.pack(); frame.show(); } 87 public void paint(Graphics g) { Graphics2D g2 = (Graphics2D)g; g2.draw(box); } /** Costruisce un pulsante che muove il rettangolo @param label l’etichetta del pulsante @param dx l’entità dello spostamento in direzione x quando si preme il pulsante @param dy l’entità dello spostamento in direzione y quando si preme il pulsante @return il pulsante */ 88 public JButton makeButton(String label, final int dx, final int dy) { JButton button = new JButton(label); class ButtonListener implements ActionListener { public void actionPerformed(ActionEvent event) { box.translate(dx, dy); repaint(); } } ButtonListener listener = new ButtonListener(); button.addActionListener(listener); return button; } 89 private private private private private Rectangle box; static final int static final int static final int static final int BOX_X = 100; BOX_Y = 100; BOX_WIDTH = 20; BOX_HEIGHT = 30; } 90