【问题标题】:JavaFX: Update ProgressBar (@FXML) from ThreadJavaFX:从 Thread 更新 ProgressBar (@FXML)
【发布时间】:2016-10-17 14:37:14
【问题描述】:

我想更新由另一个类在 FXML 文件中定义的 JavaFX ProgressBar,并在控制器线程中初始化。目前它只是没有更新。

test.fxml

<ProgressBar fx:id="progressBar" prefWidth="5000.0" progress="0.0">
    <VBox.margin>
        <Insets top="3.0" />
    </VBox.margin>
</ProgressBar>

Controller.java

@FXML
public static ProgressBar progressBar = new ProgressBar(0);

MyMain main;

@FXML
private void handleStartWork() throws Exception {
    new Thread() {
        @Override
        public void run() {
            try {
                main = new MyMain();
                main.doIt();
            } catch (final Exception v) {
                // ...
            }
        }
    }.start();
}

MyMain.java

public void doIt(){
    while(...){
        Platform.runLater(() -> PoCOverviewController.progressBar.setProgress((count / sum) * 100));
    }
}

考虑到以下帖子,我已经尝试了不同的版本:

我不知道将 ProgressBar 设为静态是否是正确的方法。我只是不想通过工作流传递对象。

更新(Xavier Lambros 回答): 现在我用单例尝试了它,但它仍然无法正常工作:

Controller.java

@FXML
public ProgressBar progressBar = new ProgressBar(0);    

private static Controller INSTANCE = new Controller();

public static Controller getInstance() {
    return INSTANCE;
}

public ProgressBar getProgressBar() {
    return progressBar;
}

MyMain.java

public void doIt(){
    while(...){
        Platform.runLater(() -> Controller.getInstance().getProgressBar()
                .setProgress((count / sum) * 100));
    }
}

【问题讨论】:

标签: java multithreading javafx fxml


【解决方案1】:

正如javafx 8 compatibility issues - FXML static fields 中所述,您不能创建@FXML 注释字段static(这样做没有意义:这些字段本质上是特定控制器的属性instance )。

要允许doIt() 方法访问进度条,您可以直接将其作为参数传递:

@FXML
public ProgressBar progressBar ;

MyMain main;

@FXML
private void handleStartWork() throws Exception {
    new Thread() {
        @Override
        public void run() {
            try {
                main = new MyMain();
                main.doIt(progressBar);
            } catch (final Exception v) {
                // ...
            }
        }
    }.start();
}

然后

public void doIt(ProgressBar progressBar){
    while(...){
        Platform.runLater(() -> progressBar.setProgress((count / sum) * 100));
    }
}

在某些情况下,Main 类依赖于 JavaFX API 可能没有意义。在这种情况下,您可以只传递一个更新进度条的函数:

@FXML
public ProgressBar progressBar ;

MyMain main;

@FXML
private void handleStartWork() throws Exception {
    new Thread() {
        @Override
        public void run() {
            try {
                main = new MyMain();
                main.doIt(progressBar::setProgress);
            } catch (final Exception v) {
                // ...
            }
        }
    }.start();
}

public void doIt(DoubleConsumer progressUpdate){
    while(...){
        Platform.runLater(() -> progressUpdate.accept((count / sum) * 100));
    }
}

请注意,您尚未显示 while 循环中发生的情况:如果您向 FX 应用程序线程提交了太多可运行文件,您可能会“淹没”它并阻止它在合理的时间内更新。您可能会考虑使用Task,它具有用于更新进度条的progress 属性可以绑定到的进度字段的特定API。如果它仍然不起作用,您应该编辑您的问题以包含MCVE

【讨论】:

    【解决方案2】:

    我认为您不能将 ProgressBar 设为静态。

    我的方法是在控制器内的 ProgressBar 上有一个访问器,并像这样初始化控制器:

    FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/YourController.fxml");
    loader.load();
    

    之后,您可以使用以下命令访问 ProgressBar:

    loader.<YourController>getController().getProgressBar();
    

    如果你需要,在不同的类中访问它,还有很多其他的可能性,一种是做一个单例:

    public class Singleton
    {   
        private ProgressBar progressBar; 
    
        private Singleton()
        {}
    
        private static Singleton INSTANCE = new Singleton();
    
        public static Singleton getInstance()
        {   
            return INSTANCE;
        }
    
        public ProgressBar getProgressBar() {
            return progressBar;
        }
    
        public ProgressBar setProgressBar() {
            return progressBar;
        }
    }
    

    叫它:

    Singleton.getInstance().getProgressBar();
    

    【讨论】:

    • 那么有没有办法调用“loader.getController().getProgressBar();”在我的 MyMain.java 类中,因为没有 FXMLLoader 对象?
    • 把你的 MyMain.java
    • 作为stackoverflow的新手,我不能直接评论你的问题。但我认为你不能直接让你的控制器成为单例。单例应该是另一个类。 FXML 控制器是特定的,必须遵守一些规则。否则,我不明白为什么您的 MyMain 中没有 FXMLLoader,因为在 javaFX 项目中 MyMain 应该包含场景初始化...无论如何,Singleton 的想法是存储您在控制器的 init 中设置的 progressBar 并制作它可以在您的项目中的任何地方访问,访问它会抛出作为设计模式的 Singleton。
    • 我不想说明显的,但是你为什么不把进度条传递给doIt()方法:main.doIt(progressBar)public void doIt(ProgressBar progressBar) { ... () -&gt; progressBar.setProgress(...) }
    猜你喜欢
    • 2016-05-10
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    • 2012-04-23
    • 1970-01-01
    • 2022-01-09
    • 1970-01-01
    相关资源
    最近更新 更多