7

I want to display HashMap contents in a JavaFX Tableview. Please find below the code I used to set the HashMap contents into the table columns. The problem I'm having is that it's displaying only one row. The for loop is iterating only 5 times: each time it is picking up the first value of the HashMap.

If I ignore the return SimpleObjectProperty line, the for loop is iterating over all the content in the HashMap.

final ObservableList<Map> data = FXCollections.observableArrayList();
data.addAll(HASHMAP);

TableColumn<Map.Entry, String> nCol = new TableColumn<Map.Entry, String>("Name");
nCol.setEditable(true);
nCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Entry, String>, ObservableValue<String>>() {

 @Override
 public ObservableValue<String> call(TableColumn.CellDataFeatures<Entry, String> p) {
        Set <String> set=HASHMAP.keySet();
    for (String key:HASHMAP.keySet())
    {
           String key1= key.toString();
           return new SimpleObjectProperty<>(key.toString());
    }
         return null;

        } 

    });
  Table.setItems(data);
  Table.getColumns().setAll(nCol,.........);
Woody Zenfell III
  • 1,905
  • 17
  • 31
mani
  • 217
  • 1
  • 4
  • 8

2 Answers2

12
  1. CellFactory.Callback.call() creates just one cell, not all cells in a loop
  2. Using return from a loop breaks loop execution.

Take a look at next example, especially comments:

public class MapTableView extends Application {

    @Override
    public void start(Stage stage) {

        // sample data
        Map<String, String> map = new HashMap<>();
        map.put("one", "One");
        map.put("two", "Two");
        map.put("three", "Three");


        // use fully detailed type for Map.Entry<String, String> 
        TableColumn<Map.Entry<String, String>, String> column1 = new TableColumn<>("Key");
        column1.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Map.Entry<String, String>, String>, ObservableValue<String>>() {

            @Override
            public ObservableValue<String> call(TableColumn.CellDataFeatures<Map.Entry<String, String>, String> p) {
                // this callback returns property for just one cell, you can't use a loop here
                // for first column we use key
                return new SimpleStringProperty(p.getValue().getKey());
            }
        });

        TableColumn<Map.Entry<String, String>, String> column2 = new TableColumn<>("Value");
        column2.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Map.Entry<String, String>, String>, ObservableValue<String>>() {

            @Override
            public ObservableValue<String> call(TableColumn.CellDataFeatures<Map.Entry<String, String>, String> p) {
                // for second column we use value
                return new SimpleStringProperty(p.getValue().getValue());
            }
        });

        ObservableList<Map.Entry<String, String>> items = FXCollections.observableArrayList(map.entrySet());
        final TableView<Map.Entry<String,String>> table = new TableView<>(items);

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

        Scene scene = new Scene(table, 400, 400);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch();
    }
}
Sergey Grinev
  • 34,078
  • 10
  • 128
  • 141
  • Thank u very much man....I have one more question suppose if we use multiple values in hashmap how to retrieve it.... – mani Sep 04 '13 at 18:34
  • what do you mean by multiple values? – Sergey Grinev Sep 04 '13 at 19:26
  • Map> map = new HashMap>(); for e.g. this map will contain {one=[1, 11, 12],two=[2, 21, 22]} – mani Sep 05 '13 at 02:49
  • yep, you just need to introduce more columns and cellvaluefactories with code like: `return new SimpleStringProperty(p.getValue().getValue().get(INDEX)`. – Sergey Grinev Sep 05 '13 at 10:46
  • Are we able to set the limit on Number of content to fetch from map and display in table view.? (E.g. : Fetch only first ten or twenty value from the map) – mani Sep 13 '13 at 12:04
  • you need to filter `items` to achieve that. – Sergey Grinev Sep 13 '13 at 15:56
  • A related example that displays the `Map` returned by `System.getenv()` is shown [here](https://stackoverflow.com/a/69781121/230513). – trashgod Dec 21 '21 at 18:02
3

Sergey Grinev; I found a solution, a generic solution for this problem

public class TableCassaController<K,V> extends TableView<Map.Entry<K,V>> implements Initializable {
@FXML   private TableColumn<K, V> column1;
@FXML   private TableColumn<K, V> column2;


public TableCassaController(ObservableMap<K,V> map, String col1Name, String col2Name) {
    System.out.println("Costruttore table");
    TableColumn<Map.Entry<K, V>, K> column1 = new TableColumn<>(col1Name);
    column1.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Map.Entry<K, V>, K>, ObservableValue<K>>() {

        @Override
        public ObservableValue<K> call(TableColumn.CellDataFeatures<Map.Entry<K, V>, K> p) {
            // this callback returns property for just one cell, you can't use a loop here
            // for first column we use key
            return new SimpleObjectProperty<K>(p.getValue().getKey());
        }
    });

    TableColumn<Map.Entry<K, V>, V> column2 = new TableColumn<>(col2Name);
    column2.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Map.Entry<K, V>, V>, ObservableValue<V>>() {

        @Override
        public ObservableValue<V> call(TableColumn.CellDataFeatures<Map.Entry<K, V>, V> p) {
            // for second column we use value
            return new SimpleObjectProperty<V>(p.getValue().getValue());
        }
    });

    ObservableList<Map.Entry<K, V>> items = FXCollections.observableArrayList(map.entrySet());

    this.setItems(items);
    this.getColumns().setAll(column1, column2);

}

Very Thanks!!! :-)