Area e perimetro del rettangolo in JavaFX

Proponiamo un esercizio semplice con il calcolo del perimetro ed area di un rettangolo per comprendere alcune dinamiche di JavaFx. Ce n’è una versione analoga qui con altri widget e scelte tecniche.

Enum Operazioni

Cominciamo col il banalissimo enum che sarà vivo dietro la tendina per la scelta dell’operazione.

package it.alfredocentinaro.calcoloareaperimetrofx;

public enum Operazione {
    AREA,
    PERIMETRO
}

Classe applicazione

Creando un progetto FX ci viene creata in automatico una classe Application che per comodità rinomino o meglio ne faccio il refactor. Nel codice non faccio molte modifiche. Mi assicuro che la scena sia della stesse dimensioni della finestra che creerò nello SceneBuilder, ad esempio 600×400. Modifico il titolo con “Gestione Rettangolo!”

package it.alfredocentinaro.calcoloareaperimetrofx;

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

import java.io.IOException;

public class Application extends javafx.application.Application {
    @Override
    public void start(Stage stage) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(Application.class.getResource("hello-view.fxml"));
        Scene scene = new Scene(fxmlLoader.load(), 600, 400);
        stage.setTitle("Gestione Rettangolo!");
        stage.setScene(scene);
        stage.show();
    }
}

Launcher

Per i nostri esercizi è una classe con scarso interesse per eventuali modifiche. Ci servirà per fare il Run della nostra applicazione. E’ interessante che non abbia delle ereditarietà e che può essere usata per la creazione successiva di artefatti eseguibili.

package it.alfredocentinaro.calcoloareaperimetrofx;

public class Launcher {
    public static void main(String[] args) {
        javafx.application.Application.launch(Application.class, args);
    }
}

Lo SceneBuilder

Con lo SceneBuilder abbiamo provveduto a realizzare in modo asciutto l’interfaccia prevedendo come elemento base una VBox con annidate una Menubar e un Pane. Nel menù abbiamo modificato le voci esistenti per avere la funzione di chiusura e di lancio dell’alert con le informazioni del software. La disposizione poi delle Label, dei TextField, ComboBox e Button risulta abbastanza semplice. Non abbiamo impostato parametri particolari del layout se non nella label della descrizione in alto dove abbiamo cliccato la rotellina (molto piccola adire la verità) per sviluppare il testo come linea multipla e l’andata a capo. I vari campi sono stati impostati con una larghezza minima prescelta per rendere la grafica omogenea. Il Field del risultato è stato contrassegnato non editabile.

A ogni Field di input e i bottoni abbiamo associato un nome semplice e descrittivo nel tab di destra Code nel campo fx:id. Nello stesso tab per i bottoni e menu abbiamo inserito il nome della funzione da scatenare On Action, ovvero al click di quell’elemento.

Altra cosa fondamentale nel nostro SceneBuilder è collegare la classe controller. Il progetto IntelliJ in genere mette una classe di esempio HelloController che possiamo rinominare a piacere. Questa classe deve necessariamente essere impostata nel menu a sinistra al tab Controller dove compaiono Controller class e anche come riepilogo i campi a cui abbiamo assegnato un nome/id e che quindi potremo usare all’interno del codice che scriveremo. Se non c’è corrispondenza, semplicemente nessun click scatenerà azioni. Il dato può essere modificato a mano anche nel file fxml ma risulta più ostico. Salvate tutto.

Preleviamo ora il codice preconfezionato del controller col menu in alto View =>Show Sample Controlelr Skeleton. Questo è fondamentale, potete usare il flag full e il tastino copy per selezionare in automatico tutto. Torniamo al nostro codice in Intellij, nella classe controller, cancelliamo il codice di esempio e facciamo incolla con la selezione precedente.

Controller

SceneBuilder non ha la bacchetta magica ma già ci fornisce un valido contributo per cominciare a modificare il codice. Il controller è decisamente il punto critico del nostro codice.

Combobox operazione

Il primo elemento è il menù a tendina. Andiamo a cercare la riga dove viene dichiarato. Tra i tag andiamo ad inserire il tipo corrispondente all’enum creato, ovvero Operazione. Questo ci permetterà di gestire la tendina appunto come se fosse un enum.

private ComboBox<Operazione> operazione;  //IMPORTANTE: Qui va inserito l'enum!!!

L’altra operazione da fare per la nostra tendina è andare ad inserire le voci. Andiamo a cercare in fondo al controller il metodo void initialize() e aggiungiamo la riga per settare tutte le voci corrispondenti all’enum Operazione.

operazione.getItems().setAll(Operazione.values());

Bottone calcola

Sicuramente il bottone più significativo. Se abbiamo copiato lo skeleton corretto da SceneBuilder dovremmo avere già un metodo calcola. Lo andiamo a personalizzare con la logica molto banale:

  1. prelevo i valori dalla caselle latoa e latob
  2. converto i valori da testo a numero, double per essere più realistici
  3. vado a valutare la scelta della tendina
    • Se AREA calcolo l’aera e scrivo nella casella risultato
    • Se PERIMETRO procedo col perimetro e scrivo nella casella risultato
@FXML
    void calcola(ActionEvent event) {
        double a = Double.parseDouble(latoa.getText());
        double b = Double.parseDouble(latob.getText());

        Operazione scelta = operazione.getValue();


        if (scelta == Operazione.AREA)
        {
            double ris = a * b;
            if (ris >0)
                risultato.setText(String.valueOf(ris));
        }

        if (scelta == Operazione.PERIMETRO)
        {
            double ris = 2*(a + b);
            if (ris >0)
                risultato.setText(String.valueOf(ris));
        }
    }

Qui ammettiamo un po’ di pigrizia ma che può trasformarsi in un esercizio per l’alunno. Non abbiamo fatto controlli sui valori di input, se testuali, se vuoti ecc fornendo un feedback colorato e/o testuale sull’errore.

Bottone cancella

    @FXML
    void cancella(ActionEvent event) {
        latoa.setText("");
        latob.setText("");
        risultato.setText("");
    }

Menu Aiuto

Il metodo aiuto lo implementiamo in modo semplice. Apriamo un alert popup con qualche informazione. Non abbiamo previsto una intera finestrella ex novo come in altri esercizi su questo sito.

    void aiuto(ActionEvent event) {
        Alert alert = new Alert(Alert.AlertType.INFORMATION); // Tipo di icona (Error, Information, Warning)
        alert.setTitle("Info");
        alert.setHeaderText("alfredocentinaro.it");
        alert.setContentText("Software realizzato dal prof. Alfredo Centinaro");

        alert.showAndWait(); // Blocca l'esecuzione finché l'utente non preme OK
    }

Menu Chiudi

    @FXML
    void chiudi(ActionEvent event) {
        System.exit(0);
    }

Listato completo

Il codice completo del nostro controller

package it.alfredocentinaro.calcoloareaperimetrofx;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;

public class Controller {

    @FXML
    private ResourceBundle resources;

    @FXML
    private URL location;

    @FXML
    private Button btbcalcola;

    @FXML
    private Button btbcancella;

    @FXML
    private TextField latoa;

    @FXML
    private TextField latob;

    @FXML
    private MenuItem menaiuto;

    @FXML
    private MenuItem menchiudi;

    @FXML
    private ComboBox<Operazione> operazione;  //IMPORTANTE: Qui va inerito l'enum!!!

    @FXML
    private TextField risultato;

    @FXML
    void aiuto(ActionEvent event) {
        Alert alert = new Alert(Alert.AlertType.INFORMATION); // Tipo di icona (Error, Information, Warning)
        alert.setTitle("Info");
        alert.setHeaderText("alfredocentinaro.it");
        alert.setContentText("Software realizzato dal prof. Alfredo Centinaro");

        alert.showAndWait(); // Blocca l'esecuzione finché l'utente non preme OK
    }

    @FXML
    void calcola(ActionEvent event) {
        double a = Double.parseDouble(latoa.getText());
        double b = Double.parseDouble(latob.getText());

        Operazione scelta = operazione.getValue();

        //if (scelta == null)
        //{
        //    risultato.setText("Scegli un'operazione");
        //}

        if (scelta == Operazione.AREA)
        {
            double ris = a * b;
            if (ris >0)
                risultato.setText(String.valueOf(ris));
        }

        if (scelta == Operazione.PERIMETRO)
        {
            double ris = 2*(a + b);
            if (ris >0)
                risultato.setText(String.valueOf(ris));
        }
    }

    @FXML
    void cancella(ActionEvent event) {
        latoa.setText("");
        latob.setText("");
        risultato.setText("");
    }

    @FXML
    void chiudi(ActionEvent event) {
        System.exit(0);
    }

    @FXML
    void initialize() {
        assert btbcalcola != null : "fx:id=\"btbcalcola\" was not injected: check your FXML file 'hello-view.fxml'.";
        assert btbcancella != null : "fx:id=\"btbcancella\" was not injected: check your FXML file 'hello-view.fxml'.";
        assert latoa != null : "fx:id=\"latoa\" was not injected: check your FXML file 'hello-view.fxml'.";
        assert latob != null : "fx:id=\"latob\" was not injected: check your FXML file 'hello-view.fxml'.";
        assert menaiuto != null : "fx:id=\"menaiuto\" was not injected: check your FXML file 'hello-view.fxml'.";
        assert menchiudi != null : "fx:id=\"menchiudi\" was not injected: check your FXML file 'hello-view.fxml'.";
        assert operazione != null : "fx:id=\"operazione\" was not injected: check your FXML file 'hello-view.fxml'.";
        assert risultato != null : "fx:id=\"risultato\" was not injected: check your FXML file 'hello-view.fxml'.";

        operazione.getItems().setAll(Operazione.values());
    }

}

Ultima modifica 29 Marzo 2026