ASD: Sistemi Distribuiti (Prof. Scarano) 11/06/2002 ASD: Sistemi Distribuiti. Vi.ttorio Scarano Organizzazione della lezione 16. Java: Swing Vittorio Scarano Algoritmi e Strutture Dati: Sistemi Distribuiti Corso di Laurea in Informatica Università degli Studi di Salerno • La programmazione grafica con Swing e AWT • Un primo approccio con Swing: frame e pannelli • Gli eventi dell’ambiente grafico – i listener (rilevatori di evento) – modifica del Look-and-feel – adapter a interfacce • Lo schema di progettazione di Swing • I gestori di layout • Campi di testo 2 Programmazione grafica Alcuni problemi di AWT • Il minimo comune denominatore” – interfaccia intuitiva e gradevole – tutti gli applicativi oggigiorno sono grafici – per piattaforme come X/Motif, Macintosh, Windows • In Java 1.0 viene introdotto Abstract Windows Toolkit (AWT) • Principi di AWT: – indipendenza dalla reale rappresentazione grafica attraverso i “peer” ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano • Una necessità: • componenti dipendenti dall’ambiente che gestivano il vero input/output grafico • Alcuni bug su varie piattaforme • Il passo successivo – Netscape progetta la Internet Foundation Classes – che rappresentano finestre in maniera uguale su tutte le piattaforme • La Sun decide di partire da IFC per presentare Swing – che fa parte delle Java Foundation Classes 3 • • • • Swing e AWT Ricca dotazione di interfacce Piattaforma più robusta e testata Minore dipendenza dalla piattaforma di base Risultato coerente su tutte le piattaforme • Di AWT si usano comunque alcune componenti: – gestione eventi, etc. ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano Caratteristiche di Swing 4 – ma possibile programmare l’aspetto (es. alla Windows) • Alcuni (piccoli) problemi: – essendo soluzioni implementate senza i peer saranno più lenti del corrispondente in AWT Swing+ AWT AWT • Di AWT si usano comunque alcune componenti: – gestione eventi, etc. 5 6 1 ASD: Sistemi Distribuiti (Prof. Scarano) 11/06/2002 Un primo passo: creazione di un frame • La programmazione grafica con Swing e AWT • Un primo approccio con Swing: frame e pannelli • Gli eventi dell’ambiente grafico ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano Organizzazione della lezione – i listener (rilevatori di evento) – modifica del Look-and-feel – adapter a interfacce • Lo schema di progettazione di Swing • I gestori di layout • Campi di testo • Una finestra di massimo livello cioè direttamente visualizzata dal Sistema Operativo è detta frame • La classe di AWT si chiama Frame, quella di Swing si chiama JFrame (notare la doppia maiuscola) • Fondamentale la ereditarietà: – tutti i nostri componenti grafici devono ereditare da una complessa (ma non necessariamente conosciuta) gerarchia • I frame sono contenitori: – possono contenere altre componenti grafiche 7 La classe SimpleFrame ASD: Sistemi Distribuiti. Vi.ttorio Scarano import javax.swing.*; public class SimpleFrame extends JFrame { public SimpleFrame () { setSize (WIDTH,HEIGHT); } public static final int WIDTH = 300; public static final int HEIGHT= 200; } La classe SimpleFrameTest SimpleFrameTest.java • Import import javax.swing.*; – per la extends • Sottoclasse di JFrame • Costruttore – uso del metodo della classe JFrame per settare la dimensione • Variabili di istanza – solo costanti utilizzate public class SimpleFrameTest { public static void main (String[] args) { SimpleFrame f = new SimpleFrame(); f.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE); f.show(); } } ASD: Sistemi Distribuiti. Vi.ttorio Scarano SimpleFrame.java 8 • Semplice programma di test • Crea un frame • Setta alcune caratteristiche – termina il programma quando il frame viene chiuso • Mostra il frame 9 Alcune caratteristiche di un frame 10 La classe CenteredFrame CenteredFrame.java – la posizione – il titolo – la icona (in alto a sinistra a sulla barra) ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano • Tra le tante caratteristiche ereditate da JFrame • Nel prossimo esempio: – vogliamo creare un frame al centro dello schermo • abbiamo bisogno di Toolkit per prelevare la dimensione corrente dello schermo – scegliendo il titolo e la icona 11 import java.awt.*; import java.awt.event.*; import javax.swing.*; public class CenteredFrame extends JFrame { public CenteredFrame () { Toolkit kit = Toolkit.getDefaultToolkit(); Dimension screenSize= kit.getScreenSize(); int screenHeight=screenSize.height; int screenWidth=screenSize.width; setSize (screenWidth/2,screenHeight/2); setLocation (screenWidth/4, screenHeight/4); Image img = kit.getImage("icon.gif"); setIconImage(img); setTitle("Centered Frame"); } } • Import – per extends e Toolkit • Uso di Toolkit – prelevare le dimensioni dello schermo • Set dimensione • Set locazione • Set immagine della icona del frame • Set titolo 12 2 ASD: Sistemi Distribuiti (Prof. Scarano) 11/06/2002 La classe CenteredFrameTest ASD: Sistemi Distribuiti. Vi.ttorio Scarano import javax.swing.*; public class CenteredFrameTest { public static void main (String[] args) { CenteredFrame f = new CenteredFrame(); f.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE); f.show(); } Usiamo i Frame come contenitori • Semplice programma di test • Crea un frame • Setta alcune caratteristiche • Possiamo aggiungere dei componenti ai Frame • Ricca disponibilità: ASD: Sistemi Distribuiti. Vi.ttorio Scarano CenteredFrameTest.java – termina il programma quando il frame viene chiuso • Mostra il frame ASD: Sistemi Distribuiti. Vi.ttorio Scarano import javax.swing.*; import java.awt.*; public class HelloWorldFrame extends JFrame{ public HelloWorldFrame () { setTitle ("Ciao Mondo!"); setSize (300,200); HelloWorldPanel p = new HelloWorldPanel(); Container c = getContentPane(); c.add(p); } } class HelloWorldPanel extends JPanel{ public void paintComponent (Graphics g) { super.paintComponent(g); g.drawString ("Ciao a tutti!", 75,100); } } • che si occupa di ridisegnare la finestra ad ogni spostamento, ridimensionamento, etc import javax.swing.*; import java.awt.*; – per extends • Costruttore: – setta il titolo e la size – crea un Panel • uso classe interna allo stesso file (privata) – preleva il ContentPane del JFrame – aggiunge il pannello p 15 14 public class HelloWorldFrame extends JFrame{ public HelloWorldFrame () { setTitle ("Ciao Mondo!"); setSize (300,200); HelloWorldPanel p = new HelloWorldPanel(); Container c = getContentPane(); c.add(p); } } class HelloWorldPanel extends JPanel{ public void paintComponent (Graphics g) { super.paintComponent(g); g.drawString ("Ciao a tutti!", 75,100); } } • Classe interna: – di uso privato di HelloWorldFrame • Override del metodo – con chiamata al metodo della superclasse – e aggiunta di una stampa di una stringa 16 La visualizzazione di immagini • Semplice programma di test • Crea un frame • Setta alcune caratteristiche ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano import javax.swing.*; import java.awt.*; public class HelloWorldTest { public static void main ( String[] args) { HelloWorldFrame f = new HelloWorldFrame(); f.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE); f.show(); } } – offre un metodo paintComponent() dalla superclasse HelloWorldFrame.java • Import La classe HelloWorldTest HelloWorldTest.java • La idea di JPanel: La classe HelloWorldFrame (2) ASD: Sistemi Distribuiti. Vi.ttorio Scarano HelloWorldFrame.java • che è un contenitore ma che può anche essere soggetto all’inserimento di testo, disegni etc. – basta fare override del metodo senza dimenticare di richiamare il metodo della superclasse 13 La classe HelloWorldFrame (1) – tra gli altri JPanel – termina il programma quando il frame viene chiuso • Mostra il frame 17 • Si usano metodi per caricare una immagine e per visualizzarla su un pannello • Alcuni commenti: – le immagini possono essere caricate da URL (e quindi da Internet) con estrema facilità – lentezza nel caricamento • nel primo esempio lo ignoriamo e poi vediamo come può essere risolto 18 3 ASD: Sistemi Distribuiti (Prof. Scarano) 11/06/2002 La classe ImageFrame (1) import javax.swing.*; import java.awt.*; import java.awt.event.*; public class ImageFrame extends JFrame{ public ImageFrame () { setTitle ("Eccomi..."); setSize (800,700); ImagePanel p = new ImagePanel(); Container c = getContentPane(); c.add(p); } } class ImagePanel extends JPanel{ //…. continua La classe ImageFrame (2) ImageFrame.java • Import – per extends • Costruttore: – setta il titolo e la size – crea un Panel • uso classe interna allo stesso file (privata) – preleva il ContentPane del JFrame – aggiunge il pannello p ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano ImageFrame.java // … continua class ImagePanel extends JPanel{ public ImagePanel () { image = Toolkit.getDefaultToolkit(). getImage("foto.gif"); } public void paintComponent (Graphics g) { super.paintComponent(g); g.drawImage ( image, 75,100, null); } private Image image; } • Variabile istanza di ImagePanel – per la immagine • Costruttore: – carica la foto.gif • L’override di paintComponent – traccia la immagine 19 La classe ImageTest import javax.swing.*; import java.awt.*; public class ImageTest { public static void main ( String[] args) { ImageFrame f = new ImageFrame(); f.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE); f.show(); } } Il problema del caricamento • Semplice programma di test • Crea un frame • Setta alcune caratteristiche • Il caricamento della immagine viene effettuato mediante un thread ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano ImageTest.java 20 – termina il programma quando il frame viene chiuso • Mostra il frame – eseguito in maniera asincrona: • il programma continua mentre viene caricata l’immagine – questo per immagini grandi oppure immagini che vanno caricate da rete non è corretto • Si deve fare in modo di fare “aspettare” nel costruttore di ImagePanel l’effettivo caricamento • Ecco come si fa: 21 ASD: Sistemi Distribuiti. Vi.ttorio Scarano ImageFrame.java // …resto del file (classe ImageFrame) identico class ImagePanel extends JPanel{ public ImagePanel () { image = Toolkit.getDefaultToolkit(). getImage("foto.gif"); MediaTracker t = new MediaTracker(this); t.addImage(image,1); // id immagine try {t.waitForID(1); } catch (InterruptedException e) {} } public void paintComponent (Graphics g) { super.paintComponent(g); g.drawImage ( image, 75,100, null); } private Image image; } Organizzazione della lezione • Si definisce un oggetto che traccia il caricamento della immagine • Si aggiunge l’immagine • Si aspetta il caricamento effettuato della immagine con ID 1 23 ASD: Sistemi Distribuiti. Vi.ttorio Scarano La classe (modificata) ImagePanel 22 • La programmazione grafica con Swing e AWT • Un primo approccio con Swing: frame e pannelli • Gli eventi dell’ambiente grafico – i listener (rilevatori di evento) – modifica del Look-and-feel – adapter a interfacce • Lo schema di progettazione di Swing • I gestori di layout • Campi di testo 24 4 ASD: Sistemi Distribuiti (Prof. Scarano) 11/06/2002 La interazione in un ambiente grafico Due approcci estremi • L’approccio alla VisualBasic ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano • Un ambiente grafico deve garantire la interazione con gli utenti – rispondere ai click dell’utente in maniera “sensata” • un click può: – – – – essere ignorato selezionare una voce da un menù attivare un bottone iniziare una azione di drag and drop – rispondere alla pressione di tasti della tastiera • scrivere testo “da qualche parte” sullo schermo • Il sistema operativo monitora l’ambiente e segnala gli eventi ricevuti al programma in esecuzione 25 L’approccio di Java: un compromesso • un pulsante HelpButton ha la azione HelpButton_Click • basta scrivere una procedura con questo nome per farne eseguire il codice in risposta ad una azione dell’utente • L’approccio alla C – necessario scrivere il codice che costantemente controlla una “coda di eventi” per trattarla (mega-switch) – possibile creare nuovi eventi – estremamente complessa 26 Gli oggetti evento • Il programmatore ha il controllo: • In un linguaggio OO come Java, è ovvio che gli eventi siano incapsulati in un oggetto java.util.EventObject • dalle sorgenti (bottoni, barre di scorrimento, etc.) • ai rilevatori (listener) • Il Modello di delega degli eventi – permette di mantenere il pieno controllo e la estendibilità del codice – al prezzo di scrivere (e debuggare) un pochino in più di codice (rispetto, ad esempio, al Visual Basic) ASD: Sistemi Distribuiti. Vi.ttorio Scarano – delle modalità di trasmissione degli eventi ASD: Sistemi Distribuiti. Vi.ttorio Scarano – ogni elemento della interfaccia grafica ha una lista di eventi fissati – con le sue sottoclassi ActionEvent e WindowEvent • Il funzionamento: – (1) un listener è una istanza di una classe che implementi la interface Listener – (2) una sorgente di eventi può registrare oggetti listener – (3) quando si verificano eventi allora la sorgente invia ai listener registrati gli oggetti Event – (4) i listener usano le informazioni nell’oggetto Event per determinare la loro reazione 27 Uno schema di funzionamento Un programma di esempio • Un frame con 3 bottoni: class MyListener implements ActionListener { …. public void actionPerformed (ActionEvent ev) { // la reazione all’evento } } • (2) La registrazione del listener sulla sorgente: ActionListener lis = new MyListener( ); JButton butt = new JButton (“Ok”); butt.addActionListener(lis); • (3) Ogni volta si verifica un evento, allora l’oggetto butt avvisa il listener lis inviando come parametro l’Event • (4) l’oggetto lis allora esegue il metodo actionPerformed() 29 ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano • (1) Il Listener 28 – alla pressione di uno di questi bottoni, il colore di sfondo cambia a seconda del bottone premuto • La struttura delle classi: – nello stesso file: Buttonframe.java • una classe ButtonPanel che contiene i bottoni • una classe ButtonFrame che contiene ButtonPanel • una classe ColorAction che fa il Listener dei bottoni – una classe ButtonTest per il semplice uso di ButtonFrame • Attenzione: esempio lievemente diverso da quello sul libro: • classe ButtonTest in un file separato • non si usano le classi “interne” (classi definite all’interno di altre classi) 30 5 ASD: Sistemi Distribuiti (Prof. Scarano) 11/06/2002 La classe ButtonTest La classe ButtonFrame (1) ButtonTest.java – per usare JFrame • Metodo main public class ButtonTest { public static void main(String[] args) { ButtonFrame frame = new ButtonFrame(); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); frame.show(); } } – crea un frame ButtonFrame – ne setta alcune caratteristiche • termina il programma quando il frame viene chiuso ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano ButtonFrame.java • Import import java.awt.*; import javax.swing.*; – mostra il frame //… continua class ButtonPanel extends JPanel { public ButtonPanel() { JButton yButton = new JButton(“Giallo"); JButton bButton = new JButton("Blu"); JButton rButton = new JButton("Rosso"); add(yButton); add(bButton); add(rButton); ColorAction yAction = new ColorAction( Color.yellow,this); ColorAction bAction = new ColorAction( Color.blue, this); ColorAction rAction = new ColorAction( Color.red, this); yButton.addActionListener(yAction); bButton.addActionListener(bAction); rButton.addActionListener(rAction); } } // fine ButtonPanel… continua • Crea 3 bottoni con etichetta • Aggiungi (add di JPanel) i tre bottoni al pannello • Crea 3 listener – ad ognuno passa il colore e una reference al Panel • Aggiungi un Listener a • Creazione di un ButtonPanel … • … e aggiunta del ButtonPanel al Frame } ButtonFrame.java class ColorAction implements ActionListener { public ColorAction(Color c, JPanel p) { backgroundColor = c; pann = p; } public void actionPerformed( ActionEvent event) { pann.setBackground(backgroundColor); pann.repaint(); } private Color backgroundColor; private JPanel pann; ciascun bottone } 33 Organizzazione della lezione 32 • Implementa la interface ActionListener • Costruttore – 2 parametri • il colore da settare • il pannello di cui cambiare il colore • Il metodo per la esecuzione della azione – set background – forza il repaint del pannello • Variabili di istanza 34 Modifica del look-and-feel • La programmazione grafica con Swing e AWT • Un primo approccio con Swing: frame e pannelli • Gli eventi dell’ambiente grafico ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano – set del titolo – set della dimensione La classe ButtonFrame (3) ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano ButtonFrame.java ButtonPanel panel = new ButtonPanel(); Container contentPane = getContentPane(); contentPane.add(panel); • Import • Costruttore: } // fine della classe ButtonFrame // … continua con le classi ButtonPanel // … e ColorAction 31 La classe ButtonFrame (2) import java.awt.*; import java.awt.event.*; import javax.swing.*; class ButtonFrame extends JFrame { public ButtonFrame() { setTitle("ButtonTest"); setSize(300, 200); – i listener (rilevatori di evento) – modifica del Look-and-feel – adapter a interfacce • Lo schema di progettazione di Swing • I gestori di layout • Campi di testo • La ambientazione grafica (look-and-feel) permette di offrire un ambiente grafico familiare all’utente • Sono disponibili: – Metal (specifico di Swing) – Windows (disponibile solo su Windows) – Mac (disponibile solo su Mac) – Motif (X) • Interessante: – è possibile far cambiare a run-time la ambientazione 35 36 6 ASD: Sistemi Distribuiti (Prof. Scarano) 11/06/2002 La classe PlafTest La classe PlafFrame (1) PlafFrame.java • Standard applicazione di esempio… import java.awt.*; import java.awt.event.*; import javax.swing.*; ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano PlafTest.java public class PlafTest { public static void main(String[] args) { PlafFrame frame = new PlafFrame(); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); frame.show(); } } • Import • Costruttore: import java.awt.*; import java.awt.event.*; import javax.swing.*; class PlafFrame extends JFrame { public PlafFrame() { setTitle("PlafTest"); setSize(300, 200); PlafPanel panel = new PlafPanel(); Container contentPane = getContentPane(); contentPane.add(panel); } } // fine della classe PlafFrame // … continua con le classi PlafPanel // … e LookAction – set del titolo – set della dimensione • Creazione di un PlafPanel … • … e aggiunta del PlafPanel al Frame 37 PlafFrame.java ASD: Sistemi Distribuiti. Vi.ttorio Scarano class PlafPanel extends JPanel { public PlafPanel() { makeButton("Metal", "javax.swing.plaf.metal.MetalLookAndFeel"); makeButton("Motif", "com.sun.java.swing.plaf.motif.MotifLookAndFeel"); La classe PlafFrame (3) • Usa un metodo per creare un bottone e registrare un listener • Argomenti – label bottone – stringa della classe da usare per cambiare look makeButton("Windows", "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } void makeButton(String name, String plafName) { JButton button = new JButton(name); add(button); LookAction l = new LookAction(this, plafName); button.addActionListener(l); } • makeButton() } // fine della classe PlafPanel .. continua … – crea bottone e aggiunge al pannello – crea listener e lo aggiunge PlafFrame.java class LookAction implements ActionListener { public LookAction(JPanel p, String s) { pann = p; look = s; } public void actionPerformed(ActionEvent event) { try { UIManager.setLookAndFeel(look); SwingUtilities.updateComponentTreeUI (pann); } catch(Exception e) { e.printStackTrace(); } } JPanel pann; String look; ASD: Sistemi Distribuiti. Vi.ttorio Scarano La classe PlafFrame (2) 38 } • Costruttore – setta le variabili di istanza: • pannello su cui cambiare look-and-feel • nome del Look da cambiare • Metodo per la azione – usa metodi statici • per cambiare il Look-and-feel • per aggiornare tutte le componenti correnti del pannello – necessario un try..catch • Variabili di istanza 39 Eventi della finestra • La programmazione grafica con Swing e AWT • Un primo approccio con Swing: frame e pannelli • Gli eventi dell’ambiente grafico ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano Organizzazione della lezione 40 – i listener (rilevatori di evento) – modifica del Look-and-feel – adapter a interfacce • Lo schema di progettazione di Swing • I gestori di layout • Campi di testo 41 • Quando la finestra è soggetta a qualche operazione da parte dell’utente, diventa sorgente di un WindowEvent • La interfaccia messa a disposizione per implementare dei listener è WindowListener: • Un problema: • implementare tutti i metodi anche se sono vuoti public interface WindowListener() { void windowOpened(WindowEvent e); void windowClosing(WindowEvent e); void windowClosed(WindowEvent e); void windowIconified(WindowEvent e); void windowDeiconified(WindowEvent e); void windowActivated(WindowEvent e); void windowDeactivated(WindowEvent e); } 42 7 ASD: Sistemi Distribuiti (Prof. Scarano) 11/06/2002 Un semplice “trucchetto”: l’adapter Organizzazione della lezione • Per evitare la implementazione di metodi vuoti: void windowOpened(WindowEvent e) { } ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano .. .. – esiste una classe di nome WindowAdapter che implementa tutti i metodi vuoti – e basta estendere questa classe ( extends non implements) • facendo override dei soli metodi da definire non vuoti! class Terminator extends WindowAdapter { void windowClosed(WindowEvent e) { System.exit(0); } } • La programmazione grafica con Swing e AWT • Un primo approccio con Swing: frame e pannelli • Gli eventi dell’ambiente grafico – i listener (rilevatori di evento) – modifica del Look-and-feel – adapter a interfacce • Lo schema di progettazione di Swing • I gestori di layout • Campi di testo 43 Elementi di una componente di interfaccia 44 Schema model-view-controller • Componenti di interfaccia utente: • Lo schema modello-vista-controller è usato da Swing • Principio guida (della programmazione OO): ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano – bottoni, campo di testo, menù etc. • Tre elementi costitutivi: – il contenuto • lo stato di un pulsante, il testo di un campo di testo, etc. – l’aspetto visivo • colori, dimensioni, font, etc. – il comportamento • reazione agli eventi utente e di altri oggetti – ogni oggetto deve avere un numero limitato di responsabilità (compiti da assolvere) • Questo schema permette, in generale, di separare all’interno della componente grafica – gli aspetti dei dati contenuti, – la rappresentazione grafica – e la loro interazione con l’ambiente circostante 45 Lo schema model-view-controller 46 Alcuni vantaggi dello schema • Memorizzazione dei dati (modello) diversa dalla presentazione (vista) ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano • Ogni componente grafica viene implementata da tre classi: – un modello • che serve a memorizzare il contenuto – per una casella di testo, memorizza la stringa – una vista • che serve a visualizzare il contenuto – per un casella di testo, contiene font, dimensioni, posizione etc. – un controller • che permette la interazione con l’utente – per una casella di testo, permette la modifica, cancellazione del contenuto, etc. 47 – lo stesso file HTML può essere presentato come “preview” (come appare sul browser) oppure come file di testo ASCII (con tutti i tag) • Il controller controlla l’input – e decide se informare il modello (cambia il contenuto) oppure la vista (è cambiata la presentazione) – l’altra componente ignora le informazioni inviate alla componente che deve essere informata 48 8 ASD: Sistemi Distribuiti (Prof. Scarano) 11/06/2002 Swing e lo schema progettuale Un esempio: la classe JButton (1) • Di norma, per ogni componente grafica esiste ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano • Normalmente i programmatori ignorano questo schema: – interagiscono con una classe wrapper (tipo JButton) – le modifiche a JButton vengono da questa inoltrata alla componente modello, vista oppure controller • Si può comunque recuperare il modello da una classe wrapper • Permette di creare ambienti innestabili – una classe modello che implementa una interfaccia – per JButton esiste una interfaccia ButtonModel che viene implementata da una classe DefaultButtonModel • I metodi di ButtonModel – getActionCommand() • stringa di comando della azione associate al bottone – getMnemonic() • scorciatoia da tastiera – isArmed(),is Enabled(), is Pressed(), is Rollover(), isSelected() – riutilizzare componenti cambiandone solamente la vista – a volte possibile a run-time! • se il bottone è stato premuto/abilitato/premuto (mouse è ancora lì)/ mouse è sul pulsante/selezionato (pulsante di scelta) 49 Organizzazione della lezione • E’ possibile recuperare l’oggetto modello della butt = new JButton (“Giallo”); componente: JButton ButtonModel model = button.getModel(); • Ogni componente usa un oggetto vista la cui classe ha un nome che termina con UI (User Interface) – per JButton esiste una classe BasicButtonUI • Alcune componenti usano un oggetto controller dedicato, la cui classe ha nome che termina con UIListener ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano Un esempio: la classe JButton (2) 50 – per JButton esiste una classe ButtonUIListener • La programmazione grafica con Swing e AWT • Un primo approccio con Swing: frame e pannelli • Gli eventi dell’ambiente grafico – i listener (rilevatori di evento) – modifica del Look-and-feel – adapter a interfacce • Lo schema di progettazione di Swing • I gestori di layout • Campi di testo 51 La classe ButtonFrameBorder (1) ButtonFrameBorder.java • Si occupano di implementare una politica di gestione del posizionamento dei componenti sulla finestra • Disponibili una varia gamma di classi ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano Gestori del layout 52 – disponibili da Sun – ma anche da altri produttori di software • Nell’esempio di ButtonFrame: – i pulsanti si trovavano al centro della finestra – e mantenevano la posizione centrale al ridimensionamento della finestra – usa il BorderLayout (di default posiziona al centro) 53 import java.awt.*; import java.awt.event.*; import javax.swing.*; class ButtonFrame extends JFrame { public ButtonFrame() { setTitle("ButtonTest"); setSize(300, 200); ButtonPanel panel = new ButtonPanel(); Container contentPane = getContentPane(); contentPane.add(panel); • Import • Costruttore: – set del titolo – set della dimensione • Creazione di un ButtonPanel … • … e aggiunta del ButtonPanel al Frame } } // fine della classe ButtonFrame // … continua con le classi ButtonPanel // … e ColorAction 54 9 ASD: Sistemi Distribuiti (Prof. Scarano) 11/06/2002 La classe ButtonFrame (2) con il Un altro Layout Manager: BorderLayout FlowLayout //… continua class ButtonPanel extends JPanel { public ButtonPanel() { setLayout (new FlowLayout(FlowLayout.RIGHT)); JButton yButton = new JButton(“Giallo"); JButton bButton = new JButton("Blu"); JButton rButton = new JButton("Rosso"); add(yButton); add(bButton); add(rButton); ColorAction yAction = new ColorAction( Color.yellow,this); ColorAction bAction = new ColorAction( Color.blue, this); ColorAction rAction = new ColorAction( Color.red, this); …… • Seleziona come gestore del Layout un oggetto FlowLayout • Permette di definire con più precisione la posizione • Divide la finestra in: – che viene creato passando una costante definita nella classe – che posizione a destra i pulsanti – altra scelta LEFT e CENTER ButtonFrameBorder.java – il Giallo a nord – il blu a est – il rosso a sud • Cosa accade? 57 La soluzione: un Panel che contiene i pulsanti JPanel cont = new JPanel(); cont.add(yellowButton); cont.add(blueButton); cont.add(redButton); add(cont, BorderLayout.SOUTH); …. • Seleziona come gestore del Layout un oggetto BorderLayout • Crea 3 bottoni • Crea un Pannello – al quale aggiunge i tre pulsanti – con il gestore di layout standard (BorderLayout) • Poi aggiunge il pannello a sud 56 //… continua class ButtonPanel extends JPanel { public ButtonPanel() { setLayout (new BorderLayout()); JButton yButton = new JButton(“Giallo"); JButton bButton = new JButton("Blu"); JButton rButton = new JButton("Rosso"); add(yButton, BorderLayout.SOUTH); add(bButton, BorderLayout.SOUTH); add(rButton, BorderLayout.SOUTH); …… • Si usa BorderLayout() • Posizioniamo: – tutti i pulsanti a sud • Cosa accade? • Solo un componente può essere inserito a sud: • l’ultimo sostituisce il precedente • Come si fa? 58 Organizzazione della lezione 59 ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano //… continua class ButtonPanel extends JPanel { public ButtonPanel() { setLayout (new BorderLayout()); JButton yellowButton = new JButton("Giallo"); JButton blueButton = new JButton("Blu"); JButton redButton = new JButton("Rosso"); South E se mettiamo tutti e tre i pulsanti a Sud? • Si usa BorderLayout() • Posizioniamo: ButtonFrameBorder.java West Center East – di default su JFrame (inserimento al centro) ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano //… continua class ButtonPanel extends JPanel { public ButtonPanel() { setLayout (new BorderLayout()); JButton yButton = new JButton(“Giallo"); JButton bButton = new JButton("Blu"); JButton rButton = new JButton("Rosso"); add(yButton, BorderLayout.NORTH); add(bButton, BorderLayout.EAST); add(rButton, BorderLayout.SOUTH); …… North • Ridimensiona i componenti in modo che riempiano tutto lo spazio disponibile 55 Cosa accade se usiamo BorderLayout()? ButtonFrameBorder.java ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano ButtonFrameBorder.java • La programmazione grafica con Swing e AWT • Un primo approccio con Swing: frame e pannelli • Gli eventi dell’ambiente grafico – i listener (rilevatori di evento) – modifica del Look-and-feel – adapter a interfacce • Lo schema di progettazione di Swing • I gestori di layout • Campi di testo 60 10 ASD: Sistemi Distribuiti (Prof. Scarano) 11/06/2002 Componenti per input di testo Listener per campi di testo • Due componenti: • Implementa la interfaccia DocumentListener con i metodi: ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano – JTextField per l’input di un rigo di testo – JTextArea per l’input di una area di testo (più righi) • Entrambe derivano dalla classe astratta JTextComponent – che contiene la maggior parte dei metodi tra cui: • void setText (String t) – modifica il testo della componente • String getText() – restituisce il testo della componente • void setEditable (boolean b) – può essere modificata oppure no TextTest.java – in uno scriviamo il nome – nell’altro (non editabile) compare “Ciao…” • Necessario (a parte la classe TextTest) – una classe TextFrame che • crea due oggetti JTextField • setta il listener di uno dei due (quello di input) a TextListener a cui passa le reference dei due campi • setta l’altro JTextField a non editabile – una classe TextListener ASD: Sistemi Distribuiti. Vi.ttorio Scarano import java.awt.*; import javax.swing.*; 62 public class TextTest { public static void main(String[] args) { TextFrame frame = new TextFrame(); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); frame.show(); } } • Import – per usare JFrame • Metodo main – crea un frame TextFrame – ne setta alcune caratteristiche • termina il programma quando il frame viene chiuso – mostra il frame 63 La classe TextFrame (1) 64 La classe TextFrame (2) • • • • Import Costruttore: (continua) Creazione di un JPanel Creazione di due JTextField – il secondo non editabile • Aggiunta del listener a nome – passando nome e saluto 65 TextFrame.java ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano • Per aggiungere un listener ad un campo si usa: La classe TextTest • nel costruttore prende due variabili di reference JTextField • quando il testo sul primo campo cambia, scrive la stringa sul secondo ASD: Sistemi Distribuiti. Vi.ttorio Scarano – si devono esplicitamente implementare i 3 metodi anche se servono vuoti JTextField nome = new JTextField(30); TextListener lis = new TextListener(); nome.getDocument().addDocumentListener(lis); • Una finestra che contenga due campi di testo: import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; class TextFrame extends JFrame { public TextFrame() { setTitle("Test sul Testo"); setSize(300, 200); Container contentPane = getContentPane(); JPanel pan = new JPanel (); JTextField nome = new JTextField(30); JTextField saluto = new JTextField(40); saluto.setEditable (false); TextListener lis = new TextListener( nome,saluto); nome.getDocument().addDocumentListener( lis); // … continua la classe TextFrame • Sfortunamente nessuna classe adapter è disponibile: 61 Un esempio di uso TextFrame.java – void insertUpdate (DocumentEvent e) { } – void removeUpdate (DocumentEvent e) { } – void changedUpdate (DocumentEvent e) { } //… // continua il costruttore di TextFrame contentPane.add(nome, BorderLayout.NORTH); contentPane.add(saluto, BorderLayout.SOUTH); } } • Aggiunge i due campi di testo al Container – uno a nord – l’altro a sud • Attenzione: – il layout manager di default di JFrame è BorderLayout // fine classe TextFrame // continua con la classe TextListener 66 11 ASD: Sistemi Distribuiti (Prof. Scarano) 11/06/2002 La classe TextFrame (3) class TextListener implements DocumentListener { public TextListener (JTextField n,JTextField s) { nome = n; saluto = s; } public void insertUpdate(DocumentEvent e) {saluto.setText("Ciao " + nome.getText());} public void removeUpdate(DocumentEvent e) {saluto.setText("Ciao " + nome.getText());} public void changedUpdate(DocumentEvent e) {saluto.setText("Ciao " + nome.getText());} JTextField nome; JTextField saluto; } Un esempio “reale”: conversione lire/euro • Implementa • Due campi di testo: DocumentListener • Costruttore – assegna i due campi di testo passati • Tre metodi per gli eventi di cui è “in ascolto” – settano il testo di saluto a seconda del contenuto di nome ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano TextFrame.java – uno (editabile) in cui si inseriscono il valore in lire – uno (non editabile) in cui viene scritto il corrispettivo in euro • Struttura simile al programma precedente: – Calculator (che istanzia CalculatorFrame) – CalculatorFrame (che istanzia i campi di testo ed usa TextListener per le modifiche al campo) – TextListener (che implementa i metodi per le modifiche al valore in lire e il calcolo del valore in euro) 67 La classe Calculator ASD: Sistemi Distribuiti. Vi.ttorio Scarano import java.awt.*; import javax.swing.*; public class Calculator { public static void main(String[] args) { CalculatorFrame frame = new CalculatorFrame(); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); frame.show(); } } La classe CalculatorFrame CalculatorFrame.java • Import – per usare JFrame • Metodo main – crea un frame CalculatorFrame – ne setta alcune caratteristiche • termina il programma quando il frame viene chiuso ASD: Sistemi Distribuiti. Vi.ttorio Scarano Calculator.java 68 // soliti import!! :-) class CalculatorFrame extends JFrame { public CalculatorFrame() { setTitle("Euroconvertitore"); setSize(100, 100); Container contentPane = getContentPane(); JPanel pan = new JPanel (); JTextField v = new JTextField(10); JTextField r=new JTextField(10); r.setEditable (false); TextListener lis = new TextListener(v,r); v.getDocument().addDocumentListener(lis); contentPane.add(v, BorderLayout.NORTH); contentPane.add(r, BorderLayout.SOUTH); – mostra il frame • • • • Import Costruttore: Creazione di un JPanel Creazione di due JTextField – il secondo non editabile • Aggiunta del listener a v – passando v e r } } 69 La classe TextListener (1) import java.util.*; import java.text.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; class TextListener implements DocumentListener { public TextListener (JTextField v, JTextField r) { valuta = v; risultato = r; } La classe TextListener (2) TextListener.java • Import • Implementa DocumentListener • Costruttore – assegna i due campi passati alle due variabili di istanza (definite nel seguito) // continua 71 ASD: Sistemi Distribuiti. Vi.ttorio Scarano ASD: Sistemi Distribuiti. Vi.ttorio Scarano TextListener.java 70 // continua… public void insertUpdate(DocumentEvent e) { int lire; try { lire = Integer.parseInt(valuta.getText()); } catch (NumberFormatException g) {lire = -1;} double euro = lire / 1936.27; if (lire >= 0) { NumberFormat fmt = NumberFormat.getNumberInstance(); fmt.setMaximumFractionDigits(2); risultato.setText(fmt.format(euro)); } else risultato.setText(ERRORE); } // identici removeUpdate e changedUpdate // continua • Prova a convertire la stringa in un intero • altrimenti lire è negativo • Converte in euro • Se il valore in lire era valido: – converte arrotondando alla seconda cifra decimale • altrimenti stampa una stringa di errore 72 12 ASD: Sistemi Distribuiti (Prof. Scarano) 11/06/2002 Cosa altro può fare Swing per me? (1) ASD: Sistemi Distribuiti. Vi.ttorio Scarano TextListener.java • Variabili di istanza per contenere i riferimenti per i due campi di testo • La stringa di errore (costante) // continua… JTextField valuta; JTextField risultato; final String ERRORE = "Valore errato"; } // fine classe TextListener ASD: Sistemi Distribuiti. Vi.ttorio Scarano La classe TextListener (3) Dialog SplitPane Frame Panel TabbedPane Toolbar InternalFrame LayeredPane 73 ScrollPane Buttons 74 ASD: Sistemi Distribuiti. Vi.ttorio Scarano Cosa altro può fare Swing per me? (2) Combo Box List Menu Slider Text Fields Color Chooser Progress Bar Label Text Tool tip File Chooser Tree Table 75 13