Javafx:问一个节点是否在视口内? [英] Javafx: Ask wether a node is inside viewport or not?

查看:107
本文介绍了Javafx:问一个节点是否在视口内?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当使用ScrollPane(使用缩放变换进行缩放)时,是否有自动方式来获取场景树中当前可见的节点(或不可见),例如通过事件回调?

When using a ScrollPane ( with a scaling transform for zooming) is there an automatic way to get the currently visible nodes in the scene tree (or non-visible) e.g by event callbacks?

或者我是否必须使用单独的结构(四叉树,RTree)来跟踪节点?

Or do I have to use a separate structure (Quadtree, RTree) for keeping track of nodes?

推荐答案

我认为没有一种特别简单的方法可以做到这一点,但你可以使用一些绑定来获得你需要的东西。这是一个基本想法:

I don't think there's a particularly straightforward way to do this, but you can use some bindings to get what you need. Here is a basic idea:

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.ObjectBinding;
import javafx.collections.ListChangeListener;
import javafx.collections.transformation.FilteredList;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Ellipse;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class ScrollPaneTracking extends Application {

    @Override
    public void start(Stage primaryStage) {
        Pane pane = new Pane();
        populatePane(pane);
        ScrollPane scrollPane = new ScrollPane();
        scrollPane.setContent(pane);

        ObjectBinding<Bounds> visibleBounds = Bindings.createObjectBinding(() -> {
            Bounds viewportBounds = scrollPane.getViewportBounds();
            Bounds viewportBoundsInScene = scrollPane.localToScene(viewportBounds);
            Bounds viewportBoundsInPane = pane.sceneToLocal(viewportBoundsInScene);
            return viewportBoundsInPane ;
        }, scrollPane.hvalueProperty(), scrollPane.vvalueProperty(), scrollPane.viewportBoundsProperty());


        FilteredList<Node> visibleNodes = new FilteredList<>(pane.getChildren());
        visibleNodes.predicateProperty().bind(Bindings.createObjectBinding(() -> 
            node -> node.getBoundsInParent().intersects(visibleBounds.get()),
            visibleBounds));


        visibleNodes.addListener((ListChangeListener.Change<? extends Node> c) -> {
                visibleNodes.forEach(System.out::println);
                System.out.println();
        });

        Scene scene = new Scene(scrollPane, 600, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private void populatePane(Pane pane) {

        Rectangle rect = new Rectangle(50, 50, 250, 100);
        rect.setFill(Color.CORNFLOWERBLUE);

        Circle circle = new Circle(450, 450, 75);
        circle.setFill(Color.SALMON);

        Polygon triangle = new Polygon(600, 600, 750, 750, 450, 750);
        triangle.setFill(Color.CHARTREUSE);

        Ellipse ellipse = new Ellipse(200, 600, 50, 150);
        ellipse.setFill(Color.DARKORCHID);

        pane.getChildren().addAll(rect, circle, triangle, ellipse);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

出于某种原因,无论什么时候,列表都会触发更改谓词变化,我认为不应该发生。您可以通过稍微庞大的实现来解决这个问题:

For some reason, the list is firing changes whenever the predicate changes, which I don't think should happen. You can get around that with a slightly bulkier implementation:

    ObservableSet<Node> visibleNodes = FXCollections.observableSet();
    visibleBounds.addListener((obs, oldBounds, newBounds) -> {
        for (Node node : pane.getChildren() ) {
            if (node.getBoundsInParent().intersects(newBounds)) {
                visibleNodes.add(node);
            } else {
                visibleNodes.remove(node);
            }
        }
    });

    visibleNodes.addListener((SetChangeListener.Change<? extends Node> c) -> {
            visibleNodes.forEach(System.out::println);
            System.out.println();
    });

请注意,我没有像滚动窗格的内容那样应用任何变换(使用比例),所以我没有测试它。您可能需要对 visibleBounds 的计算进行一些修改才能做到这一点,但这应该会为您提供一条前进的方法。

Note that I haven't applied any transforms to the scroll pane's content, as you do (with the scale), so I haven't tested it with that. You may need to tinker a little with the computation of visibleBounds to get that right, but this should give you a way forward.

这篇关于Javafx:问一个节点是否在视口内?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆