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.
Related
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 need help to load first the animation of the button then execute the onAction method because when I click the button, the animation of the button is delayed... How to fix it?
here is the sample code:
public void viewStage(ActionEvent event) {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Stage.fxml"));
Parent root1 = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.getIcons().add(new Image("/img/Stage.png"));
stage.setTitle("New Stage");
stage.setScene(new Scene(root1));
stage.show();
} catch (Exception e){
System.out.println(e);
}
}
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();
}
I am new to JavaFX. I have a window loaded with vertical split pane. Here left side of the split page I have couple of buttons. On Each button click I need to load separate fxml on the right side of the split pane. So here I paste screen shot to be clear.
Here as of now I am opening in separate stage, separate scene when search button is hit. Now I need to load Searcher in the right side of baselayout window. Here is some code which loads baseLayout.
#Override
public void start(Stage primaryStage) throws Exception {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Base Layout");
BaseController.setMlTool(this);
FXMLLoader loader = new FXMLLoader(MLTool.class.getResource("view/Base.fxml"));
baseLayout = (AnchorPane) loader.load();
Scene scene = new Scene(baseLayout);
primaryStage.setScene(scene);
primaryStage.show();
}
Here is some code which loads Searcher on button click.
#FXML
private void initialize(){
System.out.println("Testing");
}
#FXML
private void handleSearchButton(){
System.out.println("Handle Button Called");
Stage search = new Stage();
FXMLLoader loader = new FXMLLoader(MLTool.class.getResource("view/Searcher.fxml"));
search.setTitle("Searcher");
try {
AnchorPane searcherPage = (AnchorPane) loader.load();
Scene scene = new Scene(searcherPage);
search.setScene(scene);
search.show();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Here how do I load Searcher in BaseLayout's Rightside of split pane.
Hope my question is clear. Thanks for your help in anticipation.
You can take pane on right side and then load fxml as child node of that pane. Stage is same for all time and you can load fxml in pane.
ex: MainWindow.fxml is perent window. You can load in stage.
Parent root = FXMLLoader.load(getClass().getResource("MainWindow.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
Now in MainWindow.fxml you have split pane. Put anchorPan on right side where you want to load fxml on button click. Then add fxml as child in anchorpane.
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(fxml));
Pane cmdPane = (Pane) fxmlLoader.load();
try {
anchCmdController.getChildren().clear();
anchCmdController.getChildren().add(cmdPane);
fadeIn.playFromStart();
} catch (Exception e) {
e.printStackTrace();
}
try to listen to the button click, once its clicked use 'FXMLLoader.load' to load based on the root elenment, typecast it say panel and assign tot he content of the right side.
In Your handler method try with this:
first declare anchorpane. In fxml right pane put anchorpane with anchCmdController name.
#FXML
private AnchorPane anchCmdController;
then update your handleSearchButton event.
#FXML
private void handleSearchButton() throws IOException {
System.out.println("Handle Button Called");
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("view/Searcher.fxml"));
Pane cmdPane = (Pane) fxmlLoader.load();
try {
/* NEED TO DECLARE ANCHOR PANE" */
anchCmdController.getChildren().clear();
anchCmdController.getChildren().add(cmdPane);
} catch (Exception e) {
e.printStackTrace();
}
}
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();
}
}