当前位置: 首页 > 知识库问答 >
问题:

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

马臻
2023-03-14

在调试应用程序时,我希望主线程在我放入JavaFX事件队列的每个Runnable之后等待

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!
    }
}

其次,禁用此“功能”应该很容易,即等待Runnable执行(使用当前方法没有问题,但使用替代方法也应该可行)。

做这件事的最好方法是什么?

例如。是否有类似阻塞版本的东西来在JavaFX线程上执行Runnable,或者是否有一种简单的方法来检查事件队列上的所有事件是否都已执行/事件队列是否为空......?

共有2个答案

计和顺
2023-03-14

这是基于JavaFX2的一般思想:我可以暂停一个后台任务/服务吗?

基本思想是提交未来任务

// 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();

不得在FX应用程序线程上执行此代码块,因为这将导致死锁。

如果您想使其易于配置,可以执行以下操作:

// 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(...);

根据所需的可配置性,您可以基于命令行参数或属性文件(或者,如果您使用的是依赖关系注入框架,则可以注入它)有条件地创建 frontExec)。

笪智志
2023-03-14

还有< code > platform impl . runandwait()使用倒计时闩锁,只要您不从JavaFX线程调用它

 类似资料:
  • 我正在尝试处理用户的Backspace按键。我有2个处理程序绑定到一个输入元素。由于无法在onChange事件处理程序中检测按键,因此我必须在onKeyDown中进行。我想在按下backspace时停止onChange事件的传播(并在onKeyDown事件处理程序中处理)。有什么想法如何实现这一点?谢谢!

  • 如果同一个在几个线程之间共享,我可以理解这一点,但否则,我就不明白了。 这个邮件列表线程表明会更安全,但我不清楚为什么。 更确切地说,我不明白那两段话:

  • 我试图在JavaFX中重现一个JavaScript游戏的一些行为。该程序有几个数字文本字段,可以在游戏运行时进行编辑。它在运行时也接受字母键盘命令。 macOS、Java17、JavaFX17。

  • 我正在使用javafx创建一个扫雷克隆,如果有人玩过原始游戏,他们可能会记得当你按下一个磁贴并四处移动时,其他磁贴的行为就好像它们也在被按下一样...如果你放手-即使你最初按下的是一个完全不同的节点,你鼠标当前所在的节点也会被点击。我很难重新创建这个,我需要一些帮助。 我正在使用全局事件处理程序类,我不太确定这是好是坏......但是,让我的克隆的事件单独处理感觉很好。我尝试过在事件发生的节点上使

  • 我仍然是Java和JavaFX的初学者,目前我正在努力寻找一种方法来阻止/中断单击按钮时发生的事件。因此,我正在构建一个程序,将产品(类)添加到TableView中。到目前为止,一切正常,产品添加成功,其参数由我的自定义函数检查,用户是否在名称/价格/金额字段中分别输入了字符串/双精度/整数值。 在我的检查功能中,当输入的值不正确时,也会打印一个错误,但我也希望这样做,以便在输入不正确的值时,3个

  • 我有一个简单的设置,只有一个会话,支持一个JSF xhtml文件。在此范围内,我触发一个事件,期望同一会话和任何其他会话在提交时都将接收该事件。 然而,奇怪的是,我可以看到在事件触发期间,只有当前会话接收到它,而没有任何其他会话。我通过使用两种不同的浏览器(本例中为Safari和Firefox)来确保我有两个不同的会话。 我是否错误地理解了基于CDI的事件的概念? 支持会话的bean: xhtml