Reputation: 41
I'm trying to write a program similar to the contacts app on an android phone using javafx. In the fxml file I have a VBox which contains three textfields, the first two fields are for first name and last name, and the third one is for a number.
Now what I want the program to do is when the textfield for number is filled with even a single character, another textfield to be automatically added to the VBox. (for another number).
and I want the same thing to happen for the next field. and any other field that follows, so it has a recursive form.
Now the only method I know that might accomplish this, is using a listener, but I have no idea how to create such a recursive listener. and The listener to the old field would have to be removed once it has accomplished its job, so it wouldn't continuously create new fields when typing something in the old field. but you can't remove a listener while you're inside it.
Is there a way to do this?
Upvotes: 0
Views: 260
Reputation: 82461
Register a ChangeListener
to the text
property of the TextField
s that adds/removes the TextField
based on the index every time the text changes from empty to non-empty or the other way round.
public void addTextField(Pane parent) {
TextField textField = new TextField();
textField.textProperty().addListener((o, oldValue, newValue) -> {
boolean wasEmpty = oldValue.isEmpty();
boolean isEmpty = newValue.isEmpty();
if (wasEmpty != isEmpty) {
if (wasEmpty) {
// append textfield if last becomes non-empty
if (parent.getChildren().get(parent.getChildren().size() - 1) == textField) {
addTextField(parent);
}
} else {
int tfIndex = parent.getChildren().indexOf(textField);
if (tfIndex < parent.getChildren().size() - 1) {
// remove textfield if this is not the last one
parent.getChildren().remove(tfIndex);
parent.getChildren().get(tfIndex).requestFocus();
}
}
}
});
parent.getChildren().add(textField);
}
VBox root = new VBox();
addTextField(root);
Upvotes: 1
Reputation: 209330
A lambda expression can't refer to itself, but an anonymous inner class can, so if you implement your listener as an anonymous inner class, you can achieve what you're looking to do:
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class DynamicTextFields extends Application {
private TextField lastTextField ;
@Override
public void start(Stage primaryStage) {
lastTextField = new TextField();
VBox vbox = new VBox(5, lastTextField);
ChangeListener<String> textFieldListener = new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> obs, String oldValue, String newValue) {
lastTextField.textProperty().removeListener(this);
lastTextField = new TextField();
lastTextField.textProperty().addListener(this);
vbox.getChildren().add(lastTextField);
}
};
lastTextField.textProperty().addListener(textFieldListener);
Scene scene = new Scene(new ScrollPane(vbox), 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Upvotes: 1