有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

javajavafx:使节点不占用空间,但让其父节点决定其位置

我有一个文本字段和一个列表视图。当用户在文本字段中键入时,列表视图中会出现建议:

enter image description here

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

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

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

有什么想法吗


共 (1) 个答案

  1. # 1 楼答案

    将包含文本字段的容器包装成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