Presentare oggetti sulla scena

Terza lezione del corso introduttivo sun per la creazione di GUI con javaFX.

Qui si spiega l'architettura sottesa a javaFX che definisce la scena come un grafo contenente nodi che sono poi gli oggetti che vogliamo visualizzare.

Le classi coinvolte in questa architettura sono Scene, Node e Group.

La scena é un grafo che ha una struttura dati ad albero che definisce una gerarchia di oggetti grafici. Ogni elemento nel grafo é detto nodo. Ogni nodo ha un genitore, ad eccezione della radice (root node) che non ha un genitore. Ogni nodo o é una foglia (leaf) o é un ramo (branch). Una foglia non ha figli, un ramo ha zero o più figli.

I nodi in javaFX gestiscono diversi tipi di contenuti come componenti UI, forme, testi, immagini, e media. I nodi possono essere trasformati, animati, e si possono applicare loro svariati effetti.

In questa lezione si creerà una applicazione che contiene oggetti grafici un po' di tutti tipi.

Lavoriamo con il common profile, in modo da poter usare la nostra applicazione in entrambi gli ambienti desktop e mobile.

Alla base di tutto c'é la scena che, in javaFX, é un contenitore di nodi.

La classe base della gerarchia di classi che possono essere inserite in una scena é javafx.scene.Node, quindi tutte le altre classi che possono essere gestite come nodi, come ad esempio javafx.scene.shape.Circle, derivano da Node.

Per convenzione in Node si usa un sistema di ascisse e ordinate dove X aumenta muovendosi verso destra e Y aumenta scendendo verso il basso. Dunque l'angolo (0,0) é in alto a sinistra.

E' possibile raggruppare più nodi per trattarli come un unica entità, usando la classe javafx.scene.Group, che rappresenta per l'appunto un gruppo di nodi.

La finestra dell'applicazione

Creamo lo stage su cui monteremo la nostra scena:

import javafx.stage.Stage;

Stage {
title: "Nodes"
}

La scena

Per montare la scena nel nostro stage, aggiungiamo l'import per la classe Scene e Color (vogliamo infatti che la nostra scena abbia un colore di fondo diverso dal default).
Quindi assegnamo alla proprietà scene del nostro stage un'istanza di classe Scene con alcuni proprietà specificate (colore, e dimensioni):

...
import javafx.scene.Scene;
import javafx.scene.paint.Color;

Stage {
...
scene: Scene {
fill: Color.LIGHTBLUE
width: 220
height: 170
}
}

Il primo nodo

Nella variabile content della scena sono definiti i nodi che sono sulla scena stessa. Per aggiungere alla scena il nostro primo nodo, aggiungiamo l'import per la classe Circle (visto che aggiungeremo un cerchio) e assegnamo al content della nostra scena un oggetto Circle che definiamo come mostrato qua a seguire:

...
import javafx.scene.shape.Circle;

Stage {
...
scene: Scene {
...
content: Circle {
centerX: 50, centerY: 50, radius: 50
stroke: Color.YELLOW
fill: Color.WHITE
}
}
}

Un nodo di testo con trasformazione

Aggiungiamo un secondo nodo alla nostra scena, per far questo dobbiamo dire a content che ci saranno più oggetti dentro di lui, non possiamo più fare un semplice assegnamento di un oggetto ma abbiamo bisogno di definire un array. Per far ciò usiamo un parentesi quadra.
In pratica, avremo una definizione di content simile a questa:

content: [ Circle {...}, Text {...} ]

Visto che vogliamo un nodo di tipo testo, aggiungiamo l'import per la classe Text, e quindi aggiungiamo la definizione del nostro nodo nel content della nostra scena.

Ma non ci basta mettere una semplice stringa di testo, la vogliamo modificare per farla stare dentro il cerchio, ovvero, vogliamo applicare una trasformazione al nostro oggetto testo, quindi aggiungeremo l'import anche della classe Transform.
Nel nostro oggetto di testo assegneremo quindi alla sua variabile transform il risultato del metodo statico Transform.rotate(), specificando un angolo di 33 gradi e un punto pivotale per la rotazione in (10, 100):

...
import javafx.scene.text.Text;
import javafx.scene.transform.Transform;

Stage {
...
scene: Scene {
...
content: [
Circle {
...
},
Text {
transforms: Transform.rotate(33, 10, 100)
content: "Duke"
}
]
}
}

Un nodo immagine

Per mettere un immagine in scena abbiamo bisogno di due classi, una per rappresentare l'immagine in sè, e quindi aggiungeremo una import per la classe Image, e una per rappresentare la vista dell'immagine stessa, come verrà gestita dalla scena, altra import per ImageView.
Per specificare da dove va presa un'immagine c'é nella classe Image una variabile, url, che é per l'appunto l'indirizzo da cui possiamo reperire la nostra immagine. Qui usiamo un file locale alla nostra macchina, e quindi specifichiamo di andarla a prendere nella directory corrente (accertiamoci che il file ci sia, possiamo copiarlo lì dal tutorial javaFX). Non specifichiamo dove posizionare l'immagine, e perciò verrà messa nella posizione di default, angolo di sinistra in alto a (0,0):

...
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;

Stage {
...
scene: Scene {
...
content: [
Circle {
...
},
Text {
...
},
ImageView {
image: Image {url: "{__DIR__}dukewave.png"}
}
]
}
}

Nodi in gruppo

Tutto ok, ma ci piacerebbe spostare il nostro lavoretto un po' verso il centro. Per far ciò raggruppiamo tutti i nostri oggetti grafici e applichiamo una traslazione al gruppo.
Ci servirà importare la classe Group e cambiare il content della nostra scena. Nella scena torneremo ad avere un solo oggetto: il gruppo che contiene tutti gli altri oggetti.

...
import javafx.scene.Group;

Stage {
...
scene: Group {
translateX: 55, translateY: 10
content: [
Circle {
...
},
Text {
...
},
ImageView {
...
}
]
} // Group
} // Scene
} // Stage

E questo é tutto. Ci siamo costruiti un gruppo di oggetti visuali e li abbiamo mossi sulla scena. Non male, dopotutto.

A seguire, il codice completo dello script:

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Text;
import javafx.scene.transform.Transform;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.Group;

Stage {
title: "Nodes"
scene: Scene {
fill: Color.LIGHTBLUE
width: 220
height: 170
content: Group {
translateX: 55, translateY: 10
content: [
Circle {
centerX: 50, centerY: 50, radius: 50
stroke: Color.YELLOW
fill: Color.WHITE
},
Text {
transforms: Transform.rotate(33, 10, 100)
content: "Duke"
},
ImageView {
image: Image {url: "{__DIR__}dukewave.png"}
}
]
} // Group
} // Scene
} // Stage

Nessun commento:

Posta un commento