0
votes

Good afternoon everyone. I usually try to find and fix mistakes myself, but this time I got stuck for real. My assignment was to write a loan calculator. All code was working and compiling just fine until I got to the point where I need to create a Line Diagram/Graph, which pops up in a new window.
The problem lies somewhere in loading FXML files or connecting Additional Controllers to the Main Controller.
I tried different approaches and checked in different forums for solution, but couldn't implement one into my code. Could anyone propose me a solution?

Here is my Main which launches the program.

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("Scene.fxml"));
        primaryStage.setTitle("Loan calculator");
        primaryStage.setScene(new Scene(root, 770, 410));
        primaryStage.setResizable(false);
        primaryStage.show();
    }

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

This is my Main Controller. Little note. I understand that the way I use "initialize" method of my second controller in my main one is not correct, but I tried different approaches and they didn't give me any better result

public class Controller implements Initializable {
    public static int years = 0;
    public static int months = 0;
    private double desiredLoan = 1; //should be set to zero,but for testing is set differently

    private boolean graph = true; //true - linear, false - annuity

    @FXML
    private Button Button_3 = new Button();

    private LineGraphController lineGraphController = new LineGraphController("Linear");
    private AnnuityGraphController annuityGraphController = new AnnuityGraphController("Annuity");


/**Some code to count my data*/

    @Override /** This method is used to access my UI elements and access other controllers*/
    public void initialize(URL url, ResourceBundle resourceBundle) {
        Button_3.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                try {
                    if (desiredLoan == 0 && months == 0 && years == 0) {
                        throw new RuntimeException();
                    }
                    else {
                        if (whatGraph() == true) { //make linear graph
                            lineGraphController.initialize(url, resourceBundle);
                        }
                        else {//make annuity graph
                            annuityGraphController.initialize(url, resourceBundle);
                        }
                    }
                }
                catch (RuntimeException error) {
                    error.printStackTrace();
                }
            }
        });
    }

    /** Getters and setters */
    public boolean whatGraph() {
        return graph;
    }
    public void setGraph(boolean graph) {
        this.graph = graph;
    }
}

My main controllers:
Line Graph controller

/** This controller is used to load additional fxml file*/
public class LineGraphController implements Initializable {
    @FXML
    public LineChart<?, ?> LineGraph;
    private String title;

    public LineGraphController(String title) {
        this.title = title;
    }

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("LineGraph.fxml"));
        Parent lineGraph = null;
        try {
            lineGraph = (Parent)fxmlLoader.load();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Stage window = new Stage();
        window.initModality(Modality.APPLICATION_MODAL);
        window.setTitle(title);
        window.setResizable(false);
        window.setMinWidth(600);
        window.setMinHeight(400);
        window.setScene(new Scene(lineGraph));
        window.showAndWait();
    }
}

Annuity Graph Controller

/** This controller is used to load additional fxml file*/
public class AnnuityGraphController implements Initializable {
    @FXML
    public LineChart<?, ?> AnnuityGraph;
    private String title;

    public AnnuityGraphController(String title) {
        this.title = title;
    }

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("AnnuityGraph.fxml"));
        Parent lineGraph = null;
        try {
            lineGraph = (Parent)fxmlLoader.load();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Stage window = new Stage();
        window.initModality(Modality.APPLICATION_MODAL);
        window.setTitle(title);
        window.setResizable(false);
        window.setMinWidth(600);
        window.setMinHeight(400);
        window.setScene(new Scene(lineGraph));
        window.showAndWait();
    }
}

My Main FXML file.

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" style="-fx-background-color: #4a4a4a;" xmlns="http://javafx.com/javafx/10.0.2" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Paskolu_Skaiciuokle.Controller">
   <center>
      <Button fx:id="Button_3" maxWidth="150.0" mnemonicParsing="false" prefHeight="26.0" prefWidth="100.0" style="-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.3), 3, 0,5, 5, 5);" text="Show graph" BorderPane.alignment="CENTER">
         <font>
            <Font name="Times New Roman" size="12.0" />
         </font>
      </Button>
   </center>
</BorderPane>

My additional FXML files for controllers:
Line Graph FXML

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="670.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/10.0.2" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Loan_calculator.LineGraphController">
 <!-- some code -->
</AnchorPane>

Annuity Graph FXML

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="670.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/10.0.2" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Loan_calculator.AnnuityGraphController">
 <-- some code -->
</AnchorPane>

Thank you in advance for help.
p.s. These are the links in which I tried to look for solution, there were a lot of different ways to code this, but just couldn't find one which I could implement into my code.. or maybe I just lack knowledge of how to do it. Either way I hope someone will be able to help me or explain on how to fix this. Links:
Passing Parameters JavaFX FXML
How to create multiple javafx controllers with different fxml files?
Multiple FXML with Controllers, share object
My main problem is accessing additional controllers from my main controller. (All of the controllers are linked to their own FXML files).

1
What is it you're trying to achieve? I can see you have a main UI, and then a couple of other smaller components containing LineCharts, but it's not really clear where you want these to appear in relation to the main UI. Can you explain that in the question? It will probably help (both help you understand how to make this work, and make it easier for others to help you) if you create a separate application that only tries to do that part (one UI containing or somehow displaying another UI, each with an FXML file and a controller). You don't really need a chart and table to figure this out.James_D
Well, you see, I have three different fxml files, one is for main ui as you said and other two are for different loan graphs(later I will also add a tableView to them via SceneBuilder). I use fxml files since it is easier to work with graphical content than writing the code. Since I have three different FXML's, I cannot define one controller to three fxmls. That is why I have three different controllers. Without attaching fxml to a controller I couldn't update my Diagram with new parameters.ernestas20111
That's not what I'm asking though... Your main FXML file defines a border pane, containing, well, some stuff, but none of it really relevant. Your other FXML files define some other stuff (line charts, etc). I can't understand from your post where (or when?) the UI (e.g. charts) defined in the two other FXMLs are supposed to appear? Where (when?) do you want them to appear on the screen in relation to the main UI?James_D
OK, that's more helpful. But why not try to write a separate app (from scratch) that does only what you just described. I.e. a "main" fxml that displays a button (and nothing else), and a second fxml that is displayed when you press the button (and displays something very simple, like a label). If they need to share data in your real app, do the least amount that mimics that. There's something like a 95% chance that if you do that, you'll figure out how to make it work. If you don't, posting that app here, instead of all the code you posted, is much more likely to get help.James_D
Well, I will try to answer how my program works. Basically, I type in some date into textfields, then I press the button "Count" (Button_1), which counts the data and gives me the wanted results. After that, If I wanted to print a Line diagram, I press another button "Print graphs" (Button_3). By the press of this button, a new window should be opened which would contain the data from my Main Controller and would contain the FXML file loaded from Additional Controller. I hope I explained what you were asking for. (With FXML files everything is fine)ernestas20111

1 Answers

1
votes

I don't understand you problem very well, but I try to answer. I think you want to access other controller from main controller,simplest way is:

FXMLLoader mainLoader = new FXMLLoader(getClass().getResource("MainController.fxml"));
Parent main = mainLoader.load();
MainController mainController = mainLoader.getController();

FXMLLoader otherLoader = new FXMLLoader(getClass().getResource("OtherController.fxml"));
Parent other = otherLoader.load();
// set other controller in main controller
mainController.setOtherController(otherLoader.getController());

If you use javafx-weaver and spring boot, DI will make it more easy:

@Component
@FxmlView
class MainController {
    @Autowired
    private FxControllerAndView<OtherController, VBox> otherControllerAndView;

    // otherControllerAndView.getController() to access other controller
}