java - 检查 JavaFX-FlowPane 中包装的元素

标签 java javafx javafx-8

是否有一种简单的方法来检查 FlowPane 内是否有包装元素或确定元素包装的索引?

最佳答案

我不知道它是否符合“简单”的条件,但您可以检查每个子项的 boundsInParent 并将其与第一个子项进行比较。对于水平 FlowPane 这应该有效:

private List<Node> findWrapped(FlowPane flow) {
    List<Node> wrapped = new ArrayList<>();
    if (flow.getChildren().size() == 0) {
        return wrapped ;
    }
    double y = flow.getChildren().get(0).getBoundsInParent().getMaxY();
    for (Node child : flow.getChildren()) {
        if (child.getBoundsInParent().getMinY() >= y) {
            wrapped.add(child);
        }
    }
    return wrapped ;
}

SSCCE:

import java.util.ArrayList;
import java.util.List;

import javafx.application.Application;
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.FlowPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class FlowPaneWrappedNodes extends Application {


    @Override
    public void start(Stage primaryStage) {
        FlowPane flow = new FlowPane();
        for (int i = 1 ; i <= 15; i++) {
            flow.getChildren().add(createPane(i));
        }
        Button button = new Button("Find wrapped");
        button.setOnAction(e ->
                findWrapped(flow).stream().map(Node::getId).forEach(System.out::println));
        BorderPane root = new BorderPane(flow, null, null, button, null);
        Scene scene = new Scene(root, 600, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private List<Node> findWrapped(FlowPane flow) {
        List<Node> wrapped = new ArrayList<>();
        if (flow.getChildren().size() == 0) {
            return wrapped ;
        }
        double y = flow.getChildren().get(0).getBoundsInParent().getMaxY();
        for (Node child : flow.getChildren()) {
            if (child.getBoundsInParent().getMinY() >= y) {
                wrapped.add(child);
            }
        }
        return wrapped ;
    }

    private Pane createPane(int id) {
        Pane pane = new StackPane();
        pane.setMinSize(50, 50);
        pane.setId("Pane "+id);

        Label label = new Label(Integer.toString(id));
        pane.getChildren().add(label);

        return pane ;
    }

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

对于垂直流 Pane ,您可以执行类似的操作,比较边界的 x 值而不是 y

更新:

自动重新计算有点棘手。您基本上需要观察 FlowPane 的子列表(以防添加或删除新节点),然后观察流 Pane 中每个节点的边界。您可以使用如下代码来完成此操作:

    FlowPane flow = new FlowPane();

    ListView<Node> wrappedNodeView = new ListView<>();

    ChangeListener<Bounds> boundsListener = (obs, oldBounds, newBounds) -> 
        wrappedNodeView.getItems().setAll(findWrapped(flow));

    flow.getChildren().addListener((Change<? extends Node> c) -> {
        while (c.next()) {
            if (c.wasAdded()) {
                c.getAddedSubList().forEach(node -> node.boundsInParentProperty().addListener(boundsListener));
            }
            if (c.wasRemoved()) {
                c.getRemoved().forEach(node -> node.boundsInParentProperty().removeListener(boundsListener));
            }
        }
        wrappedNodeView.getItems().setAll(findWrapped(flow));           
    });

(这将创建一个 ListView ,其中显示所有“包装”节点。显然,您可以根据需要更新列表或任何内容。)

这里它被内置到之前的 SSCCE 中:

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class FlowPaneWrappedNodes extends Application {


    @Override
    public void start(Stage primaryStage) {
        FlowPane flow = new FlowPane();

        ListView<Node> wrappedNodeView = new ListView<>();

        ChangeListener<Bounds> boundsListener = (obs, oldBounds, newBounds) -> 
            wrappedNodeView.getItems().setAll(findWrapped(flow));

        flow.getChildren().addListener((Change<? extends Node> c) -> {
            while (c.next()) {
                if (c.wasAdded()) {
                    c.getAddedSubList().forEach(node -> node.boundsInParentProperty().addListener(boundsListener));
                }
                if (c.wasRemoved()) {
                    c.getRemoved().forEach(node -> node.boundsInParentProperty().removeListener(boundsListener));
                }
            }
            wrappedNodeView.getItems().setAll(findWrapped(flow));           
        });

        wrappedNodeView.setCellFactory(lv -> new ListCell<Node>() {
            @Override
            public void updateItem(Node item, boolean empty) {
                super.updateItem(item, empty);
                if (empty) {
                    setText("");
                } else {
                    setText(item.getId());
                }
            }
        });

        Button button = new Button("Add pane");
        button.setOnAction(e ->
                flow.getChildren().add(createPane(flow.getChildren().size()+1)));

        BorderPane root = new BorderPane(flow, null, wrappedNodeView, button, null);
        Scene scene = new Scene(root, 600, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private ObservableList<Node> findWrapped(FlowPane flow) {
        ObservableList<Node> wrapped = FXCollections.observableArrayList();
        if (flow.getChildren().size() == 0) {
            return wrapped ;
        }
        double y = flow.getChildren().get(0).getBoundsInParent().getMaxY();
        for (Node child : flow.getChildren()) {
            if (child.getBoundsInParent().getMinY() >= y) {
                wrapped.add(child);
            } 
        }
        return wrapped ;
    }

    private Pane createPane(int id) {
        Pane pane = new StackPane();
        pane.setMinSize(50, 50);
        pane.setId("Pane "+id);

        Label label = new Label(Integer.toString(id));
        pane.getChildren().add(label);

        return pane ;
    }

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

关于java - 检查 JavaFX-FlowPane 中包装的元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33456168/

相关文章:

java - Google Maps API 在 Eclipse 中工作,但在导出为 JAR 时无法工作

java - 解析特殊键字符串以获得KeyCode

javafx - FXML 设置 ButtonType onAction

javascript - SVG 路径元素不会在 JavaFX8 Web View 中触发鼠标事件

java - 用文件删除常见英语单词

java - 多行按钮文本忽略按钮边距的问题

JavaFX HTMLEditor 文本更改监听器

java - 如何在 Javafx 中创建更大的字体

java - 需要高性能的文本文件读取和解析(类似 split())

java - org.springframework.expression.spel.SpelEvaluationException