首页 > 解决方案 > Extracting text from dynamically created textfields inside various rows of gridpane

问题描述

I'm trying to create a grid with a textbox on each row where user can enter a number, and corresponding number of new rows are added. This works well, as shown below in the screenshot. enter image description here

Now I'm trying to extract the text from those textfields created based on the question "how many?" and since they are nested within various node elements, I'm having a hard time identifying the right way.Can anyone tell me what I'm doing wrong? I tried testing it using the save button, but I always go into the else statement of "Vboxgrid2 is empty!"on my console. I don't know why it says that my VBoxgrid2 is empty!

Following is a Minimal, Complete, and Verifiable example I've recreated:

package testing;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class ExtractThatText extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("GridPane Experiment");
        GridPane gridPane = new GridPane();

        for(int i=0;i<5;i++) {
            VBox mainVBox = new VBox(); 
            VBox vboxgrid1 = new VBox();
            VBox vboxgrid2 = new VBox();
            HBox hboxgrid = new HBox();
            hboxgrid.setPadding(new Insets(5,5,5,5));

            RadioButton rbYes = new RadioButton("Yes");
            RadioButton rbNo = new RadioButton("No");
            Label howmanyLabel = new Label("   How many?   ");
            TextField howManytxtB = new TextField();

            hboxgrid.getChildren().add(rbYes);
            hboxgrid.getChildren().add(rbNo);
            hboxgrid.getChildren().add(howmanyLabel);
            hboxgrid.getChildren().add(howManytxtB);

            vboxgrid1.getChildren().add(hboxgrid);

            howManytxtB.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    vboxgrid2.getChildren().clear();
                    Integer howManyNum = Integer.valueOf(howManytxtB.getText());
                    for(int row=0;row<howManyNum;row++) {
                        //creating rows for entering the new entities
                        HBox innerRowbox = new HBox();
                        TextField name = new TextField();
                        ComboBox cb = new ComboBox(); //empty cb for now
                        name.setPromptText("Enter name of the new Entity");
                        name.setMinWidth(200);
                        innerRowbox.getChildren().add(name);
                        innerRowbox.getChildren().add(cb);
                        vboxgrid2.getChildren().add(innerRowbox);
                    }
                }

            });

            mainVBox.getChildren().add(vboxgrid1);
            mainVBox.getChildren().add(vboxgrid2);
            gridPane.add(mainVBox,1, i);
        }

        for(int i=0;i<5;i++) {
            gridPane.add(new Label("row"+i), 0 , i);
        }

        Button saveButton = new Button("save content");

        saveButton.setOnAction(e-> {
            Node mainVBox = gridPane.getChildren().get(1); //get just the first row's 1th column which contains mainVBox
            if(mainVBox instanceof VBox) { 
                Node vboxgrid2 = ((VBox) mainVBox).getChildren().get(1);

                if(vboxgrid2 instanceof VBox) {

                    if(!((VBox) vboxgrid2).getChildren().isEmpty()) {

                        Node innerRowBox = ((VBox) vboxgrid2).getChildren().get(0);
                        if(innerRowBox instanceof HBox) {

                            for(Node howmanyTB:((HBox)innerRowBox).getChildren()) {
                                if(howmanyTB instanceof TextField) {
                                    System.out.println(((TextField) howmanyTB).getText()); //content to save, extracted from the dnamic textfields created.
                                }
                                else System.out.println("howmanyTB not an instance of TextField error!");
                            }
                        }
                        else    System.out.println("innerRowBox not an instance of HBox error!");
                    }
                    else System.out.println("Vboxgrid2 is empty!");
                }
                else System.out.println("vboxgrid2 not an instance of VBox error!");
            } 
            else    System.out.println("mainVbox not an instance of VBox error!");
        });

        gridPane.add(saveButton, 1, 5);
        gridPane.setHgap(10);
        gridPane.setVgap(10);
        Scene scene = new Scene(gridPane, 500, 500);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

** If it's difficult to understand the nesting of all my nodes, here is a summary:

gridPane -> mainVBox (in each row of the second/1th column) -> vboxgrid2 (along with vboxgrid1 above it for the radiobutton row in mainVBox) -> innerRowbox -> name (textfield)

标签: javajavafxgridpane

解决方案


如果很难理解我所有节点的嵌套

由于您似乎确实意识到您的嵌套有点令人困惑,因此最好将TextFields 保存在比场景层次结构更易于访问的数据结构中。在这种情况下,由于项目的数量在创建之前是已知的,TextField[][]因此可以使用数组,但您也可以使用 aList<List<TextField>>来允许您动态添加(内部)行。

顺便说一句:由于您使用索引1,因此您访问的是第二行,而不是第一行。

也使用一个VBoxjust 来包含你HBox似乎没有必要。您可以直接使用HBox,因为VBox没有其他孩子。

Label howmanyLabel = new Label("   How many?   ");

最好使用此间距的边距而不是空格。

@Override
public void start(Stage primaryStage) throws Exception {
    primaryStage.setTitle("GridPane Experiment");
    GridPane gridPane = new GridPane();

    final int rowCount = 5;
    TextField[][] textFields = new TextField[rowCount][0];
    final Insets hboxPadding = new Insets(5);
    final Insets labelMargin = new Insets(0, 15, 0, 15);

    for (int i = 0; i < rowCount; i++) {
        VBox vboxgrid2 = new VBox();

        RadioButton rbYes = new RadioButton("Yes");
        RadioButton rbNo = new RadioButton("No");
        Label howmanyLabel = new Label("How many?");
        HBox.setMargin(howmanyLabel, labelMargin);
        TextField howManytxtB = new TextField();

        HBox hboxgrid = new HBox(rbYes, rbNo, howmanyLabel, howManytxtB);
        hboxgrid.setPadding(hboxPadding);

        final int rowIndex = i;

        howManytxtB.setOnAction(event -> {
            vboxgrid2.getChildren().clear();
            int howManyNum = Math.max(0, Integer.parseInt(howManytxtB.getText()));
            TextField[] fields = new TextField[howManyNum];
            for (int row = 0; row < howManyNum; row++) {
                //creating rows for entering the new entities
                TextField name = new TextField();
                ComboBox cb = new ComboBox(); //empty cb for now
                name.setPromptText("Enter name of the new Entity");
                name.setMinWidth(200);
                HBox innerRowbox = new HBox(name, cb);
                vboxgrid2.getChildren().add(innerRowbox);

                fields[row] = name;
            }
            textFields[rowIndex] = fields;
        });

        VBox mainVBox = new VBox(hboxgrid, vboxgrid2);
        gridPane.addRow(i, new Label("row" + i), mainVBox);
    }

    Button saveButton = new Button("save content");

    saveButton.setOnAction(e -> {
        TextField[] secondRowFields = textFields[1];
        if (secondRowFields.length == 0) {
            System.out.println("no TextFields in row1");
        } else {
            for (TextField textField : secondRowFields) {
                System.out.println(textField.getText());
            }
        }
    });

    gridPane.add(saveButton, 1, rowCount);
    gridPane.setHgap(10);
    gridPane.setVgap(10);
    Scene scene = new Scene(gridPane, 500, 500);
    primaryStage.setScene(scene);
    primaryStage.show();
}

推荐阅读