2

I am very new to Java FX. I am trying to create a card game application with scene builder for fun but have been having issues changing the image of ImageView components.

The src folder contains two packages, one for the all the images and the other containing all the code.

In the controller class, I've tried to change the image by using many combinations of the following, where the card is an ImageView component, which matches the fx:id of the ImageView in SceneBuilder:

card.setImage(new Image("../images/cards/As.png");

card.setImage(new Image("@../images/cards/As.png");

card.setImage(new Image(getClass().getResource("As.png").toExternalForm()));

card.setImage(new Image("File:..images/cards/As.png"));

In every scenario, I end up getting either an "Invalid URL or Resource not found" or "Null Pointer" exception.

If I go to the .fxml and edit the URL to "@../images/cards/As.png", for example, then it works but when using the setImage method I can't do it.

I got those ideas from other threads on here where they worked for other people it seems. Are my images in the wrong place? Is it not possible to change the image URL of something in the .fxml file? If anyone can help me out with this i would appreciate it very much.

Project Structure:

Project Structure:


I started a new project, called JavaFXApplication1, to test image changing functionality. I am trying to do this with the click of a button. There are two source packages, as you can see from the project structure above. There is the 'images' package that just contains all of the .pngs i want to use in my application, and then the other package is called 'javafxapplication1', containing 3 files. Below is the code for each:

FXMLDocument.fxml

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

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

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication1.FXMLDocumentController">
    <children>
        <Button fx:id="button" layoutX="126" layoutY="90" onAction="#handleButtonAction" text="Click Me!" />
        <Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
      <ImageView id="rat" fx:id="card" cache="true" fitHeight="105.0" fitWidth="118.0" layoutX="39.0" layoutY="24.0" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="39.0" AnchorPane.rightAnchor="208.68595123291016">
         <image>
            <Image url="@../images/cards/back.png" />
         </image></ImageView>
    </children>
</AnchorPane>

FXMLDocumentController.java

package javafxapplication1;

import java.io.File;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;

/**
 *
 * @author wesley
 */
public class FXMLDocumentController implements Initializable {
    
    @FXML
    private Label label;
    @FXML
    private ImageView card;
 
    @FXML
    private Button button;
    
    @FXML
    private void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
        label.setText("Hello World!");
        
        System.out.println(getClass().getResourceAsStream("/images/cards/As.png"));
        Image image = new Image(getClass().getResourceAsStream("/images/cards/As.png"));
        card.setFitHeight(726); //726
        card.setFitWidth(500); //500
        card.setImage(image);
        System.out.println("You changed the pic ");
    }
    
    @Override
    public void initialize(URL url, ResourceBundle rb) 
    {
        //File file = new File("/images/cards/Ad.png");
        //Image image = new Image(file.toURI().toString());
        card = new ImageView("images/cards/Ad.png");
        //card.setFitHeight(726); //726
       // card.setFitWidth(500); //500
    }    
 
}

JavaFXApplication1.java

package javafxapplication1;

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

/**
 *
 * @author 
 */
public class JavaFXApplication1 extends Application {
    
    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
        
        Scene scene = new Scene(root);
        
        stage.setScene(scene);
        stage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
    
}

When I run the application, It loads fine, with the image there that was defined in scene builder (Note: I use a document relative path, not sure if this is ideal or could be an issue). Upon clicking the button, the setImage call executes, but I see no change in the image. I know it executes because this is my output:

You clicked me! sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@1db87651 You changed the pic

Also, I'm not sure if I should be setting the fitHeight and width from the initialize method or not.

user10113618
  • 23
  • 1
  • 1
  • 5
  • Possible duplicate of [How can I show an image using the ImageView component in javafx and fxml?](https://stackoverflow.com/questions/22710053/how-can-i-show-an-image-using-the-imageview-component-in-javafx-and-fxml) – SedJ601 Jul 21 '18 at 04:32
  • You probably just need to figure out your project structure. I recommend the `getClass` approach. Also, check your file names and extensions. – SedJ601 Jul 21 '18 at 04:34
  • I would also recommend the `File` approach in the dubplicate answer. If you don't get to your file, you will get a `FileNotFound` exception. – SedJ601 Jul 21 '18 at 04:37
  • `@` only works in fxml. You should use a absolute resource path for `getResource()` assuming you include it in the classpath: `new Image(getClass().getResource("/images/cards/As.png").toExternalForm())` – fabian Jul 21 '18 at 07:52
  • @fabian I tried using that but I am still receiving a null pointer exception and InvocationTargetException. I Checked my structure and everything seems the same as other people in their posts. I have no idea why its not working for me. – user10113618 Jul 22 '18 at 18:37
  • Perhaps I need to add code to my initialize method? the code for the image change is in a button action event listener. – user10113618 Jul 22 '18 at 18:42
  • @Sedrick after going through that thread I added the following code to my initialize method: `card = new ImageView("/images/cards/As.png");` but nothing happens. fortunately, the null pointer exception goes away but the image doesnt change at all. it remains blank. – user10113618 Jul 24 '18 at 20:08
  • @fabian Could it be important that in scene builder i have the image URL pre defiend with a document relative path? Though when I remove the URL and try to set the image with the initialize method I don\t see anything. – user10113618 Jul 24 '18 at 20:13
  • Post your project structure. – SedJ601 Jul 24 '18 at 20:26
  • @Sedrick Thanks for the response. I edited the post to include a screenshot of my structure. The link is in the first line. – user10113618 Jul 25 '18 at 20:04
  • @Sedrick Im at a loss. are you as well? – user10113618 Aug 01 '18 at 05:01
  • @Sedrick not sure if you were notified by my other comment. I edited the post to include my MCVE. – user10113618 Aug 07 '18 at 02:52

3 Answers3

3

Your problem:

card = new ImageView("images/cards/Ad.png");

This is invalid code. You created the card in the FXML. When you say = new ImageView(...);, you are effectively no longer referencing the Card/ImageView create in the FXML.

If you need to initialize the Card/ImageView in the initialize method do:

@Override
public void initialize(URL url, ResourceBundle rb)
{
    Image image = new Image(getClass().getResourceAsStream("/images/cards/Ad.png"));
    card.setFitHeight(100); //726
    card.setFitWidth(200); //500
    card.setImage(image);
}
SedJ601
  • 12,173
  • 3
  • 41
  • 59
  • it outputs: sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@21f1dc4d But unfortunately I still see no change in the image – user10113618 Jul 25 '18 at 22:44
  • If you are getting this, you should be good. Are you setting the `fitHeight` and `fitWidth`? – SedJ601 Aug 01 '18 at 05:56
  • I tried adding the following code both in the initialize method and in the button event method before and after the setImage call: ` card.setFitHeight(726); card.setFitWidth(500);` Still no change. – user10113618 Aug 02 '18 at 21:56
  • You need to create a MCVE that demos your problem. – SedJ601 Aug 02 '18 at 21:58
  • I edited the post to include my actual code. Thanks again for your help so far, hopefully I made my issue more clear/easy to recreate. – user10113618 Aug 04 '18 at 21:17
  • Sedrick I have a new problem with my ImageViews that you may be able to help me with. If you can find the time, I would appreciate it very much. The problem can be found here: https://stackoverflow.com/questions/52213660/java-fx-unable-to-initialize-and-change-the-images-for-multiple-imageviews – user10113618 Sep 07 '18 at 00:17
0

There are two methodsTo load images (I prefare)
The way mentioned by Sedrick is used when you wanna embed the images folder inside the jar (package) file, But if you wanna make the jar light weight and leave the images folder outside of the jar I'd rather use this way

card.setImage(new Image("file:images/cards/As.png"));

where file keyword make the file browser start looking from the project folder in our case JavaFXApplication1

Ahmed Emad
  • 674
  • 6
  • 19
  • Thanks for the response. I tried that and I still see no change in the image. I have no idea what the issue is. Like I said before, Could it be due to my code in my initialize method? or maybe because I have the image url predefined in the FXMLDocumentController.? Would I not want to set that if I want the image to be subject to change? Also, if I ever wanted to export this application as a standalone executable, wouldn't I want the images folder inside the package file? – user10113618 Jul 25 '18 at 22:49
0

The most consistent way I could do it - using Netbeans as my IDE - was

new Image(JavaFXApplication1.class.getClass().getResource("/img/card.jpg").toString());

And my project directory source structure has the img directory on the same level as the package. From the file system, from the .java file it is ../img/card.jpg, but using GetResource points it to the equivalent of your .../JavaFXApplication1/src/ directory

ivanivan
  • 2,155
  • 2
  • 10
  • 11
  • Thanks for the response. I tried that and I still see no change in the image. I have no idea what the issue is. Like I said before, Could it be due to my code in my initialize method? or maybe because I have the image url predefined in the FXMLDocumentController.? Would I not want to set that if I want the image to be subject to change? – user10113618 Jul 25 '18 at 22:47