从网格窗格各行内动态创建的文本字段中提取文本

Extracting text from dynamically created textfields inside various rows of gridpane

我正在尝试创建一个网格,每行都有一个文本框,用户可以在其中输入数字,并添加相应数量的新行。这很好用,如下面的屏幕截图所示。

现在我正尝试从那些基于问题 "how many?" 创建的文本字段中提取文本,并且由于它们嵌套在各种节点元素中,我很难确定正确的 way.Can 谁能告诉我我做错了什么?我尝试使用保存按钮对其进行测试,但我总是在控制台上进入 "Vboxgrid2 is empty!"else 语句。我不知道为什么它说我的VBoxgrid2是空的!

以下是我重新创建的最小、完整且可验证的示例:

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);
    }       
}

** 如果很难理解我所有节点的嵌套,这里有一个总结:

gridPane -> mainVBox(在second/1th列的每一行)-> vboxgrid2(以及 mainVBox 中单选按钮行上方的 vboxgrid1-> innerRowbox -> name(文本字段)

在演示应用程序中,我添加了一个 List<TextField> textFieldContainer = new ArrayList(); 来存储动态创建的 TextFields

如果数字发生变化并按下 Enter,下面的代码会删除相应的 TextFields

textFieldContainer.removeIf(p -> p.getUserData().toString().startsWith("TextField_" + tempRow));

Full Code:

import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
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 {
        List<TextField> textFieldContainer = new ArrayList();

        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);

            final Integer tempRow = i;
            howManytxtB.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    vboxgrid2.getChildren().clear();
                    Integer howManyNum = Integer.valueOf(howManytxtB.getText());

                    //The next two lines clears TextFields if you change the amount and/or press enter
                    textFieldContainer.removeIf(p -> p.getUserData().toString().startsWith("TextField_" + tempRow));
                    for(int row=0;row<howManyNum;row++) {
                        //creating rows for entering the new entities
                        HBox innerRowbox = new HBox();
                        TextField name = new TextField();
                        final Integer innerRow = row;
                        name.setUserData("TextField_" + tempRow + "_" + innerRow);
                        System.out.println(name.getUserData().toString());
                        textFieldContainer.add(name);
                        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-> {
            System.out.println("Saving these TextField's Text:");
            for(TextField textField : textFieldContainer)
            {
                System.out.println(textField.getUserData() + ": " + textField.getText());
            }
        });

        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);
    }       
}

Output:

Click save content to see the info currently in the TextFields.

Saving these TextField's Text:
TextField_0_0: one
TextField_1_0: two
TextField_1_1: three
TextField_2_0: four
TextField_3_0: seven
TextField_3_1: six
TextField_4_0: five

If it's difficult to understand the nesting of all my nodes

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

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

还使用 VBox 来包含您的 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();
}