JavaFX:从Thread更新ProgressBar(@FXML)

时间:2016-06-16 07:53:00

标签: java multithreading javafx fxml

我想更新另一个类在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成为静态方法。我只是不想通过工作流传递Object。

更新(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));
    }
}

2 个答案:

答案 0 :(得分:3)

正如javafx 8 compatibility issues - FXML static fields中所述,您无法创建import React from 'react'; import InfiniteCalendar from 'react-infinite-calendar'; import 'react-infinite-calendar/styles.css'; // only needs to be imported once import {TODAY} from '../../server/constants/date'; export default class DateSelector extends React.Component { render() { return ( <div> <InfiniteCalendar width={400} height={600} selectedDate={TODAY} maxDate={TODAY} /> </div> ); } } - 带注释的字段@FXML(这样做没有任何意义:这些字段本身就是特定控制器的属性实例)。

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

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)); } } 类对JavaFX API具有依赖性可能没有意义。在这种情况下,您只需传递一个更新进度条的函数:

Main

@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)); } } 循环中发生了什么:如果您向FX应用程序主题提交了太多的可运行程序,您可能会&#34;泛滥&#34;它并防止它在合理的时间内更新。您可以考虑使用Task,它具有特定的API,用于更新进度条的while属性可以绑定的进度字段。如果它仍然不起作用,您应该编辑您的问题以包含MCVE

答案 1 :(得分:0)

我认为你不能让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();