JavaFX Fehler bei ImageView, Invalid URL

Siero

Mitglied
Moin,
Ich versuche eine Memoryspiel mit javax zu konstruieren, jedoch klappt das nicht. Den Code habe ich aus einem Studienheft von meiner Weiterbildung. Das ganze baue ich mit Eclipse.
ich bekomme ständig diese Fehlermeldung und habe schon mehrere Stunden mich zu tode gegoogelt. Aber nichts funktionierte. Ich habe das Problem nun eingrenzen können und vermute das irgendwas mit ImageView von javafx nicht stimmt.
Die Fehlermeldung lautet:

Exception in Application start method
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1082)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.IllegalArgumentException: Invalid URL: Invalid URL or resource not found
at javafx.graphics/javafx.scene.image.Image.validateUrl(Image.java:1125)
at javafx.graphics/javafx.scene.image.Image.<init>(Image.java:618)
at javafx.graphics/javafx.scene.image.ImageView.<init>(ImageView.java:194)
at Memory.MemoryKarte.<init>(MemoryKarte.java:32)
at Memory.MemoryFeld.kartenZeichnen(MemoryFeld.java:58)
at Memory.MemoryFeld.initGUI(MemoryFeld.java:38)
at Memory.MemoryFX.start(MemoryFX.java:11)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
... 1 more
Caused by: java.lang.IllegalArgumentException: Invalid URL or resource not found
at javafx.graphics/javafx.scene.image.Image.validateUrl(Image.java:1117)
... 15 more
Exception running application Memory.MemoryFX

----------------------------------------------------------------------------------------------------------------------------

Ich habe auch schon versucht das per getClass umzusetzen, bekomme jedoch dann diese Fehlermeldung
getClass.PNG

----------------------------------------------------------------------------------------------------------------------------------------------------
im originalzustand kommt dieser Hinweis, ich weiß nicht ob das wichtig ist.
Java_Popup.PNG

----------------------------------------------------------------------------------------------------------------------------------

Ich stelle noch den gesamten Code mal rein und die Strukturen dahinter.

Die Strukturen
tree.PNG

---------------------------------------------------------------------------------------------------------------------------
und die Ordner Struktur
ordner.PNG
in dem Ordner grafiken befinden sich die Bilder.

path.PNG

vmpath.PNG
-----------------------------------------------------------------------------------------------------------

Nun der Code:
Code:
package Memory;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.image.ImageView;


public class MemoryKarte extends Button {
    private int bildID;
    private ImageView bildVorne, bildHinten;
    private int bildPos;
    private boolean umgedreht,imSpiel;
  
  
  
    class KartenListener implements EventHandler<ActionEvent>{
        @Override
        public void handle(ActionEvent arg0) {
            if (imSpiel == false) {
                return;
            }
            if(umgedreht == false) {
                setGraphic(bildVorne);
                umgedreht = true;
            }
        }
    }
  
    public MemoryKarte(String vorne, int bildID) {
        System.out.println(vorne + bildID);
        bildVorne = new ImageView(getClass().getResource(vorne));
        System.out.println(bildVorne);
        bildHinten =new ImageView("grafiken/hinten.jpg");
        setGraphic(bildHinten);
      
        this.bildID = bildID;
        umgedreht = false;
        imSpiel = true;
        setOnAction(new KartenListener());
    }
  
    public void rueckseiteZeigen(boolean rausnehmen) {
        if(rausnehmen == true) {
            setGraphic(new ImageView("grafiken/aufgedeckt.jpg"));
            imSpiel = false;
        }else {
            setGraphic(bildHinten);
            umgedreht = false;
        }
    }
  
    public int getBildID() {
        return bildID;
    }
  
    public int getBildPos() {
        return bildPos;
    }
  
    public void setBildPos(int bildPos) {
        this.bildPos = bildPos;
    }

}

---------------------------------------------------------------------------------------------
Code:
package Memory;

import javafx.application.Application;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
import javafx.scene.Scene;

public class MemoryFX extends Application{
  
    public void start(Stage meineStage) throws Exception{
        FlowPane rootNode = new MemoryFeld().initGUI(new FlowPane());
        Scene meineScene = new Scene(rootNode, 480, 550);
        meineStage.setTitle("Memory");
        meineStage.setResizable(false);
        meineStage.setScene(meineScene);
        meineStage.show();
    }

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

    }

}
----------------------------------------------------------------------------------------------------------------
Code:
package Memory;

import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;

public class MemoryFeld {
    private MemoryKarte[] karten;
    private String[] bilder = {
                              
                                "grafiken/apfel.jpg","grafiken/birne.jpg", "grafiken/blume.jpg","grafiken/blume2.jpg", "grafiken/ente.jpg", "grafiken/fisch.jpg", "grafiken/fuchs.jpg", "grafiken/igel.jpg", "grafiken/kaengeruh.jpg",
                                "grafiken/katze.jpg", "grafiken/kuh.jpg", "grafiken/maus1.jpg","grafiken/maus2.jpg", "grafiken/maus3.jpg", "grafiken/maus4.jpg", "grafiken/melone.jpg", "grafiken/pilz.jpg", "grafiken/ronny.jpg",
                                "grafiken/schmetterlingg.jpg", "grafiken/sonne.jpg", "grafiken/wolke.jpg"
                               };
  
    private int menschPunkte, computerPunkte;
    private Label menschPunkteLabel, computerPunkteLabel;
    private int umgedrehteKarten;
    private MemoryKarte[] paar;
    private int spieler;
    private int [] [] gemerkteKarten;
  
    public MemoryFeld() {
        karten = new MemoryKarte[42];
        paar = new MemoryKarte[2];
        gemerkteKarten = new int [2][21];
        menschPunkte = 0;
        computerPunkte = 0;
        umgedrehteKarten =0;
        spieler = 0;
      
        for(int aussen = 0; aussen <2; aussen ++)
            for(int innen = 0; innen <21; innen ++)
                gemerkteKarten[aussen][innen] = -1;
    }
      
    public FlowPane initGUI(FlowPane feld) {
        kartenZeichnen(feld);
        menschPunkteLabel = new Label();
        computerPunkteLabel = new Label();          
        menschPunkteLabel.setText(Integer.toString(menschPunkte));
        computerPunkteLabel.setText(Integer.toString(computerPunkte));
      
        GridPane tempGrid = new GridPane();
        tempGrid.add(new Label("Mensch"), 0, 0);
        tempGrid.add(menschPunkteLabel, 1, 0);
        tempGrid.add(new Label("Computer"), 0, 1);
        tempGrid.add(computerPunkteLabel, 1, 1);
        feld.getChildren().add(tempGrid);
        return feld;
      
    }
  
    private void kartenZeichnen(FlowPane feld) {
        int count = 0;
        for(int i = 0; i <= 41; i ++) {
            System.out.println(bilder[count]);
            karten = new MemoryKarte(bilder[count], count);
            System.out.println(bilder[count]);
            if((i+1)%2 == 0){
                count++;
            }
        }
        for(int i = 0; i<=41; i++) {
            feld.getChildren().add(karten);
            karten.setBildPos(i);
        }
    }
   
   
   

}
---------------------------------------------------------------------------
Ich hänge da jetzt schon seit 2 Tagen dran und so langsam gehen mir die Ideen aus. Logisch kann ich es eingrenzen und zwar hat der ImageView ein Problem den Pfad aufzulösen.
Ich habe den Pfad in einer anderen Anwendung getestet und da hat der er wunderbar Funktioniert.

MfG
 
Die Stack-Traces müssen von unten nach oben gelesen werden, da Exceptions oft gefangen und dann eine andere Exception geworfen wird. Und da dann etwas hoch gehen, bis Du auch Deinen Code erwähnt siehst (Das ist die zweite Exception von unten).

Bei Dir bedeutet dies:
Caused by: java.lang.IllegalArgumentException: Invalid URL: Invalid URL or resource not found

Und der Fehler ist bei Dir hier zu finden:
at Memory.MemoryKarte.<init>(MemoryKarte.java:32)

Und diese Stelle hattest Du ja schon gefunden. Du versuchst, eine ImageView zu laden. Der String Parameter muss eine URL angeben, wo das Bild, das geladen werden soll, zu finden ist. Das ist bei Dir also in dem Parameter vorne. Was hast Du in dem Parameter vorne übergeben? (Ich habe das jetzt nicht durchgesehen)

Was der übliche Weg ist:
  • Du packst diese Bilder als Ressourcen in dem eclipse Projekt mit in den src Ordner. (Das ist eclipse spezifisch. Maven oder Gradle Projekte wollen die Ressourcen in src/main/resources/ !!!)
  • Dann bekommst Du die URL per Klassenname.class.getResource("/pfad/resource") also z.B. MemoryKarte.class.getResource("/images/vorne.png").toString()
so du in src/images/ die Datei vorne.png haben solltest.
Das .toString wird notwendig, da die Methode eine URL zurück gibt und keinen String und Du einen String brauchst.

Das wäre, was mir hier so direkt in den Sinn kommen würde.


Edit: Jetzt beim Blick auf den genauen Code habe ich gesehen: Du hast es teilweise ja schon drin, dass eine Ressource geladen wird. Aber bei einem Aufruf fehlt es. Aber die Strings mit den Bildern sollten alle mit / starten!

Die Konkreten Anpassungen könnten sein:
a) / vor jeden Pfad bei den Bildern hinzufügen:
Java:
    private String[] bilder = {
                             
                                "/grafiken/apfel.jpg","/grafiken/birne.jpg", "/grafiken/blume.jpg","/grafiken/blume2.jpg", "/grafiken/ente.jpg", "/grafiken/fisch.jpg", "/grafiken/fuchs.jpg", "/grafiken/igel.jpg", "/grafiken/kaengeruh.jpg",
                                "/grafiken/katze.jpg", "/grafiken/kuh.jpg", "/grafiken/maus1.jpg","/grafiken/maus2.jpg", "/grafiken/maus3.jpg", "/grafiken/maus4.jpg", "/grafiken/melone.jpg", "/grafiken/pilz.jpg", "/grafiken/ronny.jpg",
                                "/grafiken/schmetterlingg.jpg", "/grafiken/sonne.jpg", "/grafiken/wolke.jpg"
                               };

b) MemoryKarte anpassen, um mit diesen Strings Ressourcen zu laden:
Java:
    public MemoryKarte(String vorne, int bildID) {
        System.out.println(vorne + bildID);
        bildVorne = new ImageView(getClass().getResource(vorne).toString()); // Hier hast Du das Laden per Resource schon versucht, aber es fehlte bei Dir das .toString()
        System.out.println(bildVorne);
        bildHinten =new ImageView(getClass().getResource("grafiken/hinten.jpg").toString()); // Dies habe ich dann auch noch angepasst
        setGraphic(bildHinten);
     
        this.bildID = bildID;
        umgedreht = false;
        imSpiel = true;
        setOnAction(new KartenListener());
    }

c) Die Bilder müssen jetzt natürlich noch nach src/grafiken/ - was ich auf den Bildschirmfotos gesehen habe, fehlten die noch.
 
Zuletzt bearbeitet:
Ach ja - es könnte natürlich auch funktionieren, wenn Du dafür sorgst, dass Du das Programm da startest, wo auch Dein Ordner grafiken ist. Eclipse startet Programme wohl aus dem Projektverzeichnis - daher könnte es als erster Schritt reichen, dass Du das Verzeichnis grafiken mit allen Bildern neben das src Verzeichnis legst. Das könnte für den Start in Eclipse ausreichen.

Aber das führt aber spätestens dann zu Problemen, wenn Du das Spiel z.B. weiter geben willst oder so. Daher empfehle ich den Weg, den ich zuerst beschrieben habe.
 
Moin, danke für die tolle Antwort. Ich habe das nun so umgesetzt und bekomme direkt den nächsten fehler.....

"Cannot invoke "java.net.URL.toString()" because the return value of "java.lang.Class.getResource(String)" is null"​

ich habe die Bilder mittlerweile in sämtliches Ordnern des Projektes gepackt, aber nichts funktioniert.
das ist mal echt anstrengend mittlerweile.
 
OK, das besagt, dass getResource null zurück gegeben hat - die Ressource wurde nicht gefunden.

Daher wären meine Fragen jetzt:
  • Wo liegen die Bilder? (der Ordner grafiken sollte direkt im src Ordner sein.)
  • Mit welchem String versuchst Du es? Hast Du da die / am Anfang hinzu gefügt?

Und ich sehe gerade: An einer Stelle habe ich selbst vergessen ein / hinzu zu fügen: Beim hinten Bild:
bildHinten =new ImageView(getClass().getResource("/grafiken/hinten.jpg").toString());
 

Zurück
Oben