问题
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 TextField
s 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