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

Sintassi dichiarativa

Vediamo la seconda lezione del corso sun introduttorio alla costruzione di applicazioni GUI con javaFX.

Per spiegare l'approccio dichiarativo in questo contesto, si scrive un semplice applicazione javaFX che visualizza un cerchio con un rettangolo smussato sopra.

Dato che usiamo il common profile, l'applicazione funziona in entrambi i contesti desktop e mobile.

Creiamo dunque uno script fx nel file declaring.fx, che riempiremo passo dopo passo per realizzare la nostra applicazione.

Per creare la finestra principale della nostra applicazione dobbiamo semplicemente dichiarare l'oggetto letterale Stage.

Per personalizzare il nostro Stage, assegnamo un valore alla sua variabile - per iniziare gli assegnamo un titolo.

import javafx.stage.Stage;

Stage {
title: "Declaring Is Easy!"
}

Con questo codice abbiamo usato l'approccio dichiarativo per creare il palcoscenico (stage) della nostra applicazione, ovvero la sua finestra principale, e abbiamo assegnato un valore ad una sua proprietà (chiamata instance variable).

La documentazione di Stage ci mostra tutte le sue variabili disponibili, tra cui, oltre al titolo, vediamo che ci sono anche la sua altezza (height) e ampiezza (width). Possiamo modificare il nostro script per vederle in uso:

import javafx.stage.Stage;

Stage {
title: "Declaring Is Easy!"
height: 150
width: 300
}

Tra le proprietà dello stage c'é anche la scena, che é il "posto" dove avverranno le cose, ovvero dove metteremo i nostri oggetti che vogliamo visualizzare. Riscriviamo perciò il nostro script per includere una scena che, inizialmente, non conterrà alcunché.

import javafx.stage.Stage;
import javafx.scene.Scene;

Stage {
title: "Declaring Is Easy!"
scene: Scene {
width: 300
height: 250
content: [ ]
}
}

Abbiamo aggiunto l'import per la scena, e abbiamo assegnato alla proprietà relativa del nostro stage l'oggetto scena che abbiamo costruito al volo.
Notiamo che non é necessario definire le dimensioni dello stage, dato che abbiamo definito quelle della scena che é contenuta nello stage. Inoltre, se l'applicazione fosse per mobile, non dovremmo definire la dimensione, visto che si assumerebbe che venga usata tutta la (modesta) area a disposizione del dispositivo.

La scena é in pratica il nodo originario (root node) dell'albero di oggetti che sono posti sullo stage.
Nel suo contenuto (content) mettiamo i nodi che desideriamo presentare all'utente, che saranno, ad esempio, oggetti grafici, testo, o componenti di interfaccia.

Mettiamo ora qualcosa nel contenuto della scena, creiamo un cerchio in content:

...
import javafx.scene.shape.Circle;
import javafx.scene.paint.Color;
...
content: [
Circle {
centerX: 150
centerY: 120
radius: 80
fill: Color.MAROON
stroke: Color.INDIANRED
strokeWidth: 10.0
}
]
...

Abbiamo modificato il nostro script aggiungendo due import e dichiarando un oggetto di tipo Circle all'interno del contenuto della scena.
Il nostro cerchio ha centro nel punto (150, 120), un raggio di 80, é riempito col colore marrone, e ha un bordo (stroke) di ampiezza 10 e colore rosso indiano.

Aggiungiamo ora un rettangolo al nostro stage.

...
import javafx.scene.shape.Rectangle;
...
content: [
Circle { ... }
Rectangle {
x: 25, y: 80, width: 250, height: 80
arcWidth: 20 arcHeight: 20
fill: Color.web("#6699ff")
stroke: Color.web("#003399")
strokeWidth: 5.0
opacity: 0.5
}
]

Abbiamo aggiunto l'import per la classe Rectangle e abbiamo aggiunto una sua istanza al contenuto della scena.
Nota che abbiamo utilizzato una sintassi leggermente diversa (le virgole tra le proprietà sono opzionali e risultano comode per migliorare la leggibilità quando se ne scrivono diverse sulla stessa riga) e che abbiamo definito qui i colori usando, invece che una costante letterale, il metodo statico pubblico web() della classe Color, che converte in colore RGB una stringa che lo rappresenta in notazione esadecimale.
Abbiamo definito l'opacità (opacity) del nostro rettangolo a 0.5 in modo da lasciar vedere il cerchio sottostante - per default i colori definiti via Color.web() hanno una opacità pari a 1.
Gli angoli del rettangolo sono smussati in accordo alla definizione di arcWidth e arcHeight.

Notiamo infine che il primo oggetto messo nella scena resti sullo sfondo e venga coperto, nel caso di sovrapposizioni da chi viene dopo. Infatti permutando l'ordine degli oggetti posti in content, mettendo come primo nodo il rettangolo e come secondo il cerchio, otteniamo che il cerchio sia in primo piano (e dato che l'opacità é settata come default a 1, nasconde completamente il rettangolo nell'area di sovrapposizione).

Javafx 1.2

All'inizio di giugno é uscita la nuova versione di javaFX, la 1.2, che sembra sia un bel passo in avanti rispetto alla precedente 1.1, soprattutto nel mettere a disposizione nuove classi che permettono di gestire più agevolmente le componenti grafiche.

Per maggiori informazioni, vedi il sito ufficiale, javafx.com che, oltre a permettere il download dell'ambiente di sviluppo, mette a disposizione documentazione introduttiva.

In realtà io non ne so ancora abbastanza per commentare il passaggio a 1.2, dato che mi sono appena cominciato a studiare il linguaggio che, per quanto ho visto, mi sembra abbastanza interessante nel suo ambito.

Vedi il blog javafxi.blogspot.com per una introduzione alle feature del linguaggio dal punto di vista di uno sviluppatore con un background in java (la cosa aiuta parecchio, a ben vedere).

Questo é il primo post sul tutorial sun introduttivo alle funzionalità di base di javafx.

E questo é il primo post relativo al tutorial sun introduttivo alla gestione della GUI con javafx.

Desktop profile

Parte finale della prima lezione del corso Oracle a introduzione su come scrivere gui con javaFX.

Per il "desktop", ovvero per gli ambienti che prevedano l'utilizzo di una periferica di output di dimensioni superiori a quelle dei pochi pollici dell'"handy", sono diponibili in ambiente javaFX un altro paio di caratteristiche interessanti: effetti e cursori.

Effetti

Per vedere gli effetti in azione, si scarichi lo script effects.fx.

Dal codice javaFX vediamo che per dare un effetto a un gruppo di oggetti usiamo classi del package javafx.scene.effect e javafx.scene.effect.light semplicemente specificando la proprietà effect dell'oggetto grafico che vogliamo modificare.

L'ombreggiatura applicata ad un elemento grafico gli dà un effetto tridimensionale, come se si librasse, o sprofondasse nel piano su cui é rappresentato.

Si usano due classi per generare una ombreggiatura: DropShadow e InnerShadow

Vediamo ad esempio il primo oggetto ombreggiato definito nello script, un gruppo comprendente un cerchio rosso con due linee che si incrociano al suo interno.

Al gruppo possiamo aggiungere l'effetto ombreggiatura, che possiamo variare in molti modi, ad esempio specificando il suo colore.

Group {
content: [
Circle{centerX: 30 centerY:40 radius:20 fill: Color.RED opacity: 0.8 cursor: Cursor.HAND},
Line {startX: 20 startY: 30 endX: 40 endY: 50 stroke: Color.WHITE strokeWidth: 2},
Line {startX: 20 startY: 50 endX: 40 endY: 30 stroke: Color.WHITE strokeWidth: 2}
]
effect: DropShadow{offsetX:5 offsetY:5 color: Color.BLACKS}
};

E' possibile creare ombreggiature più complesse mescolando diversi oggetti Shadow, usando la classe Blend

L'illuminazione gli dà anch'essa un effetto tridimensionale, ma paragonabile all'agire sull'elemento grafico come per pigiarlo nel piano o farlo saltar fuori.

Per creare l'effetto illuminazione usiamo la classe Lighting specificando il tipo di luce utilizzata nel suo parametro light.

Group {
content:[
Circle{centerX: 30 centerY:20 radius:20 fill: Color.RED opacity: 0.9},
Line {startX: 20 startY: 10 endX: 40 endY: 30 stroke: Color.WHITE strokeWidth: 2},
Line {startX: 20 startY: 30 endX: 40 endY: 10 stroke: Color.WHITE strokeWidth: 2}
]
effect: Lighting {light: DistantLight{azimuth: 90}}
};

E' possibile poi creare un effetto sfocamento usando le classi della famiglia Blur (BoxBlur, GaussianBlur, MotionBlur). Questo esempio mostra un rettangolo riempito con cerchi concentrici bianchi e verde scuro a cui viene applicato l'effetto GaussianBlur:

Rectangle {
x:5 y:25 width: 100 height: 50
fill: RadialGradient {
centerX: 55, centerY: 50, radius: 10, proportional: false
cycleMethod: CycleMethod.REFLECT
stops: [
Stop{offset: 0.3 color: Color.DARKGREEN},
Stop{offset: 1.0 color: Color.WHITE}
]
}
effect: GaussianBlur{radius: 5 }
};

Si può creare un riflesso dell'oggetto grafico, usando la classe Reflection. Nell'esempio lo si applica ad un testo:

Text {
x: 10 y: 42 content: "Reflection"
fill: Color.SEAGREEN
font: Font{size:20 name: "Verdana"}
effect: Reflection { fraction: 0.9 topOpacity: 0.9 topOffset: 0.1}
};

Per cambiare la luminescenza di una immagine si usa la classe Glow, come mostrato qui:

ImageView {
image: Image{url:"http://java.sun.com/docs/books/tutorial/images/penduke.gif"}
effect: Glow{level: 1}
};

Per virare in seppia un immagine usiamo l'effetto SepiaTone:

ImageView {
image: Image{url:"http://java.sun.com/docs/books/tutorial/images/penduke.gif"}
effect: SepiaTone {level: 0.8}
};

Si possono cambiare gli attributi del colore di un oggetto grafico con ColorAdjust:

ImageView {
image: Image{url:"http://java.sun.com/im/logo_sun_small_sdn.gif"}
effect: ColorAdjust{brightness: -0.2}
};

O, infine, trasformarlo mettendolo in prospettiva con PerspectiveTransform:

var transformed = ImageView {
image: Image{url: "http://java.sun.com/docs/books/tutorial/images/penduke.gif"}
effect: PerspectiveTransform {
ulx: 40 uly: 20
urx: 104 ury: 20
lrx: 134 lry: 115
llx: 10 lly: 105
}
}

Cursori

E' possibile specificare che forma abbia il cursore sopra una certa regione della finestra di visualizzazione. Vedi lo script cursor.fx per un esempio.

Il cursore é un attributo di un oggetto grafico, quindi lo settiamo come vediamo in questo esempio:

Group {
content:[
Circle{centerX: 30 centerY:40 radius:20 fill: Color.RED opacity: 0.8 cursor: Cursor.HAND},
Line {startX: 20 startY: 30 endX: 40 endY: 50 stroke: Color.WHITE strokeWidth: 2},
Line {startX: 20 startY: 50 endX: 40 endY: 30 stroke: Color.WHITE strokeWidth: 2}
]
effect: DropShadow{offsetX:5 offsetY:5 color: Color.BLACK}
};

I cursori a disposizione sono indicati nella classe javafx.scene.Cursor, e usati come visto sopra (Cursor.HAND).

Common Profile

Continuamo a vedere la prima lezione del corso Oracle a introduzione su come scrivere gui con javaFX. Attacchiamo ora il Common Profile. Questa lezione m'é stata cambiata sotto i piedi, infatti ci stavo lavorando sopra in questi giorni (inizio giugno 2009) proprio in corrispondenza con il rilascio della versione 1.2 di javaFX, che ha aggiunto molta roba in questo contesto.

Partiamo con gli elementi di GUI, lo script che li fa vedere in opera é UIControls.fx si trova sul sito sun. Si tratta di radio button, textbox, toggle button, check box, slider e progress bar che sono definiti nel package javafx.scene.control.

Poi si passa ai grafici. Il supporto ai quali viene fornito tramite il package javafx.scene.chart e sembra veramente notevole. Si possono costruire facilmente grafici con aree, areaChart.fx, a barre, barChart.fx, a bolle, bubbleChart.fx, a linee, lineChart.fx, a torta, pieChart.fx, o a punti, scatteredChart.fx, insomma, ce n'é per tutti i gusti.

E' estremamente semplice costruire un pannello per la gestione dei colori usando la classe javafx.scene.paint.Color, come illustrato nello script colors.fx.

Per la gestione di forme geometriche si fa riferimento al package javafx.scene.shape, e lo script shapes.fx ce ne da un esempio.

Sono a disposizione alcuni stili di riempimento per le forme geometriche, definiti nel package javafx.scene.paint, e che possiamo vedere all'opera nello script fill.fx.

Sono anche disponibili alcuni stili per la visualizzazione delle linee, definite nel package javafx.scene.shape e visibili con un esempio nello script line.fx.

Per la gestione del testo si veda lo script text.fx, che mostra come formattare stringhe di caratteri con diversi stili.

Per vedere come applicare trasformazioni a immagini c'é lo script transform.fx, nota che si fa riferimento a un file, strawberry.jpg che deve essere presente nella stessa directory dello script.

Per avere un esempio di come gestire il layout ci sono due script, hbox.fx e vbox.fx, che usano classi del package javafx.scene.layout.

Introduzione alle GUI - cellulare o desktop

Secondo tutorial per javaFX disponibile sul sito della sun. Mentre il primo era rivolto al core delle funzionalità di javaFX, qui vedremo meglio come costruire applicazioni con una GUI. La prima lezione ci serve per avere una introduzione alla materia.

javaFX é pensato per lavorare sia su un computer propriamente detto, con svariati pollici di spazio a disposizione per visualizzare il proprio output, sia su periferiche mobili, come a dire su telefoni cellulari dove lo spazio a disposizione é molto più modesto.

Ci sono due profili javaFX a disposizione, il common profile che include classi per operare in entrambi gli ambienti, e il desktop profile dedicato esclusivamente a funzionalità pensate per migliorare le applicazioni cosiddette desktop.

Per vedere l'effetto che fa un applicazione javaFX su un telefono, é possibile utilizzare l'emulatore incluso nel javaFX SDK. Se si sta usando netbeans, si può impostare nelle proprietà del progetto il modello di esecuzione in modo che l'eseguibile in fase di testing corra sul emulatore di cellulare (il tutto si trova nelle proprietà del progetto, sotto la categoria "run")

Come primo esempio per vedere come gira un applicazione javaFX é reso disponibile sul sito sun un semplice script, ball.fx, che mostra per l'appunto una palla.

Package e accesso

Ultime due lezioni, numero 10 sui package e 11 sui modificatori d'accesso, del corso Sun introduttivo a javaFX.

Niente da dire a commento aggiuntivo sui package, tutte cose che chi ha usato java conosce già. E quindi passiamo direttamente all'ultima lezione.

Accesso default

Se non specifichiamo nessun accesso intendiamo utilizzare l'accesso di default (come pare ragionevole), noto anche in javaFX come script-only, nel senso che tutto ciò che é definito in questo modo é visibile solo nel file corrente.

Questa modalità d'accesso é evidentemente specifica per javaFX, dato che in java non c'é questa interpretazione di un singolo file come unità a sé stante.

Accesso package

E' in javaFX quello che é per java l'accesso default, creando probabilmente qualche confusione. Anche perché per dichiarare che una variabile ha in javaFX un accesso package devo scrivere qualcosa del genere:

package var x;

Che può confondere le idee rispetto al concetto di package come unità contenente classi (e script).

In ogni caso: una variabile, classe o funzione dichiarata di accesso package é visibile dal codice presente nello stesso package.

Come esempio di uso della visibilità a livello package, creamoci un paio di file, nel primo, one.fx, scriviamo questo codice:

// tutorial/one.fx
package tutorial; // (1)

package var message = "Hello from one.fx!"; // (2)

// (3)
package function printMessage() {
println("{message} (in function printMessage)");
}

1: dichiariamo che il file é nel package tutorial.
2: definiamo una variabile con visibilità limitata al package corrente
3: definiamo una funzione con visibilità limitata al package corrente

Creiamo quindi un altro file, two.fx, che usa quanto definito in one.fx:

// tutorial/two.fx
package tutorial; // (1)

println(one.message); // (2)
one.printMessage(); // (3)

1: dichiariamo che il file é nel package tutorial.
2: usiamo la variabile message definita nell'oggetto one package corrente
3: definiamo la funzione printMessage() definita nell'oggetto one del package corrente

Questo modo di accedere variabili e fuzioni definite in one.fx ci spiega anche come funziona il trucco che permette a javaFX di farci definire codice e funzioni in un file all'esterno di classi: viene evidentemente definito un oggetto implicito che ha lo stesso nome del file.

Quindi per accedere la funzione printMessage() definita nel file one.fx scriviamo semplicemente:

one.printMessage();

Accesso protected

Qui siamo nel terreno conosciuto delle modalità di accesso java: l'accesso protected fa in modo che quanto definito sia accessibile all'interno del package corrente e da tutte le classi derivate da ogni classe del package stesso.

Riscriviamo l'esempio precedente dando, in one.fx, visibilità protected a un membro di classe pubblica:

package tutorial;

public class one {
protected var message = "Hello!";
}

La classe one sarà accedibile da ovunque, essendo pubblica, e message sarà accedibile da tutte le classi derivate da one, essendo protected. Per veder ciò, riscriviamo two.fx in questo modo:

import tutorial.one;

class two extends one {
function printMessage() {
println("Class two says {message}");
}
};

var t = two{};
t.printMessage();

Da notare, oltre a quanto detto per protected, un paio di cosettine: in javaFX la convenzione sui nomi é decisamente più rilassata (almeno in questo tutorial), e le classi hanno nomi che cominciano con lettere minuscole. Inoltre l'oggetto di tipo two viene costruito qui con la sintassi specifica di javaFX, ovvero, e non con quella java (var t = new two();).

Accesso public

Come per il public in java, massima accessibilità garantita per chi ha questo livello di accesso.

Accesso public-read

Altra interessante estensione di javaFX alle modalità di accesso proprie di java. Con public-read diciamo che una variabile é accedibile in lettura a tutti, ma può essere modificata solo nello script corrente.

E' possibile cambiare i privilegi in scrittura a questa variabile abbinando a public-read il modificatore di accesso package o protected.

Accesso public-init

Estende ulteriormente la public-read, rendendo la variabile anche inizializzabile da tutti. Ma, dopo l'inizializzazione, accedibile solo in lettura a livello public. L'accesso in scrittura, dopo la creazione, é gestito come nel caso public-read, ovvero solo nello script corrente per default.

Scrivere classi

Con la lezione numero 9 del corso Sun introduttivo a javaFX, torniamo a vedere cose che, per chi abbia un background java sono piuttosto scontate, si parla infatti, con un po' più di dettaglio di quanto si sia fatto precedentemente, di classi e oggetti in javaFX.

La differenza fondamentale tra java e javaFX, é che é stato rimossa la limitazione sul nome del file che dove corrispondere al nome della classe principale contenuta nel file stesso. E quindi si possono mettere tutte le classi che vogliamo in un unico file. Questo rende probabilmente la struttura di un progetto FX meno lineare di un java classico ma permette una più semplice scrittura di script.

Approfitteremo di questa feature di javaFX per scrivere tutto il codice di cui parliamo in questo post in un unico file fx.

Prima cosa, definiamo la classe Address in questo modo:

class Address {
var street: String;
var city: String;
var state: String;
var zip: String;
}

In pratica un indirizzo viene definito come un aggregato di quattro stringhe: via, città, stato, e cap.

Un poco più interessante la classe Customer, che definisce come suo dato membro un oggetto di tipo Address e tre funzioni che usano i dati della classe:

class Customer {
var firstName: String;
var lastName: String;
var phoneNum: String;
var address: Address;

function printName() {
println("Name: {firstName} {lastName}");
}

function printPhoneNum(){
println("Phone: {phoneNum}");
}

function printAddress(){
println("Street: {address.street}");
println("City: {address.city}");
println("State: {address.state}");
println("Zip: {address.zip}");
}
}

Per costruire un oggetto di tipo Customer, facciamo come si vede qui a seguire. In questo caso l'oggetto é costante (visto il def che lo introduce) ma sarebbe ovviamente potrebbe essere variabile:

def customer = Customer {
firstName: "John";
lastName: "Doe";
phoneNum: "(408) 555-1212"
address: Address {
street: "1 Main Street";
city: "Santa Clara";
state: "CA";
zip: "95050";
}
}

Definito customer di tipo Customer possiamo ora chiamare le funzioni definite per esso in questo modo:

customer.printName();
customer.printPhoneNum();
customer.printAddress();

Gerarchie di classi

E' possibile scrivere gerarchie di classi, dove classi figlie ereditano il comportamento di una classe madre. Se marchiamo una classe come astratta intendiamo che non siano creati oggetti di quel tipo. Vediamo qui un esempio:

abstract class Account {
var accountNum: Integer;
var balance: Number;

function getBalance(): Number {
return balance;
}

function deposit(amount: Number): Void {
balance += amount;
}

function withdraw(amount: Number): Void {
balance -= amount;
}
}

Data questa classe base possiamo definire ora una classe che la estende, aggiungendo dati e funzioni:

class SavingsAccount extends Account {
var minBalance = 100.00;
var penalty = 5.00;

function checkMinBalance() : Void {
if(balance < minBalance){
balance -= penalty;
}
}
}

Ed é possibile anche fare in modo che una classe figlia abbia un comportamento diverso dalle madre, possiamo infatti ridefinire una funzione nella classe figlia usando la parola chiave override:

class CheckingAccount extends Account {
var hasOverDraftProtection: Boolean;

override function withdraw(amount: Number) : Void {
if(balance-amount < 0 and hasOverDraftProtection){
// code to borrow money from an overdraft account would go here
}
else {
balance -= amount; // may result in negative account balance!
}
}
}

Visualizzare un riassunto

Una semplice modifica al template di blogger per far sì che sulla pagina principale del proprio blog venga visualizzata solo la prima parte del post.

Scopo di questo cambiamento é dare a chi accede il blog su blogspot una vista complessiva di quanto é pubblicato, lasciandogli la possibilità di andare sulla pagina che gli interessa per vedere il post nella sua interezza.

Questo dovrebbe rendere la home del blog più pulita e leggibile.

Per far questo, creo una nuova class per il tag span e la uso nel testo del nostro post.

In pratica ogni nostro post sarà strutturato in questo modo:

Qui il riassunto che voglio sia visualizzato:
  • nella home del mio blog,
  • nella pagina specifica del post
<span class="fullpost">
Qui il corpo del post, visibile solo nella sua specifica pagina.
</span>

Il template del mio blog dovrà essere cambiato per riflettere l'utilizzo di questa nuova classe:

Subito prima della fine della sezione head nel mio template, aggiungo questo pezzo di codice:

<!-- riassunto o completo -->
<style>
<b:if cond='data:blog.pageType == "item"'>
span.fullpost {display:inline;}
<b:else/>
span.fullpost {display:none;}
</b:if>
</style>
<!-- riassunto o completo -->

Potrebbe bastare così, ma aggiungiamo sulla home del mio blog anche un link al post completo subito dopo il riassunto, per renderne più semplice l'accesso al lettore.

Vado quindi a cercarmi nel template la fine della sezione dedicata al testo del post pubblicato, che sarà questo tag:

<data:post.body/>

Subito dopo metterò il mio codice, che genererà un link all'URL della pagina specifica per il mio post:

<!-- riassunto o completo -->
<b:if cond='data:blog.pageType != "item"'>
<p><a expr:href='data:post.url'>Leggi il post completo</p>
</b:if>
<!-- riassunto o completo -->

Il risultato di queste modifiche lo si vede sulla pagina principale di questo blog.

Data Binding e Trigger

La lezione numero 8 del corso Sun introduttivo a javaFX é invece piuttosto interessante, si parla qui di due funzionalità utili che sono implementate in modo elegante.

Per prima cosa parliamo di binding, ovvero della possibilità di correlare dati in modo che il cambiamento di uno si rifletta immediatamente nell'aggiornamento dell'altro.

E' ad esempio una funzionalità utilissima per codice progettato secondo i principi del MVC (Model View Controller), dove il Controller deve tenere in sincronia Model e View. La possibilità di stabilire esplicitamente un legame tra diverse variabili rende il codice molto più leggibile e manutenibile.

Vediamo ora esempi piuttosto banali di binding, giusto per prendere confidenza con l'implementazione javaFX del concetto.

Dichiariamo una variabile x e poi creiamo una costante y definita come connessa a x. Il fatto che sia costante ci impedisce di modificarla direttamente, il fatto che sia definita come "bind x" fa sì che sia in pratica un alias di x, ogni cambiamento di x si riflette in una cambiamento di y:

var x = 0;
def y = bind x;
x = 1;
println(y); // 1
x = 47;
println(y); // 47

E' possibile legare dati membro di una classe a variabili indipendenti:

var myStreet = "1 Main Street";
var myCity = "Santa Clara";
var myState = "CA";
var myZip = "95050";

def address = Address {
street: bind myStreet;
city: bind myCity;
state: bind myState;
zip: bind myZip;
};

println("address.street == {address.street}");
myStreet = "100 Maple Street";
println("address.street == {address.street}");

E' possibile creare un legame tra variabili usando una funzione, specificando la parola chiave bound:

var scale = 1.0;

bound function makePoint(xPos : Number, yPos : Number) : Point {
Point {
x: xPos * scale
y: yPos * scale
}
}

class Point {
var x : Number;
var y : Number;
}

var myX = 3.0;
var myY = 3.0;
def pt = bind makePoint(myX, myY);
println(pt.x); // 3

myX = 10.0;
println(pt.x); // 10

scale = 2.0;
println(pt.x); // 20

Nota che si crea un legame tra le variabili locali passate come parametri alla funzione e i dati membro dell'oggetto creato dalla funzione stesso. Una funzione bound é usata in pratica come un costruttore di oggetto che mantiene un legame con i parametri passati.
Nota inoltre che anche quando viene cambiato un valore globale utilizzato dalla funzione bound (nel nostro caso scale) i valori dell'oggetto creato dalla funzione bound vengono ricalcolati.

E' possibile anche usare bind in congiunzione con for per generare una nuova sequenza:

var seq1 = [1..10];
def seq2 = bind for (item in seq1) item*2;
printSeqs();

function printSeqs() {
println("First Sequence:");

for(i in seq1){
println(i);
}
println("Second Sequence:");
for(i in seq2){
println(i);
}
}

Come ci si può aspettare, la seq2 contiene dieci elementi, ognuno del quale é il doppio del corrispondente elemento della prima sequenza.

Trigger

Un trigger é, in pratica, una funzione che viene eseguita quando accade un certo evento su dei dati. In javaFX é possibile scrivere del codice che viene eseguito quando una certa variabile viene modificata usando il costrutto on replace, come esemplificato a seguire:

var password = "foo" on replace oldValue {
println("Old Value: {oldValue}");
println("New Value: {password}");
};

password = "bar";

Il trigger mantiene in oldValue, o come la voglio chiamare, il valore prima del replace, e quindi esegue il codice. Se facciamo correre il codice, vediamo che il trigger é eseguito due volte: quando la variabile su cui é posto viene inizializzata a "foo", e quando il suo valore viene cambiato in "bar".

Operatori ed espressioni

Coppia di lezioni piuttosto noiose, la sei e la sette, all'interno del tutorial sun introduttivo a javaFX.

Gli operatori sono in pratica gli stessi di java/c++, con qualche piccola variazione per far diventar matto il programmatore, vediamoceli rapidamente.

Per l'assegnamento si usa un'uguale (=)

result = num1 + num2;

Gli operatori aritmetici sono +, -, *, /, mod:

result = 10 mod 7; // 10 / 7 = 1 col resto di 3, dunque result sarà 3.

E' possibile combinare gli operatori aritmetici con l'assegnamento, con l'eccezione del modulo:

result += 1; // equivalente a result = result + 1;

Gli operatori unari sono -, --, ++, not (negazione booleana)

var success = false;
println(success); // false
println(not success); // true

Non ci sono sorpese negli operatori di uguaglianza e relazione: ==, !=, >, >=, <, <= Mentre gli operatori condizionali sono and, or Anche l'operatore per il confronto dei tipi é una vecchia conoscenza (per chi conosca java, si intende): instanceof

Espressioni

Un blocco é, a tutti gli effetti, equivalente a una funzione inline: circondato da parentesi graffe, "ritorna" il valore dell'ultima espressione inclusa. Se non c'é alcuna espressione inclusa, il blocco é di tipo Void

var nums = [5, 7, 3, 9];
var total = {
var sum = 0;
for (a in nums) {
sum += a
};
sum;
}

println("Total is {total}."); // 24

Il flusso condizionale di esecuzione é solitamente implementato usando la solita struttura if - else if - else:

if (age < ticketprice =" 0;"> 65) {
ticketPrice = 5;
}
else {
ticketPrice = 10;
}

Ma in javaFX é disponibile anche questa scorciatoia che appare molto concisa ed elegante:

ticketPrice = if (age <> 65) 5 else 10;

Le sequenze, che aevamo visto qui, sono, parlando tecnicamente, delle espressioni di ambito (in inglese: range) di cui é possibile specificare la distanza tra i vari elementi usando la parola chiave step:

var odds = [1..10 step 2];
var down = [10..1 step -1];

I loop su una sequenza sono implementati elegantemente con un for, iterando sugli elementi:

var days = ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"];

for (day in days) {
println(day);
}

Nota che la variabile day é generata al volo dal compilatore per esistere solo per la durata del ciclo for.

Il ciclo while ha invece una costruzione più tradizionale:

var count = 0;
while (count < count ="=">

Per modificare il flusso di esecuzione all'interno di un ciclo sono disponibili le espressioni continue e break:

for (i in [0..10]) {
if (i > 5) {
break;
}

if (i mod 2 == 0) {
continue;
}

println(i);
}

La gestione delle eccezioni avviene secondo lo schema stabilito dalle espressioni throw (per lanciarla) catch (per gestirla) finally (per specificare cosa fare in ogni caso, dopo aver gestito l'eccezione, o se non c'é stata eccezione)

...
if(somethingWeird) {
throw new Exception("Something weird just happened!");
}

...

try {
foo();
}
catch (e: Exception) {
println("{e.getMessage()} (but we caught it)");
}
finally {
println("We are now in the finally expression...");
}

Virtualizzazione - Iniziative di AMD

Terzo capitolo di Virtualization for Dummies di Bernard Golden e Clark Scheffy che può essere scaricato gratuitamente, nell'edizione speciale Sun AMD, dal sito della sun.

Nei processori Quad-Core AMD Opteron viene implementata una ulteriore ottimizzazione hardware per la gestione della memoria, detta Rapid Virtualiztion Indexing.

Per migliorare il supporto della virtualizzazione nel campo delle connessioni di rete e della gestione della memoria di massa, AMD introduce il concetto di IOMMU: I/O Memory
Management Unit.