0

I'm trying to finish my first solo project in Java with JavaFX and SceneBuilder. First of all, sorry for my bad English, and I'm new here too. Sorry if there is already a questions like this.

I'm trying to build a easy animal quiz with 3 different modes (kid, normal, hard). In the first scene you have to choose a mode. The first on works like I want, kidM.

Now I just copied the FXML to have the same layout and style for the normal mode.

Then I did a 2nd array list with images, options and answers. Now I'm trying to load the pictures and answers from the list. There is the problem. The first picture and radio buttons show well; after the second image, I get errors, and it doesn't refresh the img or the radio buttons. I tried all what I knew but didn't get it work.

I will share the code of the 3 classes and would appreciate it if anyone can show or explain me a solution.

The most of the code I put in one class, it is not really structured and a lots of duplicate or bad code.

I have said its my first project so please don't be to hard with me or the code. I appreciate all answers and help.

Update of the error:

Caused by: java.nio.file.InvalidPathException: Illegal char <:> at index 11: normal\file:\C:\Users\Student\java\projects\Spielkind\target\classes\img\normal\borkshireterrier.jpg
    at java.base/sun.nio.fs.WindowsPathParser.normalize(WindowsPathParser.java:182)
    at java.base/sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:153)
    at java.base/sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:77)
    at java.base/sun.nio.fs.WindowsPath.parse(WindowsPath.java:92)
    at java.base/sun.nio.fs.WindowsFileSystem.getPath(WindowsFileSystem.java:232)
    at java.base/jdk.internal.module.Resources.toSafeFilePath(Resources.java:143)
    at java.base/jdk.internal.module.Resources.toFilePath(Resources.java:97)
    at java.base/jdk.internal.module.ModuleReferences$ExplodedModuleReader.open(ModuleReferences.java:397)
    at java.base/jdk.internal.loader.BuiltinClassLoader.findResourceAsStream(BuiltinClassLoader.java:305)
    at java.base/java.lang.Class.getResourceAsStream(Class.java:2890)
    at com.example.spielkind/com.example.spielkind.HelloController.updateImageAndOptionsN(HelloController.java:114)
    at com.example.spielkind/com.example.spielkind.HelloController.onWeiterClickN(HelloController.java:149)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    ... 53 more

Code:

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

import java.util.Optional;

public class HelloController {


    @FXML
    private ToggleGroup radioGroup;
    @FXML
    private AnchorPane root;
    @FXML
    private ImageView nextBild, minusBtn, closeBtn;
    @FXML
    private Button weiterBtn, dateiBtn;
    @FXML
    private RadioButton radioBtn1, radioBtn2, radioBtn3, radioBtn4;
    @FXML
    private Pane titlePane;
    @FXML
    private Label antwortField, lifeLabel;
    @FXML
    private String[] images = {"img/image1.jpg", "img/image2.jpg", "img/image3.jpg", "img/elefant.jpg", "img/ente.jpg", "img/faultier.jpg", "img/fisch.jpg", "img/giraffen.jpg", "img/hamster.jpg", "img/igel.jpg", "img/krokodil.jpg", "img/kuh.jpg", "img/lahm.jpg", "img/pinquin.jpg", "img/quale.jpg", "img/tauben.jpg", "img/tiger.jpg", "img/wolf.jpg", "img/zebra.jpg"};
    @FXML
    private String[][] options = {{"Maus", "Hamster", "Affe","Faultier"},{"Taube", "Flamingo", "Enten", "Schwann"}, {"Fisch", "Schildkröte", "Elefant", "Qualle"}, {"Hase", "Elefant", "Papagei", "Reh"}, {"Eichhörnchen", "Vogel", "Maus", "Ente"},
            {"Fuchs", "Katze", "Faultier", "Tiger"}, {"Fisch", "Zebra", "Bär", "Hei"},{"Nashorn", "Seepferd", "Nilpferd","Giraffe"} , {"Maus","Hamster","Katze","Schlange"},{"Igel","Känguru","Wal","Spinne"}, {"Biber","Delfin","Krokodil","Esel"},{"Dachs","Kuh","Elch","Frosch"}, {"Lahm","Fuchs","Adler","Gepard"} ,{ "Vogel","Pinguin","Affe","Seepferd"},{"Löwe","Quale","Seepferd","Fische"},
            {"Spechte","Ente","Taube","Rabe"},{ "Löwe","Tiger","Leopard","Guanako"}, {"Hund","Wolf","Reh","Schaaf"}, {"Elefant","Pferd","Zebra","Giraffe"}};

    @FXML private String[] imagesN = {
            getClass().getResource("/img/normal/ziesel.jpg").toExternalForm(),
            getClass().getResource("/img/normal/borkshireterrier.jpg").toExternalForm()
    };
    private String[][] optionsN = {{"Maus", "ziesel", "Erdmänchen","Faultier"},{"Taube", "yorkshire-terrier", "Enten", "Schwann"}};
    @FXML private int [] correctAnswersN ={1,1};
    @FXML
    private int[] correctAnswers = {2, 1, 1, 1, 3, 2, 0, 3, 1, 0, 2, 1, 0, 1, 1, 2, 1, 1, 2};


    private double x, y;
    @FXML
    private Button kidM, normM, hardM;
    @FXML
    private IntegerProperty lifeV = new SimpleIntegerProperty(3);
    private int counterIndex = 0;
    private int maxIndex = images.length -1;



   @FXML void move(Stage stage) {
        titlePane.setOnMousePressed(mouseEvent -> {
            x = mouseEvent.getSceneX();
            y = mouseEvent.getSceneY();
        });

        titlePane.setOnMouseDragged(mouseEvent -> {
            stage.setY(mouseEvent.getScreenY() - y);
            stage.setX(mouseEvent.getScreenX() - x);
        });

        closeBtn.setOnMouseClicked(mouseEvent -> stage.close());
        minusBtn.setOnMouseClicked(mouseEvent -> stage.setIconified(true));
    }



    @FXML
    void initialize() {
        radioGroup = new ToggleGroup();
        radioBtn1.setToggleGroup(radioGroup);
        radioBtn2.setToggleGroup(radioGroup);
        radioBtn3.setToggleGroup(radioGroup);
        radioBtn4.setToggleGroup(radioGroup);
        weiterBtn.setDisable(true);


        updateImageAndOptions();


    }

    @FXML
    void onWeiterClick(ActionEvent event) {
        checkSelection();
        if (lifeV.get() == 0) {
            showGameOverDialog();
        } else if (counterIndex == maxIndex) {
            showCongratulationsDialog();
        } else {
            counterIndex = (counterIndex + 1) % images.length;
            updateImageAndOptions();
            weiterBtn.setDisable(true);
        }
    }
    @FXML
    void onWeiterClickN(ActionEvent event) {
        checkSelectionN();
        if (lifeV.get() == 0) {
            showGameOverDialog();
        } else if (counterIndex == maxIndex) {
            showCongratulationsDialog();
        } else {
            counterIndex = (counterIndex + 1) % imagesN.length;
            updateImageAndOptionsN();
            weiterBtn.setDisable(true);
        }
    }
    private void checkSelectionN() {
        int selectedOptionIndex = -1;
        if (radioBtn1.isSelected()) {
            selectedOptionIndex = 0;
        } else if (radioBtn2.isSelected()) {
            selectedOptionIndex = 1;
        } else if (radioBtn3.isSelected()) {
            selectedOptionIndex = 2;
        } else if (radioBtn4.isSelected()) {
            selectedOptionIndex = 3;
        }

        if (counterIndex < correctAnswersN.length) {
            if (selectedOptionIndex == correctAnswersN[counterIndex]) {
                antwortField.setStyle("-fx-text-fill:#02b12a ; -fx-font-size: 20px; -fx-font-weight:bold;");
                antwortField.setText("Richtige Antwort");
            } else {
                String correctOption = optionsN[counterIndex][correctAnswers[counterIndex]];
                lifeLabel.textProperty().bind(lifeV.asString());
                lifeV.set(lifeV.get() - 1);
                antwortField.setStyle("-fx-text-fill: red; -fx-font-size: 20px;");
                antwortField.setText("Falsche Antwort! Die richtige Antwort lautet: " + correctOption);
            }
        }
    }
    private void checkSelection() {
        int selectedOptionIndex = -1;
        if (radioBtn1.isSelected()) {
            selectedOptionIndex = 0;
        } else if (radioBtn2.isSelected()) {
            selectedOptionIndex = 1;
        } else if (radioBtn3.isSelected()) {
            selectedOptionIndex = 2;
        } else if (radioBtn4.isSelected()) {
            selectedOptionIndex = 3;
        }

        if (counterIndex < correctAnswers.length) {
            if (selectedOptionIndex == correctAnswers[counterIndex]) {
                antwortField.setStyle("-fx-text-fill:#02b12a ; -fx-font-size: 20px; -fx-font-weight:bold;");
                antwortField.setText("Richtige Antwort");
            } else {
                String correctOption = options[counterIndex][correctAnswers[counterIndex]];
                lifeLabel.textProperty().bind(lifeV.asString());
                lifeV.set(lifeV.get() - 1);
                antwortField.setStyle("-fx-text-fill: red; -fx-font-size: 20px;");
                antwortField.setText("Falsche Antwort! Die richtige Antwort lautet: " + correctOption);
            }
        }
    }

    void showCongratulationsDialog(){
        Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
        alert.setTitle("Herzlichen Glückwunsch");
        alert.setHeaderText("Du hast gewonnen, glückwunsch!");
        alert.setContentText("Du hast alle Bildern durchgespielt");

        ButtonType buttonTypeOk = new ButtonType("Ok");
        alert.getButtonTypes().setAll(buttonTypeOk);

        alert.showAndWait();

        loadStartBildFxml();
    }


    private void loadStartBildFxml() {
        try {

            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("startBild.fxml"));
            Parent root = fxmlLoader.load();
            Stage stage = (Stage) titlePane.getScene().getWindow();
            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.show();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void showGameOverDialog(){
        Alert alert = new Alert (Alert.AlertType.CONFIRMATION);
        alert.setTitle("GameOver");
        alert.setHeaderText("Game Over");
        alert.setContentText("Sie haben alle Leben verloren. Möchtest du es nochmal versuchen?");

        ButtonType buttonNein = new ButtonType("Nein");
        ButtonType buttonJa = new ButtonType("Ja");

        alert.getButtonTypes().setAll(buttonNein,buttonJa);

        Optional<ButtonType> result = alert.showAndWait();

        if (result.isPresent() && result.get() == buttonJa){
            counterIndex = 0;
            lifeV.set(3);
            updateImageAndOptions();
        }else {
            loadStartBildFxml();
        }
        }



    @FXML
    void onDateiClick(ActionEvent event) {
        try {
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("startBild.fxml"));
            Parent root = fxmlLoader.load();
            Stage stage = new Stage();
            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.show();


            ((Stage) dateiBtn.getScene().getWindow()).close();
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    @FXML
    private void updateImageAndOptions() {
        String imagePath = "/" + images[counterIndex];
        Image image = new Image(getClass().getResourceAsStream(imagePath));
        nextBild.setImage(image);
        String[] currentOptions = options[counterIndex];
        radioBtn1.setText(currentOptions[0]);
        radioBtn2.setText(currentOptions[1]);
        radioBtn3.setText(currentOptions[2]);
        radioBtn4.setText(currentOptions[3]);
        radioBtn1.setSelected(false);
        radioBtn2.setSelected(false);
        radioBtn3.setSelected(false);
        radioBtn4.setSelected(false);
    }

    @FXML
    private void updateImageAndOptionsN() {
        String imagePath = "normal/" + imagesN[counterIndex];
        Image image = new Image(getClass().getResourceAsStream(imagePath));
        nextBild.setImage(image);
        String[] currentOptions = optionsN[counterIndex];
        radioBtn1.setText(currentOptions[0]);
        radioBtn2.setText(currentOptions[1]);
        radioBtn3.setText(currentOptions[2]);
        radioBtn4.setText(currentOptions[3]);
        radioBtn1.setSelected(false);
        radioBtn2.setSelected(false);
        radioBtn3.setSelected(false);
        radioBtn4.setSelected(false);
    }

    public void loadQuestionN() {

        Image image = new Image(imagesN[counterIndex]);
        nextBild.setImage(image);

        radioBtn1.setText(optionsN[counterIndex][0]);
        radioBtn2.setText(optionsN[counterIndex][1]);
        radioBtn3.setText(optionsN[counterIndex][2]);
        radioBtn4.setText(optionsN[counterIndex][3]);

        int correctAnswer = correctAnswersN[counterIndex];
        weiterBtn.setDisable(true);
        radioGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue != null) {
                weiterBtn.setDisable(false);
            }
        });
    }

    @FXML
    void onRadioButtonSelected(ActionEvent event) {
        RadioButton selectedRadioButton = (RadioButton) radioGroup.getSelectedToggle();
        if (selectedRadioButton != null) {
            weiterBtn.setDisable(false);
        } else {
            weiterBtn.setDisable(true);
        }
    }
}
public class HelloApplication extends Application {

    @FXML
    Button kidM, normM ;

    @FXML
    ImageView MinusBtn, exitBtn;

    @FXML
    private Pane titleFens;

    private double x ,y ;

    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("startBild.fxml"));
        Parent root = fxmlLoader.load();
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.initStyle(StageStyle.TRANSPARENT);
        scene.setFill(Color.TRANSPARENT);

        root.setOnMousePressed(mouseEvent -> {
            x = mouseEvent.getSceneX();
            y = mouseEvent.getSceneY();
        });

        root.setOnMouseDragged(mouseEvent-> {
            primaryStage.setX(mouseEvent.getScreenX() - x);
            primaryStage.setY(mouseEvent.getScreenY()- y);
        });

        primaryStage.show();

    }

    @FXML
    void onKidsClick(ActionEvent event) {

        auswahlFenster af = new auswahlFenster();
        af.zeigeFensterK((Stage) kidM.getScene().getWindow());
    }

    @FXML
    void onNormalClick(ActionEvent event) {

       auswahlFenster afN = new auswahlFenster();
       afN.zeigeFensterN((Stage) normM.getScene().getWindow());

    }

    @FXML
    void onHardClick(ActionEvent event) {

    }

    @FXML
    void onExitClick(MouseEvent event) {
    Stage stage = (Stage) exitBtn.getScene().getWindow();
    stage.close();
    }

    @FXML
    void onMinusClick(MouseEvent event) {

        Stage stage =(Stage) MinusBtn.getScene().getWindow();
        stage.setIconified(true);
    }


    public static void main(String[] orgs) {
        launch(orgs);
    }
}
public class auswahlFenster {

    public void zeigeFensterK(Stage primaryStage){

        try{
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Spiel.fxml"));
            Parent root = fxmlLoader.load();
            Stage stage = new Stage();
            Scene scene = new Scene(root);
            scene.setFill(Color.TRANSPARENT);
            stage.initStyle(StageStyle.TRANSPARENT);

            stage.setTitle("Bilder-Spiel");
            ScaleTransition fd = new ScaleTransition(Duration.seconds(1.3),root);
            fd.setFromX(0.3);
            fd.setFromY(0.3);
            fd.setToX(1.0);
            fd.setToY(1.0);
            fd.play();

            FadeTransition fid = new FadeTransition(Duration.seconds(2),root);
            fid.setFromValue(0.3);
            fid.setToValue(1.0);
            fid.play();

            stage.setScene(scene);
            stage.show();

            HelloController helloController = fxmlLoader.getController();
            helloController.move(stage);

            primaryStage.close();



        }catch(Exception ex){
            ex.printStackTrace();
        }
    }

    public void zeigeFensterN(Stage primaryStage) {

        try {
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("normal.fxml"));
            Parent root = fxmlLoader.load();

            HelloController controller = fxmlLoader.getController();
            controller.move(primaryStage);
            Stage stage = new Stage();
            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.show();

            controller.loadQuestionN();
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
}
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
chikofra
  • 1
  • 2
  • Please [edit] your question to include the text of the error you get and a [mre] that produces that error. – trashgod Jul 07 '23 at 12:02
  • 4
    The stack trace is pretty clear, isn't it? The URL you are providing contains an illegal character (a `:` at an unexpected position). This is because you're converting a path to a URL and storing it as a string in the `imagesN` array (so those strings have schemas in them), and then preprending `"normal/"` to that complete URL, and then you're trying to convert the result (which will look something like `"normal/file:/.../img/..."` or `"normal/jar:/.../img/..."`) itself to a URL. So you end up with a string that has two schemas in it. – James_D Jul 07 '23 at 14:09
  • Thank you guys for the fast answers and for edit my text. i tried a few changes aggain but every time i get the same error. And if i try to do it just like on the easy mode i get a error: Invalid Url or resource not found. this error comes with that changes : private String[] imagesN = {"/img/normal/ziesel.jpg","/img/normal/borkshireterrier.jpg"}; private void updateImageAndOptionsN() { String imagePath = imagesN[counterIndex]; Image image = new Image(getClass().getResourceAsStream(imagePath)); i tried a lot but doesnt work well like the Kid mode=( – chikofra Jul 07 '23 at 22:20
  • @chikofra info on [finding resources](https://stackoverflow.com/questions/61531317/how-do-i-determine-the-correct-path-for-fxml-files-css-files-images-and-other) and a [tutorial on the same, from Eden](https://edencoding.com/where-to-put-resource-files-in-javafx/). Ensure that you have resources available in the appropriate locations and are using the correct lookup string to find them as per the guides. If issues continue, follow the troubleshooting steps from the guides. – jewelsea Jul 07 '23 at 22:38
  • Unfortunately, the Eden coding site is gone and the domain has been usurped, which means the site is probably not coming back to that domain. You need to use the [wayback machine to see the content](https://web.archive.org/web/20230608170212/https://edencoding.com/where-to-put-resource-files-in-javafx/) :-( – jewelsea Jul 07 '23 at 22:46
  • 2
    Thank you all again for your answers and links to read. After read the link and try aggain, it could load correctly the images. Now i just need to fix some little bugs. Thanks aggain it helps me a lot to improve my english and learn a bit more about java =). best regards and a wonderful weekend. – chikofra Jul 08 '23 at 11:30
  • Off topic, but your English is fine. If you would like writing assistance, try [Grammarly](https://www.grammarly.com/). – jewelsea Jul 08 '23 at 23:49
  • Thanks very much i will check it out :) – chikofra Jul 10 '23 at 07:03

0 Answers0