FXML Doccument refusing to import other fxml files - javafx

I have a main FXML document for my program which contains a TabPane. For each tab I want it to have its own controller and fxml file. When I try to include the external fmxl files into the main fxml document, my program refuses to run. here is my main FXML document:
here is a copy of my java file
#Override
public void start(Stage stage) throws Exception {
FXMLLoader fxml = new FXMLLoader();
Parent root = fxml.load(getClass().getResource("FXMLDocument.fxml").openStream());
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
FXMLDocumentController fdc = fxml.getController();
}
Error:
Caused by: javafx.fxml.LoadException: Base location is undefined. unknown path:97

This error is caused because you have not set the location property of the FXMLLoader, and instead you are specifying an InputStream from which to load the FXML. I think the FXMLLoader must need to know the location of the original fxml file in order to resolve the location of the included file. You should really only use the load(InputStream) method in exceptional circumstances: when you are loading the fxml from a source other than a resource (i.e. file or resource in your application jar file).
Instead, use
FXMLLoader fxml = new FXMLLoader();
fxml.setLocation(getClass().getResource("FXMLDocument.fxml"));
Parent root = fxml.load();
or, equivalently,
FXMLLoader fxml = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
Parent root = fxml.load();

Related

how to go another scene in javafx?

My dashboard fxml location is Dashboard/DashBoardScene.fxml. I tried to switch from Login/LoginController to dashboard screen
public void onLoginButtonClick(ActionEvent actionEvent) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Dashboard/DashBoardScene.fxml"));
Parent root1 = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.initStyle(StageStyle.UNDECORATED);
stage.setTitle("ABC");
stage.setScene(new Scene(root1));
stage.show();
}
but i got location is required error?
The code is in a class in the RestarantApp.Dashboard package (BTW, please use proper naming conventions). Your FXML file is in the same package.
The code getClass().getResource(...) will return a URL of a resource that is searched relative to the current class. Since the current class and the FXML file are in the same package, all you need is
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("DashBoardScene.fxml"));
(This assumes the FXML file is being deployed correctly, the resource name is spelled correctly, etc.)
You can also specify an "absolute" path (one that is relative to the classpath) to the resource:
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/RestarantApp/Dashboard/DashBoardScene.fxml"));
Note here the path begins with a leading /.

JavaFx optional parameters for controller class in start method when it is loaded into the FXML

with the ScheneBuilder I defined the controller class of my fxml, the code genereted inside my AnchorPane tag is:
fx:controller="demo.SplashController"
now I would like if I had args in the main, to load a new version of the controller, using the appropriate construct. I try this code in the Application.start:
FXMLLoader loader = new FXMLLoader(getClass().getResource("page.fxml"));
PageController controller;
if(!dir.equals("")){ //attribute coming from args
controller = new PageController(dir);
}else{
controller = new PageController();
}
loader.setController(controller);
AnchorPane root = loader.load();
Scene scene = new Scene(root,480,414);
primaryStage.setScene(scene);
primaryStage.show();
but using this code a conflict appears because I have already defined the controller in my project with FXML code, to solve it would be enough to remove the segment in the FXML code but I would not do it because leaving the code in the fxml allows me to access some good features of the SceneBuilder.
The only way pass parameters to the controller's constructor and specify the controller's class in the fxml is to use a controller factory:
FXMLLoader loader = new FXMLLoader(getClass().getResource("page.fxml"));
loader.setControllerFactory(cl -> dir.isEmpty() ? new PageController() : new PageController(dir));
AnchorPane root = loader.load();
Another option would be to create a method in the controller class that allows you to pass the info after loading and does the initialisation:
FXMLLoader loader = new FXMLLoader(getClass().getResource("page.fxml"));
AnchorPane root = loader.load();
PageController controller = loader.getController();
controller.setDir(dir);
Note that the method call happens after the initialize method is run assuming there is one.

Javafx FXMLLoader.getController() method returns null

When creating the display in my main loop, the loader for an AnchorPane FXML returns null when getController() is called.
//instantiates the FXMLLoader class by calling default constructor
//creates an FXMLLoader called loader
FXMLLoader loader = new FXMLLoader();
//finds the location of the FXML file to load
loader.setLocation(mainApp.class.getResource("/wang/garage/view/ItemOverview.fxml"));
//sets the AnchorPane in the FXML file to itemOverview
//so that the AnchorPane is set to the display of the app
AnchorPane itemOverview = (AnchorPane) loader.load();
rootLayout.setCenter(itemOverview);
//finds the controller of the itemOverview and
//sets it to controller variable
//then provides a reference of mainApp to controller to connect the two
ItemOverviewController controller = loader.getController();//returns null
controller.setMainApp(this);
I did not specify the controller in the FXML document. Is this necessary if I am using loader.load()? If so, how should I specify the controller in the FXML document?
If you are not setting the controller in Java code directly, you need to specify the controller class in the FXML file (else the FXMLLoader will have no information as to what kind of object it is supposed to create to use as the controller).
Just add the
fx:controller="com.mycompany.myproject.ItemOverViewController
attribute to the root element of the FXML file in the usual way.
Alternatively, you can set the controller from Java:
//instantiates the FXMLLoader class by calling default constructor
//creates an FXMLLoader called loader
FXMLLoader loader = new FXMLLoader();
//finds the location of the FXML file to load
loader.setLocation(mainApp.class.getResource("/wang/garage/view/ItemOverview.fxml"));
// create a controller and set it in the loader:
ItemOverviewController controller = new ItemOverviewController();
loader.setController(controller);
//sets the AnchorPane in the FXML file to itemOverview
//so that the AnchorPane is set to the display of the app
AnchorPane itemOverview = (AnchorPane) loader.load();
rootLayout.setCenter(itemOverview);
//provide a reference of mainApp to controller to connect the two
controller.setMainApp(this);

what must be specified in the fx:controller=""

I used some commands for getting the controller of a fxml file. at first I used an address like this:
fx:controller="PersonOverviewController"
and the code in main class was like this
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/PersonOverview.fxml"));
AnchorPane ap = loader.load();
PersonOverviewController pc = loader.getController();
pc.setTableContent(this);
but it doesn't work.
in another attempt, I changed the
fx:controller="address.view.PersonOverviewController"
and this time it worked.
Why this is the case?
FXMLLoader needs the binary name of the controller class to be specified. If the package of your PersonOverviewController is address.view you therefore have to include it in the attribute value.
FXMLLoader basically creates the controller instance like this, if no controller factory is set:
String fxController = ...
Class controllerClass = getClassLoader().loadClass(fxController);
Object controller = controllerClass.newInstance();

Error loading fxml files from a folder other than the bin folder

I am a fairly new java programmer. I only have about five weeks of experience, starting from zero, and I am having problems getting javafx fxml files created in Scene Builder to load correctly if they are not in the same folder as the controller classes.
I am using
Win7x64 running jre7x86 for this build
Eclipse Juno Service Release 1
Build id: 20120920-0800
jre version 1.7.0_07
javaFx version 2.2.1-b03
SceneBuilder version 1.0-b50
My scene loader code is
private static final String RESOURCE_PATH = "/resources/";
public static Stage buildStage(#SuppressWarnings("rawtypes") Class pClass,
String stageTitle, String resourceLocation)
{
Stage temp = new Stage();
Pane page = null;
try
{
page = FXMLLoader.load(pClass.getResource(RESOURCE_PATH + resourceLocation), null,
new JavaFXBuilderFactory());
}
catch (IOException e)
{
e.printStackTrace();
}
Scene scene = new Scene(page);
temp.setScene(scene);
temp.setTitle(stageTitle);
temp.setResizable(false);
return temp;
}
I know that the project directory is the /workspace/projectName/ so theoretically the loader should be able to find the files if it's given a relative path right? The error I'm getting is
Exception in Application start method
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:403)
at com.sun.javafx.application.LauncherImpl.access$000(LauncherImpl.java:47)
at com.sun.javafx.application.LauncherImpl$1.run(LauncherImpl.java:115)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException: Location is required.
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2737)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2721)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2707)
at outofunit.system.StageFactory.buildStage(StageFactory.java:32)
at outofunit.desktop.ArcMaster.start(ArcMaster.java:28)
at com.sun.javafx.application.LauncherImpl$5.run(LauncherImpl.java:319)
at com.sun.javafx.application.PlatformImpl$5.run(PlatformImpl.java:206)
at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:173)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:73)
... 1 more
I've tried giving the loader an absolute path as well but it just isn't accepting anything that isn't directly in the same directory. I'm grasping at straws here trying to figure this out.
I've tried to research this on my own but I haven't gotten much, the few answers on here that seemed similar didn't seem to help, that or I am too dense and/or inexperienced to make sense of them. They are JavaFX 2.0 loading fxml files with event handlers fails and JavaFX 2.0 FXML resource loading error
A buddy of mine was able to overcome this problem by using this code
public void load(String pFileName, Stage pStage, String pTitle)
{
String fName = RESOURCE_PATH + pFileName;
try
{
String externalForm = getClass().getResource(fName)
.toExternalForm();
InputStream inStream = new URL(externalForm).openStream();
FXMLLoader loader = new FXMLLoader();
Pane p = (Pane)loader.load(inStream);
pStage.setTitle(pTitle);
pStage.setScene(new Scene(p));
mWindowControl = loader.getController();
mWindowControl.setUp(pStage);
pStage.show();
}
catch (Exception e)
{
e.printStackTrace();
}
}
The biggest difference and the reason why I haven't been using his code is because my root pane is an Anchor pane instead of a normal pane, and his way URL instream forces a normal pane. Am I at fault for not using a normal pane as my base? I would love any help or input you guys can give. Thank you.
Edit: So I've been working on this problem and the error message has changed.
I changed the code to this
private final String RESOURCE_PATH = "resources/";
public void load(String pFileName, Stage pStage, String pTitle)
{
String fName = RESOURCE_PATH + pFileName;
Pane page = null;
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(fName));
try
{
page = (Pane) fxmlLoader.load();
}
catch (IOException exception)
{
throw new RuntimeException(exception);
}
Scene scene = new Scene(page);
pStage.setScene(scene);
pStage.setTitle(pTitle);
mWindowControl = fxmlLoader.getController();
mWindowControl.setUp(pStage);
pStage.show();
}
but the error I'm now getting is
java.lang.IllegalStateException: Location is not set.
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2021)
at outofunit.desktop.WindowLoader.load(WindowLoader.java:136)
at outofunit.desktop.WindowLoader.load(WindowLoader.java:62)
at outofunit.desktop.ArcMaster.start(ArcMaster.java:30)
at com.sun.javafx.application.LauncherImpl$5.run(LauncherImpl.java:319)
at com.sun.javafx.application.PlatformImpl$5.run(PlatformImpl.java:206)
at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:173)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:73)
at java.lang.Thread.run(Unknown Source)
I don't understand how the location is not being set
It's a path issue, java needs to know where to get the file from the package hierarchy.
So using "/package1/resourcename.fxml" should find the source from the root of the tree.
You normally leave off the "/" at the start as you are already at the top of the package tree.
Both exceptions say "the (FXML) file you are trying to load cannot be found in the location you have provided". Your filename is wrong or its path. Give your package structure or at least the path of class file that includes load(String pFileName, Stage pStage, String pTitle) method and the path of FXML file you want to load. Read the javadoc API of getResource() and examine sample codes about it on the net.

Resources