As the title says. Basically I have an ArrayList where DiceRoll is a class that is used successfully in a TableView to update the values as they are changed.
public class DiceRoll {
private final SimpleIntegerProperty rollNumber = new SimpleIntegerProperty();
private final SimpleIntegerProperty cubeRoll = new SimpleIntegerProperty(0);
private final SimpleIntegerProperty icosahedron = new SimpleIntegerProperty(0);
private final SimpleIntegerProperty dodecahedron = new SimpleIntegerProperty(0);
public DiceRoll(int rollNumber) {
this.rollNumber.set(rollNumber);
}
public void incrementRoll(DiceTypes type){
switch(type){
case CUBE:
this.cubeRoll.set(this.cubeRoll.getValue() + 1);
break;
case DODECAHEDRON:
this.dodecahedron.set(this.dodecahedron.getValue() + 1);
break;
case ICOSAHEDRON:
this.icosahedron.set(this.icosahedron.getValue() + 1);
break;
}
}
public int getRollNumber() {
return rollNumber.get();
}
public SimpleIntegerProperty rollNumberProperty() {
return rollNumber;
}
public int getCubeRoll() {
return cubeRoll.get();
}
public SimpleIntegerProperty cubeRollProperty() {
return cubeRoll;
}
public int getIcosahedron() {
return icosahedron.get();
}
public SimpleIntegerProperty icosahedronProperty() {
return icosahedron;
}
public int getDodecahedron() {
return dodecahedron.get();
}
public SimpleIntegerProperty dodecahedronProperty() {
return dodecahedron;
}
public void reset(){
cubeRoll.set(0);
icosahedron.set(0);
dodecahedron.set(0);
}
}
Like so:
rollNumberColumn.setCellValueFactory(new PropertyValueFactory<>("rollNumber"));
This all works, although I would prefer a non-factory approach. However I can't figure out how to do the same kind of linking with a BarChart.
My BarChart has a CategoryAxis as the X axis and a NumberAxis as the Y axis. I can successfully add data with XYGraph.Series and XYGraph.Data methods but these won't update automagically. How would I do this?
edit:
TableColumn<DiceRoll, Number> rollNumberColumn = new TableColumn<>("Roll Number");
rollNumberColumn.setCellValueFactory(new PropertyValueFactory<>("rollNumber"));
tableView.setItems(FXCollections.observableArrayList(model.getDiceRolls())); //model.getDiceRolls() returns an ArrayList<DiceRoll>
tableView.getColumns().setAll(rollNumberColumn, cubeRollNumberColumn, dodecahedronRollNumberColumn, icosahedronRollNumberColumn);
A DiceRoll is basically initialized as a number that you can roll. I've added this in my table x20 for all 20 possible rolls and just add to it if it gets rolled. In graph form this would mean 3 graphs with on the X axis the roll number and the Y axis the amount of times that it rolled.
The factory comment is kind of irrelevant to my question but I don't really like using the factory pattern which is used here.
Edit2:
ObservableList<DiceRoll> testing = FXCollections.observableArrayList(model.getDiceRolls());
testing.addListener((ListChangeListener)c -> System.out.println("I'm working!"));
I tried doing this as suggested by Chris but the program doesn't print anything. It could be that observableArrayList() returns a new list instead of wrapping existing references but that would mean my table wouldn't work either. What could be wrong?
Edit3:
What was wrong is that observables "change" when the value of the reference changes. And the values of an observablelist are other references which in my case get added once and get never touched again. This means that it NEVER actually changes in the lifetime of the program after startup. I figured out that I can attach listeners to the IntegerProperties in DiceRoll to do whatever the hell I want when one of them changes which is awesome and gives me much needed control.
edit4
this.model.getDiceRolls().parallelStream().forEach(diceRoll -> {
diceRoll.cubeRollProperty().addListener((observable, oldValue, newValue) ->
cubeSeries.getData().get(diceRoll.getRollNumber() - 1).setYValue(newValue)
);
diceRoll.dodecahedronRollProperty().addListener((observable, oldValue, newValue) ->
dodecahedronSeries.getData().get(diceRoll.getRollNumber() - 1).setYValue(newValue)
);
diceRoll.icosahedronRollProperty().addListener((observable, oldValue, newValue) ->
icosahedronSeries.getData().get(diceRoll.getRollNumber() - 1).setYValue(newValue)
);
});
This is what I used at the end to monitor changes. All it requires is that your class uses a so called *Property variable which supports listeners out of the box. The moment it changes you can run a piece of code to update your chart for example.