Andrew
Andrew

Reputation: 245

javafx tableview data from List

I've got problem with TableView in JavaFX.

Creating tables from existing class with all fields defined is easy.

But I'm wondering if it is possible to make table and add data from List?

I've made something like this but it kinda doesn't work.

    @FXML
    private TableView<List<String>> testTable;

    ....


    List<String> list = new ArrayList<>();
    list.add("1hello");
    list.add("1hello2");

    List<String> list2 = new ArrayList<>();
    list2.add("2hello");
    list2.add("2hello2");

    ObservableList<List<String>> lists = FXCollections.observableArrayList();
    lists.add(list);
    lists.add(list2);

    TableColumn<List<String>, String> coll = new TableColumn<>("one");
    coll.setCellValueFactory(new PropertyValueFactory<List<String>,String>(""));
    TableColumn<List<String>, String> coll2 = new TableColumn<>("two");
    coll2.setCellValueFactory(new PropertyValueFactory<List<String>,String>(""));

    testTable.getColumns().add(coll);
    testTable.getColumns().add(coll2);

    lists.forEach(li -> {
        System.out.println("list: " +  li);
        testTable.getItems().add(li);

    }); 

It didn't insert any data. Is something like that even possible?

Upvotes: 3

Views: 15029

Answers (2)

Sunflame
Sunflame

Reputation: 3186

You can do this by replacing String to StringProperty in the List:

@FXML
private TableView<List<StringProperty>> testTable;

then:

TableColumn<List<StringProperty>, String> coll = new TableColumn<>("one");

add the cellValueFactories:

col1.setCellValueFactory(data -> data.getValue().get(0));
col2.setCellValueFactory(data -> data.getValue().get(1));
.
.

and so on.

This means the first element of the list will be used in col1, the second element of the list will be used in col2.

Then you can populate the list like:

ObservableList<List<StringProperty>> data = FXCollections.observableArrayList();
List<StringProperty> firstRow = new ArrayList<>();
firstRow.add(0, new SimpleStringProperty("Andrew"));
firstRow.add(1, new SimpleStringProperty("Smith"));
.
.
.
data.add(firstRow);
.
.
.
and so on...
table.setItems(data);

It is doable this way but I would say it is a very bad practice.

Upvotes: 2

RobRoy
RobRoy

Reputation: 49

As a little piece for my work i need a TableView with dynamically filled data from a List. I looked at some other samples out there in StackOverflow and also at the Oracle tutorials. But nothing fits my needs.

To meet my necessity i puzzled the different solutions together. See the working sample below.

import java.util.ArrayList;
import javafx.util.Callback;
import javafx.util.StringConverter;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.application.Application;

/**
 *
 * @author Rob
 */
public class TableViewSample extends Application {

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

    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        stage.setWidth(400);
        stage.setHeight(500);

        final Label label = new Label("Student IDs");
        label.setFont(new Font("Arial", 20));

        TableView tableView = new TableView<>();
        tableView.setEditable(true);
        tableView.getSelectionModel().setCellSelectionEnabled(true);

        ObservableList<TableColumn> tableViewColumns = generateTableViewColumns();
        tableView.getColumns().setAll(tableViewColumns);

        ObservableList<TableColumn> tcs = tableView.getColumns();
        for (int i = 0; i < tcs.size(); i++) {
            TableColumn tc = tcs.get(i);

            if (i == 0) {
                Callback<TableColumn.CellDataFeatures<ArrayList, Color>, ObservableValue<Color>> cellValueFactory = buildCallbackColor(i);
                tc.setCellValueFactory(cellValueFactory);
            } else {
                Callback<TableColumn.CellDataFeatures<ArrayList, String>, ObservableValue<String>> cellValueFactory = buildCallbackString(i);
                tc.setCellValueFactory(cellValueFactory);
            }

        }

        ObservableList<ArrayList> tableViewRows = generateTableViewRows();
        tableView.getItems().setAll(tableViewRows);

        for (int i = 0; i < tcs.size(); i++) {
            TableColumn dataColumn = tcs.get(i);

            if (i == 0) {
                Callback<TableColumn<ArrayList, Color>, TableCell<ArrayList, Color>> cellFactoryPane = buildCallbackPane();
                dataColumn.setCellFactory(cellFactoryPane);
            } else {
                Callback<TableColumn<ArrayList, String>, TableCell<ArrayList, String>> cellFactoryTextFieldTableCell = buildCallbackTextFieldTableCell();
                dataColumn.setCellFactory(cellFactoryTextFieldTableCell);
            }

        }

        final VBox vbox = new VBox();

        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(label, tableView);

        ((Group) scene.getRoot()).getChildren().addAll(vbox);

        stage.setScene(scene);

        stage.show();
    }

    private ObservableList<TableColumn> generateTableViewColumns() {
        ObservableList<TableColumn> tableViewColumns = FXCollections.observableArrayList();
        TableColumn firstDataColumn = new TableColumn<>("Activity");
        TableColumn secondDataColumn = new TableColumn<>("Class A");
        TableColumn thirdDataColumn = new TableColumn<>("Class B");

        firstDataColumn.setMinWidth(80);
        secondDataColumn.setMinWidth(130);
        thirdDataColumn.setMinWidth(130);

        tableViewColumns.add(firstDataColumn);
        tableViewColumns.add(secondDataColumn);
        tableViewColumns.add(thirdDataColumn);        

        return tableViewColumns;
    }

    private ObservableList<ArrayList> generateTableViewRows() {
        int max = 6;
        ObservableList<ArrayList> tableViewRows = FXCollections.observableArrayList();
        for (int i = 1; i < max; i++) {
            ArrayList dataRow = new ArrayList<>();

            Color value1 = Color.GREEN;
            String value2 = "A" + i;
            String value3 = "B" + i;

            dataRow.add(value1);
            dataRow.add(value2);
            dataRow.add(value3);

            tableViewRows.add(dataRow);
        }
        return tableViewRows;
    }

    private Callback<TableColumn.CellDataFeatures<ArrayList, Color>, ObservableValue<Color>> buildCallbackColor(int index) {
        Callback<TableColumn.CellDataFeatures<ArrayList, Color>, ObservableValue<Color>> cellValueFactory = new Callback<TableColumn.CellDataFeatures<ArrayList, Color>, ObservableValue<Color>>() {
            @Override
            public ObservableValue<Color> call(TableColumn.CellDataFeatures<ArrayList, Color> param) {
                return new SimpleObjectProperty(param.getValue().get(index));
            }
        };
        return cellValueFactory;
    }

    private Callback<TableColumn.CellDataFeatures<ArrayList, String>, ObservableValue<String>> buildCallbackString(int index) {
        Callback<TableColumn.CellDataFeatures<ArrayList, String>, ObservableValue<String>> cellValueFactory = new Callback<TableColumn.CellDataFeatures<ArrayList, String>, ObservableValue<String>>() {
            @Override
            public ObservableValue<String> call(TableColumn.CellDataFeatures<ArrayList, String> param) {
                return new SimpleStringProperty((String) param.getValue().get(index));
            }
        };
        return cellValueFactory;
    }

    private Callback<TableColumn<ArrayList, Color>, TableCell<ArrayList, Color>> buildCallbackPane() {
        Callback<TableColumn<ArrayList, Color>, TableCell<ArrayList, Color>> cellFactory = new Callback<TableColumn<ArrayList, Color>, TableCell<ArrayList, Color>>() {
            @Override
            public TableCell call(TableColumn tableColumn) {
                double cellWidth = tableColumn.getMinWidth();
                double cellHeight = 35;

                TableCell tableCell = new TableCell<Object, Color>() {
                    @Override
                    protected void updateItem(Color item, boolean empty) {
                        super.updateItem(item, empty);

                        if (empty) {
                            setText(null);
                            setGraphic(null);
                        } else {
                            Pane p = new Pane();
                            p.setPrefSize(cellWidth, cellHeight);
                            Canvas canvasRectLayerColor = new Canvas();
                            p.getChildren().add(canvasRectLayerColor);
                            canvasRectLayerColor.setWidth(20);
                            canvasRectLayerColor.setHeight(20);
                            GraphicsContext gc = canvasRectLayerColor.getGraphicsContext2D();      
                            gc.setFill(item);
                            gc.fillRect(0, 0, canvasRectLayerColor.getWidth(), canvasRectLayerColor.getHeight());
                            setGraphic(p);
                        }
                    }
                };

                return tableCell;
            }
        };

        return cellFactory;
    }

    private Callback<TableColumn<ArrayList, String>, TableCell<ArrayList, String>> buildCallbackTextFieldTableCell() {
        Callback<TableColumn<ArrayList, String>, TableCell<ArrayList, String>> cellFactory = new Callback<TableColumn<ArrayList, String>, TableCell<ArrayList, String>>() {
            @Override
            public TableCell call(TableColumn tc) {
                TextFieldTableCell tftc = new TextFieldTableCell(new StringConverter() {
                    @Override
                    public String toString(Object t) {
                        return t.toString();
                    }

                    @Override
                    public Object fromString(String string) {
                        return string;
                    }
                });

                return tftc;
            }
        };
        return cellFactory;
    }

}

Hope this one help even it is quite late.

Upvotes: 0

Related Questions