JavaFX:如何在向TableView添加列时显示动画ProgressIndicator?

JavaFX:如何在向TableView添加列时显示动画ProgressIndicator?,javafx,javafx-2,tableview,Javafx,Javafx 2,Tableview,在我的应用程序中,将TableColumn对象添加到我的TableView是一个漫长的操作,它会导致所有内容冻结3-4秒。我希望在发生这种情况时保持UI的响应性,但这正是必须在JavaFX应用程序线程上完成的事情。有什么办法吗 package tableviewpausetest; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import javafx.applicati

在我的应用程序中,将
TableColumn
对象添加到我的
TableView
是一个漫长的操作,它会导致所有内容冻结3-4秒。我希望在发生这种情况时保持UI的响应性,但这正是必须在JavaFX应用程序线程上完成的事情。有什么办法吗

package tableviewpausetest;

import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.WorkerStateEvent;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;


/**
 *
 * @author drmc
 */
public class TableViewPauseTest extends Application {

    public static final int ROW_COUNT = 100;
    public static final int COLUMN_COUNT = 80;
    public static final ExecutorService executor = Executors.newSingleThreadExecutor();

    private TableView<String> tableView = new TableView<>();
    private Button button = new Button("Toggle Columns Visibility");
    private ProgressIndicator progressIndicator = new ProgressIndicator();
    private HBox buttonBox = new HBox(8);
    private BorderPane borderPane = new BorderPane();
    private Task task = null;

    public void start(Stage primaryStage) {

        this.tableView.setColumnResizePolicy(
            TableView.CONSTRAINED_RESIZE_POLICY);
        for (int i = 0; i < ROW_COUNT; ++i) {
            this.tableView.getItems().add(":)");
        }

        this.button.setOnAction(new ToggleHandler(this));
        this.buttonBox.getChildren().setAll(this.button);

        this.borderPane.setCenter(this.tableView);
        this.borderPane.setBottom(this.buttonBox);

        Scene scene = new Scene(this.borderPane, 1024, 768);
        primaryStage.setTitle("tableviewpausetest");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private class ToggleHandler implements EventHandler<ActionEvent> {

        private TableViewPauseTest app;

        public ToggleHandler(TableViewPauseTest app) {
            this.app = app;
        }

        @Override
        public void handle(ActionEvent event) {
            // Show the progress indicator.
            this.app.buttonBox.getChildren().add(this.app.progressIndicator);
            this.app.progressIndicator.setPrefHeight(this.app.button.getHeight());

            // Ensure the columns exist.
            if (this.app.tableView.getColumns().isEmpty()) {
                for (int i = 0; i < COLUMN_COUNT; ++i) {
                    TableColumn<String, String> tableColumn = new TableColumn<>(
                        String.format("%s", i));
                    tableColumn.setVisible(false);
                    this.app.tableView.getColumns().add(tableColumn);
                }
            }

            // Create and submit a concurrent task to toggle column visibility.
            this.app.task = new ToggleTask(this.app);
            this.app.task.setOnSucceeded(new ToggleSucceededHandler(this.app));
            executor.submit(this.app.task);
        }

    }

    private class ToggleSucceededHandler implements EventHandler<WorkerStateEvent> {

        private TableViewPauseTest app;

        public ToggleSucceededHandler(TableViewPauseTest app) {
            this.app = app;
        }

        @Override
        public void handle(WorkerStateEvent event) {
            // Hide the progress indicator.
            this.app.buttonBox.getChildren().remove(this.app.progressIndicator);
        }

    }

    private class ToggleTask extends Task<String> {

        private TableViewPauseTest app;

        public ToggleTask(TableViewPauseTest app) {
            this.app = app;
        }

        @Override
        public String call() {
            boolean newState = false;
            String action = "hide";
            if (this.app.tableView.getVisibleLeafColumns().isEmpty()) {
                newState = true;
                action = "show";
            }

            // This action must be performed on the JavaFX Application Thread,
            // and it causes an extremely uncomfortable pause in my application.
            Platform.runLater(new ToggleRunnable(this.app.tableView, newState));

            return action;
        }

    }

    private class ToggleRunnable implements Runnable {

        private TableView<?> tableView;
        private boolean newState;

        public ToggleRunnable(TableView<?> tableView, boolean newState) {
            this.tableView = tableView;
            this.newState = newState;
        }

        @Override
        public void run() {
            for (TableColumn<?, ?> tableColumn : this.tableView.getColumns()) {
                tableColumn.setVisible(this.newState);
            }
        }

    }

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

}
package tableviewpausetest;
导入java.util.concurrent.Executors;
导入java.util.concurrent.ExecutorService;
导入javafx.application.application;
导入javafx.application.Platform;
导入javafx.concurrent.WorkerStateEvent;
导入javafx.concurrent.Task;
导入javafx.event.ActionEvent;
导入javafx.event.EventHandler;
导入javafx.scene.scene;
导入javafx.scene.control.Button;
导入javafx.scene.control.ProgressIndicator;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TableView;
导入javafx.scene.layout.BorderPane;
导入javafx.scene.layout.HBox;
导入javafx.stage.stage;
/**
*
*@author-drmc
*/
公共类TableViewPauseTest扩展了应用程序{
公共静态最终整数行计数=100;
公共静态最终整数列计数=80;
public static final executor service executor=Executors.newSingleThreadExecutor();
private TableView TableView=new TableView();
私有按钮按钮=新按钮(“切换列可见性”);
私有ProgressIndicator ProgressIndicator=新ProgressIndicator();
专用HBox按钮盒=新HBox(8);
private BorderPane BorderPane=新建BorderPane();
私有任务任务=null;
公共无效开始(阶段primaryStage){
this.tableView.setColumnResizePolicy(
TableView.constrated_RESIZE_策略);
对于(int i=0;i
我认为这个示例代码对您很有用

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package progressbartablecelltest;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;

/**
 *
 * @author reegan
 */
public class ProgressBarTableCellTest extends Application {

    public void start(Stage primaryStage) {
    TableView<TestTask> table = new TableView<>();
    Random rng = new Random();
    for (int i = 0; i < 20; i++) {
      table.getItems().add(
              new TestTask(rng.nextInt(3000) + 2000, rng.nextInt(30) + 20));
    }

    TableColumn<TestTask, String> statusCol = new TableColumn("Status");
    statusCol.setCellValueFactory(new PropertyValueFactory<TestTask, String>(
            "message"));
    statusCol.setPrefWidth(75);

    TableColumn<TestTask, Double> progressCol = new TableColumn("Progress");
    progressCol.setCellValueFactory(new PropertyValueFactory<TestTask, Double>(
            "progress"));
    progressCol
            .setCellFactory(ProgressIndicatorTableCell.<TestTask>forTableColumn());

    table.getColumns().addAll(statusCol, progressCol);

    BorderPane root = new BorderPane();
    root.setCenter(table);
    primaryStage.setScene(new Scene(root));
    primaryStage.show();

    ExecutorService executor = Executors.newFixedThreadPool(table.getItems().size(), new ThreadFactory() {
      @Override
      public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
      }
    });


    for (TestTask task : table.getItems()) {
      executor.execute(task);
    }
  }

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

  static class TestTask extends Task<Void> {
    private final int waitTime; // milliseconds
    private final int pauseTime; // milliseconds
    public static final int NUM_ITERATIONS = 100;

    TestTask(int waitTime, int pauseTime) {
      this.waitTime = waitTime;
      this.pauseTime = pauseTime;
    }

    @Override
    protected Void call() throws Exception {
      this.updateProgress(ProgressIndicator.INDETERMINATE_PROGRESS, 1);
      this.updateMessage("Waiting...");
      Thread.sleep(waitTime);
      this.updateMessage("Running...");
      for (int i = 0; i < NUM_ITERATIONS; i++) {
        updateProgress((1.0 * i) / NUM_ITERATIONS, 1);
        Thread.sleep(pauseTime);
      }
      this.updateMessage("Done");
      this.updateProgress(1, 1);
      return null;
    }
  }
}

class ProgressIndicatorTableCell<S> extends TableCell<S, Double> {
  public static <S> Callback<TableColumn<S, Double>, TableCell<S, Double>> forTableColumn() {
    return new Callback<TableColumn<S, Double>, TableCell<S, Double>>() {
      @Override
      public TableCell<S, Double> call(TableColumn<S, Double> param) {
        return new ProgressIndicatorTableCell<>();
      }
    };
  }

  private final ProgressIndicator progressIndicator;
  private ObservableValue observable;

  public ProgressIndicatorTableCell() {
    this.getStyleClass().add("progress-indicator-table-cell");

    this.progressIndicator = new ProgressIndicator();
    setGraphic(progressIndicator);
  }

  @Override public void updateItem(Double item, boolean empty) {
    super.updateItem(item, empty);

    if (empty) {
      setGraphic(null);
    } else {
      progressIndicator.progressProperty().unbind();

      observable = getTableColumn().getCellObservableValue(getIndex());
      if (observable != null) {
        progressIndicator.progressProperty().bind(observable);
      } else {
        progressIndicator.setProgress(item);
      }

      setGraphic(progressIndicator);
    }
  }
}
/*
*要更改此模板,请选择工具|模板
*然后在编辑器中打开模板。
*/
包装试验;
导入java.util.Random;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.ThreadFactory;
导入javafx.application.application;
导入javafx.beans.value.observeValue;
导入javafx.concurrent.Task;
导入javafx.scene.scene;
导入javafx.scene.control.ProgressIndicator;
导入javafx.scene.control.TableCell;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TableView;
导入javafx.scene.control.cell.PropertyValueFactory;
导入javafx.scene.layout.BorderPane;
导入javafx.stage.stage;
导入javafx.util.Callback;
/**
*
*@auth