Colori e figure geometriche riempite

Uso dei colori standard

Le istruzioni grafiche viste fino ad ora disegnano figure geometriche con il colore nero. Vediamo ora come si fa a disegnare delle linee in rosso, o dei cerchi in blu, ecc.

In Java, non è possibile specificare con una sola istruzione che si vuole per esempio disegnare una linea in rosso. Java utilizza invece il concetto di colore corrente. Ogni volta che si disegna qualcosa, questo viene fatto usando il colore corrente. All'inizio, il colore corrente è nero, ma può venire cambiato. In questo modo, se si vogliono disegnare due linee in rosso e un cerchio in blu, quello che occorre fare è:

In altre parole, ogni volta che si cambia il colore corrente, tutte le successive istruzioni di disegno avverrano con il nuovo colore corrente. Per disegnare con un altro colore, occorre di nuovo cambiare il colore corrente.

L'istruzione che permette di cambiare il colore corrente si chiama setColor. I colori standard che Java mette a disposizione sono i seguenti:

Color.black Color.blue Color.cyan Color.darkGray Color.gray 
Color.green Color.lightGray Color.magenta Color.orange 
Color.pink Color.red Color.white Color.yellow 
Per disegnare le linee in rosso, occorre quindi eseguire la istruzione g.setColor(Color.red), che cambia il colore corrente in rosso, e poi disegnare le linee normalmente (usando la drawLine come al solito).

Il programma Standard.java usa tre colori standard (rosso, blu e nero) per disegnare varie figure geometriche.

/*
  Uso dei colori standard.
*/

import java.awt.*;

public class Standard extends java.applet.Applet {
  public void paint(Graphics g) {

    /* da qui in poi, disegna in rosso */
    g.setColor(Color.red);
    g.drawLine(0,0,100,100);
    g.drawLine(0,100,100,0);
    g.drawRect(0,0,100,100);

    /* da qui in poi, disegna tutto in blu */
    g.setColor(Color.blue);
    g.drawLine(100,100,200,200);
    g.drawOval(200,200,100,50);

    /* disegna in nero */
    g.setColor(Color.black);
    g.drawRect(0,200,50,50);

  }
}

Va notato che per tornare a usare il nero, occorre l'istruzione g.setColor(Color.black). In altre parole, una volta cambiato colore, per tornare a usare quello precedente occorre usare la setColor: non esiste una istruzione che dice di tornare al colore precedente senza specificare quale era. Il risultato è il seguente:

Figure geometriche riempite

Le istruzioni di disegno viste fino ad ora tracciavano in effetti solo il contorno delle figure, ossia il loro perimetro. In Java, è possibile anche disegnare figure geometriche il cui interno sia riempito con il colore corrente. Il modo di farlo è molto semplice: mentre le istruzioni per disegnare il contorno si chiamano drawQualcosa, le istruzioni per disegnare anche l'interno si chiamano fillQualcosa. Qui sotto ci sono tutte le istruzioni di disegno viste fino ad ora, con accanto le istruzioni che riempiono:

FiguraDisegno del contornoDisegno riempito
RettangolodrawRectfillRect
PoligonodrawPolygonfillPolygon
OvaledrawOvalfillOval
ArcodrawArcfillArc

Le istruzioni di riempimento hanno esattamente gli stessi argomenti delle istruzioni che disegnano il contorno. Per esempio, fillRect prende quattro numeri, che sono le coordinate del punto in alto a sinistra del rettangolo, la larghezza e l'altezza.

Il programma Riempite.java disegna alcune figure geometriche riempite.

/*
  Alcune figure geometriche riempite.
*/

import java.awt.*;

public class Riempite extends java.applet.Applet {
  public void paint(Graphics g) {
    Polygon p=new Polygon();

    g.fillRect(0,0,100,100);

    g.setColor(Color.red);
    g.fillOval(100,100,50,100);
    g.fillArc(200,0,80,120,45,150);

    p.addPoint(200,200);
    p.addPoint(200,250);
    p.addPoint(250,400);
    p.addPoint(190,500);
    p.addPoint(160,200);
    
    g.setColor(Color.blue);
    g.fillPolygon(p);
  }
}

Il risultato è il seguente:

Diagramma a torta

Siano dati un insieme di percentuali. Si vuole realizzare il loro diagramma a torta, che è costituito da un cerchio diviso in tanti settori quante sono le percentuali. Ogni arco ha un angolo che è proporzionale alla corrispondente percentuale. Per rendere più chiaro il diagramma, i vari settori devono essere colorati con colori diversi.

Si suppone che le percentuali siano memorizzate in un vettore di interi, per esempio:

    int percentuali[]={10, 15, 30, 25, 20};

L'istruzione fondamentale è chiaramente quella di disegno di un angolo riempito fillArc, insieme a quella di cambiamento del colore. Concentriamoci per il momento sul disegno dei settori, rimandando il cambiamento di colore a un secondo momento.

Come si è detto, ogni settore deve avere un angolo proporzionale a una percentuale. Per esempio, il primo settore deve avere un angolo proporzionale a percentuali[0]. Quanto deve essere grande esattamente questo angolo? In tutti i casi in cui occorre stabilire una relazione lineare tre due grandezze, è sufficiente considerare i due casi estremi:

Ora, diciamo che a è l'angolo e p è la percentuale. Sappiamo che a deve essere proporzionale a p, quindi una relazione lineare intercorre fra loro:
a = x * p + y

Per trovare i valori delle costanti x e y, usiamo i due casi estremi, che diventano:

0 = x * 0 + y
360 = x * 100 + y

Dalla prima equazione si ricava y=0, per cui la seconda equazione diventa 360 = x * 100, ossia x=360/100. Quindi, data una percentuale p, l'angolo a si ricava dalla equazione:

a = (360/100)*p

Parte del problema è quindi risolto: ora sappiamo quanto è grande ogni angolo che va disegnato. Manca ora da specificare quale è il suo punto di partenza. Per il primo angolo questo è ovvio: il punto di partenza si trova a 0 gradi. Il punto di partenza del secondo arco si trova esattamente dove finisce il primo, il terzo dove finisce il secondo, ecc. La regola è quindi semplice: il punto d'inizio dell'i-esimo arco è il punto finale dell'arco disegnato precedentemente. Basta quindi memorizzare in una variabile il punto in cui l'arco corrente finisce, e questo sarà il punto di inizio dell'arco successivo. Il punto di fine di ogni arco si trova sommando l'ampiezza dell'arco al punto in cui l'arco inizia. Usiamo la variabile fine per indicare l'angolo a cui ogni arco finisce (e quindi il successivo inizia). Il disegno degli archi si può quindi effettuare con il codice seguente:

    int i;
    int fine;

    fine=0;

    for(i=0; i<=percentuali.length-1; i++) {
      g.fillArc(100,100, 300, 300, fine, percentuali[i]*360/100);

      fine=fine+percentuali[i]*360/100;
    }
A parole: si usa una variabile i per scandire il vettore delle percentuali. La variabile fine indica l'angolo a cui inizia il settore successivo, e quindi parte a 0. Ad ogni passo, si disegna un nuovo settore, e si aggiorna il punto in cui il nuovo settore deve cominciare.

Veniamo ora alla questione dei colori. Supponiamo che le percentuali da visualizzare siano solo cinque, per cui bastano cinque colori diversi. Supponiamo quindi di voler usare, per le varie percentuali, i seguenti colori:

Color.green, Color.red, Color.blue, Color.yellow, Color.orange, Color.gray

L'ideale sarebbe poter mettere una istruzione setColor all'interno del ciclo, in modo tale che quando i vale 0 si esegue g.setColor(Color.green), quando i vale 1 si esegue g.setColor(Color.red), quando i vale 2 si esegue g.setColor(Color.yellow), ecc.

In effetti, conosciamo un modo per associare un valore a dei numeri interi: i vettori. In questo caso, per i=0 ci serve Color.green, per i=0 ci serve Color.red, ecc. Quindi, usiamo un vettore in cui memorizziamo Color.green nella posizione 0, Color.red nella posizione 1, ecc. Ad ogni passo, basta cambiare il valore corrente usando il contenuto di una delle celle che costituiscono il vettore colori.

Il programma Torta.java è stato realizzato a partire dalle considerazioni riportate sopra.

import java.awt.*;

public class Torta extends java.applet.Applet {
  public void paint (Graphics g) {
    int percentuali[]={10, 15, 30, 25, 20};
    Color colori[]={Color.green, Color.red, Color.blue, Color.yellow,
                    Color.orange, Color.gray };
    int i;
    int fine;

    fine=0;

    for(i=0; i<=percentuali.length-1; i++) {
      g.setColor(colori[i]);

      g.fillArc(100,100, 300, 300, fine, percentuali[i]*360/100);

      fine=fine+percentuali[i]*360/100;
    }
  }
}

Il grafico delle percentuali viene visualizzato come segue.

Creazione di nuovi colori

Come si è detto, in Java sono disponibili alcuni colori ``standard'':
           Color.black 
           Color.blue 
           Color.cyan 
           Color.darkGray 
           Color.gray 
           Color.green 
           Color.lightGray 
           Color.magenta 
           Color.orange 
           Color.pink 
           Color.red 
           Color.white 
           Color.yellow 
In alcuni casi semplici, questi colori possono essere sufficienti. D'altra parte, ci sono dei casi in cui occorrono altri colori oltre a questi. In Java, è possibile definire un colore attraverso le sue tre coordinate RGB.

Come è noto, ogni colore si può ottenre ``mischiando'' quantità opportune dei tre colori fondamentali rosso, verde e blu. Ogni colore è quindi determinato dalle quantità dei tre colori fondamentali che lo compongono. In Java, si assume che le componenti di colore variano da 0 a 255, per cui (0,0,0) è il nero, mentre (255,255,255) è il bianco. Per esempio, il colore rosso è composto da una componente rossa di massima intensità, e da nessun altro colore fondamentale, per cui il rosso è identificato dalla terna di coordinate (255,0,0).

Per creare un nuovo colore occorre una variabile di tipo Color, che è una zona di memoria in cui si memorizza un colore. Per decidere il colore da memorizzare in questa locazione si usa il comando:

  c = new Color(a,b,c);
dove a, b, c sono le coordinate di colore del nuovo colore da creare.

Vediamo ora un esempio di uso della allocazione di nuovi colori. Vogliamo disegnare dei quadrati colorati, ognuno di lato 20, disposti a griglia. Vogliamo che il quadrato in posizione (0,0) sia riempito del colore di coordinate (0,0,0), mentre quello di coordinate (20,0) abbia colore (20,0,0) e quello in posizione (0,10) sia colorato con (0,20,0), e così via: il quadrato in posizione (i,j) deve essere colorato con il colore (i,j,0).

Il programma NuoviColori.java disegna la griglia facendo un ciclo in cui la variabile i va da 0 a 250 aumentando ogni volta di 20. Per ogni valore di i occorre considerare tutti i valori di j da 0 a 250, per cui all'interno del ciclo for si mette un secondo ciclo for. Quello che si trova all'interno del secondo ciclo viene quindi eseguito per ogni valore di i e per ogni valore di j. Quello che si deve fare è creare un nuovo colore, dire che si vuole usare questo nuovo colore da ora in avanti, e disegnare il quadrato.

/*
  Allocazione di nuovi colori.
*/

import java.awt.*;

public class NuoviColori extends java.applet.Applet {
  public void paint(Graphics g) {
    int i,j;
    Color c;

    for(i=0; i<=250; i=i+20) {
      for(j=0; j<=250; j=j+20) {
        c=new Color(i,j,0);

        g.setColor(c);

        g.fillRect(i,j,20,20);
      }
    }
  }
}

Cancellazione

Finora si è visto come disegnare figure geometriche vuote e riempite. Vediamo ora come si fa a cancellare una parte della finestra.

L'istruzione che si usa è la clearRect. Questa istruzione ha quattro argomenti, che sono le coordinate in alto a sinistra di un rettangolo, la sua larghezza e la sua altezza. L'effetto è che la zona rettangolare determinata da questi quattro numeri viene cancellata. In altre parole clearRect(x,y,w,h) è equivalente a disegnare un rettangolo riempito con il colore dello sfondo, il che equivale a cancellare tutto quello che si trova all'interno del rettangolo.

Il seguente programma Cancella.java disegna una griglia e cancella la sua parte centrale usando l'istruzione clearRect.

/*
  Disegna una griglia, e ne cancella una parte.
*/

import java.awt.*;

public class Cancella extends java.applet.Applet {
  public void paint(Graphics g) {
    int x,y;

    /* disegna le linee verticali */
    for(x=0; x<=200; x=x+10) {
      g.drawLine(x, 0, x, 200);
    }

    /* disegna le linee orizzontali */
    for(y=0; y<=200; y=y+10) {
      g.drawLine(0, y, 200, y);
    }

    /* cancella una zona */
    g.clearRect(45,45,100,100);
  }
}

Il risultato dell'esecuzione è il seguente disegno.