I cant set the text of a Textfield. There is no error but the Textfield is still empty.
The rest of the program is working, the method is called and the System.out.println(...) prints the right text.
So the problem is, the text of the textfield cant be set. Even if i just write textField.setText("0"); the textfield is still empty.
When I set the text for the textfield under public void initialize(...) it also works. So why doesn't it work in setCurrentInfo?
#FXML
private TextField textField;
private Info currentInfo;
#Override
public void initialize(URL url, ResourceBundle rb) {
}
public void setCurrentInfo(Info currentInfo) {
textField.setText(currentInfo.getpw1());
System.out.println(currentInfo.getpw1());
this.currentInfo = currentInfo;
}
The part of the controller where setCurrentInfo is called:
#FXML
private void handleBtn1(ActionEvent event) throws Exception{
Info info = new Info(textFieldA.getText(), textFieldB.getText());
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("FXMLPassword.fxml"));
loader.load();
Stage stage;
Parent root;
if(event.getSource()==btn1){
//get reference to the button's stage
stage=(Stage) btn1.getScene().getWindow();
//load up OTHER FXML document
root = FXMLLoader.load(getClass().getResource("FXMLPassword.fxml"));
}
else{
stage=(Stage) btn1.getScene().getWindow();
root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
}
//create a new scene with root and set the stage
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
FXMLPasswordController passwordController = loader.getController();
passwordController.setCurrentInfo(info);
}
You are retrieving the controller from the wrong FXMLLoader. In particular, you do:
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("FXMLPassword.fxml"));
loader.load();
and then later
FXMLPasswordController passwordController = loader.getController();
In this code, you create an FXMLLoader and point it to the FXMLPassword.fxml file. But when you call loader.load(), which reads the fxml file and creates the UI defined in it, you do nothing with the result. So the UI created by that call to loader.load() is never displayed.
Consequently, when you get the controller from that loader, and use it to make changes to the UI, you will never see those changes because that instance of the TextField is not displayed.
The TextField that is displayed is created when you call
root = FXMLLoader.load(getClass().getResource("FXMLPassword.fxml"));
but since you use the static version of the FXMLLoader.load(...) method here, you have no opportunity to get the controller associated with it.
You need to refactor the code as follows:
#FXML
private void handleBtn1(ActionEvent event) throws Exception{
Info info = new Info(textFieldA.getText(), textFieldB.getText());
Stage stage;
Parent root;
if(event.getSource()==btn1){
//get reference to the button's stage
stage=(Stage) btn1.getScene().getWindow();
//load up OTHER FXML document
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("FXMLPassword.fxml"));
root = loader.load();
FXMLPasswordController passwordController = loader.getController();
passwordController.setCurrentInfo(info);
}
else{
stage=(Stage) btn1.getScene().getWindow();
root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
}
//create a new scene with root and set the stage
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
Related
I'm still new in Java, and I have a problem with passing objects between two windows in JavaFX.
I have mainStage with mainStageController. There are two things inside the controller: a label and a button. The button is opening a new window (childStage) with childStageController.
In childStageController I have a method, which gets the text "TEST CONTENT" from textField. I want to pass this text to the existing mainStage and set the label text to "TEST CONTENT".
There are a lot of topics handle similar problems, but in every case I found, the problem is with passing the object to a new created window. My case is exactly the opposite: I need to pass the object from the new opened window to the existing one.
#FXML
private Label label;
#FXML
private Button button;
private void configureButton() {
button.setOnAction(event -> {
newStageOpener(mainPaneResource, mainPaneStageTitle);
// There is magic to do
label.setText(message);
});
}
private void newStageOpener(String resource, String stageTitle){
try {
Parent parent = FXMLLoader.load(getClass().getResource(resource));
Scene scene = new Scene(parent);
Stage stage = new Stage();
stage.setScene(scene);
stage.setTitle(stageTitle);
stage.showAndWait();
} catch (IOException e) {
e.printStackTrace();
}
}
I try to do something like this, but every time I get a NullPointerException (the debugger says that childStageController is null).
FXMLLoader loader = new FXMLLoader(getClass().getResource(childPaneResource));
ChildStageController childStageController = loader.getController();
String message = childStageController.getMessage;
I also try: using setLocation, using loader.load(), "reverse" problem (setText directly from childStageController, instead of getting it from mainStageController), put newStageOpener into a configureButton, but nothing works - I always get the same NullPointerException.
What should I do to fix it?
There was mistake in newStageOpener - I rebuild it like this:
private void newStageOpener(String resource, String stageTitle) {
try {
FXMLLoader loader = new FXMLLoader(ChildStageController.class.getResource(resource));
Parent root = loader.load();
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setScene(scene);
stage.setTitle(stageTitle);
stage.showAndWait();
getObjectFromResource(resource, loader);
} catch (IOException e) {
e.printStackTrace();
}
}
private void getObjectFromResource(String resource, FXMLLoader loader) {
loader.setLocation(ChildStageController.class.getResource(resource));
ChildStageController childStageController = loader.getController();
message = childStageController.getMessage();
}
getMessage obviously is getting text from TextField.
Now it's working perfect.
I dont know what is happening, Im trying to go back to the previous windows with some values already defined, but it doesnt work, I created an static ObservableList, so each time I add a new objective it will be added it, this part works, heres the code:
public void AddList(ActionEvent e) throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Form.fxml"));
Parent root = loader.load();
Formcontroller = loader.getController();
Scene scene = new Scene(root);
Stage Newstage = (Stage)((Node)e.getSource()).getScene().getWindow();
Newstage.setScene(scene);
Newstage.show();
}
it will send me to the window where the form is, heres the code to add a new objective:
public void addObjective(ActionEvent e) throws IOException {
if (this.saving.getText().equalsIgnoreCase("")) {
Objectives object = new Objectives (this.objective.getText(), Double.parseDouble(this.price.getText()), 0);
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Objectives.fxml"));
Parent root = loader.load();
Objectivescontroller = loader.getController();
controller.AgregarObjetivo(object);
Scene scene = new Scene(root);
Stage Pstage = (Stage) button.getScene().getWindow();
Pstage.setScene(scene);
Pstage.show();
}else {
if (Double.parseDouble(this.saving.getText()) != 0 || Double.parseDouble(this.saving.getText()) == 0) {
Objectives object = new Objectives (this.objective.getText(), Double.parseDouble(this.price.getText()), Double.parseDouble(this.saving.getText()));
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Objectives.fxml"));
Parent root = loader.load();
Objectivescontroller = loader.getController();
controller.addObjetive(object);
Scene scene = new Scene(root);
Stage Pstage = (Stage) button.getScene().getWindow();
Pstage.setScene(scene);
Pstage.show();
}
}
}
here is the code to add the objective to the list:
public void addObjective (Objectives objective) {
objectives.add(objective);
listview.getItems().addAll(objectives);
}
each new objectives that I add it will stay in the list, the problem now its that Im trying to make a button in the form window, where I can click on it and go back without adding a new objective, but it shows me the list empty, i dont know why it doesnt show me the list that is already with objectives, heres the code:
public void goback (ActionEvent e) throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Objectives.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
Stage Pstage = (Stage) button.getScene().getWindow();
Pstage.setScene(scene);
}
its the same code that I used to add new objective, the only difference its that Im not calling the controller, sorry if my code is ugly or noob, but Im new in java - javafx and im just starting, thanks!
I create application in JavaFX with a lot of controllers and Scene.
When I start MainApp.class it creates Stage primaryStage with Scene from startPage.fxml.
There are 2 buttons located which give a choice to open firstWindow or secondWindow.
I have 2 differs way to open that Windows
First one, When I open firstWindow I go back from startPage into MainApp and init firstWindow. It looks in MainApp.class as
public void initFirstWindow() {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource(fxmlFirstWindow));
rootLayout = (BorderPane) loader.load();
firstWindow controller = loader.getController();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
in FirstWindow.class
#FXML
private BorderPane root;
public Controller controller;
...
The second way, I can start my secondWindow from the startPage when I press the button as
private MainApp main;
private BorderPane rootLayout;
private Stage childrenStage;
#FXML
public void btnSecondWindowOpen(ActionEvent actionEvent) {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource(fxmlSecondWindow));
rootLayout = (BorderPane) loader.load();
SecondWindow controller = loader.getController();
Scene scene = new Scene(rootLayout);
childrenStage = main.getStage();
childrenStage.setScene(scene);
childrenStage.show();
}
And the question is which way is better and is any memory-leaks while i start first or second Window?
As I wrote I have a lot of fxml which openes after first/second buttons, so I need to know.
I've got single window JavaFX application, created from one of the JavaFX tutorial.
I'm setting new window content by following function:
private Initializable replaceSceneContent(final String fxml) throws Exception {
// wczytanie fxml
FXMLLoader loader = new FXMLLoader();
InputStream in = Main.class.getResourceAsStream(fxml);
loader.setBuilderFactory(new JavaFXBuilderFactory());
loader.setLocation(Main.class.getResource(fxml));
AnchorPane page;
try {
page = (AnchorPane) loader.load(in);
} finally {
in.close();
}
Scene scene = new Scene(page, w, h);
stage.setScene(scene);
return (Initializable) loader.getController();
}
But i want to choose one of TextFields from this fxml file to be active by default. How to do this? I've tried to call requestFocus method in controller's initialize method but it didn't work. I haven't found any suitable property in TextField class either in AnchorPane class (AnchorPane is root element of fxml controls tree).
Try wrapping your requestFocus() call with PlatForm.runlater
Platform.runLater(new Runnable() {
public void run() {
textField.requestFocus();
}
});
Is there any way of getting the Stage/Window object of an FXML loaded file from the associated class controller?
Particularly, I have a controller for a modal window and I need the Stage to close it.
I could not find an elegant solution to the problem. But I found these two alternatives:
Getting the window reference from a Node in the Scene
#FXML private Button closeButton ;
public void handleCloseButton() {
Scene scene = closeButton.getScene();
if (scene != null) {
Window window = scene.getWindow();
if (window != null) {
window.hide();
}
}
}
Passing the Window as an argument to the controller when the FXML is loaded.
String resource = "/modalWindow.fxml";
URL location = getClass().getResource(resource);
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(location);
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
Parent root = (Parent) fxmlLoader.load();
controller = (FormController) fxmlLoader.getController();
dialogStage = new Stage();
controller.setStage(dialogStage);
...
And FormController must implement the setStage method.
#FXML
private Button closeBtn;
Stage currentStage = (Stage)closeBtn.getScene().getWindow();
currentStage.close();
Another way is define a static getter for the Stage and Access it
Main Class
public class Main extends Application {
private static Stage primaryStage; // **Declare static Stage**
private void setPrimaryStage(Stage stage) {
Main.primaryStage = stage;
}
static public Stage getPrimaryStage() {
return Main.primaryStage;
}
#Override
public void start(Stage primaryStage) throws Exception{
setPrimaryStage(primaryStage); // **Set the Stage**
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
}
Now you Can access this stage by calling
Main.getPrimaryStage()
In Controller Class
public class Controller {
public void onMouseClickAction(ActionEvent e) {
Stage s = Main.getPrimaryStage();
s.close();
}
}