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

JavaFXUI在事件侦听器的JavaFX应用程序线程中冻结,但与平台一起工作。朗莱特

孟俊发
2023-03-14

在我的JavaFX程序中,我目前所有的代码都在JavaFX应用程序线程上运行(包括不一定更新UI的游戏逻辑代码)。我已经读到,您应该在单独的后台线程中运行非UI代码,然后在JavaFX应用程序线程中使用平台相应地更新它。稍后运行任务,这样UI就不会被阻止,但我仍然不明白为什么在我简单地调用myFlowPane时UI会冻结。getChildren()。在JavaFX应用程序线程上删除()。

下面的代码有望提供足够的上下文

hand.getTiles().addListener((ListChangeListener<ObservableTile>) change -> {
    while (change.next()) {
        if (change.wasAdded()) {
            for (Tile t : change.getAddedSubList()) {
                var btn = tileButtonFactory.newTileButton(t);
                fpHand.getChildren().add(change.getFrom(), btn);
            }
        } else if (change.wasRemoved()) {
            // Player can only remove 1 tile at a time
            Tile tile = change.getRemoved().get(0);
            fpHand.getChildren().removeIf(node -> ((TileButton)node).getTile().equals(tile));
        }
    }
});

我有一个包含一串按钮的流程窗格,我正在收听一个包含一串平铺的observeList。当此分幅列表发生更改时,我希望相应地更新FlowPane,以便在FlowPane中创建任何新的分幅按钮。类似地,当从该平铺列表中删除平铺时,我希望从FlowPane中删除包含该平铺的按钮。

因此,从我在网上发现的情况来看,事件侦听器在JavaFX应用程序线程上运行。这意味着上面的代码正在JavaFX Application线程上运行。当我将按钮添加到我的FlowPane时,UI不会冻结/被阻止fpHand.get儿童(). add()。另一方面,当我从FlowPane中删除一个按钮时,UI在fpHand.getChildren.remove上冻结。

但是,当我将fpHand.getChildren.remove()调用包装为Platform.run稍后()时,UI是响应的,不会冻结。这是为什么呢?所有代码当前都运行在JavaFX应用程序线程上。

另外,我的代码的另一部分也有类似的问题。我有一个包含128个单元格的GridPane(每个单元格都有一个HBox),我需要更新表。我有以下代码:

private void updateTable() {
    Platform.runLater(() -> {
        clearTable();
        table.forEach(this::addTilesToTable);
    });
}
private void clearTable() {
    for (int row = 0; row < gpTable.getRowCount(); row++) {
        for (int col = 0; col < gpTable.getColumnCount(); col++) {
            getCellFromGridPane(row, col).ifPresent(hbox -> hbox.getChildren().clear());
        }
    }
}

如果我移除平台。runLater(),用户界面不会完全冻结,但是我之前在现场添加的任何互动程序,就好像桌子上有一个不可见的互动程序,因此我无法在那里添加互动程序,即使它应该是空的。updateTable()函数也在JavaFX应用程序线程和事件侦听器中调用。似乎hbox。找孩子。如果我删除平台,则clear()未被正确调用。runLater()


共有1个答案

欧阳睿范
2023-03-14

我遇到的问题是,我对根窗格使用了setMouseTransparent(true),这些根窗格包含用于单击和拖动的平铺按钮,而不使用鼠标事件。

    node.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {
        root.setMouseTransparent(true);
        dragContext.setMouseX(e.getSceneX());
        dragContext.setMouseY(e.getSceneY());
        dragContext.setInitialTranslateX(node.getTranslateX());
        dragContext.setInitialTranslateY(node.getTranslateY());
        e.consume();
    });

当您释放鼠标时,它会将其设置回false

    node.addEventHandler(MouseEvent.MOUSE_RELEASED, e -> {
        root.setMouseTransparent(false);
        node.setTranslateX(0);
        node.setTranslateY(0);
        e.consume();
    });

这里的问题是,当我从场景中移除按钮时,它会破坏所有事件处理程序,即使我释放鼠标,它也不会运行此代码。

 类似资料:
  • 当我运行任何JavaFX代码(甚至是hello world http://docs.oracle.com/JavaFX/2/get_started/hello_world.htm)并按下capslock键时,应用程序将冻结,直到关闭caps lock为止。 我在Kubuntu12.04中运行JavaFX,可能是Kubuntu的bug,我没有机会在另一个操作系统上尝试。 知道吗?

  • 问题内容: 我的应用程序中有一个通知表的Firebase 事件侦听器,当该应用程序在后台时,我想触发推送通知。 这是监听器: 当应用程序位于前台时,这非常有用。然后,在我的应用程序委托方法中添加一个后台观察器,以在后台对其进行观察: 但是当应用程序在后台运行时,事件观察器不会触发。Ive调查了Firebase Cloud Messenger以解决此问题,并遇到了类似这样的帖子: 是否可以使用Fir

  • 问题内容: 我为终端编写了一个简单的小迷宫游戏,反复要求用户做某事(例如“您想朝哪个方向前进?[N / E / S / W]”)。我有一个循环运行的方法,可以触发这些问题,存储其答案并根据答案执行某些操作。 现在,我为我的游戏编写了一个简单的GUI。我特意把到终端的所有引用的类,它实现一个接口(这有类似方法) -的想法是,我可以创建一个类,并有我的游戏 无论是 作为终端游戏 或者 作为GUI的游戏

  • 我正在尝试使用来自另一个实现的类。我的所有GUI都在一个类中(我的文本区域就在这个类中),我正在创建一个线程,并在创建GUI时运行它。我正在尝试使用

  • 问题内容: 我正在尝试使用TableView组件的onScroll事件侦听器: FXML: Java控制器: 但这不起作用!我做错了什么? 我需要捕获垂直滚动器以手动控制滚动位置并根据向下或向上滚动获取相关数据。 谢谢大家! 问题答案: 我认为可能发生的情况是TableView包含的自身正在消耗scroll事件并在内部对其进行处理,因此它永远不会到达您的应用程序处理程序。 最初,我认为您可能要使用

  • 我想在获取事件侦听器中访问我的服务工作者的作用域。我计划的解决方法是使用,但在服务人员内部不可用。我还尝试使用ServiceWorkerRegistration。作用域(MDN doc),它将返回我想要的值,但这在fetch事件处理程序中也是不可访问的。 我希望有类似的(在注册处理程序中可用),但用于获取处理程序。这可能吗?