tela

disegnare forme geometriche su una superficie

Oltre che utilizzare componenti già fatti o caricare immagini da disco adesso vorremmo disegnare qualcosa noi da programma... non è una esigenza così singolare!

In verità c'è un componente già fatto che ha lo stesso uso di una tela da disegno e, coincidenza, si chiama Canvas (per i più precisi il suo nome completo è javafx.scene.canvas.Canvas), questo componente lo possiamo piazzare in una parte della finestra a nostra scelta esattamente come facciamo con un Button o un TextField e ci consente di disegnarci su linee, cerchi, punti e via di seguito.

Vediamo direttamente un esempio:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class HelloCanvas extends Application {

  @Override
  public void start(Stage primaryStage) {
    // creiamo un pannello specificando larghezza e altezza
    Canvas quadro = new Canvas(300, 260);
    // otteniamo l'oggetto che ci permette di disegnare
    GraphicsContext gc = quadro.getGraphicsContext2D();
    gc.setFill(Color.YELLOW);
    gc.setLineWidth(1);
    gc.fillOval(50, 50, 200, 200);
    gc.setFill(Color.BLACK);
    gc.fillOval(100, 100, 20, 20);
    gc.fillOval(180, 100, 20, 20);
    gc.setStroke(Color.RED);
    gc.setLineWidth(8);
    gc.strokeLine(100, 200, 150, 220);
    gc.strokeLine(150, 220, 200, 200);

    GridPane root = new GridPane();
    // inseriamo il nostro canvas nella finestra
    root.add(quadro, 0, 0);

    Scene scene = new Scene(root);
    primaryStage.setTitle("Hello Canvas!");
    primaryStage.setScene(scene);
    primaryStage.show();
  }

  public static void main(String[] args) {
    launch(args);
  }
}

Come avrai notato non possiamo disegnare direttamente su un canvas ma ci serve ottenere un oggetto di tipo GraphicsContext che abbiamo chiamato gc.

Nell'esempio qui sopra disegnamo con diversi colori linee e ovali di spessori diversi, un oggetto GraphicsContext ha molte istruzioni per disegnare diversi tipi di forme geometriche come linee, rettangoli cerchi (sia pieni che vuoti) e molte altre.

Le coordinate nell'oggetto Canvas

Le coordinate funzionano come quello del piano cartesiano con alcune cose da tenere a mente:

Cerchio e linea

Nel disegno qui sotto (un Canvas di dimensioni 400x300) abbiamo 2 elementi:

Una linea e un cerchio
gc.setLineWidth(1);
gc.setStroke(Color.RED);
gc.strokeLine(0, 100, 400, 50);
gc.setStroke(Color.GREEN);
gc.strokeOval(50, 0, 200, 200);

Cerchio e quadrato

In questo altro disegno che usa un Canvas 200x200 abbiamo un quadrato rosso di lato 200 e un cerchio verde di diametro 200:

gc.setLineWidth(2);
gc.setStroke(Color.RED);
gc.strokeRect(0, 0, 200, 200); 
gc.setStroke(Color.GREEN);
gc.strokeOval(0, 0, 200, 200);
Una linea e un cerchio

Effetti speciali

Proviamo a modificare il programma precedente inserendo in start un pulsante e l'usuale codice per gestire la sua pressione:

pulsante.setOnAction( e -> clickEffetto() );

Inseriamo poi prima della chiusura della classe il seguente frammento di codice:

public void clickEffetto(){
    gc.applyEffect(new GaussianBlur(20));
}

Siccome l'oggetto gc viene usato sia in start che in clickEffetto dovremo anche spostare la sua dichiarazione (soltanto la dichiarazione!) al livello di classe (fuori da start).

Ora che il programma non ha più errori: che succede se si preme il pulsante?