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 /…