Extracting text from dynamically created textfields inside various rows of gridpane

风格不统一 提交于 2020-01-06 07:08:17

问题


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.

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)


回答1:


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

Since you do seem to realize that your nesting is a bit confusing, it would be preferable to save the TextFields in a data structure that is easier to access than your scene hierarchy. In this case since the number of items is known before they are created, a TextField[][] array could be used, but you could also go for a List<List<TextField>> to allow you to dynamically add (inner) rows.

BTW: since you use index 1 you access the second row, not the first one.

Also using a VBox just to contain your HBox seems unnecessary. You could simply use the HBox directly, since the VBox has no other children.

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

Better use a margin for this spacing instead of spaces.

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



回答2:


In the demo app, I added a List<TextField> textFieldContainer = new ArrayList(); that stores the dynamically create TextFields.

The code below delete the appropriate TextFields if the numbers change and Enter is pressed.

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


来源:https://stackoverflow.com/questions/50690240/extracting-text-from-dynamically-created-textfields-inside-various-rows-of-gridp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!