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();
}
}
}