【问题标题】:JavaFX Progress Indicator not updating properlyJavaFX 进度指示器未正确更新
【发布时间】:2018-07-26 04:49:52
【问题描述】:

我正在创建一个 JavaFX 桌面应用程序,在该应用程序上模拟一些工作负载。我希望应用程序有一个动态更新的进度指示器(随着时间的推移),以显示加载过程的进展情况。这是我的应用程序类:

public class App extends Application {

@Override
public void init() throws InterruptedException{
    //Simulation of time consuming code.
    for(int i = 0; i<=10; i++) {
        notifyPreloader(new Preloader.ProgressNotification(i/10));
        System.out.println("Progress is being set by the app to: " + (i/10));
        Thread.sleep(500);
    }
}

@Override
public void start(Stage primaryStage) {
    Parent root;
    try {
        root = FXMLLoader.load(getClass().getResource("/gui/fxml/App.fxml"));
        Scene scene = new Scene(root, 600, 400);

        scene.getStylesheets().add("/gui/style/app.css");

        primaryStage.setScene(scene);
        primaryStage.setTitle("Hello World!");
        primaryStage.show();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
}

这是我的预加载器类:

public class AppPreloader extends Preloader {
private Stage preloaderStage;
private Parent root;
private Scene scene;
private ProgressIndicator progress_indicator;

@Override
public void start(Stage primaryStage) throws Exception {
    this.preloaderStage = primaryStage;
    this.preloaderStage.setScene(this.scene);
    this.preloaderStage.show();
    this.progress_indicator = (ProgressIndicator) scene.lookup("#progressIndicator");
}


@Override
public void init() throws Exception {
    root = FXMLLoader.load(getClass().getResource("/gui/fxml/AppPreloader.fxml"));
    Platform.runLater(new Runnable() { 
        @Override
        public void run() {
            scene = new Scene(root, 600, 400);
            scene.getStylesheets().add("/gui/style/appPreloader.css");
        }
    });
}

@Override
public void handleProgressNotification(ProgressNotification pn) {
    if(pn instanceof ProgressNotification){
        progress_indicator.setProgress(pn.getProgress());
        System.out.println("Progress is being set by the handle method to: " + pn.getProgress());
    }
}

@Override
public void handleStateChangeNotification(StateChangeNotification evt) {
    if (evt.getType() == StateChangeNotification.Type.BEFORE_START) {
        preloaderStage.hide();
    }
}    
}

通过打印语句,我发现了两个问题:首先, 在 App 类的 init 方法的循环开始之前,handleProgressNotification 方法被调用了两次,一次设置为 0,另一次设置为 1。 谁在打电话?我该如何避免呢?

第二个问题是app类的init方法里面的print语句总是打印0.0。 这怎么可能?是并发的问题吗?

此外,我需要说明的是,我已经检查了这两个问题(progressbar in preloader does not updatejavafx preloader not updating progress),但没有找到解决问题的方法。

非常感谢您的宝贵时间。

【问题讨论】:

    标签: java javafx


    【解决方案1】:

    首先,您没有看到您期望的进度值,因为您使用的是整数运算:i10 都是整数,因此对于 0 &lt;= i &lt; 101i/100 i=10.

    其次,handleProgressNotificationhandleStateChangeNotification 方法是与加载资源相关的应用程序生命周期的一部分。这些确实是 JavaFX 仍然支持 Web 部署的时代遗留下来的,现在可能用途有限。

    要接收来自应用程序的通知,您需要改写handleApplicationNotification(...) 方法。这是两个类的更正版本(也被修改为独立的,因此可以复制和运行它们:请在您的问题中提供这些类型的示例):

    package application;
    
    import javafx.application.Application;
    import javafx.application.Preloader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.scene.control.Label;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class App extends Application {
    
        @Override
        public void init() throws InterruptedException{
            //Simulation of time consuming code.
            for(int i = 0; i<=10; i++) {
                notifyPreloader(new Preloader.ProgressNotification(i/10.0));
                System.out.println("Progress is being set by the app to: " + (i/10.0));
                Thread.sleep(500);
            }
            notifyPreloader(new Preloader.StateChangeNotification(Preloader.StateChangeNotification.Type.BEFORE_START));
        }
    
        @Override
        public void start(Stage primaryStage) {
            Parent root;
                root = new StackPane(new Label("Hello World"));
                Scene scene = new Scene(root, 600, 400);
    
                primaryStage.setScene(scene);
                primaryStage.setTitle("Hello World!");
                primaryStage.show();
    
        }
    
    }
    
    package application;
    
    import javafx.application.Preloader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.scene.control.ProgressIndicator;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class AppPreloader extends Preloader {
        private Stage preloaderStage;
        private Parent root;
        private Scene scene;
        private ProgressIndicator progress_indicator;
    
        @Override
        public void start(Stage primaryStage) throws Exception {
            progress_indicator = new ProgressIndicator();
            root = new StackPane(progress_indicator);
            scene = new Scene(root, 600, 400);
            this.preloaderStage = primaryStage;
            this.preloaderStage.setScene(this.scene);
            this.preloaderStage.show();
        }
    
    
        @Override
        public void handleApplicationNotification(PreloaderNotification pn) {
            if (pn instanceof ProgressNotification) {
               //expect application to send us progress notifications 
               //with progress ranging from 0 to 1.0
               double v = ((ProgressNotification) pn).getProgress();
               progress_indicator.setProgress(v);            
            } else if (pn instanceof StateChangeNotification) {
                StateChangeNotification scn = (StateChangeNotification) pn ;
                if (scn.getType() == StateChangeNotification.Type.BEFORE_START) {
                    preloaderStage.hide();
                }
            }
        } 
    }
    

    【讨论】:

    • 谢谢,答案的第二部分是评论家,在你回答之前我找不到有关它的信息。
    • @Drubio 我刚刚使用了this(这是旧的;我认为现在预加载器的用例不多)和Javadocs
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-26
    • 1970-01-01
    • 1970-01-01
    • 2016-06-08
    • 1970-01-01
    • 2018-12-17
    相关资源
    最近更新 更多