【问题标题】:How to listen when a pane comes to front in StackPane (JavaFX)?当 StackPane (JavaFX) 中的窗格出现在最前面时如何收听?
【发布时间】:2016-02-04 03:12:55
【问题描述】:

所以这是我的问题。在 JavaFX 中,我创建了一个 StackPane,并在其中添加了各种其他窗格。结果如下图所示。当我点击下面的按钮时,使用“toFront()”方法会出现相应的窗格。我想在所有窗格上创建侦听器,只要它们出现在前面就会触发。 我尝试过使用

pane.sceneProperty().addListener((obs, oldValue, newValue) -> {});

但在我的情况下不起作用,因为窗格已经是 StackPane 的子级,因此已经在场景中。

我在这里想要实现的是在场景中实际渲染窗格/节点时进行监听。据我了解,堆栈窗格中位于前窗格后面的窗格未呈现。

问候, 强尼

【问题讨论】:

    标签: events javafx rendering listener stackpanel


    【解决方案1】:

    据我了解,堆栈窗格中位于前窗格后面的窗格未呈现。

    这并不完全正确。堆栈窗格中的窗格以与其在子列表中的位置相对应的 z 顺序呈现;换句话说,它们在另一个之上呈现,列表中的第一个元素位于堆栈的底部,最后一个元素位于顶部。如果它们都是不透明的并且都填满了整个堆栈窗格,那么只有最后一个对用户可见。

    您可以将跟踪堆栈窗格列表中最后一项的绑定(即位于前面的节点)与

    放在一起
    ObjectBinding<Node> frontLayer = Bindings.valueAt(stack.getChildren(), 
        Bindings.size(stack.getChildren()).subtract(1));
    

    SSCCE:

    import java.util.Random;
    import java.util.stream.IntStream;
    
    import javafx.application.Application;
    import javafx.beans.binding.Bindings;
    import javafx.beans.binding.ObjectBinding;
    import javafx.geometry.Insets;
    import javafx.geometry.Pos;
    import javafx.scene.Node;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    import javafx.scene.layout.BorderPane;
    import javafx.scene.layout.Pane;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class StackPaneReorderTest extends Application {
    
        private final Random rng = new Random();
    
        @Override
        public void start(Stage primaryStage) {
            StackPane stack = new StackPane();
            IntStream.rangeClosed(1, 10).mapToObj(this::createPane).forEach(stack.getChildren()::add);
            Button button = new Button("Change");
            button.setOnAction(e -> 
                stack.getChildren().get(rng.nextInt(stack.getChildren().size() - 1)).toFront());
            BorderPane root = new BorderPane(stack, null, null, button, null);
            BorderPane.setAlignment(button, Pos.CENTER);
            BorderPane.setMargin(button, new Insets(10));
    
            ObjectBinding<Node> frontLayer = Bindings.valueAt(stack.getChildren(), 
                Bindings.size(stack.getChildren()).subtract(1));
            frontLayer.addListener((obs, oldLayer, newLayer) ->  
                System.out.println(newLayer.getId() + " moved to front"));
    
            Scene scene = new Scene(root, 400, 400);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        private Pane createPane(int i) {
            Pane pane = new StackPane();
            pane.setId("Layer "+i);
            pane.setStyle(String.format("-fx-background-color: -fx-background; -fx-background: #%x%x%x;", 
                rng.nextInt(16), rng.nextInt(16), rng.nextInt(16)));
            pane.getChildren().add(new Label("Layer "+i));
            return pane ;
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    请注意,对于您的特定用例,您正在尝试做的事情可能会有更好的解决方案。例如。您可以使用BorderPane 并使用您要显示的节点调用setCenter。然后BorderPanecenterProperty 总是持有可见节点。还有很多其他方法可以做到这一点。

    【讨论】:

    • 好吧,我之前一直在使用 AnchorPane,我正在向其中添加和删除窗格。但是我在渲染中遇到了性能缓慢的问题,因为添加和删除节点的成本很高。但是,通过在窗格中使用 sceneProperty() 并在可见时捕获事件,这可以正常工作。
    • 你能推荐一个替代方案吗?
    • 我已经做到了。如果没有一个可以参考的例子,我无法让它更精确。但是我发布的代码有什么问题?
    • 您好,很抱歉回复晚了,但我这几天正在旅行,没有时间写一些代码。好吧,我会尽量做到精确。列表视图可以在窗格中,窗格可以在滚动窗格中,堆栈窗格中的滚动窗格,可以在边框窗格中等。我想要一种侦听器,以便当列表视图出现在前面或呈现在用数据加载列表视图的场景
    • 为什么不直接在列表视图中加载数据?
    猜你喜欢
    • 1970-01-01
    • 2017-03-25
    • 2022-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多