Es5

annuncio pubblicitario
Quinta esercitazione di Linguaggi e Traduttori
Primo Problema
Descrizione del problema:
Far comparire una finestra centrata nel centro dello schermo e divisa in due parti, una centrale in cui
disegnare una crocetta di dimensioni 10x10 pixiel posta al centro e la parte sud con un pulsante “Quit”
centrato orizzontalmente. L’applicazione si deve chiudere se si preme il pulsante Quit o tramite il bottone di
chiusura della finestra.
Analisi:
La finestra deve essere di dimensioni fisse, date al momento della costruzione della finestra stessa, deve
essere formata da due pannelli uno in cui disegnare la crocetta, che deve essere al centro del pannello,
l’altro in cui posizionare il pulsante con la scritta Quit: quando viene premuto il pulsante Quit deve essere il
pannello stesso ad accorgersene e a chiudere la finestra e l’applicazione.
Progetto:
Per la realizzazione della finestra usiamo la classe JFrame che fa parte dei package java.awt e javax.swing
che sono i package grafici di java.
Ho creato una mia finestra MyFrame che eredita da JFrame e nel costruttore richiama il costruttore
JFrame(string s), che crea una finestra vuota di titolo s, e poi setta le dimensioni della finestra con il metodo
setBounds(int x, int y, int width, int height) dove x e y sono le coordinate dello spigolo in alto a sinistra
della finestra, width è la larghezza e height è l’altezza. Per centrare la finestra nello schermo si usa il
metodo getScreenSize() da invocare su Toolkit ma, dato che non è un metodo statico e non può essere
invocato su di una classe, bisogna prima creare un oggetto di tipo Toolkit, cosa che si fa attraverso
l’invocazione getDefaultToolkit().GetScreenSize ritorna un oggetto di tipo Dimension formato da una coppia
d’interi in duplice precisione che rappresentano la larghezza e la lunghezza dello schermo in pixiel. Tramite i
metodi getWidth() e getHeight() si accede rispettivamente alla larghezza e alla lunghezza. Per aggiungere
un qualsiasi componente alla finestra bisogna prima recuperare il contenitore al suo interno tramite
getContentPane() e poi aggiungere a questo i componenti con il metodo add.
Mi sono poi creato un pannello, da inserire nel contenitore della finestra, MyPanel in cui mettere i due
pannelli contenenti la crocetta e il pulsante. MyPanel eredita da JPanel e implementa le interfacce
WindowListener e ActionListener che servono rispettivamente per renderlo “ascoltatore” delle azioni del
pulsante Quit e dei pulsanti della finestra. MyPanel in fase di costruzione richiama il costruttore di JPanel() e
crea al suo interno due pannelli, uno di tipo JPanel in cui sarà inserito il pulsante, e l’altro di tipo MyPanel1 in
cui disegnare la crocetta. Per dividere il pannello in due parti; Centro e Sud, si usa il BorderLayout che viene
settato come Layout con il metodo setLayout(new BorderLayout) e poi quando i due pannelli vengono
aggiunti a quello principale tramite il metodo add si specifica la zona dove devono essere posizionati, ad
esempio add(p, BorderLayout.CENTER) dove p è un pannello o un qualsiasi altro componente. Poi viene
creato il pulsante Quit che è un JButton tramite il costruttore JButton(string s) dove s è la stringa che si
vedrà stampata sul pulsante. Per fare in modo che il pannello diventi l’ascoltatore del pulsante si ricorre al
metodo addActionListener(Component c) da invocare sul pulsante e che rende il componente c
l’ascoltatore delle azioni del pulsante. Si passa quindi ad “aggiungere il pulsante al pannello situato nella
zona sud e poi si aggiungono i due pannelli a quello principale.
La classe MyPanel1 eredita da JPanel e al suo interno definisce i metodi per disegnare la crocetta, infatti,
quando viene creato un nuovo oggetto di tipo MyPanel1, questo invoca automaticamente il metodo
paintComponent che specifica gli elementi da disegnare all’interno del pannello ad esempio il colore del
background, quello delle linee che disegna tramite il metodo drawLine(int x, int y, int x1, int y1) che disegna
una linea dal punto di coordinate(x, y) a quello di coordinate(x1, y1).Per centrare la crocetta nel pannello
uso metodo screenSize() da invocare sul pannello e ritorna un oggetto di tipo Dimension contenente le
dimensioni del pannello stesso.
Come ho già detto la classe MyPanel implementa le interfacce WindowListener e ActionListener e questo fa
sì che il pannello diventi l’ascoltatore delle azioni del pulsante e della finestra, infatti, quando il pulsante
viene premuto, si genera un evento di tipo ActionEvent che viene inviato all’ascoltatore che lo gestisce in
questo caso chiudendo l’applicazione. Allo stesso modo quando viene premuto il pulsante di chiusura della
finestra si genera un WindowEvent e sta sempre all’ascoltatore gestirlo in modo opportuno.
Implementazione:
Implementazione della finestra:
import java.awt.*;
import javax.swing.*;
public class MyFrame extends JFrame{
private Dimension d;
private int dim=500;
public MyFrame(){
super("Esercitazione");
d=new Dimension(Toolkit.getDefaultToolkit().getScreenSize());
setBounds((int)(d.getWidth()/2-dim/2),(int)(d.getHeight()/2-dim/2),dim,dim);
}
}
Implementazione del pannello MyPanel:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class MyPanel extends JPanel implements ActionListener, WindowListener {
public MyPanel(){
super();
setLayout(new BorderLayout());
JPanel p=new JPanel();
JButton b=new JButton("Quit");
b.addActionListener(this);
p.add(b);
MyPanel1 p1=new MyPanel1();
add(p1,BorderLayout.CENTER);
add(p,BorderLayout.SOUTH);
}
public void actionPerformed(ActionEvent e){
System.exit(0);
}
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowActivated(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowOpened(WindowEvent e){}
}
Implementazione del pannello MyPanel1:
import java.awt.*;
import javax.swing.*;
public class MyPanel1 extends JPanel{
public void paintComponent(Graphics g){
Dimension d=new Dimension(getSize());
super.paintComponent(g);
g.setColor(Color.black);
g.drawLine((int)(d.getWidth()/2),(int)(d.getHeight()/2),(int)(d.getWidth()/2+5),(int)(d.getHeight()/2));
g.drawLine((int)(d.getWidth()/2),(int)(d.getHeight()/2),(int)(d.getWidth()/2),(int)(d.getHeight()/2+5));
}
}
Casi d’uso:
import java.awt.*;
import javax.swing.*;
public class Esercizio {
public static void main(String[] v){
MyFrame f = new MyFrame();
Container c=f.getContentPane(); / recupero il contenitore all’interno della finestra /
MyPanel p=new MyPanel();
c.add(p);
f.show();
/ per mostrare la finestra sullo schermo /
}
}
Secondo Problema
Descrizione del problema:
Si vuole aggiungere alla finestra la possibilità di muovere la crocetta di un numero di pixiel uguale al valore
riportato in un area di testo situata nella parte nord della finestra. La crocetta deve muoversi in conseguenza
della pressione dei tasti, U(up) D(down) L(left) R(right), situati nella zona sud.
Analisi:
Si riutilizza la finestra del primo problema ma a questa vanno aggiunti i quattro pulsanti nella zona sud,
un’area di testo nella zona nord e una scritta vicino all’area di testo. Premendo uno dei quattro tasti la
crocetta deve muoversi nella direzione indicata dal tasto di tanti pixiel quanto è il valore nell’area di testo in
quel momento, valore che può essere cambiato in ogni istante dall’utente che, premendo il tasto enter, rende
effettivo il cambiamento.
Progetto:
Il Frame usato è lo stesso dell’esercizio precedente gli unici componenti che cambiano sono il MyPanel e il
MyPanel1. Il MyPanel questa volta è diviso in tre parti una centrale, una sud e una nord. In quella nord ci
sono un JLabel e un JTextField: il primo consiste in un componente non reattivo in grado di visualizzare una
scritta o un immagine, il secondo invece è un componente attivo formato da una casella in cui può essere
immessa una stringa e che genera un evento quando viene schiacciato il tasto enter. Nel costruttore del
MyPanel vengono quindi creati tre pannelli, che verranno posizionati tramite il BorderLayout, uno che
contiene il JLabel e il JTextField di tipo JPanel, un altro, contenente la crocetta, di tipo MyPanel1 e l’ultimo,
contenente i pulsanti, di tipo MyPanel2.Il MyPanel1 è quasi uguale a quello usato nell’esercizio precedente
ma ha in più i metodi pubblici incx(int n) e incy(int n) che spostano la posizione della crocetta
rispettivamente in orizzontale e in verticale di n pixiel, controllando che non esca dal pannello, e poi
invocano il metodo reapaint() sul pannello in modo che si ridisegni ogni volta. Gli spostamenti vengono ogni
volta memorizzati in due variabili private della classe in modo che la volta successiva la crocetta si trovi nella
posizione in cui era stata lasciata prima. Il pannello sito a nord della finestra contenente il JLabel e il
JTextField viene definito all’interno del MyPanel e invoca il costruttore JLabel(string s), che crea un JLabel
che visualizza la stringa s, e il costruttore JTextField(string s, int c) che crea una casella di testo di c spazi
in cui è scritta la stringa s. All’interno della casella di testo può essere inserita una qualsiasi stringa e quando
viene schiacciato il tasto enter si genera un ActionEvent che viene mandato all’ascoltatore.
All’interno del MyPanel ho creato una classe privata MyPanel2 che deriva sempre dal JPanel e al suo
interno contiene i quattro pulsanti direzionali U, D, L, R e il pulsante Quit. Il MyPanel2 in fase di costruzione
ha il compito di creare questi cinque pulsanti e assegnare i loro ascoltatori. Il MyPanel2 inoltre implementa
l’interfaccia ActionListener, al posto del MyPanel, infatti è l’ascoltatore di tutti e cinque i pulsanti e del
JTextField: quando arriva un ActionEvent il MyPanel2 gli chiede la sua sorgente tramite il metodo
getSource(), se è il pulsante Quit invoca il metodo exit(0) sulla classe System, se è il JTextField recupera il
valore scritto nella casella di testo tramite il metodo getText() e prova a convertirlo in un intero invocando
valueOf() sulla classe Wrapper Integer e di seguito intValue(). In questo modo cerca di convertire la stringa
presente nella casella di testo in un intero e, se ci riesce la salva in una variabile privata i della classe
altrimenti solleva una NumberFormatException che viene catturata riportando il valore della casella di testo e
della variabile i a uno. Nel caso in cui il pulsante premuto è uno dei quattro tasti direzionali viene invocato il
metodo incx(int n) o incy(int n), dove n è il valore che è memorizzato nella variabile i, sul pannello
MyPanel1.
Implementazione:
Il MyFrame è identico a quello dell’esercizio precedente.
Implementazione di MyPanel:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class MyPanel extends JPanel implements WindowListener {
private JButton up,down,left,right,quit;
private MyPanel1 p1;
private JTextField f;
private int i=1;
public MyPanel(){
super();
setLayout(new BorderLayout());
Panel p3=new Panel();
JLabel l=new JLabel("Griglia:");
f=new JTextField("1",5);
p3.add(l);
p3.add(f);
MyPanel2 p=new MyPanel2();
f.addActionListener(p);
p1=new MyPanel1();
add(p1,BorderLayout.CENTER);
add(p,BorderLayout.SOUTH);
add(p3,BorderLayout.NORTH);
}
public void windowClosing(WindowEvent e){
System.exit(0);
}
public void windowActivated(WindowEvent e){}
public void windowClosed(WindowEvent e){}
public void windowDeactivated(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowIconified(WindowEvent e){}
public void windowOpened(WindowEvent e){}
private class MyPanel2 extends JPanel implements ActionListener{
public MyPanel2(){
super();
quit=new JButton("Quit");
up=new JButton("U");
down=new JButton("D");
left=new JButton("L");
right=new JButton("R");
quit.addActionListener(this);
up.addActionListener(this);
down.addActionListener(this);
left.addActionListener(this);
right.addActionListener(this);
add(up);
add(down);
add(left);
add(right);
add(quit);
}
public void actionPerformed(ActionEvent e){
Object pulsantePremuto=e.getSource();
if(pulsantePremuto==up)(p1.incy(-i));
if(pulsantePremuto==down)(p1.incy(+i));
if(pulsantePremuto==left)(p1.incx(-i));
if(pulsantePremuto==right)(p1.incx(+i));
if(pulsantePremuto==quit)(System.exit(0));
if(pulsantePremuto==f){
try{
(i=Integer.valueOf(f.getText()).intValue());
}
catch(NumberFormatException e1){
i=1;
f.setText("1");
}
}
}
}
}
Implementazione di MyPanel1:
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class MyPanel1 extends JPanel{
private int x=0;
private int y=0;
private int a,b;
public void paintComponent(Graphics g){
setBackground(Color.white);
Dimension d=new Dimension(getSize());
a=(int)(d.getWidth()/2);
b=(int)(d.getHeight()/2);
super.paintComponent(g);
g.setColor(Color.black);
g.drawLine((a-5+x),(b+y),(a+x+5),(b+y));
g.drawLine((a+x),(b+y-5),(a+x),(b+y+5));
}
public void incx(int n){
x+=n;
if(x>a)(x=a);
if(x<-a)(x=-a);
repaint();
}
public void incy(int n){
y+=n;
if(y>b)(y=b);
if(y<-b)(y=-b);
repaint();
}
}
Casi d’uso:
Anche il main rimane identico a quello dell’esercizio precedente:
import java.awt.*;
import javax.swing.*;
public class Esercizio {
public static void main(String[] v){
MyFrame f = new MyFrame();
Container c=f.getContentPane();
MyPanel p=new MyPanel();
c.add(p);
f.show();
}
}
Terzo Problema
Descrizione del problema:
Si vuole aggiungere alla finestra la possibilità di spostare la crocetta dove si clicka col mouse e, premendo
un tasto, la possibilità di disegnare delle linee.
Analisi:
Partendo dalla finestra precedente bisogna rendere la finestra sensibile al click del mouse e fare in modo
che la crocetta si sposti a seconda di dove si clicka. Inoltre bisogna aggiungere un pulsante nella zona nord
con la scritta "Start" che se viene premuto abilita il disegno di linee e la scritta viene cambiata in "Stop". Le
linee vengono disegnate dalla posizione corrente della crocetta al punto in cui viene spostata dopo che si è
clickato col mouse.
Progetto:
Anche questa volta gli unici componenti che cambiano sono il MyPanel e il MyPanel1 e anche il MyPanel è
quasi identico a quello precedente. Le differenze tra il MyPanel precedente e quello attuale sono: in quello
attuale in fase di costruzione viene aggiunto un pulsante start con la scritta “Start” al pannello situato nella
zona nord e vi è un booleano privato st che dice se start è premuto o no. L’ascoltatore di start è il MyPanel2
che, quando riceve l’ActionEvent da parte di start va a controllare il booleano st e a seconda di st cambia la
scritta “Start” in “Stop” o viceversa, modifica il valore di st e invoca il metodo setStart(boolean b) sul
MyPanel1 passandogli come parametro st.
Nel MyPanel1 invece le differenze sono maggiori infatti per disegnare delle linee nel pannello ho bisogno di
un array di oggetti di tipo Line che aumenti di uno ogni volta che si clicka col mouse e per questo uso la
classe Vector. Un Vector è un contenitore di oggetti e viene inizializzato tramite il costruttore Vector(int
initialCapacity, int capacityIncrement) dove initialCapacity rappresenta la capienza iniziale e
capacityIncrement la quantità di cui si vuole aumentare la capienza ogni volta che il numero di oggetti
contenuti supera la capienza del Vector. La classe Line rappresenta una linea ed è formata da due oggetti
privati di tipo Point. Ogni oggetto di tipo Point è definito da due interi, che rappresentano le coordinate del
punto, cui si può accedere tramite i metodi getX() e getY(), che ritornano rispettivamente il valore
dell’ascissa e dell’ordinata con la precisione di un double. Per accedere ai punti di ogni interni, la classe Line
fornisce i metodi getStartPoint() e getEndPoint() che ritornano il punto di partenza e di arrivo della linea.
Nel MyPanel1 c’è un booleano privato che può essere modificato invocando il metodo pubblico
setStart(boolean b) che assegna alla variabile interna il valore di b. Quindi in fase di costruzione il
MyPanel1, oltre a fare tutto ciò che faceva prima, crea un oggetto di tipo Vector con capienza iniziale 0 e
incremento di capienza 1, inizializza una variabile booleana (draw) a false e crea un oggetto privato di tipo
Point che servirà a memorizzare la posizione attuale della crocetta (currPos). Il MyPanel1 diventa inoltre
l’ascoltatore degli eventi lanciati dalle azioni del mouse infatti implementa l’interfaccia MouseListener: ogni
volta che si genera un evento di tipo MouseEvent che invochi il metodo mouseClicked(MouseEvent e) si
risale al punto in cui si è clickato con il metodo getPoint() da invocare sull’oggetto e, si memorizza il punto in
una variabile temporanea e poi si va a controllare il valore di draw e a seconda del valore si memorizza il
punto in currPos o si crea un nuovo oggetto di tipo Line da memorizzare nel Vector con il metodo add e si
memorizza in currPos la nuova posizione. Alla fine si chiede al pannello di ridisegnarsi. Nella fase di
disegno il pannello va a controllare la capienza del Vector e se è 0 non fa niente altrimenti disegna tutte le
linee memorizzate.
Implementazione:
Il MyFrame resta identico.
Impelmentazione di MyPanel:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class MyPanel extends JPanel implements WindowListener {
private JButton up,down,left,right,quit,start;
private MyPanel1 p1;
private Panel p3;
private JTextField f;
private int i=1;
private boolean st=false;
public MyPanel(){
super();
setLayout(new BorderLayout());
p3=new Panel();
JLabel l=new JLabel("Griglia");
f=new JTextField("1",5);
start=new JButton("Start");
p3.add(l);
p3.add(f);
p3.add(start);
MyPanel2 p=new MyPanel2();
start.addActionListener(p);
f.addActionListener(p);
p1=new MyPanel1();
add(p1,BorderLayout.CENTER);
add(p,BorderLayout.SOUTH);
add(p3,BorderLayout.NORTH);
}
public void windowClosing(WindowEvent e){
System.exit(0);
}
public void windowActivated(WindowEvent e){}
public void windowClosed(WindowEvent e){}
public void windowDeactivated(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowIconified(WindowEvent e){}
public void windowOpened(WindowEvent e){}
private class MyPanel2 extends JPanel implements ActionListener{
public MyPanel2(){
super();
quit=new JButton("Quit");
up=new JButton("U");
down=new JButton("D");
left=new JButton("L");
right=new JButton("R");
quit.addActionListener(this);
up.addActionListener(this);
down.addActionListener(this);
left.addActionListener(this);
right.addActionListener(this);
add(up);
add(down);
add(left);
add(right);
add(quit);
}
public void actionPerformed(ActionEvent e){
Object pulsantePremuto=e.getSource();
if(pulsantePremuto==up)(p1.incy(-i));
if(pulsantePremuto==down)(p1.incy(+i));
if(pulsantePremuto==left)(p1.incx(-i));
if(pulsantePremuto==right)(p1.incx(+i));
if(pulsantePremuto==quit)(System.exit(0));
if(pulsantePremuto==start){
if(!st){
start.setText("Stop");
st=true;
}
else{
start.setText("Start");
st=false;
}
p1.setStart(st);
}
if(pulsantePremuto==f){
try{
(i=Integer.valueOf(f.getText()).intValue());
}
catch(NumberFormatException e1){
i=1;
f.setText("1");
}
}
}
}
}
Implementazione di MyPanel1:
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import java.util.*;
public class MyPanel1 extends JPanel implements MouseListener{
private boolean draw=false;
private Vector v=new Vector(0,1);
private Point currPos;
private int x=0;
private int y=0;
private int a,b;
public void paintComponent(Graphics g){
addMouseListener(this);
setBackground(Color.white);
Dimension d=new Dimension(getSize());
a=(int)(d.getWidth()/2);
b=(int)(d.getHeight()/2);
super.paintComponent(g);
currPos=new Point(a+x,b+y);
g.setColor(Color.black);
g.drawLine((a-5+x),(b+y),(a+5+x),(b+y));
g.drawLine((a+x),(b-5+y),(a+x),(b+5+y));
if(v.capacity()!=0){
for(int i=0; i<v.capacity(); i++){
Line l=(Line)v.elementAt(i);
Point p1=l.getStartPoint();
Point p2=l.getEndPoint();
g.drawLine((int)p1.getX(),(int)p1.getY(),(int)p2.getX(),(int)p2.getY());
}
}
}
public void incx(int n){
x+=n;
if(x>a)(x=a);
if(x<-a)(x=-a);
repaint();
}
public void incy(int n){
y+=n;
if(y>b)(y=b);
if(y<-b)(y=-b);
repaint();
}
public void mouseClicked(MouseEvent e){
Point p=e.getPoint();
x=(int)(p.getX()-a);
y=(int)(p.getY()-b);
if(draw)
v.add(new Line(currPos,p));
repaint();
}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void setStart(boolean b1){
draw=b1;
}
}
Implementazione di Line:
import java.awt.*;
public class Line{
private Point x,y;
public Line(Point n,Point m){
x=n;
y=m;
}
public Point getStartPoint(){
return x;
}
public Point getEndPoint(){
return y;
}
}
Casi d’uso:
Il main rimane sempre identico:
import java.awt.*;
import javax.swing.*;
public class Esercizio {
public static void main(String[] v){
MyFrame f = new MyFrame();
Container c=f.getContentPane();
MyPanel p=new MyPanel();
c.add(p);
f.show();
}
}
Concetti e tecniche acquisiti:
Con questa esercitazione ho imparato l’uso di alcuni componenti facenti parte dei package grafici di java, la
gestione degli eventi e delle eccezioni che vengono generati durante l’esecuzione di un’applicazione e
l’utilizzo della classe Vector per la creazione di array che possono variare durante l’esecuzione.
Scarica