停止主线程,直到JavaFX事件队列中的所有事件都已执行

时间:2015-04-30 11:46:43

标签: events javafx

在调试应用程序时,我希望主线程在每个Runnable之后等待我使用

放入JavaFX事件队列
Platform.runLater(new Runnable()... )

等待它被执行(即可见)。但是这里有两个曲折:

首先,它不是一个标准的,GUI驱动的JavaFX应用程序。它是一个显示和更新JavaFX阶段的脚本。所以结构看起来像这样:

public static void main(String [] args){
    //do some calculations
    SomeView someView = new SomeView(data); //SomeView is basically a wrapper for  a stage
    PlotUtils.plotView(someView) //displays SomeView (i.e. the stage)
    //do some more calculations
    someView.updateView(updatedData)
    //do some more calculations
}

public class SomeView {
    private static boolean viewUpdated = false;
    private ObservableList<....> observableData;
    public void updateView(Data data){
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                observableData.addAll(data);
                boolean viewUpdated = true; 
            }
        });
    //If configured (e.g using boolean switch), wait here until
    //the Runnable has been executed and the Stage has been updated.
    //At the moment I am doing this by waiting until viewUpdated has been
    //set to true ... but I am looking for a better solution!
    }
}

其次,应该很容易禁用这个&#34;功能&#34;,即等待Runnable执行(使用当前的方法这是没有问题的,但也可以使用替代方法)。

最好的方法是什么?

E.g。有什么像阻塞版本在JavaFX线程上执行Runnable或有一个简单的方法来检查事件队列上的所有事件是否已执行/事件队列是否为空....?

2 个答案:

答案 0 :(得分:2)

只要您不从JavaFX线程调用它,PlatformImpl.runAndWait()也会使用倒计时锁定

答案 1 :(得分:1)

这是基于JavaFX2: Can I pause a background Task / Service?

的一般想法

基本想法是向gotEnd提交FutureTask<Void>,然后在Platform.runLater()上致电get()FutureTask将阻止任务完成:

get()

必须 在FX应用程序线程上执行此代码块,因为这会导致死锁。

如果您希望可以轻松配置,可以执行以下操作:

// on some background thread:

Runnable runnable = () -> { /* code to execute on FX Application Thread */};
FutureTask<Void> task = new FutureTask<>(runnable, null);
Platform.runLater(task);
task.get();

现在,您可以在应用程序中执行以下操作:

// Wraps an executor and pauses the current thread 
// until the execution of the runnable provided to execute() is complete

// Caution! Calling the execute() method on this executor from the same thread
// used by the underlying executor will result in deadlock.

public class DebugExecutor implements Executor {
    private final Executor exec ;

    public DebugExecutor(Executor executor) {
        this.exec = executor ;
    }

    @Override
    public void execute(Runnable command) {
        FutureTask<Void> task = new FutureTask<>(command, null);
        exec.execute(command);
        try {
            task.get();
        } catch (InterruptedException interrupt) {
            throw new Error("Unexpected interruption");
        } catch (ExecutionException exc) {
            throw new RuntimeException(exc);
        }
    }
}

并替换所有来电 // for debug: Executor frontExec = new DebugExecutor(Platform::runLater); // for production: // Executor frontExec = Platform::runLater ; Platform.runLater(...)

。{

根据您想要的配置方式,您可以根据命令行参数或属性文件有条件地创建frontExec.execute(...);(或者,如果您使用依赖注入框架,则可以注入它)。