LINGUAGGI & TRADUTTORI
“Quinta relazione”
Albertazzi Luca, matricola 2134230
DESCRIZIONE DEL PROBLEMA
Far comparire una finestra centrata nello schermo di dimensioni fisse, ad esempio 400 x 400.
Gestire la chiusura della finestra. Il pannello della finestra è diviso in due zone: 1_ Zona
centrale: disegnare una crocetta (10x10) in mezzo. 2_ Zona inferiore: un pulsante, centrato
orizzontalmente con la scritta “Quit”, quando lo si preme la finestra deve essere chiusa. Nella
parte inferiore aggiungere quattro pulsanti (“Up”,”Down”,”Left”,”Right”) tutti allineati a
sinistra, ora il pulsante “Quit” allineato a destra. Fissata una certa dimensione di griglia D (es.:
5 pixel), la pressione di “Up” fa salire la crocetta di D pixel, la pressione di “Down” fa scendere
la crocetta di D pixel, etc… Evitare di far uscire la crocetta dai margini. Permettere la
variazione di D.
ANALISI DEL PROBLEMA
Il
problema in questo caso non è di tipo concettuale, occorre imparare ad utilizzare gli
strumenti messi a disposizione dal linguaggio che deciderò di utilizzare: frame, container,
pannelli, bottoni, campi di testo, disegni. La complessità risiede nel fare dialogare tutti questi
componenti, la cosa potrà risultare più o meno difficile a seconda del tipo di implementazione
deciderò di utilizzare.
PROGETTO
Le classi create sono solamente tre:
Ese5.java
Panels.java
Terminator.java
La classe
La classe
Ese5.java è il componente software, non ha metodi.
Panels.java è il cuore del programma, possiede i seguenti metodi:
Method Summary
void actionPerformed(java.awt.event.ActionEvent e)
void paintComponent(java.awt.Graphics g)
void setGrid()
Setta la dimensione della griglia (in pixel)
void setPanel5Down()
Sposta la crocetta in basso di n pixel. n = numero di griglia
void setPanel5Left()
Sposta la crocetta a sinistra di n pixel. n = numero di griglia
void setPanel5Right()
Sposta la crocetta a destra di n pixel. n = numero di griglia
void setPanel5Up()
Sposta la crocetta in alto di n pixel. n = numero di griglia
Anche la classe
Terminator.java non possiede metodi.
IMPLEMENTAZIONE
file Ese5.java
Questo è il componente software. Come primo passo occorre importare due package grafici:
java.awt.* e javax.swing.* sono rispettivamente il vecchio package grafico (nato con Java
1.0) e il nuovo package grafico (conosciuto con il nome Swing). La prima cosa che ho fatto nel
main è stato creare il JFrame che è la struttura principale sul quale verranno visualizzati tutti
gli oggetti successivi. Ogni frame possiede un container richiamabile con il comando
f.getContentPane(), tutti i nuovi oggetti verranno aggiunti al container. Successivamente ho
creato un oggetto della classe Panels e lo ho aggiunto al container. Le tre righe di comando
successive: Dimension d = new Dimension();
Toolkit tk = Toolkit.getDefaultToolkit();
d = tk.getScreenSize();
sono servite ad ottenere la risoluzione dello schermo in modo da potere successivamente
posizionare il frame al centro del monitor. L’ultimo passo è quello di mostrare a video il frame
contenente tutti gli oggetti sopra descritti, con il comando f.show().
Ho aggiunto anche al frame un WindowListener per gestire la chiusura della finestra (la X in
alto a destra), l’ascoltatore è un nuovo oggetto della classe Terminator(), il codice utilizzato è il
seguente:
/**
*
* Class Ese5
*
*/
import java.awt.*;
import javax.swing.*;
public class Ese5 {
public static void main(String[] v){
JFrame f = new JFrame("Esercitazione 5");
Container c = f.getContentPane();
Panels panel = new Panels();
c.add(panel);
Dimension d = new Dimension();
Toolkit tk = Toolkit.getDefaultToolkit();
d = tk.getScreenSize();
System.out.println("\n" +d +"\n");
f.setBounds(d.width/3, d.height/4, 400, 400);
f.addWindowListener(new Terminator());
f.show();
}
}
file Terminator.java
Questa
è la classe che gestisce la finestra di Windows. L’unico aspetto rilevante è la
ridefinizione formale del metodo windowClosing, che permette di uscire dal programma
ciccando sulla croce in alto a destra nella finestra. Poiché questa classe è un listener occorre
importare la classe java.awt.event.*, ecco il codice utilizzato:
/**
*
* Class Terminator
*
*/
import java.awt.event.*;
public class Terminator implements WindowListener {
public void windowClosed(WindowEvent e){}
public void windowClosing(WindowEvent e){
System.exit(0);}
public void windowOpened(WindowEvent e){}
public void windowIconified(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowActivated(WindowEvent e){}
public void windowDeactivated(WindowEvent e){}
}
file Panels.java
Dopo aver importato
le classi per la gestione della grafica, delle Swing e degli eventi si
procede con la definizione della classe Panels: questa classe estende JPanel acquisendone tutti
i metodi e implementa ActionListener in quanto deve fare da ascoltatore per gli eventi legati
alla pressione dei bottoni e della pressione del tasto Invio legato al cambiamento della Text
Field. Il costruttore è parecchio grande, dopo aver creato un nuovo Layout Manager
(BorderLayout) vengono creati tre pannelli: il primo viene aggiunto nella zona inferiore del
pannello Panels stesso creato nel main del componente software, il secondo pannello e il terzo
vengono aggiunti al primo pannello, rispettivamente nella zona ovest ed est. Dopo aver creato
cinque bottoni vengono aggiunti nel secondo pannello. Dopo aver creato un ulteriore pannello,
gli vengono aggiunti una JLabel e una JTextField con valore “5” di default. Infine vengono
registrati gli ActionListener dei bottoni e della Text Field: l’ascoltatore è uno solo ed è l’oggetto
derivato dalla classe Panels stessa. Il metodo paintComponent serve per disegnare la crocetta
su un pannello aggiuntivo tramite due drawLine. I quattro interi passati a ciascuna drawLine
sono le coordinate degli estremi dei due segmenti. I quattro metodi successivi sono strutturati
in maniera simile ed attuano il movimento della crocetta sul pannello nelle quattro direzioni.
Ho inserito anche dei controlli (tramite delle strutture if) affinché la crocetta non esca dal
pannello. Ciascuno dei quattro metodi funziona in maniera semplice: ricalcola le quattro
coordinate dei punti e dice al pannello di ridisegnarsi (repaint) con i nuovi parametri. Il metodo
successivo, setGrid, modifica il valore della variabile intera D corrispondente al valore della
griglia, cioè al numero di pixel percorsi in una delle quattro direzioni ad ogni pressione di un
bottone. Poiché il risulato della getText sulla JtextField restituisce una string inconvertibile in
un valore intero, double o float, occorre fare un parsing sul testo: D
=
Integer.parseInt(txt1.getText()), il risultato di tale operazione è un numero intero che
viene memorizzato nella variabile D. L’ultimo metodo è ActionPerformed: poiché questa classe
funge da ascolatore degli eventi deve per forza implementare il metodo suddetto. Se il
pulsante premuto è Quit viene forzata l’uscita dal programma, a seconda invece che il pulsante
premuto sia Up, Down, Left, Right viene invocato il metodo corrispondente per lo spostamento
della corocetta. Infine, per gestire il cambiamento della griglia c’è anche l’invocazione del
metodo setGrid(). A seguire il codice utilizzato:
/**
*
* Class Panels
*
*/
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Panels extends JPanel implements ActionListener{
public Panels() {
setLayout(new BorderLayout());
panel1 = new Panel();
add(panel1, BorderLayout.SOUTH);
panel2 = new Panel();
panel1.add(panel2, BorderLayout.WEST);
panel3 = new Panel();
panel1.add(panel3, BorderLayout.EAST);
b1 = new JButton("U");
b2 = new JButton("D");
b3 = new JButton("L");
b4 = new JButton("R");
b = new JButton("QUIT");
panel2.add(b1);
panel2.add(b2);
panel2.add(b3);
panel2.add(b4);
panel3.add(b);
panel4 = new Panel();
add(panel4, BorderLayout.NORTH);
JLabel lb1 = new JLabel("GRIGLIA: ");
panel4.add(lb1);
txt1 = new JTextField("5", 3);
panel4.add(txt1);
b.addActionListener(this);
b1.addActionListener(this);
b2.addActionListener(this);
b3.addActionListener(this);
b4.addActionListener(this);
txt1.addActionListener(this);
}
public void paintComponent(Graphics g){
panel5 = new Panel();
add(panel5, BorderLayout.CENTER);
super.paintComponent(g);
g.drawLine(x11, y11, x12, y12);
g.drawLine(x21, y21, x22, y22);
}
/**
*
* Sposta la crocetta in alto di n pixel. n = numero di griglia
*
*/
public void setPanel5Up(){
x11 = x11;
x12 = x12;
x21 = x21;
x22 = x22;
y11 -= D;
if(y11<37){
y11=37;}
y12 -= D;
if(y12<37){
y12=37;}
y21 -= D;
if(y21<32){
y21=32;}
y22 -= D;
if(y22<42){
y22=42;}
repaint();
}
/**
*
* Sposta la crocetta in basso di n pixel. n = numero di griglia
*
*/
public void setPanel5Down(){
x11 = x11;
x12 = x12;
x21 = x21;
x22 = x22;
y11 += D;
if(y11>320){
y11=320;}
y12 += D;
if(y12>320){
y12=320;}
y21 += D;
if(y21>315){
y21=315;}
y22 += D;
if(y22>325){
y22=325;}
repaint();
}
/**
*
* Sposta la crocetta a destra di n pixel. n = numero di griglia
*
*/
public void setPanel5Right(){
y11 = y11;
y12 = y12;
y21 = y21;
y22 = y22;
x11 = x11+D;
if(x11>380){
x11=380;}
x12 = x12+D;
if(x12>390){
x12=390;}
x21 = x21+D;
if(x21>385){
x21=385;}
x22 = x22+D;
if(x22>385){
x22=385;}
repaint();
}
/**
*
* Sposta la crocetta a sinistra di n pixel. n = numero di griglia
*
*/
public void setPanel5Left(){
y11 = y11;
y12 = y12;
y21 = y21;
y22 = y22;
x11 = x11-D;
if(x11<0){
x11=0;}
x12 = x12-D;
if(x12<10){
x12=10;}
x21 = x21-D;
if(x21<5){
x21=5;}
x22 = x22-D;
if(x22<5){
x22=5;}
repaint();
}
/**
*
* Setta la dimensione della griglia (in pixel)
*
*/
public void setGrid(){
D = Integer.parseInt(txt1.getText());
}
public void actionPerformed(ActionEvent e){
Object pulsantePremuto = e.getSource();
if (pulsantePremuto == b){
System.out.println("\nQUITTING...");
try {
Thread.currentThread().sleep(3000);
} catch (Exception ex){
}
System.exit(0);}
if (pulsantePremuto == b1){
setPanel5Up();
System.out.println("UP " +D +" pixel");}
if (pulsantePremuto == b2){
setPanel5Down();
System.out.println("DOWN " +D +" pixel");}
if (pulsantePremuto == b4){
setPanel5Right();
System.out.println("RIGHT " +D +" pixel");}
if (pulsantePremuto == b3){
setPanel5Left();
System.out.println("LEFT " +D +" pixel");}
setGrid();
}
//data
int x11
int y11
int x12
int y12
int x21
int y21
int x22
int y22
int D =
JButton
JButton
JButton
JButton
= 190;
= 180;
= x11+10;
= y11;
= x11+5;
= y11-5;
= x21;
= y21+10;
5;
b1;
b2;
b3;
b4;
JButton b;
JTextField txt1;
Panel panel1;
Panel panel2;
Panel panel3;
Panel panel4;
Panel panel5;
}
CASI D’USO
Riporto alcune schermate del programma eseguito:
CONCETTI E TECNICHE ACQUISITE
Il
più importante concetto acquisito è sicuramente stato quello di evento: la grandissima
differenza tra i programmi fino ad ora realizzati e quest’ultimo risiede proprio nel concetto di
programmazione ad eventi. Analizzando uno qualsiasi dei programmi realizzarti per le
esercitazioni precedenti si scopre che la struttura è sempre del tipo: inserimento dati 
elaborazione dei dati attraverso un algoritmo  visualizzazione dei dati manipolati. Con questo
tipo di approccio è impossibile realizzare applicazioni moderne come quelle che siamo abituati
ad utilizzare ogni giorno (es: Word, Excel, …) in quanto questi programmi non seguono un
flusso algoritmico predefinito: deve essere l’utente a decidere cosa fare, non il programma.
Grazie a questa esercitazione ho cominciato ad esplorare la programmazione ad eventi: ad
ogni oggetto con il quale l’utente può interagire (bottone, text field, …) possono essere
associati uno o più eventi. Il concetto base risiede nell’associare ad un oggetto un ascoltatore
(una classe che implementi il metodo ActionPerformed), quando questo oggetto viene
sollecitato (es: bottone premuto), l’ActionPeformed mette in esecuzione un pezzo di codice in
risposta all’evento.
Poiché questa esercitazione si basava sull’uso della grafica in Java ho anche imparato ad
utilizzare le Swing: ho imparato che alla base di ogni finestra c’è il frame. Non si possono
applicare direttamente gli oggetti sul frame ma bisogna richiamare il container associato ad
ogni frame e applicare gli oggetti ad esso.
Le difficoltà che ho incontrato nella scrittura del programma non sono state di tipo concettuale
ma di tipo implementativo. Ho capito che in questo caso era necessario creare meno classi
possibile cercando di mantenere tutti gli oggetti che interagivano tra di loro (pannelli, bottoni,
textfields) nella stessa classe. L’approccio che avevo deciso di utilizzare all’inizio (data la mia
poca esperienza) era quello di creare una classe per ogni pannello, in questo modo non
riuscivo a fare in modo che gli oggetti si vedessero tra di loro. La soluzione finale è stata quella
di creare una classe Panels che contenesse tutti i pannelli di cui avevo bisogno e che facesse
anche da ActionListener.
Infine ho voluto convertire il programma in un’applet visibile all’interno di un browser, di come
funzionano le applet parlerò nella prossima relazione. Comunque se vuole vedere l’applet di
questa esercitazione l’ho caricata nel mio sito internet: http://digilander.iol.it/thunderbird79/