GenerationLost
GenerationLost

Reputation: 461

JavaFX - TableView doesn't update items

I'm programming a little vocabulary trainer for my wife using JavaFX. Each word stores it's own statistic values like how often she encountered the word and how often she provided a correct answer. I've set up a TableView for that, but after a training session the stats won't update. The word objects themselves have the right values but they're just not shown in the TableView. Usually the TableView always displays the current values of on object due to the nature of ObservableList, right? Not in this case though.

This is my word-class:

public class Vocable
{
    private String german;
    private String english;
    private int givenAnswers, correctAnswers, skippedAnswers;

    public Vocable(String ger, String eng)
    {
        german = ger;
        english = eng;
        givenAnswers = 0;
        correctAnswers = 0;
        skippedAnswers = 0;
    }

    public String getGerman()
    {
        return german;
    }

    public String getEnglish()
    {
        return english;
    }

    public int getGivenAnswers() 
    {
        return givenAnswers;
    }

    public void increaseGivenAnswers() 
    {
        this.givenAnswers++;;
    }

    public int getCorrectAnswers() 
    {
        return correctAnswers;
    }

    public void increaseCorrectAnswers() 
    {
        this.correctAnswers++;
    }

    public int getSkippedAnswers() 
    { 
        return skippedAnswers;
    }

    public void increaseSkippedAnswers() 
    {
        this.skippedAnswers++;
    }
}

And this is my View-class:

public class OverviewView extends VBox
{
    private OverviewPresenter presenter;

    private TableView<Vocable> overviewTable;
    private TableColumn<Vocable, String> german;
    private TableColumn<Vocable, String> english;
    private TableColumn<Vocable, Number> given;
    private TableColumn<Vocable, Number> correct;
    private TableColumn<Vocable, Number> skipped;

    private Button delete, back, showStats, add;

    public OverviewView()
    {
        initView();
    }

    private void initView()
    {
        BorderPane pane = new BorderPane();

        overviewTable = new TableView<>();
        german = new TableColumn<>("German");
        english = new TableColumn<>("English");
        given = new TableColumn<>("given");
        correct = new TableColumn<>("correct");
        skipped = new TableColumn<>("skipped");

        german.setResizable(true);
        english.setResizable(true);
        given.setResizable(true);
        correct.setResizable(true);
        skipped.setResizable(true);

        delete = new Button("Delete");
        delete.setOnAction(e ->     presenter.deleteVocable(overviewTable.getSelectionModel().getSelectedItem()));

        back = new Button("Back");
        back.setOnAction(e -> presenter.showMainView());

        showStats = new Button("Statistics");
        showStats.setOnAction(e -> presenter.showStatistics());

        add = new Button("Add Vocbale");
        add.setOnAction(e -> presenter.showAddDialog());

        overviewTable.getColumns().add(german);
        overviewTable.getColumns().add(english);
        overviewTable.getColumns().add(given);
        overviewTable.getColumns().add(correct);
        overviewTable.getColumns().add(skipped);

        german.prefWidthProperty().bind(overviewTable.widthProperty().multiply(0.35));
        english.prefWidthProperty().bind(overviewTable.widthProperty().multiply(0.35));
        given.prefWidthProperty().bind(overviewTable.widthProperty().multiply(0.10));
        correct.prefWidthProperty().bind(overviewTable.widthProperty().multiply(0.10));
        skipped.prefWidthProperty().bind(overviewTable.widthProperty().multiply(0.10));

        pane.setCenter(overviewTable);

        HBox box = new HBox(50);
        box.getChildren().addAll(back, delete, add, showStats);

        pane.setBottom(box);
        BorderPane.setMargin(box, Constants.DEFAULT_BP_MARGINS);

        pane.setPadding(Constants.DEFAULT_PADDING);

        getChildren().add(pane);
    }

    public void setTableContent(ObservableList<Vocable> list)
    {
        overviewTable.setItems(list);

        german.setCellValueFactory(item -> new     SimpleStringProperty(item.getValue().getGerman()));
    english.setCellValueFactory(item -> new     SimpleStringProperty(item.getValue().getEnglish()));

        given.setCellValueFactory(item -> new     SimpleIntegerProperty(item.getValue().getGivenAnswers()));
        correct.setCellValueFactory(item -> new     SimpleIntegerProperty(item.getValue().getCorrectAnswers()));
    skipped.setCellValueFactory(item -> new     SimpleIntegerProperty(item.getValue().getSkippedAnswers()));
    }
}

Any idea on how to fix this?

Upvotes: 1

Views: 1371

Answers (1)

James_D
James_D

Reputation: 209225

Implement the mutable properties in Vocable using the JavaFX properties pattern. This allows the table cells to observe the appropriate properties and respond if they change. For values that don't change, such as german and english, you can still use regular (and final) fields. For values that change but you want to control how they change (e.g. you want an increaseGivenAnswers() method, but no general setGivenAnswers(int) method), you can use a ReadOnlyXXXWrapper and expose a ReadOnlyXXXProperty. So, e.g.:

public class Vocable
{

    private final String german;
    private final String english;
    private final ReadOnlyIntegerWrapper givenAnswers = new ReadOnlyIntegerWrapper();
    private final ReadOnlyIntegerWrapper correctAnswers = new ReadOnlyIntegerWrapper();
    private final ReadOnlyIntegerWrapper skippedAnswers = new ReadOnlyIntegerWrapper();


    public Vocable(String ger, String eng)
    {
        german = ger;
        english = eng;
        givenAnswers.set(0);
        correctAnswers.set(0);
        skippedAnswers.set(0);
    }

    public String getGerman()
    {
        return german;
    }

    public String getEnglish()
    {
        return english;
    }

    public ReadOnlyIntegerProperty givenAnswersProperty() {
        return givenAnswers.getReadOnlyProperty() ;
    }

    public final int getGivenAnswers() 
    {
        return givenAnswersProperty().get();
    }

    public void increaseGivenAnswers() 
    {
        givenAnswers.set(getGivenAnswers()+1);
    }


    public ReadOnlyIntegerProperty correctAnswersProperty() {
        return correctAnswers.getReadOnlyProperty();
    }

    public final int getCorrectAnswers() 
    {
        return correctAnswersProperty().get();
    }

    public void increaseCorrectAnswers() 
    {
        this.correctAnswers.set(getCorrectAnswers()+1);
    }

    public ReadOnlyIntegerProperty skippedAnswersProperty() {
        return skippedAnswers.getReadOnlyProperty();
    }

    public final int getSkippedAnswers() 
    {
        return skippedAnswersProperty().get();
    }

    public void increaseSkippedAnswers() 
    {
        this.skippedAnswers.set(getSkippedAnswers()+1);
    }

}

For the cells to observe these properties, map the cell value factories to the properties that are defined:

german.setCellValueFactory(item -> new SimpleStringProperty(item.getValue().getGerman()));
english.setCellValueFactory(item -> new SimpleStringProperty(item.getValue().getEnglish()));

given.setCellValueFactory(item -> item.getValue().givenAnswersProperty());
correct.setCellValueFactory(item -> item.getValue().correctAnswersProperty());
skipped.setCellValueFactory(item -> item.getValue().skippedAnswersProperty());

Upvotes: 2

Related Questions