Ben Hortin
Ben Hortin

Reputation: 1

Getting an FXML window to open when running a java file

I am currently trying to build a picture viewing program using java and an FXML window. I have had a fiddle about - getting to know FXMLs and accessing them from a program and was able to get buttons to disappear and reappear - but upon adapting said code for this picture viewer, I found that the FXML panel wouldn't open upon running the file. There are no errors/warnings besides warnings about (as yet) unused libraries being declared. Upon start up, there's no error messages, no text boxes and no outputs to the terminal so I can't supply anything from there. The code is as follows:

package practice1;

import javafx.application.Application;
import javafx.stage.Stage;
import java.io.IOException;
import javax.imageio.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.*;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.*;
import javafx.scene.image.ImageView;
import javafx.scene.image.*;
import java.awt.image.BufferedImage;

public class MainProgram extends Application{


    public void start(Stage stage) {



        try {

            FXMLLoader fxmlLoader = new FXMLLoader();
            String viewerFxml = "WindowPanel.fxml";
            AnchorPane page = (AnchorPane)fxmlLoader.load(
                    this.getClass().getResource(viewerFxml).openStream());
            Scene scene = new Scene(page);
            stage.setScene(scene);
            stage.show();

        } catch (IOException ex) {
            Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
            System.exit(1);
        }
    }

    public static void main(String args[]) {
        launch(args);
            System.exit(0);
        }
    }

And the FXML is as follows:

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

<?import javafx.scene.text.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="practice1.MyController">
   <children>
      <Button fx:id="TurnLeft" layoutX="113.0" layoutY="353.0" mnemonicParsing="false" onAction="#hide1" text="Turn Left" />
      <Button fx:id="TurnRight" layoutX="237.0" layoutY="353.0" mnemonicParsing="false" onAction="#hide2" text="Turn Right" />
      <ToolBar prefHeight="40.0" prefWidth="600.0">
        <items>
            <MenuButton mnemonicParsing="false" text="Pick Up">
              <items>
                <MenuItem mnemonicParsing="false" text="Action 1" />
                <MenuItem mnemonicParsing="false" text="Action 2" />
              </items>
            </MenuButton>
            <MenuButton mnemonicParsing="false" text="Drop">
              <items>
                <MenuItem mnemonicParsing="false" text="Action 1" />
                <MenuItem mnemonicParsing="false" text="Action 2" />
              </items>
            </MenuButton>
        </items>
      </ToolBar>
      <Button fx:id="proceed" layoutX="178.0" layoutY="315.0" mnemonicParsing="false" onAction="#changeImage" text="Proceed" />
      <ImageView fx:id="mainImage" fitHeight="259.0" fitWidth="426.0" layoutY="40.0" pickOnBounds="true" preserveRatio="true">
         <image>
            <Image url="@Picture1.png" />
         </image></ImageView>
      <Text layoutX="436.0" layoutY="60.0" strokeType="OUTSIDE" strokeWidth="0.0" text="You have" />
      <Text layoutX="436.0" layoutY="86.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Object1" />
      <Text layoutX="436.0" layoutY="111.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Object2" />
      <Text layoutX="436.0" layoutY="139.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Object 3" />
      <ImageView fx:id="SmallImage2" fitHeight="89.0" fitWidth="117.0" layoutX="266.0" layoutY="45.0" pickOnBounds="true" preserveRatio="true" />
      <ImageView fx:id="SmallImage3" fitHeight="89.0" fitWidth="117.0" layoutX="266.0" layoutY="142.0" pickOnBounds="true" preserveRatio="true" />
      <ImageView fx:id="SmallImage1" fitHeight="89.0" fitWidth="117.0" layoutX="152.0" layoutY="45.0" pickOnBounds="true" preserveRatio="true" />
   </children>
</AnchorPane>

The file "Picture1.png" is located in the workspace with the position being:

WorkspaceA/Practice1/scr/practice1/Picture1.png

Upvotes: 0

Views: 600

Answers (1)

jewelsea
jewelsea

Reputation: 159576

Background

The @ notation is used in JavaFX to specify a relative location which is "assumed to be located at a path relative to the current FXML file".

What is Wrong

You load the FXML as a stream using the following code:

 AnchorPane page = (AnchorPane)fxmlLoader.load(
     this.getClass().getResource(viewerFxml).openStream());

A steam is not a location, so there is no concept of locations relative to the stream.

If I run your application locally, I will get a stack trace where it cannot find the picture file (here is just the last portion of it):

Caused by: java.lang.IllegalArgumentException: Invalid URL or resource not found
at javafx.scene.image.Image.validateUrl(Image.java:1081)
... 18 more

How to fix it

Set the location in the loader prior to loading the FXML:

fxmlLoader.setLocation(getClass().getResource(viewerFxml));
AnchorPane page = fxmlLoader.load();

The loader will then be able to resolve the relative reference to your picture file.

Check your directory structure and build output

This may or may not be an issue for you.

You specify your image using the location specifier:

<Image url="@Picture1.png" />

Which tells the FXMLLoader to look for Picture1.png at the same location it got the FXML from; e.g. if you loaded the FXML from the filesystem, the image would be in the same folder on the filesystem as the FXML - similarly if you load the FXML from a jar, the image should be on the same path within the jar as your FXML was retrieved from.

You state that you place your picture at: WorkspaceA/Practice1/scr/practice1/Picture1.png. I'm not sure what that location is, but if it is the same location as your MainProgram.java source, your MyController.java source, WindowPanel.fxml and if your build system is set to copy the image and fxml over to the compile and packaging target directory, then it will work fine - if it's not, you will need to move the image to the appropriate source location.

Upvotes: 2

Related Questions