Andre Mac Gonz
Andre Mac Gonz

Reputation: 25

Read from CSV to populate tableview containing checkbox and string

I have a JavaFX desktop application I am trying to update/re-create and I am having an issue reading a csv and populating a tableview containing a checkbox column and a string column.

I have tried on line 91-92 to set the boolean value for the column row right before creating using the boolean above (false) and the 2nd part of the string from the csv file but this results in error: "cannot convert BooleanProperty to boolean"

I have also tried to set the false via adding it to the csv in the 1st column, ie:

false; "NameString1" (linebreak) false; "NameString2" etc This results in the program running but the list is empty.

PersonTableController.class

package com.lil;

import com.lil.Person;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.SingleSelectionModel;
import javafx.scene.text.Text;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import java.util.ArrayList;
import java.util.List;
import java.util.Comparator;
import java.util.Collections;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;

/**
 * View-Controller for the person table.
 */
public class PersonTableController {
    @FXML
    Button generate;
    @FXML
    Text status;
    @FXML
    TextField textVorname;
    @FXML
    TextField textNachname;
    @FXML
    TextField textUsergroup;
    @FXML
    TextField adname;
    @FXML
    CheckBox checkbox;
    @FXML
    CheckBox checkbox2;
    //@FXML
    //CheckBox selected;
    @FXML
    public TextField filterField;
    @FXML
    public TableView<Person> personTable = new TableView<Person>();
    @FXML
    public TableColumn<Person, Boolean> colSelected;
    @FXML
    public TableColumn<Person, String> colName;

    private BufferedReader br;
    private InputStream importPath;
    /**
     * Just add some sample data in the constructor.
     */

    public ObservableList<Person> myItems = FXCollections.observableArrayList();

    // IMPORT GROUPS FUNCTION
    private ObservableList<Person> importGroups()
    {
      this.importPath = getClass().getResourceAsStream("/input/groups.csv");

      String line = "";

      List<Person> groups = new ArrayList();

      this.br = new BufferedReader(new InputStreamReader(this.importPath));
      ObservableList<Person> observableList;
      try
      {
        while ((line = this.br.readLine()) != null) {
          if (!line.startsWith("Benutzergruppen_ID"))
          {
            String[] parts = line.split(";");
            //BooleanProperty b = new SimpleBooleanProperty(false);
            //boolean r = Boolean.FALSE;
            //Person person = new Person(r, parts[0]);
            Person person = new Person(parts[0], parts[1]);
            groups.add(person);
          }
        }
        observableList = FXCollections.observableList(groups);
      }
      catch (IOException e)
      {
        observableList = FXCollections.observableList(groups);
        System.out.println("IO Exception while reading groups");
      }
      return observableList;
    }
    // IMPORT GROUPS FUNCTION END
    /**
     * Initializes the controller class. This method is automatically called
     * after the fxml file has been loaded.
     * 
     * Initializes the table columns and sets up sorting and filtering.
     */

    @FXML
    public void initialize() {

        // We need the TableView to be editable in order to allow each CheckBox
        personTable.setEditable(true);

        // Bind the columns with our model's properties
        colSelected.setCellValueFactory(f -> f.getValue().selectedProperty());
        colName.setCellValueFactory(f -> f.getValue().firstNameProperty());

        // Set the CellFactory to use a CheckBoxTableCell
        colSelected.setCellFactory(param -> {
            return new CheckBoxTableCell<Person, Boolean>();
        });

        // Add our columns to the TableView
        personTable.getColumns().addAll(colSelected, colName);

        // Set our items to the TableView
        // personTable.setItems(myItems);
        // set Groups from CSV
        personTable.setItems(importGroups());

        // 1. Wrap the ObservableList in a FilteredList (initially display all data).
        FilteredList<Person> filteredData = new FilteredList<>(myItems, p -> true);

        // 2. Set the filter Predicate whenever the filter changes.
        filterField.textProperty().addListener((observable, oldValue, newValue) -> {
            filteredData.setPredicate(person -> {
                // If filter text is empty, display all persons.
                if (newValue == null || newValue.isEmpty()) {
                    return true;
                }

                // Compare first name and last name of every person with filter text.
                String lowerCaseFilter = newValue.toLowerCase();

                if (person.getFirstName().toLowerCase().indexOf(lowerCaseFilter) != -1) {
                    return true; // Filter matches first name.
                }
                return false; // Does not match.
            });
        });

        // 3. Wrap the FilteredList in a SortedList. 
        SortedList<Person> sortedData = new SortedList<>(filteredData);

        // 4. Bind the SortedList comparator to the TableView comparator.
        //    Otherwise, sorting the TableView would have no effect.
        sortedData.comparatorProperty().bind(personTable.comparatorProperty());

        // 5. Add sorted (and filtered) data to the table.
        personTable.setItems(sortedData);
    }

    public void generateImpex() {
        Alert warning = new Alert(AlertType.WARNING, "Generating Impex!", ButtonType.YES, ButtonType.CANCEL);
        warning.showAndWait();
    }
}

And Person.class

package com.lil;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
//import java.util.Comparator;

public class Person
{
  public BooleanProperty selected = new SimpleBooleanProperty();
  public StringProperty firstName;

  public Person(boolean paramBoolean, String paramString)
  {
    this.selected.setValue(Boolean.valueOf(paramBoolean));
    this.firstName = new SimpleStringProperty(paramString);
  }

  public String toString()
  {
    return getFirstName();
  }

  public String getFirstName()
  {
    return (String)this.firstName.get();
  }

  public void setFirstName(String paramString)
  {
    this.firstName.set(paramString);
  }

  public StringProperty firstNameProperty()
  {
    return this.firstName;
  }

  public boolean isSelected()
  {
    return this.selected.get();
  }

  public BooleanProperty selectedProperty()
  {
    return this.selected;
  }

  public void setSelected(boolean paramBoolean)
  {
    this.selected.set(paramBoolean);
  }
}

I expect the above to populate the tableView with an unchecked checkbox in the first column and the relevant name string from the csv

It should work like it does with the example below, except setting the initial false inside the csv is NOT a requirement:


    /**
     * Just add some sample data in the constructor.
     */

    public ObservableList<Person> myItems = FXCollections.observableArrayList();

    public PersonTableController() {
        myItems.add(new Person(false, "Hans"));
        myItems.add(new Person(false, "Ruth"));
        myItems.add(new Person(false, "Heinz"));
        myItems.add(new Person(false, "Cornelia"));
        myItems.add(new Person(false, "Werner"));
        myItems.add(new Person(false, "Lydia"));
        myItems.add(new Person(false, "Anna"));
        myItems.add(new Person(false, "Stefan"));
        myItems.add(new Person(false, "Martin"));
        myItems.add(new Person(false, "Joni"));
        myItems.add(new Person(false, "Chachi"));
        myItems.add(new Person(false, "Phillip"));
        myItems.add(new Person(false, "Susan"));
        myItems.add(new Person(false, "Joan"));
    }

    /**
     * Initializes the controller class. This method is automatically called
     * after the fxml file has been loaded.
     * 
     * Initializes the table columns and sets up sorting and filtering.
     */
    @FXML
    public void initialize() {

        // We need the TableView to be editable in order to allow each CheckBox to be selectable
        personTable.setEditable(true);

        // Bind the columns with our model's properties
        colSelected.setCellValueFactory(f -> f.getValue().selectedProperty());
        colName.setCellValueFactory(f -> f.getValue().firstNameProperty());

        // Set the CellFactory to use a CheckBoxTableCell
        colSelected.setCellFactory(param -> {
            return new CheckBoxTableCell<Person, Boolean>();
        });

        // Add our columns to the TableView
        personTable.getColumns().addAll(colSelected, colName);

        // Set our items to the TableView
        personTable.setItems(myItems);

If I remove the csv inputstream and use the above to fill the table everything works correctly.

Any ideas? Is it best to add 'false' in csv or fix BooleanProperty > boolean issue? I have read and tested a few things like .booleanValue(), .getValue()...

Many thanks to everyone and this great community!!

Upvotes: 0

Views: 472

Answers (1)

Andre Mac Gonz
Andre Mac Gonz

Reputation: 25

The error was that I was trying to compile Controller from a directory that I should'nt be. I have now got the csv read working and a select all checkbox working. Currently I'm working on the listener for the table column checkboxes in order to show a status message regarding what group has been selected and its boolean value.

Ok I was able to get it working like so:

package com.lil;

import com.lil.Person;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.SingleSelectionModel;
import javafx.scene.text.Text;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import java.util.ArrayList;
import java.util.List;
import java.util.Comparator;
import java.util.Collections;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;

/**
 * View-Controller for the person table.
 */
public class PersonTableController {
    @FXML
    Button generate;
    @FXML
    Text status;
    @FXML
    TextField textVorname;
    @FXML
    TextField textNachname;
    @FXML
    TextField textUsergroup;
    @FXML
    TextField adname;
    @FXML
    CheckBox checkbox;
    @FXML
    CheckBox checkbox2;
    //@FXML
    //CheckBox selected;
    @FXML
    public TextField filterField;
    @FXML
    public TableView<Person> personTable = new TableView<Person>();
    @FXML
    public TableColumn<Person, Boolean> colSelected;
    @FXML
    public TableColumn<Person, String> colName;

    private BufferedReader br;
    private InputStream importPath;
    /**
     * Just add some sample data in the constructor.
     */

    public ObservableList<Person> myItems = FXCollections.observableArrayList();

    // IMPORT GROUPS FUNCTION
    private ObservableList<Person> importGroups()
    {
      this.importPath = getClass().getResourceAsStream("/input/groups.csv");

      String line = "";

      this.br = new BufferedReader(new InputStreamReader(this.importPath));
      ObservableList<Person> observableList;
      try
      {
        while ((line = this.br.readLine()) != null) {
          if (!line.startsWith("Benutzergruppen_ID"))
          {
            String[] parts = line.split(";");
            myItems.add(new Person(false, parts[1]));
          }
        }
        observableList = FXCollections.observableList(myItems);
      }
      catch (IOException e)
      {
        observableList = FXCollections.observableList(myItems);
        System.out.println("IO Exception while reading myItems");
      }
      return observableList;
    }
    // IMPORT GROUPS FUNCTION END
    /**
     * Initializes the controller class. This method is automatically called
     * after the fxml file has been loaded.
     * 
     * Initializes the table columns and sets up sorting and filtering.
     */

    @FXML
    public void initialize() {

        // We need the TableView to be editable in order to allow each CheckBox
        personTable.setEditable(true);

        // Bind the columns with our model's properties
        colSelected.setCellValueFactory(f -> f.getValue().selectedProperty());
        colName.setCellValueFactory(f -> f.getValue().firstNameProperty());

        // Set the CellFactory to use a CheckBoxTableCell
        colSelected.setCellFactory(param -> {
            return new CheckBoxTableCell<Person, Boolean>();
        });

        // Add our columns to the TableView
        personTable.getColumns().addAll(colSelected, colName);

        // Set our items to the TableView
        // personTable.setItems(myItems);
        // set Groups from CSV
        personTable.setItems(importGroups());

        // 1. Wrap the ObservableList in a FilteredList (initially display all data).
        FilteredList<Person> filteredData = new FilteredList<>(myItems, p -> true);

        // 2. Set the filter Predicate whenever the filter changes.
        filterField.textProperty().addListener((observable, oldValue, newValue) -> {
            filteredData.setPredicate(person -> {
                // If filter text is empty, display all persons.
                if (newValue == null || newValue.isEmpty()) {
                    return true;
                }

                // Compare first name and last name of every person with filter text.
                String lowerCaseFilter = newValue.toLowerCase();

                if (person.getFirstName().toLowerCase().indexOf(lowerCaseFilter) != -1) {
                    return true; // Filter matches first name.
                }
                return false; // Does not match.
            });
        });

        // 3. Wrap the FilteredList in a SortedList. 
        SortedList<Person> sortedData = new SortedList<>(filteredData);

        // 4. Bind the SortedList comparator to the TableView comparator.
        //    Otherwise, sorting the TableView would have no effect.
        sortedData.comparatorProperty().bind(personTable.comparatorProperty());

        // 5. Add sorted (and filtered) data to the table.
        personTable.setItems(sortedData);
    }

    public void generateImpex() {
        Alert warning = new Alert(AlertType.WARNING, "Generating Impex!", ButtonType.YES, ButtonType.CANCEL);
        warning.showAndWait();
    }
}

Now I am trying to figure out how to add a change listener to each checkbox so I can print a status message when it is checked.

Upvotes: -4

Related Questions