TableView and setOnCloseListener JavaFX

2

my problem is that when I load the .txt in the tableview it loads it but the text does not appear in the columns, it goes empty but when I select the row if it collects the data belonging to each column but in the table it does not come out and For more than I look on the internet, the code is well written ...

And as I have seen on the internet there is the setOnCloseListener () that detects when it closes or is going to close and can do something about it and it does not work for me either. The idea is to add and remove objects to the table.

Thank you very much in advance!

Controller

package flightfx;

import flightfx.model.Flight;
import flightfx.utils.FileUtils;
import flightfx.utils.MessageUtils;
import java.io.IOException;
import java.net.URL;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.OptionalDouble;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;


public class FXMLMainViewController implements Initializable {

    private Label label;
    @FXML
    private TableView<Flight> TV;
    @FXML
    private TableColumn<Flight, String> TVFlightNumber;
    @FXML
    private TableColumn<Flight, String> TVDestination;
    @FXML
    private TableColumn<Flight, LocalDateTime> TVDeparture;
    @FXML
    private TableColumn<Flight, LocalTime> TVDuration;
    @FXML
    private TextField TextFlightNumber;
    @FXML
    private TextField TextDestination;
    @FXML
    private TextField TextDeparture;
    @FXML
    private TextField TextDuration;
    @FXML
    private Button ButtonAdd;
    @FXML
    private Button ButtonDelete;
    @FXML
    private Button ButtonFilter;
    @FXML
    private ChoiceBox<String> TextChoiseBox;

    private List<Flight> flights;
    private ObservableList<Flight> currentFlight;   



    @Override
    public void initialize(URL url, ResourceBundle rb) {
        //Creo el contenido del ChoiceBox para hacer el filtro
        TextChoiseBox.setItems(
                FXCollections.observableArrayList("Show all flights", 
                        "Show flights to currently selected city","Show long flights", 
                        "Show next 5 flights" ,"Show flight duration average")); 
        //Selecciono el primero 
        TextChoiseBox.getSelectionModel().selectFirst();

        try {
            //Cargo en el List los vuelos del fichero txt
            flights = FileUtils.loadFlights();
        } catch (IOException ex) {
            Logger.getLogger(FXMLMainViewController.class.getName()).log(Level.SEVERE, null, ex);
        }
            //Llamo a la funcion donde carga la tabla segun el filtro escogido
            loadTable();

        if(TV.getSelectionModel().getSelectedItem() == null){ 
            //Si no hay nada seleccionado de la tabla el boton pasa a ser desactivado
            ButtonDelete.setDisable(true);
        }
    }
    /**
     * Vacio los cambios despues de insertar
     */
    private void clearTextFields(){
        TextFlightNumber.setText("");
        TextDestination.setText("");
        TextDeparture.setText("");
        TextDuration.setText("");        
    }
    /**
     * Haciendo click al boton añado el vuelo a la lista y saldra en la tabla
     * @param event 
     */
    @FXML
    private void ButtonAddAction(ActionEvent event) throws IOException 
    {
        Flight flight = null;
        DateTimeFormatter dtfDate = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
        DateTimeFormatter dtfHour = DateTimeFormatter.ofPattern("H:mm");
        //Compruebo que no esten vacios
        if (TextFlightNumber.getText().equals("") || TextDestination.getText().equals("")|| TextDeparture.getText().equals("")|| TextDuration.getText().equals("")){
            MessageUtils.showMessage(" the Flight number, Destination, Date and Duration can't be empty");
        }
        else
        {
            //Añado el vuelo y le doy el formato a los LocalDateTime y LocalTime
            flight = new Flight(TextFlightNumber.getText(),TextDestination.getText(), LocalDateTime.parse(TextDeparture.getText(),dtfDate),LocalTime.parse(TextDuration.getText(),dtfHour)); 
        }
        if (flight != null){
            //Añado el vuelo a la Lista
            flights.add(flight);
            currentFlight.add(flight);
        }
    }
    /**
     * Haciendo click al boton eliminar recogo el vuelo seleccionado y lo elimino
     * @param event 
     */
    @FXML
    private void ButtonDeleteAction(ActionEvent event) throws IOException {

        Flight flight = TV.getSelectionModel().getSelectedItem();
        //Saco una ventana de confirmacion en caso de querer eliminarlo
        if (MessageUtils.confirmationMessage()){
            flights.remove(flight);            
            currentFlight.remove(flight);
            TV.getSelectionModel().clearSelection();
            clearTextFields(); 
            FileUtils.saveFlights(flights);
        }
    }
    /**
     * Inicio la tabla con sus columnas y añado los vuelos
     */
    private void initializeFlightsTable() { 
        //Si la tabla no tiene nada sacar el mensaje
        TV.setPlaceholder(new Label("No Flights to show"));
        //Unir el id del formulario de las columnas con los atributos de la clase Flight
        TVFlightNumber.setCellValueFactory(new PropertyValueFactory<Flight,String>("flightNumber"));
        TVDestination.setCellValueFactory(new PropertyValueFactory<Flight,String>("destination"));
        TVDeparture.setCellValueFactory(new PropertyValueFactory<Flight,LocalDateTime>("time"));
        TVDuration.setCellValueFactory(new PropertyValueFactory<Flight,LocalTime>("duration"));
        //Añadir los vuelos
        TV.setItems(currentFlight);
        //Obtengo los valores del vuelo seleccionado para habilitar o no el boton de eliminar
        TV.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
            if (newSelection != null) {
                TextFlightNumber.setText(newSelection.GetFlightNumber());
                TextDestination.setText(newSelection.GetDestination());
                TextDeparture.setText(newSelection.GetTime().toString());
                TextDuration.setText(newSelection.GetDuration().toString());               
                ButtonDelete.setDisable(false);
            } else {
                ButtonDelete.setDisable(true);
            }
        });
    }
    /**
     * Cargo la tabla respecto al filtro escogido
     */
    private void loadTable() {
        switch(TextChoiseBox.getSelectionModel().getSelectedIndex()) {
            case 0:
                filterAllFlight();
                break;
            case 1:
                filterSelectedDestination();
                break;
            case 2:
                filterFlightAverage();
                break;
        }
    }
    /**
     * Al pinchar en el boton del filtro carga la tabla
     * @param event 
     */
    @FXML
    private void ButtonFilterAction(ActionEvent event) {
        loadTable();
    }
    /**
     * Se filtra todos los vuelos (por defecto siempre sera este ya que muestra todos los vuelos)
     */
    private void filterAllFlight() {
        currentFlight = FXCollections.observableArrayList(flights);
        initializeFlightsTable();
    }
    /**
     * Se filtra el promedio de minutos de los vuelos
     */
    private void filterFlightAverage() {
        //Creo una expresion lambda que dara un formato double para el promedio de minutos
        //Filtro las duraciones que no sean nulas, paso a double, la duracion de horas las multiplico por 60 para pasarlas
        //a minutos y las sumo con los minutos haciendo un promedio con el resultado
        OptionalDouble avgDuration = flights.stream()
                .filter(e -> e.GetDuration() != null)
                .mapToDouble(e -> ((e.GetDuration().getHour()*60) + e.GetDuration().getMinute())).average();
        Double n = avgDuration.orElse(0);
        //Luego divido entre 60 para sacar las horas
        n = n/60;
        MessageUtils.showMessage(String.format("The average of the selected flights is %.2f", n));

    }
    /**
     * Se filtra por el destino seleccionado
     */
    private void filterSelectedDestination() {
        //recogo el destino seleccionado
        Flight flight = TV.getSelectionModel().getSelectedItem();
        //guardo solo el nombre del destino
        String destination = flight.GetDestination();
        //limpio la tabla
        currentFlight.clear();
        //recorro los vuelos y comparo los destinos para despues agregar los que son iguales
        for (Flight e : flights) {
            if (e.GetDestination().equals(destination))
                currentFlight.add(e);
        }        
        //inicio la tabla
        initializeFlightsTable();
    } 
    //Cuando cierro el Listener (escucha) guardo los vuelos en el txt
    public void setOnCloseListener(Stage stage) {
        stage.setOnCloseRequest(e -> {
            if (!MessageUtils.confirmationMessage())
                e.consume();
            else{
                try {                
                    FileUtils.saveFlights(flights);
                } catch (IOException ex) {
                    Logger.getLogger(FXMLMainViewController.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
    }   
}

Flight class

package flightfx.model;

import java.time.LocalDateTime;
import java.time.LocalTime;

/**
 *
 * @author killtrols
 */
public class Flight {
    private  String flightNumber;
    private  String destination;
    private  LocalDateTime time;
    private  LocalTime duration;

    public Flight(String newFlightNumber)
    {
        flightNumber = newFlightNumber;
    }
    public Flight(String newFlightNumber,String newDestination,LocalDateTime newTime,LocalTime newDuration)
    {       
        flightNumber = newFlightNumber;
        destination = newDestination;
        time = newTime;
        duration = newDuration;
    }
    public void SetFlightNumber(String newFlightNumber)
    {
        flightNumber = newFlightNumber;
    }
    public String GetFlightNumber()
    {
        return flightNumber;
    }
    public void SetDestination(String newDestination)
    {
        destination = newDestination;
    }
    public String GetDestination()
    {
        return destination;
    }
    public void SetTime(LocalDateTime newTime)
    {        
        time = newTime;
    }
    public LocalDateTime GetTime()
    {
        return time;
    }
    public void SetDuration(LocalTime newDuration)
    {
        duration = newDuration;
    }
    public LocalTime GetDuration()
    {
        return duration;
    }
    public String getData() {
        String data;
        if (destination == null && time == null && duration == null)
            data = flightNumber;
        else
            data = flightNumber + ";" + destination + ";" + time + ";" + duration;
        return data;
    }
}

The class where the txt is saved and loaded

package flightfx.utils;

import flightfx.model.Flight;
import java.util.List;
import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 *
 * @author killtrols
 */
public class FileUtils {


    private static final String EXAMS_LIST_FILE = "flights.txt";

    public static List<Flight> loadFlights() throws FileNotFoundException, IOException
    {
        List<Flight> listFlight = new ArrayList<Flight>();
        DateTimeFormatter dtfDate = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
        DateTimeFormatter dtfHour = DateTimeFormatter.ofPattern("H:mm");


        FileReader file = new FileReader(EXAMS_LIST_FILE);
        BufferedReader in = new BufferedReader(file);
        String read;
        while((read = in.readLine()) != null)
        {           
            String[] split = read.split(";");  

            listFlight.add(new Flight(split[0],split[1],LocalDateTime.parse(split[2],dtfDate),LocalTime.parse(split[3],dtfHour)));            
        }
        return listFlight;        
    }
    public static void saveFlights(List<Flight> saveFlight) throws IOException
    {
        DateTimeFormatter dtfDate = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
        DateTimeFormatter dtfHour = DateTimeFormatter.ofPattern("H:mm");
        BufferedWriter writer;
        String line;
        File file = new File("flights.txt");
        if(file.exists())
        {
            writer = new BufferedWriter(new FileWriter(file,true));
            line = saveFlight.get(0).GetFlightNumber() + ";" + saveFlight.get(0).GetDestination() + ";" + saveFlight.get(0).GetTime().format(dtfDate) + ";" + saveFlight.get(0).GetDuration().format(dtfHour);
            writer.newLine();
            writer.write(line);
            writer.close();
        }
        else if(!file.exists())
        {
            writer = new BufferedWriter(new FileWriter(file,false));
            line = saveFlight.get(0).GetFlightNumber() + ";" + saveFlight.get(0).GetDestination() + ";" + saveFlight.get(0).GetTime().format(dtfDate) + ";" + saveFlight.get(0).GetDuration().format(dtfHour);
            writer.write(line);
            writer.close();
        }

    }  
    /*public static List<Flight> loadFlights(){

        DateTimeFormatter dtfDate = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
        DateTimeFormatter dtfHour = DateTimeFormatter.ofPattern("H:mm");
        List<Flight> flights = new ArrayList<>();

        try (Stream<String> stream = Files.lines(
            Paths.get("", EXAMS_LIST_FILE))) {

            flights = stream.map(line -> {
                        String[] data = line.split(";");

                        if (data.length == 1)
                            return new Flight(data[0]);
                        else
                            return new Flight(data[0],data[1],LocalDateTime.parse(data[2],dtfDate),LocalTime.parse(data[3],dtfHour));
            }).collect(Collectors.toList());

        } catch (FileNotFoundException e) {
            System.err.println("File " + EXAMS_LIST_FILE + " doesn't exist!");
        } catch (IOException e) {
            System.err.println("Error reading exams in file " + EXAMS_LIST_FILE);
            flights = new ArrayList<>(); // Empty list if it fails to read file
        }

        return flights;
    }

    public static void saveFlights(List<Flight> exams) {
        try (PrintWriter print = new PrintWriter(
                Paths.get("", EXAMS_LIST_FILE).toFile())) {

            for (Flight e : exams) {
                print.println(e.getData());
            }

        } catch (IOException e) {
            System.err.println("Error writing: " + e.getMessage());
        }
    }*/
}
    
asked by Alexis 08.11.2017 в 20:28
source

1 answer

2

This happened to me many times and the detail is simple. Especially when working with FXML. The issue is solvable when you initialize the table and the data in the table in the same controller being in this way.

Variables

@FXML
    private ObservableList<Modelo_Inventario> datos = FXCollections.observableArrayList();

@FXML 
    private TableColumn<Modelo_Inventario, String> cota;

@FXML 
    private TableView<Modelo_Inventario> inventario;

public void initialize(URL url, ResourceBundle rb) {

    **cota**.setCellValueFactory(new PropertyValueFactory<**Modelo_Inventario**, **String**>("**cota**"));

    **nombreDelObjeto**.setCellValueFactory(new PropertyValueFactory<**clase**, **Tipo de dato**>("**variable de clase**"));

}

public class Modelo_Inventario {

    private String cota;
    private Pane contenedor;
    //Constructor
    //SETTERs y GETTERs

}

If you notice the nameObject is the variable declared as TableColumn , class represents the class that contains the attributes mapped by the table. The data type refers to whether int , string , etc., and the class variable must be the name of the referenced attribute of the class that maps the data. This is how each column in the table is initialized. You must do it with all.

    
answered by 27.11.2017 в 19:40