JavaFX:如何在 JavaFX 中正确使用 ProgressIndicator

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22098288/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 13:35:38  来源:igfitidea点击:

JavaFX: How can I use correctly a ProgressIndicator in JavaFX

javathread-safetytaskjavafx-8

提问by Bran Stark

I′m newbe in JavaFX. I have a problem with my JavaFX application, I need to start my ProgressIndicator (type INDETERMINATE) before a database query. This is part of my code:

我是 JavaFX 的新手。我的 JavaFX 应用程序有问题,我需要在数据库查询之前启动我的 ProgressIndicator(类型 INDETERMINATE)。这是我的代码的一部分:

spinner.setVisible(true);
passCripto = cripto.criptoPass(pass);
MyDao dao = new MyDaoImpl();
boolean isLoginOk = dao.isUserOk(user, passCripto);
boolean isStatusOk = dao.idStatusUser(user);

When finished, I need to set spinner to FALSE but the spinner only is showed when database query is finished. How can I solve this ?

完成后,我需要将微调器设置为 FALSE,但微调器仅在数据库查询完成时显示。我该如何解决这个问题?

Thanks.

谢谢。

I do this, but not resolved:

我这样做,但没有解决:

Task<Boolean> taskValidaLogin = new Task<Boolean>() {
    @Override
    protected Boolean call() throws Exception {
        boolean validaLogin = ACDCDao.validaUsuario(usuario, senhaCripto);

        return validaLogin;
    }
};

Task<Boolean> taskValidaStatus = new Task<Boolean>() {
    @Override
    protected Boolean call() throws Exception {
        boolean validaStatus = ACDCDao.validaStatusUsuario(usuario);

        return validaStatus;
    }
};

new Thread(taskValidaLogin).start();
new Thread(taskValidaStatus).start();
if (taskValidaLogin.getValue()) {
    if (taskValidaStatus.getValue()) {
        //do something
    }

采纳答案by agonist_

You have to do your database stuff into an other thread, cause if the operation take time it will freez the JavaFX thread (The GUI)

您必须将数据库内容放入另一个线程中,因为如果操作需要时间,它将冻结 JavaFX 线程(GUI)

In JavaFx you can use Service and Task to do background stuff. You should read

在 JavaFx 中,您可以使用 Service 和 Task 来做后台工作。你应该阅读

By executing your database stuff into a service, you will be able to monitor it easely cause Service provide the necessary to do that, and have method like onSuccedeed, onFailed...

通过将您的数据库内容执行到服务中,您将能够轻松监控它,因为服务提供了这样做的必要条件,并拥有诸如 onSucceed、onFailed 之类的方法...

Really have a look to that, is an essential part if you want to do JavaFx correctly.

如果你想正确地做 JavaFx,真的看看它是必不可少的部分。

Main.java

主程序

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 300, 275));
        primaryStage.show();
    }

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

ServiceExample.java

服务示例.java

import javafx.concurrent.Service;
import javafx.concurrent.Task;

public class ServiceExample extends Service<String> {
    @Override
    protected Task<String> createTask() {
        return new Task<String>() {
            @Override
            protected String call() throws Exception {
                //DO YOU HARD STUFF HERE
                String res = "toto";
                Thread.sleep(5000);
                return res;
            }
        };
    }
}

Controller.java

控制器.java

import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.ProgressIndicator;

public class Controller {

    @FXML
    private ProgressIndicator progressIndicator;

    public void initialize() {
        final ServiceExample serviceExample = new ServiceExample();

        //Here you tell your progress indicator is visible only when the service is runing
        progressIndicator.visibleProperty().bind(serviceExample.runningProperty());
        serviceExample.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent workerStateEvent) {
                String result = serviceExample.getValue();   //here you get the return value of your service
            }
        });

        serviceExample.setOnFailed(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent workerStateEvent) {
                //DO stuff on failed
            }
        });
        serviceExample.restart(); //here you start your service
    }
}

sample.fxml

示例文件

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.ProgressIndicator?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="200.0" prefWidth="200.0" xmlns:fx="http://javafx.com/fxml/1"
            xmlns="http://javafx.com/javafx/2.2" fx:controller="Controller">
    <ProgressIndicator fx:id="progressIndicator" layoutX="78.0" layoutY="55.0"/>
</AnchorPane>

I do that example quickly it's basic but I think it's what you want. (I don't add my progressIndicator to a node it's just for the example)

我很快就做了那个例子,它是基本的,但我认为这是你想要的。(我没有将我的 progressIndicator 添加到节点,它只是作为示例)

回答by brian

After spinner.setVisible(true);, start the spinner spinning by setting it to an indeterminate value (-1). spinner.setProgress(-1d);

之后spinner.setVisible(true);,通过将其设置为不确定值 (-1) 来启动微调器旋转。 spinner.setProgress(-1d);

Then I guess when the task is done you want it stopped. There are two events to use, succeeded and failed. That means the task failed, not the login. Here's an example for succeeded.

然后我猜当任务完成时你希望它停止。有两个事件可以使用,成功和失败。这意味着任务失败,而不是登录。这是一个成功的例子。

taskValidaStatus.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
    @Override
    public void handle(WorkerStateEvent event) {
        spinner.setProgress(0d);
        //and now you can check valida here after the task is finished
        if (taskValidaLogin.getValue()) {
            if (taskValidaStatus.getValue()) {
            //do something
            }
    }
});
//now start the tasks after they're all set up.
new Thread(taskValidaLogin).start();
new Thread(taskValidaStatus).start();

I didn't test this code because you didn't provide a working example.

我没有测试这段代码,因为你没有提供一个工作示例。

There's another issue in that validaLogin may not be finished yet. I only checked if one thread was finished. What you should do is start one thread in the other threads onSucceeded event. I'm not sure of the order you need, but it might look like this in the taskLogin onSucceeded.

另一个问题是validaLogin 可能还没有完成。我只检查了一个线程是否完成。您应该做的是在其他线程的 onSucceeded 事件中启动一个线程。我不确定您需要的顺序,但它在 taskLogin onSucceeded 中可能看起来像这样。

        if (taskValidaLogin.getValue()) {
            new Thread(taskValidaStatus).start();
        }