ciaoMondo

passo per passo il primo programma funzionante con interfaccia grafica

Creazione progetto

I nostri programmi saranno scritti usando Java e la sua interfaccia grafica JavaFX, per la creazione del nostro primo progetto in Eclipse vai sul menu File/New/Project... nella finestra che si apre apri il gruppo Java e seleziona Java Project e poi premi Next > NetBeans vai sul menu File/New Project... nella finestra che si apre scegliere come categoria Samples/OpenJFX e poi in Projects esempio JavaFX. Ora indica il nome del progetto (per esempio ciaoMondo) e termina con Finish. se viene chiesto di creare il file "module-info.java" rispondere di no. Il progetto nuovo comparirà sulla sinistra.

Prima classe

Nello svolgere le prossime operazioni fai attenzione al Maiuscolo/minuscolo nei nomi degli elementi: apri le cartelle del progetto, diventerà visibile una cartella src Source Packages, fai click con il destro e poi click sul menu contestuale New/class, chiamala CiaoMondo (nel campo Name) e scrivi ciaomondo nel campo Package. A questo punto fai doppio click sulla classe appena creata per aprirla.

Il file "CiaoMondo", conterrà qualche linea di codice che va cancellata e sostituita con il programma qui sotto:

Il file "CiaoMondo", conterrà il testo qui sotto.

package ciaomondo;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

/**
 * La mia prima classe
 */
public class CiaoMondo extends Application {

  Button pSaluto = new Button(); 

  public void start(Stage finestra) {
    pSaluto.setText("Saluta!");
    pSaluto.setOnAction(e -> esegui());

    BorderPane principale = new BorderPane();
    principale.setCenter(pSaluto);

    Scene scena = new Scene(principale, 300, 250);

    finestra.setTitle("Hello World!");
    finestra.setScene(scena);
    finestra.show();
  }

  private void esegui(){
    pSaluto.setText("Ciao Mondo!");
  }

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

Non tutto ciò che vi è scritto viene interpretato dal computer: noterai alcune parti sono racchiuse dal simboli /* e */. Tali delimitatori indicano i commenti, cioè cose che il programmatore inserisce a scopo chiarificare affinché altri (o lui stesso) possano meglio capire cosa fa quella parte di programma. In questi commenti spesso si inserisce un asterisco ad ogni inizio riga ma solo per motivi estetici e di leggibilità. Tutti i commenti appariranno nell'editor come un testo di colore diverso e verranno scartati in fase di compilazione.

Pacchetti

La prima riga non dice al programma cosa fare ma piuttosto serve ad inserire questo file in una gerarchia. Noi abbiamo sbrigativamente scritto il nome ciaomondo ma non è questa la pratica: i programmi sono solitamente fatti da tanti file e usualmente almeno in parte non scritti da noi, per questo avere tutto mantenuto in maniera ordinata è di aiuto allo sviluppo. La strategia standard per gestire i pacchetti è piuttosto semplice: ogni classe (per adesso possiamo considerare che un file sia la stessa cosa) appartiene ad un pacchetto il cui nome possiamo deciderlo noi (per convenzione scritto tutto in minuscolo), questo pacchetto può essere a sua volta contenuto in altri pacchetti e così via. Ogni pacchetto in pratica è una cartella e la struttura inizia con il nome del dominio (che vengono registrati pubblicamente) scritto al rovescio... sembra complicato?

Il dominio della mia organizzazione è aspix.it e sto scrivendo il programma per una chat come chiamerò il pacchetto?

mio pacchettonon possono esserci spazi chat il nome sarebbe sensato ma non contiene il nome del dominio chat.it.aspix il nome del dominio non va messo in fondo it.aspix.chatesatto! prima il dominio di primo livello e poi di seguito le altre parti

Nella pratica i pacchetti sono delle cartelle quindi la classe Prova che sta nel pacchetto com.azienda.esperimenti sarà un file che si chiama Prova che sta nella cartella esperimenti che a sua volta sta nella cartella azienda contenuta nella cartella com.

import

Il gruppo successivo indica tutte le funzionalità di cui ha bisogno questa parte di programma per funzionare (detto nei termini di java: gli altri oggetti che useremo); queste vengono importate (import) per poter essere poi usate nel programma.

Dal punto di vista formale gli import non sono essenziali, in realtà potremmo farne a meno ma poi nel programma devremmo usare quello che si chiama nome completamente qualificato per gli oggetti, niente di complicato, solo estremamente noioso: anziché scrivere Button dovrei scrivere ogni volta javafx.scene.control.Button: meglio usare gli import!

La classe

La riga contenente la parola chiave class indica – per ora – la nostra finestra (il programma in esecuzione appare all'utente come una finestra). Osserva che a fine riga c'è una { ed in fondo al file c'è la rispettiva }. Queste parentesi rappresentano rispettivamente l'inizio e la fine di tutto ciò che farà la finestra, contengono cioè le istruzioni del nostro programma.

Una istruzione è una parte elementare del programma che viene eseguita dalla macchina e determina l'avanzamento del processo in memoria.

Procediamo con la lettura, la riga contenente start indica la prima funzionalità del nostro programma, quella cioè che viene avviata nel momento in cui deve essere disegnata la finestra (da cui, appunto, start). Nota che anch'essa ha la { a fine riga e si conclude con la corrispettiva } che si trova dopo la riga "finestra.show();". Le graffe delimitano l'insieme di istruzioni che deve essere eseguito. Quando scriveremo nostre funzionalità useremo le graffe per raccogliere tutte le istruzioni atte a raggiungere il risultato previsto.

Passiamo alla riga:

Button pSaluto = new Button();

Si tratta di una forma contratta molto utilizzata per fare due cose insieme, proviamo a vedere la forma più lunga:

Button pSaluto; // dichiarazione
pSaluto = new Button(); // creazione

La prima riga è la dichiarazione di una variabile, un modo per dire che pSaluto sta ad indicare uno specifico pulsante. Le dichiarazioni di variabile hanno sempre la sintassi:

tipo nomeVariabile;

quindi noi nel nostro programma abbiamo dichiarato una variabile chiamata pSaluto che è di tipo Button, vuol dire che potrà contenere soltanto dei pulsanti, e abbiamo creato il pulsante corrispondente.

Una variabile è una zona di memoria identificata da un nome che contiene una sola informazione di un determinato tipo detta valore, questa informazione può variare nel tempo.

Alcune variabili sono di un tipo semplice come un intero, un numero con la virgola, un carattere ecc.; altre variabili sono invece più complesse come la nostra pSaluto, in tal caso oltre che dichiararla va anche creata aggiungendo = new tipo(). Il perché lo vedremo tra un po' di tempo. Ogni componente di una finestra è un tipo non semplice, quindi per ciascuno di essi dovremo usare questa specifica sintassi. Essendo il pulsante un tipo non semplice, tale parte va aggiunta. Se avessi dovuto dichiarare invece una etichetta di testo avresti dovuto scrivere:

Label testo = new Label();

Il pulsante ancora non ha un testo al suo interno da mostrare all'utente. Questo si imposta con la riga successiva: pSaluto.setText("Saluta!"). Osserva la strana sintassi d'inizio riga: pSaluto. che in generale è nomeVariabile.: tale notazione sta a significare “sto parlando dell'oggetto pSaluto”; cosa si vuol fare con l'oggetto in questione è specificato subito dopo il punto ed in questo caso si tratta di impostare il testo, appunto setText("Testo da mostrare").

Quale istruzione serve per utilizzare nel nostro programma degli elementi (oggetti) scritti da altri?

class la usiamo per definire qualcosa di nuovo noi import BorderPane questo è il nome di uno specifico oggetto Copyright non compare nel nostro programma

Quali parentesi si usano per raggruppare delle parti di codice?

tonde () quadre [] graffe {} angolari <>

Salta una riga sulla quale si tornerà tra pochissimo ed arriva a:

BorderPane principale = new BorderPane();

si vede subito che si tratta di una dichiarazione di una variabile di tipo BorderPane chiamata principale (e relativa creazione dell'oggetto). Tutti gli oggetti grafici che utilizzi nella finestra (pulsanti, caselle di testo, elenchi, ...) devono essere disposti in quello che possiamo considerare il pannello di una bacheca mentre i nostri oggetti sono il contenuto di tale bacheca. Un BorderPane è una di queste possibili bacheche che serve ad organizzare gli oggetti, non è l'unico modo per organizzare gli elementi dell'interfaccia grafica, ne vedremo degli altri.

Arrivi a

principale.setCenter(pSaluto);

parli di principale ed utilizzi la funzionalità setCenter( pSaluto )... non sarai tanto sorpreso di sapere che il nostro pulsante pSaluto verrà inserito al centro del pannello.

Uno degli oggetti che si usano come contenitore di altri elementi dell'interfaccia grafica si chiama:

Label questa è una singola etichetta (testo non modificabile dall'utente) Button questo è il pulsante BorderPane Scene questa è l'area interna della finestra

Vorrei che pSaluta comparisse sulla destra, cosa potrei scrivere al posto di principale.setCenter(pSaluto);?

setLeft(pSaluto)manca all'inizio il nome dell'oggetto in cui inserire il pulsante principale.setLeft(pSaluto); quasi giusto ma comparirebbe a sinistra principale.setRight(pSaluto); giusto

La riga successiva contiene ancora una dichiarazione:

Scene scena = new Scene(principale, 300, 250);

la scena indica l'area contenuta nella finestra vera e propria. Tale dichiarazione è leggermente diversa da quanto affermato (per semplicità) fino ad ora: le parentesi tonde in questo caso hanno un contenuto, questo perché in questo caso per costruire un nuovo oggetto Scene servono delle informazioni in più. Il primo argomento – principale – sta ad indicare come si chiama il pannello (la nostra bacheca) da inserire in quest'area mentre il secondo ed il terzo – 300, 250 – ne indicano le misura (larghezza, altezza), quindi indicano la misura della finestra a meno dei bordi e della barra del titolo.

Per creare la scena è possibile utilizzare un modo diverso: Scene scena = new Scene(principale); senza mettere larghezza e altezza, in questo caso la finestra verrà dimensionata automaticamente alla dimensione minima che gli consente di visualizzare tutti gli oggetti che contiene, per esercizio prova a vedere cosa succede.

cosa fa il seguente frammento di programma?

/* StackPane root = new StackPane() */
crea un nuovo StackPane potrebbe sembrare... ma è contenuta in /* */ avvia il programma per avviare un programma bisogna usare altri strumenti niente giusto! è un commento

Andando avanti vedi l'uso della funzionalità .setTitle("il titolo") per l'oggetto finestra. Tale oggetto, che è la finestra vera e propria, non deve essere dichiarato in quanto viene già fornito al tuo programma. Tornando alla funzionalità, questa imposta il testo da visualizzare sulla barra del titolo della tua applicazione. La linea che segue abbina la finestra con la sua scena, cioè la sua area tramite finestra.setScene(scena).

Non resta che visualizzare, mostrare (show()) la finestra e tutto il suo contenuto. Lo fai tramite l'ultima riga:

finestra.show();

Da osservare che questa è l'ultima istruzione della funzionalità start. Ciò significa – tra l'altro – che tutte le variabile qui dichiarate appena fatta la show() finiranno di essere accessibili, in quanto la } fa scomparire tutti i nomi. Altre funzionalità non potranno quindi farne uso.

Il pulsante

Abbiamo finora evitato la parte che ha a che fare con il pulsante:

pSaluto.setOnAction(e -> esegui());

di questa riga non entriamo in grande dettaglio ma ci serve di notare due cose: la prima è che stiamo interagendo con il pulsante e lo si capisce dalla notazione pSaluto. e l'altra è che stiamo specificando cosa fare una volta che il pulsante verrà premuto: eseguire il metodo esegui() che troviamo più in basso:

private void esegui(){
  pSaluto.setText("Ciao Mondo!");
}

In questo caso il programma farà una sola cosa: scriverà sul pulsante il messaggio "Hello world!"