0

I have an arraylist made of 10 Comboboxes. I would like to load each combobox with n imageviews.

I get the data i need from a class which gaves me the correct data. The arraylist of arraylist you find in the code is the "simulation" of different dices one over another, creating different columns. For example i have max 10 columns each made by n dices.

Here is the code:

        //LOADING DICES INTO MY COMBOBOXES
    //List used to load strings  
    ObservableList<String> options = FXCollections.observableArrayList();
    //Arraylist made of arraylist containing the data I need
    ArrayList<ArrayList<Dice>> roundTrackData = gameManager.roundTrack.getDices();
    System.out.println(roundTrackData);
    for(int h=0; h<roundTrackData.size();h++){
        System.out.println(" h Value:" + h);
        ArrayList<Dice> testing = roundTrackData.get(h);
         System.out.println(" Testing:" + testing);
         System.out.println(" Testing size:" + testing.size());


        for(int u=0; u<testing.size();u++){
             System.out.println(" Inside cicle ");

             String color = Character.toString(testing.get(u).getColor());
             String value = testing.get(u).getValue().toString();
             String diceRound = value+color+".png";

             options.add(diceRound);
             //listaComboBox is an array list containing 10 comboboxes
             listaComboBox.get(h).setItems(options);
             listaComboBox.get(h).setCellFactory(c -> new StatusListCell());
             System.out.println("Dice color "+ color);
             System.out.println("Dice value"+ value);
       }
   }

StatusListCell class:

public class StatusListCell extends ListCell<String> {
protected void updateItem(String item, boolean empty) {
    super.updateItem(item, empty);
    System.out.println("IT'S NULL");

    setGraphic(null);
    setText(null);
    if (item != null) {
        System.out.println("IT'S NOT NULL!");

        ImageView imageView = new ImageView(new Image(item));
        imageView.setFitWidth(40);
        imageView.setFitHeight(40);
        setGraphic(imageView);
        setText("a");
    }
  }
}

I have developed my code following this question: JavaFX ComboBox Image

The code works and insert the images i need into my Comboboxes, the problem is that it adds everytime more images to every combobox.

For Example: the first combobox loads properly the first 5 dices. When i add other 5 dices (which should only be added to the second combobox), they are added both to the first and second comboboxes, and i'll get two identical groups of elements (this keeps going on until the end).

I tried to change my code adding a options.clear() before the second cycle, so the options ObservableList is resetted and i can add my elements from 0, and then add them into my h combobox.

The problem is that i actually get no inserted imageView.

I also tried to move

listaComboBox.get(h).setItems(options);
listaComboBox.get(h).setCellFactory(c -> new StatusListCell());

out of the second for cycle, but i still get nothing.

Any ideas of what's the problem? I have been trying for so long but i can't still figure out what's the real problem.

Mattia Surricchio
  • 1,362
  • 2
  • 21
  • 49

1 Answers1

1

You're always adding to the same list. For different items lists you need to use a different ObservableList for each ComboBox though.

Furthermore reloading the images and recreating the ImageViews should be avoided to improve the efficiency of your program:

//Arraylist made of arraylist containing the data I need
ArrayList<ArrayList<Dice>> roundTrackData = gameManager.roundTrack.getDices();
System.out.println(roundTrackData);
final Map<String, WeakReference<Image>> cache = new HashMap<>();

for(int h = 0; h < roundTrackData.size(); h++) {
    ComboBox<String> combo = listaComboBox.get(h);
    combo.setCellFactory(c -> new StatusListCell(cache));
    ObservableList<String> options = FXCollections.observableArrayList();

    List<Dice> testing = roundTrackData.get(h);
    System.out.println(" Testing:" + testing);
    System.out.println(" Testing size:" + testing.size());

    for(Dice die : testing){
         System.out.println(" Inside cicle ");
         String color = Character.toString(die.getColor());
         String value = die.getValue().toString();
         String diceRound = value+color+".png";

         options.add(diceRound);
         //listaComboBox is an array list containing 10 comboboxes
         System.out.println("Dice color "+ color);
         System.out.println("Dice value"+ value);
    }

    combo.setItems(options);
}
public class StatusListCell extends ListCell<String> {

    private final Map<String, WeakReference<Image>> cache;
    private final ImageView imageView;

    public StatusListCell(Map<String, WeakReference<Image>> cache) {
        imageView = new ImageView();
        imageView.setFitWidth(40);
        imageView.setFitHeight(40);
        setGraphic(imageView); // keep image even if empty for constant cell size
        this.cache = cache;
    }

    protected void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);

        if (empty || item == null) {
            setText("");
            imageView.setImage(null); // don't display a image
        } else {
            cache.compute(item, (k, v) -> {
                // retrieve image or load
                Image img = null;
                if (v != null) {
                    img = v.get();
                }
                if (img == null) {
                    img = new Image(k);
                    v = new WeakReference<>(img);
                }

                // change image in imageview
                imageView.setImage(img);

                return v;
            });
            setText("a");
        }
    }

}
fabian
  • 80,457
  • 12
  • 86
  • 114
  • I made the reload of imageviews because the original Arraylist could be modified from outside, and the content in my combobox could change as a result. Is your solution still working (and better) than mine (reload imageviews each time) in this scenario? – Mattia Surricchio Jun 11 '18 at 19:17
  • 1
    @MattiaSurricchio (Just edited in a missing parameter for `compute`.) Reducing reloads of `Image`s is just an optimisation. (One of the least significant parts of the answer). `cache` has a chance of keeping the reference to a `Image`. Since it stores the `Image`s by the url/constructor parameter and `Image`s can be considered immutable in this case, this should not change the results (either your original code and this code both work or both don't work). – fabian Jun 11 '18 at 20:06
  • The code of StatusListCell says that "item" has private access in 'java.fx.Control.Cell', i'm talking about the item inside new Image (item). How can i solve that? – Mattia Surricchio Jun 13 '18 at 15:01