Swing
Introduzione (Swing vs AWT) Swing Swing sono delle librerie introdotte a partire dalla versione 1.2 del JDK come evoluzione concettuale delle librerie precedenti (Abstract Window Toolkit (AWT)) AWT sono specializzati in relazione alla piattaforma di esecuzione componenti veloci e performanti SWING sono indipendenti dal sistema grafico che e indipendente dalla piattaforma portabili ma meno veloci e performanti
Differenti Look and Feel Settabile tramite alcuni metodi della classe UIManager: 1 static void setlookandfeel(lookandfeel newlookandfeel); 2 static void setlookandfeel(string classname);
Diagramma delle classi di Swing
Diagramma delle classi di Swing: Component Component: rappresenta l astrazione (classe astratta) di un oggetto grafico visualizzabile sullo schermo e che puo interagire con l utente.
Diagramma delle classi di Swing: Container Container: rappresenta un contenitore dove i componenti sono innestati per la visualizzazione e l utilizzo.
Diagramma delle classi di Swing: JComponent JComponent che è il tipo fondamentale di Swing e dalla quale discendono i widget fondamentali di un interfaccia grafica quali pulsanti, campi di testo etc;
Diagramma delle classi di Swing: Window Window rappresenta una finestra top-level senza bordi e barre dei menu, dalla quale discendono le classi Frame e Dialog che rappresentano, principalmente, finestre con titolo e bordi.
Container Container rappresentano aree all interno delle quali inserire i componenti nella GUI (Interfaccia Utente) si dividono in top-level container (JFrame, JApplet, JDialog) almeno uno di essi deve essere presenti per costruire l interfaccia utente altri container, sono numerose classi che servono per particolare utilizzi ma non sono obbligatori
Container Container Ogni gerarchia di contenimento ha un top level container che è composto dai seguenti strati root pane: è il layer principale che gestisce gli altri layer successivi. layered pane: racchiude il content pane e un eventuale barra dei menu e consente di visualizzare i componenti. content pane: consente di inserire e visualizzare gli altri componenti (puo anche contenere la barra dei menu) glass pane: nascosto e posto davanti agli altri layer consente di compiere azioni.
JFrame JFrame appartiene alla classe dei root pane Permette di avere una finestra con titolo, bordi un icona e i pulsanti di riduzione a icona, ingrandimento, ripristino e chiusura. come tutte le classi java e possibile consuntare la relativa javadoc per informazioni sull utilizzo http://docs.oracle. com/javase/7/docs/api/javax/swing/jframe.html
Primo Esempio Utilizzo di JFrame 1 package swing; 2 import javax.swing.jframe; 3 public class SwingJFrame 4 { 5 public static void main(string[] args) 6 { 7 JFrame window = new JFrame(); 8 // decido le dimensioni della finestra 9 window.setsize(500, 600); 10 // rendo visibile la finestra 11 window.setvisible(true); 12 // scelgo che cosa succedera quando si chiudera la finestra 13 window.setdefaultcloseoperation(jframe.exit_on_close); 14 // centro la finestra nello schermo 15 window.setlocationrelativeto(null); 16 } 17 }
Layout È possibile definire la posizione di ciascun container (scomodo). Alternativamente è possibile utilizzare un LayoutManager per gestire il posizionamento degli oggetti.
FlowLayout Semplice layout manager. Componenti su una riga finchè c è spazio, poi a capo. I componenti vengono visualizzati solo se c è spazio a sufficienza.
BorderLayout Area divisa in 5 sotto-aree: PAGE_START PAGE_END LINE_START LINE_END CENTER PAGE_START e PAGE_END occupano tutta la larghezza e riservano l altezza necessaria al componente. LINE_START e LINE_END occupano tutta l altezza restante e la larghezza necessaria al componente. CENTER occupa tutta l area rimasta. Non è necessario usare tutte le aree.
GridLayout Definisce una griglia di elementi. Tutti i componenti devono essere uguali. È possibile stabilire uno spazio tra i componenti.
GridBagLayout Versione evoluta del GridLayout. Più versatile ma anche più complessa da utilizzare. Un componente può espandersi su più celle. Righe e colonne possono non avere la stessa altezza e/o larghezza. Vengono specificati dei vincoli per ciascun componente.
Attributi GridBagConstraint gridx,gridy: posizione del componente (in righe/colonne). gridwidth,gridheight: dimensione del componente (in righe/colonne). fill: come riempire lo spazio aggiuntivo, valori possibili HORIZONTAL, VERTICAL, NONE, BOTH. ipadx, ipady: quanto spazio aggiungere al componente (in pixel). insets: spaziatura tra gli altri componenti (oggetto Insets). anchor: se il componente è più piccolo dello spazio riservato indica come deve essere posizionato. Possibili valori CENTER (default), PAGE_START, PAGE_END, LINE_START, LINE_END, FIRST_LINE_START, FIRST_LINE_END, LAST_LINE_END, LAST_LINE_START. weightx, weighty: servono a distribuire eventuale spazio avanzato su una riga/colonna.
Layout annidati È possibile annidare layout differenti. JPanel fornisce un semplice contenitore.
Bordi È possibile abbellire l interfaccia grafica inserendo dei bordi. I bordi possono essere aggiunti a ciascun componente. È possibile specificarne lo spazio riservato al bordo e l aspetto.
Top-level container JApplet JFrame JDialog
General-purpose container JPanel JSplitPane JScrollPane JTabbedPane
Special-purpose container JLayeredPane JInternalFrame JToolBar
Controlli di base JButtons JMenu JComboBox JSlider JTextField JList
Visualizzatori di informazioni non editabili JLabel JProgressBar settooltiptext(string)
Visualizzatori di informazioni editabili JColorChooser JTable JTree JFileChooser JTextComponent
Recap Finora abbiamo visto come progettare programmaticamente una GUI. Tuttavia non abbiamo ancora trattato come interagire con l interfaccia grafica. Tale interfaccia deve intercettare le azioni dell utente e gestirle opportunamente.
Gestione degli eventi In Swing i vari componenti comunicano per mezzo di eventi. Le tre entità coinvolte in tale processo sono: La sorgente degli eventi. L evento inviato. Il gestore degli eventi.
Event listener Il listener ha il compito di ricevere l evento e processarlo. Un listener deve: Essere associato al componente. Essere informato quando il componente genera un evento del tipo richiesto. Rispondere facendo qualcosa di appropriato. Vi ricorda qualcosa?
Differenti eventi/listener MouseEvent MouseListener/MouseMotionListener KeyEvent KeyListener ItemEvent ItemListener TextEvent TextListener AdjustmentEvent AdjustmentListener ActionEvent ActionListener WindowEvent WindowListener Focus FocusEvent
ActionEvent/ActionListener Serve per ricevere l azione su bottoni, menu, etc. Metodi utili: 1 String getactioncommand(); //Ritorna la command string associata all azione 2 int getmodifiers(); //Ritorna eventuali tasti speciali premuti durante l evento 3 long getwhen(); //Ritorna un timestamp relativo al momento dell evento Listener: 1 void actionperformed(actionevent e);
MouseEvent/MouseListener Serve per ricevere le azioni del mouse. Metodi utili: 1 int getbutton(); //Ritorna i bottoni del mouse che hanno cambiato stato 2 int getclickcount();//ritorna il numero di click associati all evento 3 Point getlocationonscreen(); //Ritorna la posizione (assoluta) dell evento 4 Point getpoint(); //Ritorna la posizione (relativa al componente) dell evento Listener: 1 void mouseclicked(mouseevent e); 2 void mouseentered(mouseevent e); 3 void mouseexited(mouseevent e); 4 void mousepressed(mouseevent e); 5 void mousereleased(mouseevent e);
MouseMotionListener Serve per gestire i movimenti del mouse. Listener: 1 void mousedragged(mouseevent e); 2 void mousemoved(mouseevent e); La classe MouseAdapter fornisce un implementazione vuota di tutti i metodi relativi ad eventi del mouse.
WindowEvent/WindowListener Serve per ricevere gli eventi relativi alle finestre. Listener: 1 void windowactivated(windowevent e); //La finestra viene impostata come attiva 2 void windowclosed(windowevent e); //La finestra viene chiusa 3 void windowclosing(windowevent e);//l utente ha richiesto la chiusura della finestra 4 void windowdeactivated(windowevent e); //La finestra passa in secondo piano 5 void windowdeiconified(windowevent e);//la finestra viene ripristinata 6 void windowiconified(windowevent e); //La finestra viene ridotta a icona 7 void windowopened(windowevent e); //La finestra diventa visibile La classe WindowAdapter fornisce un implementazione vuota di tutti i metodi.
Swing & multithreading In Swing viene utilizzato un paradigma ad eventi. Può essere conveniente gestire gli eventi in un thread separato (perchè?).
Thread possibili Vi sono 3 tipi di thread: Thread iniziale Thread di gestione degli eventi Worker thread
Thread iniziale È il thread che esegue il main. Dopo aver inizializzato l interfaccia grafica, può essere utilizzato per altro.
Event Dispatch Thread (EDT) Tutto il codice per la gestione dell interfaccia grafica viene eseguito dentro l EDT. Esiste una coda di eventi di sistema che raccogli tutti gli eventi generati. L EDT controlla la coda e gestisce un evento alla volta (richiamando gli handler associati). La gestione mediante coda garantisce che venga rispettato un certo ordine nella gestione degli eventi. È importante il fatto che venga azionato un solo evento alla volta, in quanto previene problemi di concorrenza.
Inizializzazione GUI tramite EDT È possibile (e preferibile) creare la GUI attraverso l EDT. Per fare ciò si utilizzi il metodo invokelater della classe SwingUtilities: 1 SwingUtilities.invokeLater(new Runnable() { 2 public void run() { 3 createandshowgui(); 4 } 5 })
Coda degli eventi
Regole di buona progettazione Una buona interfaccia grafica deve essere molto reattiva! I comandi dati dall utente devo essere elaborati immediatamente (no lag!) Gli event handler devono quindi essere veloci, altrimenti un altro evento può restare in coda per lungo tempo. Come fare nel caso di compiti lunghi?
Worker thread Un worker thread viene eseguito dal programmatore per eseguire compiti lunghi in background. Per una migliore interfaccia grafica deve notificare alla GUI i progressi/essere terminato. In Swing è possibile usare un oggetto SwingWorker.
Centrale di polizia Vogliamo realizzare un applicazione per la centrale di polizia. L applicazione è molto semplice ed è composta da solamente 6 bottoni che rappresentano 6 zone della metropoli. Quando si verifica un crimine in una determinata zona uno degli operatori della centrale preme il bottone corrispondente nella sua applicazione. Il bottone della zona X notifica quindi tutte le volanti che si trovano in quella zona. NB: Si vuole disaccoppiare il più possibile logica applicativa e GUI.
Struttura dell applicazione class Volante : modella la volante. class VolanteManager: raccoglie le volanti e offre le funzionalità per segnalare i crimini. class MainPoliceFrame: visualizza la GUI. class AlarmHandler: disaccoppia la GUI dalla logica applicativa. In particolare: Possiede un istanza di VolanteManager. Possiede un istanza della TextArea dove andrà visualizzato il risultato delle segnalazioni.
Bancarella Realizzare un applicazione Java che permette a un produttore di un mercato locale di aggiungere prodotti di prima necessità sulla sua bancarella. Il produttore ha a disposizione un interfaccia grafica con i prodotti da inserire sulla bancarella. Mentre i prodotti vengono inseriti i clienti, desiderosi di prodotti freschi, li consumano. Il produttore può mettere in vendita Pomodoro, Basilico e Patate. L applicazione dovrà quindi: mostrare 3 bottoni per inserire rispettivamente i diversi prodotti sul mercato. mostrare 3 text field con il resoconto del numero di prodotti rimasti sulla bancarella.
Particolarità L applicazione si presta perfettamente come una modifica del problema del produttore-consumatore tipico dei sistemi concorrenti. Si dovrebbe garantire che il consumatore (cliente della bancarella) non compri se non c è niente da comprare, viceversa il produttore non dovrebbe produrre se la bancarella è piena. Non tratteremo questi aspetti ma è uno spunto per chi fosse interessato.
Struttura dell applicazione Bancarella: contiene i prodotti disponibili Cliente: compra i prodotti dalla bancarella GUI, contiene 3 bottoni: ogni bottone genera un evento che corrisponde alla volontà di voler produrre un prodotto. tale evento viene catturato da un opportuno ProduttoreListener ProduttoreListener: si occupa di catturare gli eventi della GUI (che rappresentano la volontà di voler mettere qualcosa sulla bancarella) e esegue.
Dettagli implementativi Come realizzare l interazione bottone/listener? Se uso un unico listener come individuo il bottone corretto? Come aggiorno la gui?
Calcolatrice La calcolatrice dovrà avere sia un interfaccia testuale che un interfaccia grafica. L interfaccia testuale dovrà mostrare il risultato corrente e le possibili operazioni.
Struttura dell applicazione L interfaccia grafica dovrà essere quella di una classica calcolatrice e fornire le stesse operazioni disponibili per l interfaccia testuale. L applicazione è divisa principalmente in 3 classi: Matematica GraphicalUserInterface TextUserInterface La classe Matematica conterrà il valore corrente del risultato (inizializzato a zero), l operazione corrente, e l operando corrente. Le due interfacce potranno essere aggiornate con il risultato corrente e l espressione calcolata. In tal modo la classe Matematica sarà indipendente dal tipo di interfaccia usata.
Dettagli implementativi Come realizzare l interazione bottone/listener? Se uso un unico listener come individuo il bottone corretto? Come aggiorno la gui?