简体   繁体   中英

Javafx location is required (loading FXML file from another folder/package)

I have an issue using Java with FXML files.

I searched for hours now and couldn't find anything that solves my problem, so my last hope is to ask the question for my specific case (I'm aware of question like this one and others but none really helped me in this regard.

Simple explanation: I have an Eclipse Java Project and my (important for this question) classes are in the package [Project Name]/src/measurements.gui. My FXML file is in the folder [Project Name]/resources.

My class that loads the FXML file ElementsProperties.java looks like this:

import java.io.IOException;

import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.Window;

public class ElementsProperties {

  public static void show(Window parent, String title) {

    ElementsProperties el = new ElementsProperties();
    BorderPane root = el.loadFXMLFile("resources/TestWindow.fxml");

    Stage dialog = new Stage();
    dialog.initOwner(parent);
    dialog.setTitle(title);
    dialog.initModality(Modality.WINDOW_MODAL);
    dialog.setScene(new Scene(root));
    dialog.show();
  }

  @SuppressWarnings({ "finally", "static-access" })
  private BorderPane loadFXMLFile(String filePath) {
    BorderPane borderPane = null;
    try {
      borderPane = new BorderPane();
      FXMLLoader fxmlLoader = new FXMLLoader();
      Parent content = fxmlLoader.load(getClass().getResource(filePath));
      borderPane.setCenter(content);
    }
    catch (IOException e) {
      e.printStackTrace();
      System.err.println("Couldn't find the specified file");
    }
    catch(Exception e){
      e.printStackTrace();
    }
    finally {
     return borderPane;
    }
}}

The FXML file is shown as a dialog with the following simple line: ElementsProperties.show(parent, "TestWindow");

My FXML file (created with the JavaFXSceneBuilder 2.0) looks like this: `

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.effect.*?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.text.*?>

<VBox prefHeight="400.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
  <children>
    <MenuBar VBox.vgrow="NEVER">
      <menus>
        <Menu mnemonicParsing="false" text="File">
          <items>
            <MenuItem mnemonicParsing="false" text="New" />
            <MenuItem mnemonicParsing="false" text="Open…" />
            <Menu mnemonicParsing="false" text="Open Recent" />
            <SeparatorMenuItem mnemonicParsing="false" />
            <MenuItem mnemonicParsing="false" text="Close" />
            <MenuItem mnemonicParsing="false" text="Save" />
            <MenuItem mnemonicParsing="false" text="Save As…" />
            <MenuItem mnemonicParsing="false" text="Revert" />
            <SeparatorMenuItem mnemonicParsing="false" />
            <MenuItem mnemonicParsing="false" text="Preferences…" />
            <SeparatorMenuItem mnemonicParsing="false" />
            <MenuItem mnemonicParsing="false" text="Quit" />
          </items>
        </Menu>
        <Menu mnemonicParsing="false" text="Edit">
          <items>
            <MenuItem mnemonicParsing="false" text="Undo" />
            <MenuItem mnemonicParsing="false" text="Redo" />
            <SeparatorMenuItem mnemonicParsing="false" />
            <MenuItem mnemonicParsing="false" text="Cut" />
            <MenuItem mnemonicParsing="false" text="Copy" />
            <MenuItem mnemonicParsing="false" text="Paste" />
            <MenuItem mnemonicParsing="false" text="Delete" />
            <SeparatorMenuItem mnemonicParsing="false" />
            <MenuItem mnemonicParsing="false" text="Select All" />
            <MenuItem mnemonicParsing="false" text="Unselect All" />
          </items>
        </Menu>
        <Menu mnemonicParsing="false" text="Help">
          <items>
            <MenuItem mnemonicParsing="false" text="About MyHelloApp" />
          </items>
        </Menu>
      </menus>
    </MenuBar>
    <AnchorPane maxHeight="-1.0" maxWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS">
      <children>
        <Label alignment="CENTER" layoutX="155.0" layoutY="177.0" style="&#10;" text="Drag components from Library here…" textAlignment="CENTER" textFill="#9f9f9f" wrapText="false">
          <font>
            <Font size="18.0" />
          </font>
        </Label>
            <GridPane layoutX="-2.0" layoutY="-3.0" prefHeight="407.0" prefWidth="659.0">
              <columnConstraints>
                <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
              </columnConstraints>
              <rowConstraints>
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
              </rowConstraints>
               <children>
                  <HBox prefHeight="134.0" prefWidth="654.0" spacing="20.0" GridPane.rowIndex="1">
                     <children>
                        <Button mnemonicParsing="false" prefHeight="46.0" prefWidth="60.0" text="Click me" wrapText="true" />
                        <Button mnemonicParsing="false" prefHeight="47.0" prefWidth="73.0" text="No, click me" wrapText="true" />
                        <Button mnemonicParsing="false" prefHeight="46.0" prefWidth="120.0" text="Don't you dare click me" wrapText="true" />
                     </children>
                     <padding>
                        <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
                     </padding>
                  </HBox>
                  <TextField promptText="Type something here..." GridPane.columnIndex="1" GridPane.rowIndex="1">
                     <GridPane.margin>
                        <Insets left="20.0" right="20.0" />
                     </GridPane.margin>
                  </TextField>
               </children>
            </GridPane>
      </children>
    </AnchorPane>
  </children>
</VBox>

This is actually all that is needed. If I try to run the programm and make the dialog show up, the Exception

java.lang.NullPointerException: Location is required.

is given. If I move the FXML file into the same package as the main class, being measurements.gui, and change the filePath in the ELementsProperties.java class' show-method to "TestWindow.fxml" , it all works fine and I see the created window in my application. But I want to have the fxml file in the seperate resource folder for convenience of inserting other fxml files.

I hope I could explain my problem clearly and you can help me solve this. Any ideas on how to load fxml files from a different package than the main class is? Btw, things I've already tried are:

  1. adding the resource folder to the class path
  2. set the path to "/resources/TestWindow.fxml" (with the forward slash at the beginning
  3. use getClass().getClassLoader().getResource(filePath) as parameter for the FXMLLoader's load method

Thank you in advance.

Thanks, Roland, for the link. I've tried to copy the folder structure and came up with the following (for others who might have the same problem):

I created a test project JavaFXTest. I have one main class in the package org.example.main. The package is, as usual, in the src folder of the project.

MyJavaFXDialog.java:

package org.example.main;

import java.io.IOException;

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

public class MyJavaFXDialog extends Application{

    public void start(Stage primaryStage) {

    MyJavaFXDialog javaFx = new MyJavaFXDialog();
    BorderPane root = javaFx.loadFXMLFile("/resources/TestWindow.fxml");

    Stage dialog = new Stage();
    dialog.initModality(Modality.WINDOW_MODAL);
    dialog.setScene(new Scene(root));
    dialog.show();
    }

    @SuppressWarnings({ "finally", "static-access" })
    private BorderPane loadFXMLFile(String filePath) {
    BorderPane borderPane = null;
    try {
        borderPane = new BorderPane();
        FXMLLoader fxmlLoader = new FXMLLoader();
        Parent content = fxmlLoader.load(getClass().getResource(filePath));
        borderPane.setCenter(content);
    }
    catch (IOException e) {
        e.printStackTrace();
        System.err.println("Couldn't find the specified file");
    }
    catch(Exception e){
        e.printStackTrace();
    }
    finally {
        return borderPane;
    }
    }

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

I created a normal folder "resources" in the src folder. That resource folder contains only my TestWindow.fxml file which is exactly the same as in my question above. Now, the fxml file is found and displayed as the main window when I start the application.

So the solution was actually to move the resources folder into the src folder, which is still a viable solution for my case. I just didn't want the enduser to have to poke around in the depths of other packages to save his own fxml file.

Again, thanks, Roland, for pointing me towards that solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM