Search code examples
javajavafxhashmaptableviewtablecolumn

How to fill TableView with ObservableMap<KeyObject, ObservableList<CustomObject>> in JavaFX


My Java program produces a lot of data, with which 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 separate 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.


Solution

  • 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);
        }
    
    }