1
votes

My Java programm produces a lot of data, with wich I construct individual ResultObject. Because only certain ResultsObjects will be of interest, I populate an ObservableHashMap<> with my results. The CustomObject consists of a handful ints + doubles and one JSONObject. With this CustomObject I want to map similar ResultObjects(which have certain properties in common) to that one CustomObject.

While mapping and handling those results works as intended, I am pretty much helpless to populate a TableView with that ObservableHashMap<>.

My CustomObject (JSONObject simply to check, if two CustomObjects have the same properties):

public CustomObject(Simulation data) {

    this.datapoint1 = data.datapoint1;
    this.datapoint2 = data.datapoint2;

    this.jsonCompareObject = new JSONObject()
            .put("datapoint1", data.datapoint1)
            .put("datapoint1", data.datapoint2);
}

My ObservableHashMap Object:

private ObservableMap <CustomObject, ObservableList<Simulation>> topResultsList;

public SomeObjectWithObservableMap(){
    this.topResultsList = FXCollections.observableHashMap();
}

By using the following code, I check if there is a key with the corresponding datapoints already present to then add to its ObservableList (Value):

private boolean isKeyPresent(CustomObject newCustomObject, Simulation data) {
    for (CustomObject oldCustomObject : this.topResultsList.keySet()) {
        if (oldCustomObject.jsonCompareObject.toString().equals(newCustomObject.jsonCompareObject.toString())) {
            this.topResultsList.get(oldCustomObject).add(data);
            return true;
        }
    }
    return false;
}

I populate some other TableView like this:

{
    tableColumn.setCellValueFactory(new PropertyValueFactory<>("datapoint1"));
    tableColumn.setCellFactory(TextFieldTableCell.<SomeObject, Double>forTableColumn(twoDigits));
    tableView.setItems(someObject.getObservableList());
}

In the end I want some TableColumns to show properties from the CustomObject. Later on, I would want the individual mapped ObservableLists of a selected CustomObject to be shown in a seperate TableView.

I am pretty new to Java and JavaFX and I hope to have described my problem as professional as possible. Please let me know, if I missed anything.

2
Since you can't back a TableView with a Map, have you tried to use an ObservableList backed by the keySet of the map as your TableView items? You should be able to listen for changes to the observable map and then either a) whole sale update the TableView items or b) dynamically add/remove just those entries updated in the map. - kendavidson

2 Answers

1
votes

The other way to create a TableView with one Map<String,String> is:

enter image description here

Main.java

package tester;

import java.util.HashMap;
import java.util.Map;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TableView;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class Tester extends Application
{

    @Override
    public void start(Stage primaryStage)
    {
        MapTable mapTable = new MapTable(getDatabaseRecord());

        TableView table = mapTable.getTableView();

        HBox root = new HBox();
        root.getChildren().addAll(table);

        Scene scene = new Scene(root, 500, 500);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        launch(args);
    }

    private Map<String, String> getDatabaseRecord()
    {
        Map<String, String> record1 = new HashMap<>();

        record1.put("firstName", "Joe");
        record1.put("lastName", "Blob");
        record1.put("address", "95 circle ave");
        record1.put("city", "Toronto");
        record1.put("postalCode", "L9Y4Z4");

        return record1;
    }
}

MapTable.java

package tester;

import java.util.Map;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;

public class MapTable
{

    private final TableView<Map.Entry<String, String>> table;
    private final ObservableList<Map.Entry<String, String>> data;

    public MapTable(Map map)
    {

        this.table = new TableView<>();
        this.data = FXCollections.observableArrayList(map.entrySet());
        setUpTable();
    }

    private void setUpTable()
    {
        this.table.setEditable(false);
        this.table.setItems(this.data);
        this.table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        // use fully detailed type for Map.Entry<String, String> 
        TableColumn<Map.Entry<String, String>, String> column1 = new TableColumn<Map.Entry<String, String>, String>();
        column1.setMinWidth(125);
        column1.setSortable(false);
        column1.setCellValueFactory((TableColumn.CellDataFeatures<Map.Entry<String, String>, String> p) -> new SimpleStringProperty(p.getValue().getKey()));

        TableColumn<Map.Entry<String, String>, String> column2 = new TableColumn<Map.Entry<String, String>, String>();
        column2.setMinWidth(350);
        column2.setSortable(false);
        column2.setCellValueFactory((TableColumn.CellDataFeatures<Map.Entry<String, String>, String> p) -> new SimpleStringProperty(p.getValue().getValue()));


        this.table.getColumns().setAll(column1, column2);

    }

    public TableView getTableView()
    {
        return this.table;
    }
}
1
votes

This should work for a List<Map<String,String>>

enter image description here

Main.java

package tester;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class Tester extends Application
{

    @Override
    public void start(Stage primaryStage)
    {

        TableView<LineItem> table = new TableView<>();
        List<Map<String, String>> databaseObject = getDatabaseObject();

        for (String key : databaseObject.get(0).keySet())
        {
            TableColumn<LineItem, String> col = new TableColumn<>(key);
            col.setCellValueFactory((TableColumn.CellDataFeatures<LineItem, String> cellData) -> cellData.getValue().fieldProperty(key));            
            table.getColumns().add(col);

        }
        List<LineItem> data = new ArrayList<>();
        LineItem sequence1 = new LineItem(databaseObject.get(0));
        LineItem sequence2 = new LineItem(databaseObject.get(1));
        data.add(sequence1);
        data.add(sequence2);

        table.setItems(FXCollections.observableArrayList(data));

        table.setPrefWidth(500);

        HBox root = new HBox();
        root.getChildren().addAll(table);

        Scene scene = new Scene(root, 500, 500);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        launch(args);
    }

    private List<Map<String, String>> getDatabaseObject()
    {
        List<Map<String, String>> values = new ArrayList<>();

        Map<String, String> record1 = new HashMap<>();
        record1.put("firstName", "Joe");
        record1.put("lastName", "Blob");
        record1.put("address", "95 circle ave");
        record1.put("city", "Toronto");
        record1.put("postalCode", "L9Y4Z4");
        values.add(record1);

        Map<String, String> record2 = new HashMap<>();
        record2.put("firstName", "Sarah");
        record2.put("lastName", "Blob");
        record2.put("address", "92 main st");
        record2.put("city", "London");
        record2.put("postalCode", "T9Y4K4");
        values.add(record2);

        return values;
    }

}

LineItem.java

package tester;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class LineItem
{

    private final Map<String, StringProperty> fields;

    public LineItem(Map<String, String> record)
    {
        this.fields = new HashMap<>();
        for (String key : record.keySet())
        {
            this.fields.put(key, new SimpleStringProperty());
        }
        for (Entry<String, String> entry : ((Set<Entry<String, String>>) record.entrySet()))
        {

            this.fields.get(entry.getKey()).set(entry.getValue());
        }
    }

    public final StringProperty fieldProperty(String key)
    {
        return this.fields.get(key);
    }

}