0

I am new to JavafX. I wanted to change the CSS file of my first GUI through the second one.

I have the following code:

Main1.java

package javafxapplication3.a;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main1 extends Application{

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Parent root = null;
        try {
            root = FXMLLoader.load(getClass().getResource("/main1.fxml"));
        } catch (Exception e) {
        }

        String css = Main1.class.getResource("/main1.css").toExternalForm();
        Scene scene = new Scene(root, 400, 400);
        scene.getStylesheets().clear();
        scene.getStylesheets().add(css);
        primaryStage.setResizable(false);
        primaryStage.setScene(scene);
        primaryStage.setTitle("JCal");
        primaryStage.show();
    }

}

Main1Controller.java

package javafxapplication3.a;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;

public class Main1Controller {

    @FXML
    private Button button1;

    public void initialize() {

        button1.setOnAction(value -> {
            Stage primaryStage = new Stage(); 
        Parent root = null;
        try {
            root = FXMLLoader.load(getClass().getResource("/main2.fxml"));
        } catch (Exception e) {
        }

        Scene scene = new Scene(root, 400, 400);
        primaryStage.setResizable(false);
        primaryStage.setScene(scene);
        primaryStage.setTitle("JCal");
        primaryStage.show();
        });

    }
}

main1.fxml

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication3.a.Main1Controller">
   <children>
      <Button fx:id="button1" layoutX="271.0" layoutY="173.0" mnemonicParsing="false" text="Main-1" />
   </children>
</AnchorPane>

main2.fxml

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication3.a.Main2Controller">
   <children>
      <Button fx:id="button" layoutX="271.0" layoutY="173.0" mnemonicParsing="false" text="Main-2" />
   </children>
</AnchorPane>

In the FXML I have a Button called button1, when ever I click on it, it opens a new GUI which has another button in it called button. In the end what I wanted to do was that when ever I click on the second button i.e. button the colour of the button in the primary GUI should change should change.

I did try getting the controllers shown in this example, But this dint help me.

Do I need to create a second controller and create a new stage and scene all together? or is there any alternative way to it?

Community
  • 1
  • 1
Akshay
  • 2,622
  • 1
  • 38
  • 71

1 Answers1

0

In the controller for your main2.fxml, provide a mechanism in it for setting an action to be executed when the button is pressed. For example:

public class Main2Controller {

    @FXML
    private Button button ;

    private Runnable buttonAction = () -> {} ; // do nothing by default

    public void setButtonAction(Runnable action) {
        this.buttonAction = action ;
    }

    public void initialize() {
        button.setOnAction(e -> buttonAction.run());
    }
}

Now in your Main1Controller you can retrieve the controller when you load the FXML, and set the button action:

button1.setOnAction(value -> {
    Stage primaryStage = new Stage(); 
    Parent root = null;
    try {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/main2.fxml"));
        root = loader.load();
        Main2Controller controller = loader.getController();
        controller.setButtonAction(() -> {
            // perform button action here...
        });
    } catch (Exception e) {
        e.printStackTrace();
    }

    Scene scene = new Scene(root, 400, 400);
    primaryStage.setResizable(false);
    primaryStage.setScene(scene);
    primaryStage.setTitle("JCal");
    primaryStage.show();
});

An alternative approach is to let both controllers have access to the same observable state, e.g. an ObjectProperty<Color>. This approach might be better if you have a lot of actions in one controller that affect state elsewhere (you just bundle all the data into a single "model" class that you pass). This looks like:

public class Main1Controller {

    private final ObjectProperty<Color> color = new SimpleObjectProperty<>();

    @FXML
    private Button button1;

    public void initialize() {

        color.addListener((obs, oldColor, newColor) -> {
            String style = String.format("-fx-background-color: #%02x%02x%02x;",
                (int) (newColor.getRed() * 255),
                (int) (newColor.getGreen() * 255),
                (int) (newColor.getBlue() * 255));
            button1.setStyle(style);
        });

        button1.setOnAction(value -> {
            Stage primaryStage = new Stage(); 
            Parent root = null;
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/main2.fxml"));
            root = loader.load();
            Main2Controller controller = loader.getController();
            controller.setColorModel(color);
        } catch (Exception e) {
            e.printStackTrace();
        }

        Scene scene = new Scene(root, 400, 400);
        primaryStage.setResizable(false);
        primaryStage.setScene(scene);
        primaryStage.setTitle("JCal");
        primaryStage.show();
        });

    }
}

and Main2Controller looks like

public class Main2Controller {

    @FXML
    private Button button ;

    private ObjectProperty<Color> colorModel = new SimpleObjectProperty<>();

    public void setColorModel(ObjectProperty<Color> color) {
        this.colorModel = color ;
    }


    public void initialize() {
        button.setOnAction(e -> {
            colorModel.set(/* some color */);
        });
    }
}
James_D
  • 201,275
  • 16
  • 291
  • 322