I'm working on Java project with JavaFX using IntelliJ. My idea is separate .java file in differents folders for model-view-controller arq. To get in context, this is my project structure:
And each class (I've omit imports and redundant content for my issue):
Main.java
public class Main extends Application { @Override public void start(Stage stage) throws IOException { Parent parent = FXMLLoader.load(Main.class.getResource("main-view.fxml")); Scene scene = new Scene(parent, 900, 500); stage.setTitle("Tennis Tournament!"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(); } }
Views.java
public class Views extends Controller implements Initializable{ public Views() { } @Override public void initialize(URL arg0, ResourceBundle arg1) { } public void startTournament(ActionEvent event) throws IOException { this.parent = FXMLLoader.load(getClass().getResource("tournament-view.fxml")); //this.parent = FXMLLoader.load(getClass().getResource("tournament-view.fxml")); this.stage = (Stage) ((Node)event.getSource()).getScene().getWindow(); this.scene = new Scene(this.parent); this.stage.setScene(this.scene); this.stage.show(); } public void salir(ActionEvent event){ System.exit(0);} }
TournamentController.java
public class TournamentController extends Controller implements Initializable { @FXML private ChoiceBox choiceNumSets; private Tournament tournament; private Integer[] sets = {3, 5}; public TournamentController(){ tournament = new Tournament(); } @Override public void initialize(URL url, ResourceBundle resourceBundle) { choiceNumSets.getItems().addAll(sets); choiceNumSets.setOnAction(this::setNumSets); } private void setNumSets(Event event) { tournament.setNum_sets((Integer) choiceNumSets.getValue()); System.out.println(tournament.getNum_sets()); } public void startMatch(ActionEvent event) throws IOException { this.parent = FXMLLoader.load(getClass().getResource("match-view.fxml")); this.stage = (Stage) ((Node)event.getSource()).getScene().getWindow(); this.scene = new Scene(this.parent); this.stage.setScene(this.scene); this.stage.show(); } public void salir(ActionEvent event){ System.exit(0);} }
MatchController.java
public class MatchController extends Controller implements Initializable { private Match match; public MatchController(){ match = new Match(); } @Override public void initialize(URL url, ResourceBundle resourceBundle) { match.setCurrentSets(1); System.out.println(match.getCurrentSets()); } public void salir(ActionEvent event){ System.exit(0);} }
model-info.java
module dux.tennis_tournament { requires javafx.controls; requires javafx.fxml; opens dux.tennis_tournament.controllers to javafx.fxml; exports dux.tennis_tournament.controllers; opens dux.tennis_tournament to javafx.fxml; exports dux.tennis_tournament; }
main-view.fxml -->
fx:controller="dux.tennis_tournament.Views
tournament-view.fxml
fx:controller="dux.tennis_tournament.controllers.TournamentController">
match-view.fxml
fx:controller="dux.tennis_tournament.controllers.MatchController">
So as you can see, everything seems to be fine. But the problem comes when I try to open match-view.fxml from TournamentController.java. I get these errors:
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at javafx.fxml@19-ea/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1857)
...
Caused by: java.lang.NullPointerException: Location is required.
...
at javafx.fxml@19-ea/javafx.fxml.FXMLLoader.load(FXMLLoader.java:3196)
at dux.tennis_tournament/dux.tennis_tournament.controllers.TournamentController.startMatch(TournamentController.java:47)
where this last error is referenced to this line, in TournamentController.java
this.parent = FXMLLoader.load(getClass().getResource("match-view.fxml"));
I tried to delete "to javafx.fxml" in model-info.java, I called match-view.fxml from Main.java and everything woks fine, I also tried other similars ways to generate de Parent and even move Main.java into controllers folder, but nothing fix my problem...
I'm sure the problem is where I place the controllers, because in dux.tennis_tournament folder EVERYTHING works fine BUT if I move controllers to controllers folder, I don't get the spected results. I read it could be some module-info.java but I don't know how to figure this out. The easy solution is create ALL controllers in dux.tennis_tournament folder but this project is important to me so I want to do this in "the right way".