JavaFX TableView is not updating

2020-07-24 06:08发布

问题:

I am trying to show the progress and the status of the each task in the JavaFX TableView. Each task represents by a row into a TableView.

Each task executes in a separate Thread. Task may be like - downloading files from server, copy files from one account to another account etc. Threads may take long time to finish there task. My app also control the number of threads to perform operation in queue. With default setting, It can run maximum 5 threads at a time.

My Issue is - My TableView does not show the updated status and progress. I have to click on column headers to refresh the TableView. How to make TableView update aromatically? In background, if I run a thread that triggers automatically after specific time interval for refreshing the TableView making my UI freeze.

The sample does not show what exactly I am doing in my app but I tried to demonstrate what issue I am facing. When you run the program you will see the TableView with two columns 1. Name and 2. Progress. On start-up Name will will be "Before" for each row whereas the you will see the progress bar running. I have added delay of 1 second in updating cell values and stop progress bar.

import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.ProgressBarTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.StackPaneBuilder;
import javafx.stage.Stage;

public class UpdateTableView extends Application {

    private TableView<Person> personTable = new TableView<>();
    private TableColumn colName = new TableColumn<>("Name");
    private TableColumn colProgressBar = new TableColumn("Progress Bar");

    @Override
    public void start(Stage primaryStage) {
        showDialog(primaryStage);

        colName.setCellValueFactory(new PropertyValueFactory("name"));
        colProgressBar.setCellValueFactory(new PropertyValueFactory("progressBar")); // "name" here is for just to render the column
        colProgressBar.setCellFactory(ProgressBarTableCell.forTableColumn());
        personTable.getColumns().addAll(colName, colProgressBar);

        for (int i = 0; i < 10; i++) {
            Person person = new Person();
            person.setProgressBar(-1.0);
            person.setName("Before" + i);
            personTable.getItems().add(person);
        }


        Thread threadAction1 = new Thread() {
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    Logger.getLogger(UpdateTableView.class.getName()).log(Level.SEVERE, null, ex);
                }
                ObservableList<Person> items = personTable.getItems();
                for (int i = 0; i < items.size(); i++) {
                    Person person = items.get(i);
                    person.setName("After" + i);
                    person.setProgressBar(0.0);
                }
            }
        };
        threadAction1.start();
    }

    public void showDialog(Stage primaryStage) {
        try {
            StackPane root = StackPaneBuilder.create().children(personTable).build();
            primaryStage.setScene(new Scene(root, 300, 250));
            primaryStage.show();
        } catch (Exception ex) {
            System.out.println("Exception caught while showing dialog" + ex.getMessage());
        }
    }

    public static class Person {

        private StringProperty name;

        public void setName(String name) {
            this.name = new SimpleStringProperty(name);
        }
        private DoubleProperty progressBar;

        private Person() {
        }

        public double getProgressBar() {
            return progressBar.get();
        }

        public void setProgressBar(double surname) {
            this.progressBar = new SimpleDoubleProperty(surname);
        }

        public Person(String name, double surname) {
            this.name = new SimpleStringProperty(name);
            this.progressBar = new SimpleDoubleProperty(surname);

        }

        public String getName() {
            return name.get();
        }

        public StringProperty nameProperty() {
            return name;
        }

        public DoubleProperty progressBarProperty() {
            return progressBar;
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

回答1:

You should have to update your Person class as given below :

public static class Person {

    private StringProperty name;
    private DoubleProperty progressBar;

    private Person() {
       name = new SimpleStringProperty();
       progressBar = new SimpleDoubleProperty();
    }

    public Person(String name, double surname) {
        this.name = new SimpleStringProperty(name);
        this.progressBar = new SimpleDoubleProperty(surname);
    }

    public void setName(String name) {
        this.name.set(name);
    }

    public double getProgressBar() {
        return progressBar.get();
    }

    public void setProgressBar(double surname) {
        this.progressBar.set(surname);
    }

    public String getName() {
        return name.get();
    }

    public StringProperty nameProperty() {
        return name;
    }

    public DoubleProperty progressBarProperty() {
        return progressBar;
    }
}

in setter methods you are creating new object of name & progressbar each-time, so that TableView is not getting update.