Università degli Studi di Pisa Dipartimento di Informatica Lezione 12 Laboratorio Programmazione Rete GUI JAVA: nozioni di base per il progetto 13/12/2016 Laura Ricci Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci PERCHE' UNA INTERFACCI GRAFICA? ● consideriamo il Client del progetto Text Twist. Il Client deve: ● visualizzare i messaggi che provengono dal server (callback) corrispondenti agli inviti da parte degli altri giocatori ● gestire i messaggi provenienti da gruppo di multicast ● accettare le richieste provenienti dall'utente di aperture di nuove partite e di proposte di parole ● in una interfaccia a linea di testo, le righe introdotte dall'utente potrebbero essere visualizzate in interleaving con messaggi provenienti dal server ● una semplice interfaccia grafica può risolvere questo problema ● ● diverse aree per l'immissione dei dati, visualizzazione messaggi importante: il progetto dell'interfaccia non è una priorità del progetto, deve essere solo un mezzo per rendere più semplice l'implementazione! Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci GOSSIP (PROGETTO 2014): L'INTERFACCIA Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci JAVA GUI: INTRODUZIONE Struttura generale di un programma JAVA che utilizza una GUI: ● main() routine sempre presente: ● in generale crea una o più componenti GUI e le rende visibili sullo schermo ● ● dopo che le componenti sono state create, esse sono autonome il comportamento di ogni componente è programmato all'interno della componente stessa, e la componente gestisce gli eventi generati dall'utente Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci COMPONENTI BASE: JFRAME Componente fondamentale: La classe JFrame che rappresenta una window: (inclusa nel package javax.swing) ● apertura e chiusura ● resizing e diversi attributi: ● titlebar, dimensioni,.... import javax.swing.*; public class GUIClass { public static void main (String args[]) { JFrame window = new JFrame("GUI Test"); window.setSize(800,600); window.setLocation(100,100); window.setVisible(true); } } Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci COMPONENTI BASE: CONTENTPANE ● il contenuto visualizzato in un JFrame viene indicato come content pane (pane = vetro). ● un JFrame possiede per default un content pane: si possono aggiungere oggetti direttamente a questo content pane oppure crearne uno nuovo ● gli oggetti possono essere, a loro volta, contenitori oppure oggetti semplici import javax.swing.*; public class GUIClass { public static void main (String args[]) { JFrame window = new JFrame("GUI Test"); window.setSize(800,600); window.setLocation(100,100); window.setVisible(true); }} Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci JAVA CONTAINERS ● componenti: elementi base visibili che possono formare una GUI ● containers: componenti che possono contenere altri componenti: oggetto che appartiene ad una sottoclasse di java.awt.Container ● esempi di contenitori ● ● ● il content pane di default di un oggetto Jframe Jpanel: può contenere un altro Jpanel in modo da organizzare l'interfaccia in modo gerarchico. all'interno di un Jpanel possono essere posizionati componenti elementari (bottoni, text areas,...) JPanel annidati Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci JAVA LAYOUTS ● i componenti aggiunti ad un contenitore (ad esempio un JPanel) devono essere posizionati all'interno di esso: ● ● ● diversi layout definiti per default (FlowLayout, BorderLayout,, GridLayout) possibile anche creare nuovi layout Layout manager: oggetto associato ad un contenitore che implementa qualche strategia per il posizionamento dei componenti. ● per associare un layout ad un contenitore Cont : Cont.setLayout(....), parametro un oggetto di tipo LayoutManager ● per aggiungere un componente ad un contenitore Cont: Cont.add(....), parametri: coomponente da aggiungere + indicazioni (dipendenti dal Layout) su come posizionare quella componente Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci BASIC LAYOUT MANAGER: FLOWLAYOUT Allinea i componenti in righe successive: ● la dimensione di ogni componente è stabilita dal sistema ● quando una riga è riempita, passa ad inserire componenti nella riga successiva ● layout di default per un oggetto JPanel ● può essere impostato mediante il metodo setLayout(). ● costruttore public FlowLayout(int align, int hgap, int vgap) align: allineamento al centro, a sinistra o a destra hgap, vgap: spazio orizzontale e verticale tra le componenti ● Esempio di inserimento di 5 buttons in un FlowLayout Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci BASIC LAYOUT MANAGER: BORDERLAYOUT ● una grande componente centrale e 4 componenti più piccole ai lati della componente centrale ● per aggiungere una componente comp in questo layout associato ad un container comp cntr.add(comp, borderLayoutPosition); Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci BASIC LAYOUT MANAGER: GRIDLAYOUT ● un GridLayout organizza le componenti in una gliglia composta con righe e colonne tutte della stessa dimensione ● una griglia con 4 righe e 3 colonne ● costruttori: new GridLayout(R,C) new GridLayout(R,C,H,V) ● R,C: numero righe e colonne ● H,V: numero di pixel tra righe e colonne Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci COMPONENTI BASE ● componenti standard definiti come sottoclassi della classe JComponent, sottoclasse della classe Component. ● per utilizzare una componente: ● creare la componente ● aggiungere la componente ad un contenitore ● registrare un listener per quella componente che consenta di intercettare gli eventi da essa generati ● componenti standard: ● JButton ● JLabel ● JCheckBox ● JTextField, JTextArea Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci COMPONENTI BASE: JBUTTON ● rappresenta un oggetto selezionabile identificato da una label stopGoButton = new Jbutton("Go") ● diversi metodi per disabilitare il bottone, stabilirne le caratteristiche,... ● quando l'utente clicca sul bottone, il bottone stesso genera un evento di tipo Action-Event. ● Listener: per gestire eventi che vengono generati dai buttons, occorre implementare l'interfaccia ActionListener che contiene un unico metodo: public void actionPerformed(ActionEvent evt) che viene invocato quando viene generato un evento dal bottone Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci COMPONENTI BASE: JLABEL ● Jlabel: un semplice componente utilizzata per visualizzare una linea di testo, impostata nel costruttore ● non cliccabile (a differenza di Jbutton) ● il testo non può essere editato dall'utente, solo impostato da programma JLabel message = new JLabel("Hello World!", JLabel.CENTER); message.setForeground(Color.RED); // Display red text... message.setBackground(Color.BLACK); // on a black background... message.setFont(new Font("Serif",Font.BOLD,18)); // in a big bold font. message.setOpaque(true); // Make sure background is filled in. JPanel jp = new JPanel(); jp.add(message); JFrame window = new JFrame("GUI Test"); window.setContentPane(jp); window.setVisible(true); }} Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci COMPONENTI BASE: JTEXTFIELD E JTEXTAREA ● JTextField e JTextArea: rappresentano componenti che possono contenere testo editabile ● JTextField può contenere una singola linea di testo ● JtextArea può contenere più di una linea di testo JPanel jp1 = new JPanel(); JTextField inputArea = new JTextField("0",10); inputArea.setEditable(true); jp1.add(inputArea); JFrame window = new JFrame("GUI Test"); window.setContentPane(jp1); window.setSize(800,600); window.setLocation(100,100); window.setVisible(true); Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci GOSSIP (PROGETTO 2014): L'INTERFACCIA import java.awt.*; import javax.swing.*; public class GossipInterface extends JFrame { public GossipInterface( ) { setTitle("GOSSIP"); setSize(1000,800); JPanel panel1= new JPanel(); panel1.setLayout(null); } public static void main (String args[ ]) { GossipInterface gi = new GossipInterface( ); gi.setVisible(true); } } con setLayout(null) il posizionamento delle componenti è a carico dell'utente. Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci GOSSIP (PROGETTO 2014): L'INTERFACCIA Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci GOSSIP (PROGETTO 2014): L'INTERFACCIA JLabel statusLabel = new JLabel("Stato"); statusLabel.setBounds(100,20,30,30); panel1.add(statusLabel); public void setBounds(int x,int y,int width,int height) • ereditato dalla classe awt.component • stabilisce la locazione del componente all'interno del pannello e la dimensione del componente x 0,0 y Parametri • x,y - individuano la posizione del vertice superiore sinistro in un sistema di assi cartesiani orientati nel modo seguente • width, height - individuano ampiezza ed altezza del componente Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci GOSSIP (PROGETTO 2014): L'INTERFACCIA JTextArea statusArea = new JTextArea( ); statusArea.setEditable(true); JScrollPane scrollPaneStatus = new JScrollPane(statusArea); scrollPaneStatus.setBounds(30,50,200,400); panel1.add(scrollPaneStatus); statusArea.append("jack online\n"); statusArea.append("john offline\n"); statusArea.append("laura online\n"); statusArea.append("paolo offline\n"); • SetEditable – proprietà che consente di specificare se l'area di testo può essere editata o meno dall'utente • JScrollPane – aggiunge barre di scorrimento all'area ● metodo append: consente di aggiungere linee di caratteri ad una text area. Le linee sono separate da un carattere di new line \n Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci GOSSIP (PROGETTO 2014): L'INTERFACCIA JLabel statusMsg = new JLabel("Messaggi"); statusMsg.setBounds(380,20,80,30); panel1.add(statusMsg); JTextArea printArea= new JTextArea(); printArea.setEditable(true); JScrollPane scrollPane = new JScrollPane(printArea); scrollPane.setBounds(320,50,200,400); panel1.add(scrollPane); printArea.append("ciao, ciao sono jack, come stai?"); Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci GOSSIP (PROGETTO 2014): L'INTERFACCIA JLabel inputLabel = new JLabel("Scrivi"); inputLabel.setBounds(30,480,100,100); panel1.add(inputLabel); JTextField InputArea = new JTextField(); InputArea.setBounds(30,550,600,30); InputArea.setEditable(true); panel1.add(InputArea); • JTextField = campo di testo, si può leggere il valore inserito in questo campo dall'utente Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci GOSSIP (PROGETTO 2014): L'INTERFACCIA JButton invia = new JButton("invia"); invia.setEnabled(true); invia.setBounds(690,550,80,30); panel1.add(invia); • JButton E' un pulsante che l'utente preme per lanciare una specifica azione • nel nostro caso l'azione corrisponde all'invio del testo editato nell'area JtextField • al costruttore viene passata la stringa che rappresenta il testo visualizzto sul pulsante Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci GOSSIP (PROGETTO 2014): L'INTERFACCIA JButton chiudi = new JButton("chiudi"); chiudi.setEnabled(true); chiudi.setBounds(30,600,80,30); panel1.add(chiudi); getContentPane().add(panel1); • questo pulsante è utilizzato per chiudere l'applicazione • infine il pannello creato viene aggiunto al JFrame (la finestra) mediante la funzione getContentPane(). Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci JAVA GUI: GESTIONE DEGLI EVENTI • Quando un utente esegue qualche operazione sulle componenti inserite in una finestra viene generato un evento asincrono. • Alcuni esempi di eventi: • ● digitazione di un tasto ● spostamento del mouse ● click di un pulsante del mouse ● selezione di un elemento dell'intefaccia grafica (es: un bottone) ● chiusura della finestra Il gestore delle finestre invia una segnalazione al programma identificando l'evento mediante un codice Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci JAVA GUI: GESTIONE DEGLI EVENTI • l'applicazione deve definire un gestore di eventi, un Listener, per ogni evento che interessa gestire • JAVA definisce interfacce diverse per ogni essere generato dall'interfaccia • ● KeyListener ● MouseListener ● WindowListener ● ActionListener, ● .... tipo di evento che può il gestore degli eventi viene definito mediante una implementazione di questa interfaccia Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci JAVA GUI: GESTIONE DEGLI EVENTI • consideriamo GOSSIP, l'applicazione descritta nel progetto 2014, che implementava una chat con consegna di messaggi a proxy nel caso gli utenti non siano online • è necessario definire un insieme di pulsanti per interagire con l'applicazione, ad esempio il tasto invia, che consente di inviare un messaggio, o quello che consente di chiudere una finestra • gli eventi interessanti per l'applicazione sono quelli legati alla selezione di questi bottoni • deve essere utilizzata l'interfaccia: public interface ActionListener { void actionPerformed (actionEvent event); • } compito del programmatore è implementare il metodo actionPerformed, in modo che esegua il codice da eseguire quando viene selezionato il pulsante Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci GESTIONE DEGLI EVENTI: UN ESEMPIO consideriamo la seguente interfaccia: quando viene selezionato il bottone, l'applicazione stampa a linea di comando il messaggio “I was clicked” Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci GESTIONE DEGLI EVENTI: UN ESEMPIO import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class ClickListener implements ActionListener { public void actionPerformed(ActionEvent event) { System.out.println("I was clicked"); } il parametro event contiene ulteriori dettagli sull'evento, ad esempio l'istante in cui esso è avvenuto Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci GESTIONE DEGLI EVENTI: UN ESEMPIO import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; public class interfaceevents{ private static final int FRAME_WIDTH = 700; private static final int FRAME_HEIGHT = 500; public static void main(String args[]) { JFrame frame = new JFrame(); JButton button = new JButton("click me!!!"); frame.add(button); Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci GESTIONE DEGLI EVENTI: UN ESEMPIO ActionListener listener = new ClickListener(); button.addActionListener(listener); frame.setSize(FRAME_WIDTH,FRAME_HEIGHT); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci UN CONTATORE DI 'CLICKS' modifichiamo il programma precedente in modo che, ogni volta che viene selezionato il bottone, venga visualizzato il numero di volte che il pulsante è stato selezionato fino a quel momento Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci UN CONTATORE DI 'CLICKS' import javax.swing.*; import java.awt.*; import java.awt.event.*; public class swingexample extends JFrame { private static String labelPrefix = "Number of clicks: "; private int numClicks = 0; JLabel label = null; JButton button = null; Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci UN CONTATORE DI CLICKS public swingexample() { label = new JLabel(labelPrefix + "0 "); button = new JButton("Click me!"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { numClicks++; label.setText(labelPrefix + numClicks); } }; Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci UN CONTATORE DI CLICKS Container panel = getContentPane (); panel.setLayout(new GridLayout(2, 1)); panel.add(button); panel.add(label); addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e) { System.exit(0);} } ); setVisible(true); } Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci MINI CALCOLATRICE ● 2 JTextFields dove l'utente può immettere i numeri ● 4 JButtons che l'utente può cliccare per selezionare l'operazione di somma, sottrazione, moltiplicazione o divisione ● 1 Jlabel per visualizzare il risultato della operazione ● 2 event handlers Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci MINI CALCOLATRICE import java.awt.*; import java.awt.event.*; import javax.swing.*; public class SimpleCalculator extends JPanel implements ActionListener { private JTextField xInput, yInput; private JLabel answer; public static void main(String[] args) { JFrame window = new JFrame("Simple Calculator"); SimpleCalculator content = new SimpleCalculator(); window.setContentPane(content); window.pack(); window.setLocation(100,100); window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE ); window.setVisible(true); Dipartimento di Informatica Università degli Studi di Pisa } GUI: Nozioni di Base Laura Ricci MINI CALCOLATRICE ● window.pack(): effettua il resizing della finestra, in modo che le sue dimensioni siano adatte alla dimensione ottimale delle componenti in essa contenute ● funziona correttamente se e solo se la dimensione ottimale dei componenti è determinata automaticamente dal sistema ● ● questo non avviene se si utilizza un container con un null LayoutManager ● se si utilizza null Layout Manager l'utente autonomamente la dimensione dei componenti deve determinare window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE): specifica l'azione da fare al momento della chiusura della finestra ● Jframe.EXIT_ON_CLOSE: quit dell'applicazione ● Jframe.HIDE_ON_CLOSE: nasconde il frame ma l'applicazione rimane attiva ● Jframe.DISPOSE_ON_CLOSE: dispose del frame, applicazione attiva ● Jframe.DO_NOTHING_ON_CLOSE: ignora il click Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci MINI CALCOLATRICE public SimpleCalculator() { setBackground(Color.GRAY); setBorder(BorderFactory.createEmptyBorder(5,5,5,5)) xInput = new JTextField("0", 10); xInput.setBackground(Color.WHITE); yInput = new JTextField("0", 10); yInput.setBackground(Color.WHITE); JPanel xPanel = new JPanel(); xPanel.add( new JLabel(" x = ")); xPanel.add(xInput); JPanel yPanel = new JPanel(); yPanel.add( new JLabel(" y = ")); yPanel.add(yInput); Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci MINI CALCOLATRICE ● setBorder: impostazioni dei bordi del pannello principale ● BorderFactory.createEmptyBorder(5,5,5,5) ● ● i quattro valori definiscono l'ampiezza dei quattro bordi del pannello uso di pannelli annidati: ● un pannello per ogni componente ● i sottopannelli utilizzano il default layout manager, FlowLayout layout manager: in questo modo la Label ed il TextField vengono semplicemente posti uno di fianco all'altro ● i singoli pannelli verrano quindi aggiunti al pannello principale (vedi lucidi successivi) con un opportuno LayoutManager Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci MINI CALCOLATRICE JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new GridLayout(1,4)); JButton plus = new JButton("+"); plus.addActionListener(this); buttonPanel.add(plus); JButton minus = new JButton("-"); minus.addActionListener(this); buttonPanel.add(minus); JButton times = new JButton("*"); times.addActionListener(this); buttonPanel.add(times); JButton divide = new JButton("/"); divide.addActionListener(this); buttonPanel.add(divide); Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci MINI CALCOLATRICE answer = new JLabel("x + y = 0", JLabel.CENTER); answer.setForeground(Color.red); answer.setBackground(Color.white); answer.setOpaque(true); setLayout(new GridLayout(4,1,3,3)); add(xPanel); add(yPanel); add(buttonPanel); add(answer); riferimento implicito a this, cioè al pannello principale ● setLayout: ● utilizzato un GridLayout con quattro righe Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci MINI CALCOLATRICE public void actionPerformed(ActionEvent evt) { double x, y; // The numbers from the input boxes. try { String xStr = xInput.getText(); x = Double.parseDouble(xStr); } catch (NumberFormatException e) { answer.setText("Illegal data for x."); xInput.requestFocusInWindow(); return; } try { String yStr = yInput.getText(); y = Double.parseDouble(yStr); } catch (NumberFormatException e) { answer.setText("Illegal data for y."); yInput.requestFocusInWindow(); return; } Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci MINI CALCOLATRICE String op = evt.getActionCommand(); if (op.equals("+")) answer.setText( "x + y = " + (x+y) ); else if (op.equals("-")) answer.setText( "x - y = " + (x-y) ); else if (op.equals("*")) answer.setText( "x * y = " + (x*y) ); else if (op.equals("/")) { if (y == 0) answer.setText("Can't divide by zero!"); else answer.setText( "x / y = " + (x/y) ); } } } Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci MINI CALCOLATRICE ● poichè abbiamo associato lo stesso Listener ai quattro bottoni (per le quattro operazioni aritmetiche), occorre distinguere quale bottone è stato premuto ● evt.getActionCommand(): ● restituisce la stringa associata al bottone che è stato premuto ● la stringa identifica l'operazione che deve essere eseguita Dipartimento di Informatica Università degli Studi di Pisa GUI: Nozioni di Base Laura Ricci