如何在 JavaFX 中使用不确定的 ProgressIndicator 来制作可暂停任务?

问题描述 投票:0回答:1

我有一个并发任务,可以处于两种状态 - 活动(工作)和暂停(通过

Thread.sleep(xxxx)
)。当任务不确定地工作时,
ProgressIndicator
应该可见,以向用户显示正在运行的
Task
。当任务暂停时,不应显示
ProgressIndicator

这是我的解决方案:

public class JavaFxTest7 extends Application {

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

    @Override
    public void start(Stage stage) {
        var indicator = new ProgressIndicator();
        indicator.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS);
        var vBox = new VBox(indicator);
        var scene = new Scene(vBox, 300, 200);
        stage.setScene(scene);
        stage.show();

        Task<Boolean> task = new Task<Boolean>() {
            @Override
            protected Boolean call() throws Exception {
                while(!isCancelled()) {
                    this.updateValue(true);
                    for (long l = 1; l < 150000L; l++) {
                        System.out.println("Working");
                    }
                    System.out.println("Pause");
                    this.updateValue(false);
                    Thread.sleep(2500);
                }
                return null;
            }
        };
        indicator.visibleProperty().bind(task.valueProperty());
        new Thread(task).start();
    }

}

这段代码按预期工作,并完成了我需要的一切。但是,我不喜欢这个解决方案,因为它不合逻辑。我使用任务值来控制指标的可见性,但效果不好。我想将侦听器添加到

Task
状态属性,但据我所知,我无法控制状态。

对于这样的问题有更好的解决方案吗?也许我应该使用

Service
而不是
Task

java javafx
1个回答
0
投票

不幸的是,您将无法通过

state
属性来执行此操作。
Task
API 不提供设置该属性的方法。尽管即使您可以设置它,但没有一个枚举常量似乎能够正确传达“暂停”的概念。

为了避免通过

value
属性实现此目的,您可以创建自己的
Task
子类,它公开一个新的“暂停”布尔属性。然后,您只需确保仅更新 JavaFX 应用程序线程 上的该属性。下面是一个示例,其中对属性的更新以与
Task
合并对
title
message
progress
value
的更新的方式合并。

import java.util.concurrent.atomic.AtomicReference;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.concurrent.Task;

public abstract class PauseableTask<T> extends Task<T> {

  private final ReadOnlyBooleanWrapper paused = new ReadOnlyBooleanWrapper(this, "paused");
  private void setPaused(boolean paused) { this.paused.set(paused); }
  public final boolean isPaused() { return paused.get(); }
  public final ReadOnlyBooleanProperty pausedProperty() {
    return paused.getReadOnlyProperty();
  }

  private final AtomicReference<Boolean> pausedConflater = new AtomicReference<>();

  protected final void updatePaused(boolean paused) {
    if (Platform.isFxApplicationThread()) {
      setPaused(paused);
    } else if (pausedConflater.getAndSet(paused) == null) {
      Platform.runLater(() -> setPaused(pausedConflater.getAndSet(null)));
    }
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.