Elementi di
programmazione grafica
• Introduzione alle applicazione grafiche
contesto grafici
forme geometriche elementari
colori
“input dialogs” per ottenere input dall’utente
• Frames e applets
Frames
•
La classe JFrame
JFrame frame = new JFrame();
frame.setSize(300, 400);
frame.setTitle(“An Empty Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
•
import javax.swing.*;
Frames
File EmptyFrameViewer.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
import javax.swing.*;
class EmptyFrameViewer
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
final int FRAME_WIDTH = 300;
final int FRAME_HEIGHT = 400;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle(“Un frame vuoto");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Domande
1. Come dobbiamo modificare
EmptyFrameViewer per ottenere un frame
quadrato con titolo "Hello, World!"?
2. Come scriviamo un programma che lancia
due frames?
Risposte
1. Modifca EmptyFrameViewer come segue:
frame.setSize(300, 300);
frame.setTitle("Hello, World!");
2. Costruisci due oggetti JFrame definendone
la dimensione e poi invoca
setVisible(true) su ciascuno
Disegno di forme geometriche
• JComponent
La classe che definisce contenitori
generici, al cui interno includiamo
forme geometriche
• Possiamo definire nuovi JComponent
class ShapeComponent extends JComponent
{
. . .
}
Disegno di forme geometriche
• paintComponent
metodo che produce il disegno
invocato (automaticamente) tutte le volte che
il componente per il quale è definito viene
ridisegnato
Disegno di forme geometriche
• paintComponent(Graphics g)
g contesto grafico
Graphics classe che permette di manipolare
lo stato del contesto grafico
class ShapeComponent extends JComponent
{
public void paintComponent(Graphics g)
{
// Converti in Graphics2D
Graphics2D g2 = (Graphics2D) g;
. . .
}
}
Disegno di forme geometriche
• Graphics2D estende Graphics con metodi
per il rendering in due dimensioni
• Ad esempio:
// g2: Graphics
Rectangle rect = new Rectangle(5, 10, 20, 30);
g2.draw(rect);
• package java.awt
File ShapeComponent.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
import
import
import
import
import
java.awt.Graphics;
java.awt.Graphics2D;
java.awt.Rectangle;
javax.swing.JPanel;
javax.swing.JComponent;
/**
Un Component che disegna due rettangoli.
*/
class ShapeComponent extends JComponent
{
public void paintComponent(Graphics g)
{
// Ottieni un graphics2D
Graphics2D g2 = (Graphics2D) g;
Continua…
File ShapeComponent.java
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27: }
// Costruisci un rettangolo e disegna
Rectangle r = new Rectangle(5, 10, 20, 30);
g2.draw(r);
// Trasla il rettangolo (15 a dx, 25 in basso)
r.translate(15, 25);
// Disegna il rettangolo traslato
g2.draw(r);
}
Applicazioni
• ShapeViewer
classe che lancia una finestra all’interno della
quale vengono raffigurate Ie componenti
L’applicazione è costruita interamente
all’interno del metodo main della classe
Disegna due rettangoli
Continua…
Applicazione ShapeViewer
Il metodo main
1. Costruisci il frame
2. Costruisci un oggetto della classe component
ShapeComponent component = new ShapeComponent();
3. Aggiunti il component al frame
frame.add(component);
La chiamata è leggermente più complicata per
versioni di Java precedenti alla 5:
frame.getContentPane().add(component);
4. Rendi visibile il frame
File ShapeViewer.java
01: import javax.swing.JFrame;
02:
03: class ShapeViewer
04: {
05:
public static void main(String[] args)
06:
{
07:
JFrame frame = new JFrame();
08:
09:
final int FRAME_WIDTH = 300;
10:
final int FRAME_HEIGHT = 400;
11:
12:
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
13:
frame.setTitle(“Two Rectangles");
14:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
15:
Continua…
File ShapeViewer.java
16:
17:
18:
19:
20:
21: }
ShapeComponent component = new ShapeComponent();
frame.add(component);
frame.setVisible(true);
}
Domanda
3. Che succede se sostituiamo la chiamata
g2.draw(box)con g.draw(box) ?
Risposta
3. Il compilatore segnala un errore
g : Graphics non ha un metodo draw
Applets
• Applets sono applicazioni eseguite
all’interno di un browser
• L’implementazione di una Applet utilizza il
pattern seguente:
public class MyApplet extends JApplet
{
public void paint(Graphics g)
{
// Ottieni un contesto grafico
Graphics2D g2 = (Graphics2D) g;
// Istruzioni per il disegno
. . .
}
}
Applets
•
Struttura molto simile a quella di un
JComponent, con due differenze:
1. Estende JApplet, invece di JComponent
2. codice del disegno incluso nel metodo
paint, invece che nel metodo
paintComponent
File ShapeApplet.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
import
import
import
import
java.awt.Graphics;
java.awt.Graphics2D;
java.awt.Rectangle;
javax.swing.JApplet;
/**
Un applet che disegna due rettangoli.
*/
public class ShapeApplet extends JApplet
{
public void paint(Graphics g)
{
// Ottieni un contesto grafico
Graphics2D g2 = (Graphics2D) g;
Continua…
File ShapeApplet.java
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27: }
// Costruisci un rettangolo e disegna
Rectangle r = new Rectangle(5, 10, 20, 30);
g2.draw(r);
// Trasla il rettangolo (15 a dx, 25 in basso)
r.translate(15, 25);
// Disegna il rettangolo traslato
g2.draw(r);
}
Applets
• Esecuzione
creare un file HTML ed inserire il codice che
lancia l’applet mediante la tag applet
Un file HTML può contenere diverse applets,
ciascuno delle quali introdotta da una
corrispondente tag (di tipo applet)
• Una applet può essere lanciata mediante
l’appletviewer, o all’interno di un browser
appletviewer RectangleApplet.html
File RectangleApplet.html
<html>
<head>
<title>Due rettangoli</title>
</head>
<body>
<p>Here’s my first applet:</p>
<applet code="RectangleApplet.class" width="300" height="400">
</applet>
</body>
</html>
Applets
Forme Geometriche
• Rectangle, Ellipse2D.Double,
Line2D.Double (package java.awt.geom)
• Alcune classi, e.g. Line2D.Double, sono
interne. Per il momento ignoriamo, ma notiamo
la dichiarazione import
import java.awt.geom.Ellipse2D; // no .Double
• Per ottenere una forma dobbiamo costruirla e
disegnarla
Ellipse2D.Double e = new Ellipse2D.Double(x, y, width, height);
g2.draw(e);
Una ellisse e la sua bounding box
Linee
• Due modi per disegnare una linea:
Line2D.Double segmento = new Line2D.Double(x1, y1, x2, y2);
oppure,
Point2D.Double from = new Point2D.Double(x1, y1);
Point2D.Double to = new Point2D.Double(x2, y2);
Line2D.Double segmento = new Line2D.Double(from, to);
Stringhe
g2.drawString("Message", 50, 100);
Basepoint
Domande
4. Quale è la sequenza di istruzioni per
disegnare un cerchio con centro (100, 100)
e raggio 25?
5. Quale è una usequenza di istruzioni per
disegnare la lettera "V" all’origine (0,0)
componendo due segmenti di linea?
6. Quale è la sequenza di istruzioni per
disegnare la stringa costituita dalla lettera
"V" ?
Risposte
4.
5.
6.
g2.draw(new Ellipse2D.Double(75, 75, 50, 50);
Line2D.Double segm1 = new Line2D.Double(0, 0, 10, 30);
g2.draw(segm1);
Line2D.Double segm2 = new Line2D.Double(10, 30, 20, 0);
g2.draw(segm2);
g2.drawString("V", 0, 30);
Colori
• Colori standard Color.BLUE, Color.RED, …
• Nuovi colori: formato rgb settando i valori delle
componenti red, green, blue tra 0.0F e 1.0F
Color magenta = new Color(1.0F,0.0F,1.0F), // F = float
• setColor setta il colore del Graphic Contexts
g2.setColor(magenta);
• Usa il colore con i metodi draw e fill
g2.fill(rectangle); // riempito con il colore corrente
Domanda
7.
Quale è la sequenza di istruzioni per
disegnare un quadrato giallo su uno
sfondo rosso?
Risposta
7.
Disegna un quadrato giallo all’interno di un
quadrato rosso:
g2.setColor(Color.RED);
g2.fill(new Rectangle(0, 0, 200, 200));
g2.setColor(Color.YELLOW);
g2.fill(new Rectangle(50, 50, 100, 100));
Progetto di applicazioni
grafiche
Disegno di forme complesse
• Prassi : un classe per ciascuna forma
class Car
{
. . .
public void draw(Graphics2D g)
{
// Istruzioni per il disegno
. . .
}
}
• Progetta la forma individuando le componenti
base
Esempio: due automobili
Progetto della Forma
Origine e punto di
riferimento della forma
File Car.java
01:
02:
03:
04:
05:
06:
07:
08:
import
import
import
import
import
java.awt.Graphics2D;
java.awt.Rectangle;
java.awt.geom.Ellipse2D;
java.awt.geom.Line2D;
java.awt.geom.Point2D;
/**
Una forma di auto posizionabile in un
un punto qualunque di una finestra.
09: */
10: public class Car
11: {
12:
/**
13:
Costruisce una auto a partire da una data origine
14:
@param x la coordinata x dell’origine
15:
@param y la coordinata y dell’origine
16:
*/
Continua…
File Car.java
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
public Car(int x, int y)
{
xLeft = x;
yTop = y;
}
/**
Disegna l’auto.
@param g2 il contesto grafico per il disegno
*/
public void draw(Graphics2D g2)
{
Rectangle scocca
= new Rectangle(xLeft, yTop + 10, 60, 10);
Ellipse2D.Double ruotaAnteriore
= new Ellipse2D.Double(xLeft + 10, yTop
+ 20, 10, 10);
Continua…
Ellipse2D.Double ruotaPosteriore
File Car.java
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
= new Ellipse2D.Double(xLeft + 40, yTop
+ 20, 10, 10);
// estremo inferiore del parabrezza
Point2D.Double p1
= new Point2D.Double(xLeft + 10,
// estremo anteriore del tetto
Point2D.Double p2
= new Point2D.Double(xLeft + 20,
// estremo posteriore del tetto
Point2D.Double p3
= new Point2D.Double(xLeft + 40,
// estremo inferiore del lunotto
Point2D.Double p4
= new Point2D.Double(xLeft + 50,
Line2D.Double parabrezza
= new Line2D.Double(p1, p2);
yTop + 10);
yTop);
yTop);
yTop + 10);
Continua…
File Car.java
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68: }
Line2D.Double tetto
= new Line2D.Double(p2, p3);
Line2D.Double lunotto
= new Line2D.Double(p3, p4);
g2.draw(scocca);
g2.draw(ruotaAnteriore);
g2.draw(ruotaPosteriore);
g2.draw(parabrezza);
g2.draw(tetto);
g2.draw(lunotto);
}
public static int WIDTH = 60;
public static int HEIGHT = 30;
private int xLeft;
private int yTop;
Costruiamo l’applicazione
JComponent contenente il disegno
• Ricordiamo: istruzioni per il disegno nel
metodo paintComponent
• Posizione in basso a dx:
int x = getWidth() – Car.WIDTH;
int y = getHeight()– Car.HEIGHT;
Car bottomCar = new Car(x, y);
• getWidth e getHeight chiamati sull’oggetto
che esegue paintComponent
• Se cambia la dimensione della finestra
paintComponent viene invocato e la posizione
dell’auto ricalcolata
Continua…
File CarComponent.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
/**
This component draws two car shapes.
*/
class CarComponent extends JComponent
{
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Car topCar = new Car(0, 0);
Continua…
File CarComponent.java
16:
17:
18:
19:
20:
21:
22:
23:
24: }
int x = getWidth() - Car.WIDTH;
int y = getHeight() - Car.HEIGHT;
Car bottomCar = new Car(x, y);
topCar.draw(g2);
bottomCar.draw(g2);
}
• Il metodo draw della classe Car invoca i
metodi del contesto grafico g2 per comporre
il disegno
L’applicazione CarViewer.java
01: import javax.swing.JFrame;
02:
03: public class CarViewer
04: {
05:
public static void main(String[] args)
06:
{
07:
JFrame frame = new JFrame();
08:
09:
final int FRAME_WIDTH = 300;
10:
final int FRAME_HEIGHT = 400;
11:
12:
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
13:
frame.setTitle("Two cars");
14:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Continua…
File CarViewer.java
15:
16:
17:
18:
19:
20:
21: }
CarComponent component = new CarComponent();
frame.add(component);
frame.setVisible(true);
}
Domanda
8.
Quale classe dobbiamo modificare per
ottenere un disegno in cui le auto sono
disposte una vicino all’altra?
Risposta
8.
CarComponent
Altre forme grafiche
Rectangle fasciaVerde = new
Rectangle fasciaRossa = new
Line2D.Double topLine
= new Line2D.Double(130,
Line2D.Double bottomLine
= new Line2D.Double(130,
Rectangle(100, 100, 30, 60);
Rectangle(160, 100, 30, 60);
100, 160, 100);
160, 160, 160);
Lettura da un dialog box
• In una una applicazione grafica possiamo
dare input mediante un JOptionPane
• Il metodo showInputDialog
attiva una finestra che dà un prompt e attende
input
restituisce la stringa fornita dall’utente
String input = JOptionPane.showInputDialog("Enter x");
double x = Double.parseDouble(input);
Continua…
Un dialog box
ColorViewer
• Una applicazione che permette all’utente di
comporre un colore decidendo i parametri
del formato rgb
• I valori vengono richiesti in seguenza
mediante dialog boxes
• Al termine l’applicazione attiva una finestra
con un quadrato del colore composto
dall’utente
File ColorViewer.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
class ColorViewer
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
final int FRAME_WIDTH = 300;
final int FRAME_HEIGHT = 400;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String input;
Continua…
File ColorViewer.java
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38: }
// Chiedi all’utente I valori di red, green, blue
input = JOptionPane.showInputDialog("red:");
double red = Double.parseDouble(input);
input = JOptionPane.showInputDialog("green:");
double green = Double.parseDouble(input);
input = JOptionPane.showInputDialog("blue:");
double blue = Double.parseDouble(input);
Color coloreScelto = new Color(
(float) red, (float) green, (float) blue);
ColorComponent component
= new ColorComponent(coloreScelto);
frame.add(component);
frame.setVisible(true);
}
File ColorComponent.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
import
import
import
import
import
java.awt.Color;
java.awt.Graphics;
java.awt.Graphics2D;
java.awt.Rectangle;
javax.swing.JComponent;
/**
Una componente che include un quadrato colorato
*/
class ColorComponent extends JComponent
{
private Color fillColor; // colore di riempimento
/**
Costruisce la componente
@param c il colore di riempimento del quadrato
*/
public ColorComponent(Color c)
Continua…
File ColorComponent.java
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
{
fillColor = c;
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
// Seleziona il colore del contesto grafico
g2.setColor(fillColor);
// Costruisci e colora un quadrato al centro
// della finestra
Continua…
File ColorComponent.java
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
43: }
final int LATO = 100;
Rectangle quadrato = new Rectangle(
(getWidth() - LATO) / 2,
(getHeight() - LATO) / 2,
LATO,
LATO);
g2.fill(quadrato);
}
Output
Domande
9.
Sarebbe possibile chiedere i tre valori per
r,g, e b in un unico dialog box?
10. Perché l’applicazione invoca
showInputDialog dal metodo main main
della classe ColorViewer e non dal
metodo paintComponent della classe
ColorComponent?
Risposte
9.
Certo, ma in quel caso è necessario
estrarre poi le singole componenti … un
utile esercizio di semplice su stringhe
10. Perchè in quel caso i dialog box
verrebbero rilanciati tutte le volte che la
finestra viene mossa / resized /
deiconificata /…