0

I have an ArrayList and the data inside it has been read from an excel file. I now want to create a TableView in my JavaFX app that gets populated from the ArrayList that has been created. I have a class that contains all the address data that gets read such as building number, street name etc. but I can't seem to take this data and put it into the table view, which is just blank.

Here is the code I have produced so far:

List<AddressDetails> addressList = ReadExcel.readExcel();

TableView<AddressDetails> table = new TableView<>();
ObservableList<AddressDetails> addresses = FXCollections.observableArrayList(addressList);

TableColumn<AddressDetails, String> buildNameCol 
  = new TableColumn<AddressDetails, String>("Building Name");
buildNameCol.setCellValueFactory(new PropertyValueFactory<AddressDetails, String>("buildName"));

TableColumn<AddressDetails, Double> buildNumCol
  = new TableColumn<AddressDetails, Double>("Building Number");
buildNumCol.setCellValueFactory(new PropertyValueFactory<AddressDetails, Double>("buildNum"));

TableColumn<AddressDetails, String> streetCol
  = new TableColumn<AddressDetails, String>("Street Name");
streetCol.setCellValueFactory(new PropertyValueFactory<AddressDetails, String>("streetName"));

TableColumn<AddressDetails, String> cityCol
  = new TableColumn<AddressDetails, String>("City");
cityCol.setCellValueFactory(new PropertyValueFactory<AddressDetails, String>("city"));

TableColumn<AddressDetails, String> postCol 
  = new TableColumn<AddressDetails, String>("Postcode");
postCol.setCellValueFactory(new PropertyValueFactory<AddressDetails, String>("postCode"));

TableColumn<AddressDetails, String> countryCol
  = new TableColumn<AddressDetails, String>("Country");
countryCol.setCellValueFactory(new PropertyValueFactory<AddressDetails, String>("country"));

table.getColumns().addAll(buildNameCol, buildNumCol, streetCol, cityCol, postCol, countryCol); 
table.setItems(addresses);

This is my AddressDetails Class:

public class AddressDetails {

    private String buildName;
    private double buildNum;
    private String streetName;
    private String city;
    private String postCode;
    private String country;

    public AddressDetails() {

    }

    public String getBuildName() {
        return buildName;
    }

    public void setBuildName(String buildName) {
        this.buildName = buildName;
    }

    public double getBuildNum() {
        return buildNum;
    }

    public void setBuildNum(double buildNum) {
        this.buildNum = buildNum;
    }

    public String getStreetName() {
        return streetName;
    }

    public void setStreetName(String streetName) {
        this.streetName = streetName;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getPostCode() {
        return postCode;
    }

    public void setPostCode(String postCode) {
        this.postCode = postCode;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }
}

This is the excel reader which adds the addresses from the excel file into an ArrayList:

public class ReadExcel {  

public static List<AddressDetails> readExcel() {

    List<AddressDetails> addressList = null;

    try {

        Workbook workbook = WorkbookFactory.create(new FileInputStream(FileSelector.getSelectedFile()));

        // Get the first sheet from the excel file
        Sheet sheet = workbook.getSheetAt(0);
        if (sheet != null) {
            addressList = readExcelSheet(sheet);

        }

    } catch (EncryptedDocumentException | IOException | ParseException e) {
        e.printStackTrace();

    }

    if (addressList == null)
        addressList = Collections.emptyList();

    return addressList;

}

private static List<AddressDetails> readExcelSheet(Sheet sheet) throws ParseException {

    Iterator<Row> rowItr = sheet.iterator();
    List<AddressDetails> addressList = new ArrayList<>();

    // Iterate each row in the sheet
    while (rowItr.hasNext()) {
        AddressDetails address = new AddressDetails();
        Row row = rowItr.next();
        // First row is header so skip it
        if (row.getRowNum() <= 2) {
            continue;

        }

        Iterator<Cell> cellItr = row.cellIterator();
        // Iterate each cell in a row
        while (cellItr.hasNext()) {

            Cell cell = cellItr.next();
            int index = cell.getColumnIndex();
            switch (index) {
            case 0:
                address.setBuildName((String) getValueFromCell(cell));
                break;
            case 1:
                address.setBuildNum((double) getValueFromCell(cell));
                break;
            case 2:
                address.setStreetName((String) getValueFromCell(cell));
                break;
            case 3:
                address.setCity((String) getValueFromCell(cell));
                break;
            case 4:
                address.setPostCode((String) getValueFromCell(cell));
                break;
            case 5:
                address.setCountry((String) getValueFromCell(cell));
                break;

            }

        }

        addressList.add(address);

    }

    return addressList;

}

// Method to get cell value based on cell type
private static Object getValueFromCell(Cell cell) {
    switch (cell.getCellType()) {
    case STRING:
        return cell.getStringCellValue();

    case NUMERIC:
        return cell.getNumericCellValue();

    case BLANK:
        return "";
    default:
        return "";

    }

}

}

2
  • 2
    AddressDetails addressList = new AddressDetails(); i dont see you add values to this Object. Commented Jan 24, 2019 at 15:02
  • @StephanHogenboom sorry this was meant to say List<AddressDetails> addressList = ReadExcel.readExcel(); As this is where I created my array list from reading an excel file Commented Jan 31, 2019 at 16:34

1 Answer 1

2

Your addressList should be a List<AddressDetails> instead of a single AddressDetails.

Application screenshot

import java.util.*;
import javafx.application.Application;
import javafx.collections.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class AddressView extends Application {
    private static final String APPLICATION_TITLE = "Address List";

    public static final List<Column<?>> COLUMNS = new ArrayList<>(Arrays.asList(
        new Column<String>(String.class, "buildName", "Building Name"),
        new Column<Double>(Double.class, "buildNum", "Building Number"),
        new Column<String>(String.class, "streetName", "Street Name"),
        new Column<String>(String.class, "city", "City"),
        new Column<String>(String.class, "postCode", "Postcode"),
        new Column<String>(String.class, "country", "Country")
    ));

    private static List<AddressDetails> ADDRESS_LIST = new ArrayList<>(Arrays.asList(
        new AddressDetails("Building A", 1, "Street 1", "City X", "10101", "USA"),
        new AddressDetails("Building B", 2, "Street 2", "City Y", "02020", "USA"),
        new AddressDetails("Building C", 3, "Street 3", "City X", "30303", "USA"),
        new AddressDetails("Building D", 4, "Street 4", "City Y", "04040", "USA"),
        new AddressDetails("Building E", 5, "Street 5", "City X", "50505", "USA")
    ));

    @Override
    public void start(Stage primaryStage) throws Exception {
        StackPane root = new StackPane();
        TableView<AddressDetails> table = createTable(COLUMNS, ADDRESS_LIST);
        root.getChildren().add(table);
        primaryStage.setTitle(APPLICATION_TITLE);
        primaryStage.setScene(new Scene(root, 500, 200));
        primaryStage.show();
    }

    private <E> TableView<E> createTable(List<Column<?>> columns, List<E> data) {
        TableView<E> table = new TableView<>();
        ObservableList<E> addresses = FXCollections.observableArrayList(data);
        for (Column<?> column : columns) {
            table.getColumns().add(createColumn(column));
        }

        table.setItems(addresses);
        return table;
    }

    private <E, C> TableColumn<E, C> createColumn(Column<?> column, C type) {
        TableColumn<E, C> tableColumn = new TableColumn<E, C>(column.getTitle());
        tableColumn.setCellValueFactory(new PropertyValueFactory<E, C>(column.getFieldName()));
        return tableColumn;
    }

    private <E> TableColumn<E, ?> createColumn(Column<?> column) {
        switch (column.getType().getCanonicalName()) {
            case "java.lang.Integer":
                return createColumn(column, Integer.class);
            case "java.lang.Double":
                return createColumn(column, Double.class);
            case "java.lang.String":
            default:
                return createColumn(column, String.class);
        }
    }

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

I created a column class to hold column data so that columns can be dynamically created.

public class Column<T> {
    private Class<T> type;
    private String fieldName;
    private String title;

    public Column(Class<T> type, String fieldName, String title) {
        this.type = type;
        this.fieldName = fieldName;
        this.title = title;
    }

    public Class<T> getType() {
        return type;
    }

    public void setType(Class<T> type) {
        this.type = type;
    }

    public String getFieldName() {
        return fieldName;
    }

    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

Also, don't forget to create a field constructor in AddressDetails.

public AddressDetails(String buildName, double buildNum, String streetName, 
        String city, String postCode, String country) {
    this.buildName = buildName;
    this.buildNum = buildNum;
    this.streetName = streetName;
    this.city = city;
    this.postCode = postCode;
    this.country = country;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Just out of curiosity, why are you using E and C and on the other class T?
@m0skit0 T is usually the goto for CLASS template type and E is usually the goto for METHOD template types (so you do not confuse it with T in the case where T is present). I chose C to represent the type of the class you are passing in. These can be names whatever you want. E could be (element) DATA_TYPE and C could be named CLASS_TYPE if you wanted.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.