JavaFX:Make节点不占用空间,但让它的父节点决定它的位置

时间:2015-02-27 18:44:02

标签: java layout javafx overlap

我有一个TextField和一个ListView。当用户在TextField中键入时,ListView中会出现建议:

enter image description here

当TextField为空时,ListView会通过将visible和managed属性设置为false来消失。

但是,当用户开始输入时,ListView会占用空间并将所有内容都按下。使用.setManaged(false)允许它不占用任何空间,但它不再显示,因为我还没有为它定义一个位置。我已经尝试设置搜索列表的layoutX和layoutY,但它仍然没有显示。

理想情况下,我希望ListView的位置受到布局的影响,但不占用任何空间。

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

将包含文本字段的容器包装在AnchorPane中。在文本字段容器之后将ListView添加到AnchorPane(因此它保持在顶部)。然后,当您使文本字段可见时,您需要相对于文本字段正确定位ListView;我认为最好的方法是首先将文本字段的边界从本地坐标转换为Scene坐标,然后将这些边界转换为相对于AnchorPane的坐标。

这是一个SSCCE:

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

public class SuggestionList extends Application {

    @Override
    public void start(Stage primaryStage) {
        AnchorPane root = new AnchorPane();

        ListView<String> suggestionBox = new ListView<>();
        suggestionBox.getItems().addAll("Here", "Are", "Some", "Suggestions");
        suggestionBox.setMaxHeight(100);
        suggestionBox.setVisible(false);

        // Grid pane to hold a bunch of text fields:
        GridPane form = new GridPane();
        for (int i=0; i<10; i++) {
            form.addRow(i, new Label("Enter Text:"), createTextField(suggestionBox));
        }

        // just move the grid pane a little to test suggestion box positioning:
        AnchorPane.setLeftAnchor(form, 20.0);
        AnchorPane.setRightAnchor(form, 20.0);
        AnchorPane.setTopAnchor(form, 20.0);
        AnchorPane.setBottomAnchor(form, 20.0);

        // allows focus on grid pane, so user can click on it to remove focus from text field.
        form.setFocusTraversable(true);

        root.setPadding(new Insets(20));

        root.getChildren().addAll(form, suggestionBox);

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

    private TextField createTextField(ListView<String> suggestionBox) {
        TextField textField = new TextField();
        ChangeListener<String> selectionListener = (obs, oldItem, newItem) -> {
            if (newItem != null) {
                textField.setText(newItem);
            }
        };
        textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
            if (isNowFocused) {
                suggestionBox.setVisible(true);

                // compute bounds of text field relative to suggestion box's parent:
                Parent parent = suggestionBox.getParent(); // (actually the anchor pane)
                Bounds tfBounds = textField.getBoundsInLocal();
                Bounds tfBoundsInScene = textField.localToScene(tfBounds);
                Bounds tfBoundsInParent = parent.sceneToLocal(tfBoundsInScene);

                // position suggestion box:
                suggestionBox.setLayoutX(tfBoundsInParent.getMinX());
                suggestionBox.setLayoutY(tfBoundsInParent.getMaxY());
                suggestionBox.setPrefWidth(tfBoundsInParent.getWidth());

                suggestionBox.getSelectionModel().selectedItemProperty().addListener(selectionListener);
            } else {
                suggestionBox.setVisible(false);
                suggestionBox.getSelectionModel().selectedItemProperty().removeListener(selectionListener);
            }
        });
        textField.setOnAction(event -> {
            suggestionBox.setVisible(false);
            suggestionBox.getSelectionModel().selectedItemProperty().removeListener(selectionListener);         
        });
        return textField ;
    }

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

您可以使用类似的位置技巧,只需将其添加到同一场景,managed设置为false。