LINGUAGGI E TRADUTTORI RELAZIONE N° 5 QUIETI FABIO Descrizione del problema Questa esperienza riguarda la grafica in java, ovvero lo studio del package grafico swing. In particolare si vogliono creare due finestre, simili, infatti la seconda deriva dalla prima con l’aggiunta di qualche elemento. Analisi La prima finestra che si vuole creare deve essere centrata nello schermo e di dimensioni fisse; deve avere una crocetta al centro (10x10) e un bottone in basso al centro, che verrà chiamato Quit e premendo il quale la finestra si chiude. Nella seconda finestra si aggiungono alla prima quattro pulsanti in basso a sinistra (Up, Down, Left e Right, spostando Quit a destra), premendo i quali la crocetta si deve spostare, nella direzione corrispondente al tasto premuto, di un intervallo di griglia, che verrà visualizzato in alto e che può essere settato da tastiera. Progetto La prima finestra che si vuole creare è definita nella classe Window1 che è un componente software, infatti contiene il main. Come in tutte le classi che si definiranno in questa esperienza si devono importare i package awt, swing e awt.event, quest’ultimo solo se si devono definire dei componenti attivi che generano eventi, come nel caso del bottone quit premendo il quale si deve chiudere la finestra. In questo main di Window1 si definisce e si crea subito il JFrame f dandogli come titolo proprio Window1. Quindi si definiscono posizione del vertice alto sinistro e dimensioni di f con il metodo setBounds. Creato il JFrame opportuno viene richiamato il suo container, c, con il metodo getContentPane. Infatti è al container che va aggiunto il pannello sul quale disegnare e al quale aggiungere i nostri componenti. Quindi si crea un nuovo oggetto JPanel p e si setta il suo layout come BorderLayout. Questo verra aggiunto a c alla fine con il comando add. Al JPanel p vengono aggiunti due pannelli: il primo (panel) è un oggetto MyPanel di una nuova classe che estende JPanel, che viene aggiunto con un BorderLayout.CENTER, quindi centrato nel JFrame; il secondo (pbutt) è un Jpanel che viene aggiunto a p con un BoederLayout.SOUTH, quindi nella parte bassa del JFrame. A pbutt viene aggiunto inoltre q, un oggetto MyButton che è una classe che estende JButton. Infine viene aggiunto al frame f WindowListener per gestire la chiusura e l’uscita dall’applicazione della finestra con la classe Terminator nella quale viene definito il metodo WindowClosing con System.exit(0). Nella classe MyPanel troviamo la ridefinizione di paintComponent che mi permette di disegnare il pannello grazie alle istruzioni passate al Graphics g. Si hanno due drawLine per disegnare la crocetta con le coordinate opportune in modo che sia centrata e 10x10 pixel. Inoltre vi è il comando setBackground(Color.white) che mi definisce il colore dello sfondo bianco. L’altra classe MyButton è quella che mi definisce Quit. Questa classe oltre che estendere JPanel deve implementare anche ActionListener in quanto vi è un evento generato da Quit. Troviamo il costruttore nel quale viene creato il JButton b con etichetta “Quit”, e il quale è ascoltatore degli eventi da esso stesso generati con il comando b.addActionListener(this). Il this indica appunto che è il bottone b stesso che registra gli eventi. Quindi viene aggiunto il JButton b con la solita add. Inoltre vi è un metodo che gestice l’evento ovvero actionPerformed; questo metodo è definito da System.exit(0) in quanto con la pressione del tasto Quit si voleva chiudere la finestra. La classe Window2 è quella che definisce la seconda finestra; rispetto al main di Window1 troviamo in più: tpanel, un oggetto TextPanel che è sempre una nuova classe derivata da JPanel. Questo viene aggiunto al pannello principale p con BorderLayout.NORTH; sarà il pannello che mi definisce la griglia modificabile da tastiera. Il pannello della zona centrale è cambiato e viene definito nella nuova classe NewPanel. Quindi notiamo che il pannello pbutt viene settato con BorderLayout: infatti gli vengono aggiunti il Mybutton q con BorderLayout.EAST e un ButtonPanel (bpanel) con BorderLayout.WEST. La nuova classe ButtonPanel sarà quella che mi definisce i nuovi quattro tasti. La classe TextPanel estende JPanel e implementa ActionListener in quanto si registra il cambiamento del valore della griglia con la pressione del tasto invio. Vi è il costruttore nel quale viene creata la JLabel l “Griglia” e aggiunta con add; quindi viene creato il campo di testo editabile JTextField text di lunghezza 5, il quale è anche l’ascoltatore degli eventi da esso generati (text.addActionListener(this)), infine viene aggiunto anche text. Vi è poi un primo metodo che è il solito actionPerformed nel quale il valore di text, ottenuto con getText( ), viene convertito in intero e assegnato alla variabile D, che verrà utilizzata per definire gli eventi dei nuovi tasti. L’ultimo metodo (getD( )) serve proprio per avere il valore settato della griglia, infatti restituisce un intero ed è definito da return D. Anche la nuova classe ButtonPanel estende JPanel e implementa ActionListener. Il costruttore ha due parametri: un NewPanel e un TextPanel. Chiaramente quelli passati in Window2 sono quelli che si sono definiti e creati. Nel costruttore troviamo la creazione dei quattro JButton (up, down, left, right) ognuno con la propria etichetta; quindi ognuno è anche definito come ascoltatore dei propri eventi e infine vengono tutti aggiunti. Quindi troviamo il solito metodo che gestisce gli eventi actionPerformed: viene assegnato all’oggetto pushedbutton il tasto premuto con e.getSource ( ), dove e è l’evento; quindi con degli if viene controllato quale tasto è stato premuto uguagliando pushedbutton ad up, a down, ecc. Per ogni tasto viene controllato che la crocetta non esca dalla finestra sommando o aggiungendo il valore di D (ottenuto con getD) al valore corrente delle variabili x o y. Se così fosse viene bloccato il valore della variabile corrispondente (x o y), altrimenti viene aggiornato il valore stesso. Infine troviamo due metodi (getx( ) e gety( )) che mi danno i valori delle corrispondenti variabili per poter dare le coordinate per ridisegnare la crocetta. L’ultima classe che estende JPanel è NewPanel; in questa troviamo sempre la ridefinizione di paintComponent come in MyPanel. Viene sempre settato il colore dello sfondo bianco e vi sono quindi due drawLine, dove però le coordinate sono date dai metodi getx e gety richiamati su un ButtonPanel che viene settato con il metodo setButtonPanel. Quindi in Window2 vi sarà anche l’istruzione panel.setButtonPanel(bpanel). Implementazione Classe Window1 import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Window1 { public static void main(String[] v){ JFrame f = new JFrame("Window 1"); f.setBounds(200,100,400,400); Container c = f.getContentPane(); JPanel p = new JPanel(); p.setLayout(new BorderLayout()); MyPanel panel = new MyPanel(); p.add(panel, BorderLayout.CENTER); JPanel pbutt = new JPanel(); MyButton q = new MyButton(); pbutt.add(q); p.add(pbutt, BorderLayout.SOUTH); c.add(p); f.addWindowListener(new Terminator()); f.show(); } } Classe MyPanel import java.awt.*; import javax.swing.*; public class MyPanel extends JPanel{ public void paintComponent( Graphics g){ super.paintComponent (g); setBackground(Color.white); g.drawLine(200,195,200,205); g.drawLine(195,200,205,200); } } Classe MyButton import java.awt.*; import javax.swing.*; import java.awt.event.*; public class MyButton extends JPanel implements ActionListener { public MyButton() { super(); JButton b=new JButton("Quit"); b.addActionListener(this); add(b); } public void actionPerformed(ActionEvent e) { System.exit(0); } } Classe Window2 import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Window2 { public static void main(String[] v){ JFrame f = new JFrame("Window 2"); f.setBounds(200,100,400,400); Container c = f.getContentPane(); JPanel p = new JPanel(); p.setLayout(new BorderLayout()); TextPanel tpanel = new TextPanel(); p.add(tpanel, BorderLayout.NORTH); NewPanel panel = new NewPanel(); panel.setButtonPanel(bpanel); p.add(panel, BorderLayout.CENTER); JPanel pbutt = new JPanel(); p.add(pbutt, BorderLayout.SOUTH); pbutt.setLayout(new BorderLayout()); MyButton q = new MyButton(); ButtonPanel bpanel = new ButtonPanel(); panel.setButtonPanel(bpanel); pbutt.add(q, BorderLayout.EAST); pbutt.add(bpanel, BorderLayout.WEST); c.add(p); f.addWindowListener(new Terminator()); f.show(); } } Classe TextPanel import java.awt.*; import javax.swing.*; import java.awt.event.*; public class TextPanel extends JPanel implements ActionListener { JtextField text; int D; public TextPanel() { super(); JLabel l = new JLabel("Griglia:"); add(l); text = new JTextField(5); text.addActionListener(this); add(text); } public void actionPerformed(ActionEvent e) { D = Integer.parseInt(text.getText()); } public int getD() { return D; } } Classe ButtonPanel import java.awt.*; import javax.swing.*; import java.awt.event.*; public class ButtonPanel extends JPanel implements ActionListener { JButton up,down,left,right; TextPanel t; NewPanel p; int x=200, y=200; public ButtonPanel(TextPanel tp, NewPanel mp) { super(); t=tp; p=mp; up = new JButton("Up"); down = new JButton("Down"); left = new JButton("Left"); right = new JButton("Right"); left.addActionListener(this); right.addActionListener(this); up.addActionListener(this); down.addActionListener(this); add(left); add(right); add(up); add(down); } public void actionPerformed(ActionEvent e) { Object pushedbutton = e.getSource(); if(pushedbutton==up) { if((y-t.getD())<5) y=5; else y=y-t.getD(); p.repaint(); } if(pushedbutton==down) { if((y+t.getD())>395) y=395; else y=y+t.getD(); p.repaint(); } if(pushedbutton==left) { if((x-t.getD())<5) y=5; else x=x-t.getD(); p.repaint(); } if(pushedbutton==right) { if((x+t.getD())>395) y=395; else x=x+t.getD(); p.repaint(); } } public int getx() { return x; } public int gety() { return y; } } Classe NewPanel import java.awt.*; import javax.swing.*; public class NewPanel extends JPanel{ ButtonPanel bp; public void paintComponent( Graphics g){ super.paintComponent (g); setBackground(Color.white); g.drawLine(bp.getx(),bp.gety()-5,bp.getx(),bp.gety()+5); g.drawLine(bp.getx()-5,bp.gety(),bp.getx()+5,bp.gety()); } public void setButtonPanel(ButtonPanel bpanel) { bp=bpanel; } } Casi d’uso La seguente immagine mostra la prima finestra creata: La seguente immagine mostra invece la seconda finestra creata modificando la prima: Concetti e tecniche acquisiti Questa esecrcitazione è servita per conoscere e prendere confidenza con la grafica in java, ovvero il package swing con tutte le sue classi. Inoltre si è imparato un nuovo metodo per progammare: non più elaborazione dei dati in ingresso con in uscita i risultati, ma programmazione event-driven, di reazione a eventi generati da i componenti grafici detti attivi, tipo un tasto quando viene premuto. In particolare ho imparato che il JFrame è il componente usato per disegnare una finestra con un titolo con delle dimensioni a piacere. Poi che il JPanel è quello su cui disegnare e sul quale aggiungere altri componenti, anche altri pannelli, magari creati a proprio bisogno estendendo JPanel. Per avere una disposizione grafica esatta come pare a noi si deve specificare il layout di un pannello. Un pannello va sempre aggiunto al container del frame che lo contiene, come ogni altro componente contenuto in un pannello va aggiunto al pannello stesso. I componenti incontrati nell’esercitazione oltre al JPanel sono il JButton, il JTextField e il JLabel. Si è visto come per un componente attivo, come i tasti usati, la classe che li definisce deve implementare una interfaccia che contiene il metodo per la gestione dell’evento; inoltre va specificato anche un componente ascoltatore degli eventi, che nei casi dell’esercitazione sono sempre i componenti stessi che generano l’evento.