Reputation: 133
Recently I started learning JavaFX and now something is bothering me and I can’t find a solution to my “problem”. I have found similar questions and couple of solutions to problems like mine, but I couldn’t find one that’s working for me or simply I am doing something wrong. What I want to do is to have one main FXML file with its own FXML Controller Class. Then I want to add (import) other FXML files, which also have controllers, in the main FXML. I tried couple of things, but nothing worked, so I decided to describe what I am doing. First I am creating the Main FXML file with Scene Builder and then I am creating the Controller for the Main FXML. Then I am setting in Scene Builder the controller class for the Main FXML to be the Main Controller (of course…). After that I am doing the same for the second FXML. Then I am trying to import the second FXML to the Main FXML and it works fine, if I haven’t set a controller for the second FXML. If I have however selected a controller for the second FXML before importing it to the Main FXML, I am still able to import the FXML file and save it, but after I try to run the program, I am getting an error. So basically what I am trying to do is to have multiple FXML files with their own controllers in one Main FXML file, which also has a Controller Class. I am not exactly sure that this is possible at all, so please tell me is that possible at all, and if it’s possible, what am I doing wrong. This is my code :
public class MainSceneController implements Initializable {
@FXML
private TextField mainTxtField;
public MainSceneController() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MainScene.fxml"));
fxmlLoader.setController(this);
fxmlLoader.setRoot(this);
try {
fxmlLoader.load();
} catch (IOException exc) {
} }
@FXML
public void buttonActionMethod(ActionEvent event) {
mainTxtField.setText("Button1 is clicked");
}
@Override
public void initialize(URL location, ResourceBundle resources) {
} }
I called the second FXML and the second controller LeftScene and LeftSceneController, so here is the code for the second controller :
public class LeftSceneController implements Initializable {
@FXML
private TextField leftTxtField;
public LeftSceneController() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MainScene.fxml"));
fxmlLoader.setController(this);
fxmlLoader.setRoot(this);
try {
fxmlLoader.load();
} catch (IOException exc) {
}
}
@FXML
public void button2Action(ActionEvent event) {
leftTxtField.setText("Button 2 is clicked");
}
@Override
public void initialize(URL location, ResourceBundle resources) {
} }
And finally, this is the MainClass, in which are the main method and the start method :
public class MainClass extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("MainScene.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setTitle("Multiple FXMLs in one");
primaryStage.show();
} }
I hope you are getting what I want to do. As I said, I have tried a lot of things and none of them worked how I wanted it to. This version is compiling and it’s running, if I don’t set a controller class for the second FXML before importing it, but as you can expect, the second button from the imported FXML is not doing anything. I would post screenshots, if I could, but I am new here and usually I am only reading, so I am not allowed to post screenshots. Also I tried to post my FXML code, but I was having problems with the system and I couldn't post more than one line of the code.
So… Is it possible to make this work how I want it to or not?
And also if you read all this mess, thanks at least for your time! :)
Upvotes: 3
Views: 4679
Reputation: 133
It has been a while, but finally I found an answer to my question. I found this video on YouTube and it is showing exactly what I needed. Although I found a couple of problems while I was doing the things from the video step by step.
First of all, if I import another FXML file into the main FXML, like in this tutorial, SceneBuilder is importing the FXML like the things from the imported FXML are in the main FXML and this causes problems. What I mean is for example if you have a Button in the imported FXML, when you import it in the main FXML with SceneBuilder, the imported Button appears in the main FXML like a new Button with all the information for it (postion, onClickMethod, etc.) and that it's not how it's supposed to be. This causes errors, because Java is looking for the onClickMethod for the imported button in the Main Controller and not in the Controller of the imported FXML. I don't know why it's different by me and it is not like in the video, but the solution is simple. If you want to import a FXML file into another FXML, you should do it with an editor and you just have to add the following line in the content of the main FXML :
<fx:include fx:id="importedFXML" source="ImportedFXML.fxml" />
The important thing in this case is that the fx:id should be with the same name as the .FXML file, but with a small first letter.
And the other thing, which was shown in the video and which caused problems by me was if you want to have a multiple imported FXML files and you want them to communicate with each other. The video is showing how to do that, but it is not mentioning that the Controller objects of the imported FXML files, which you have to create in the MainController, must have the same names like the fx:id + the word Controller. For example with the fx:id from above, the object should look like this :
@FXML private ImportedFXMLController importedFXMLController
if the ImportedFXMLController is the controller of the importedFXML
So, I hope that this is going to be helpful to someone.
Upvotes: 7