JavaFX、Scene Builder (IntelliJ) 程序从 StackOverFlow 中抛出 java.lang.reflect.InvocationTargetException

JavaFX, Scene Builder (IntelliJ) program throws java.lang.reflect.InvocationTargetException from StackOverFlow

在我的代码中,我试图为我的 Battleship 项目设置主菜单,在我将 Scene Builder 中的播放按钮分配给 MainMenu class 中的 usePlayButton 方法后,程序停止工作。这是我第一次尝试将程序链接在一起,之前我只是展示了主菜单屏幕。

偶尔,我会收到错误 "java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding",消息转换方法调用失败,位于 JPLISAgent.c 行:844" 但是,此错误似乎是随机发生的,没有任何已知原因。 运行 调试器,在我的 MainController class 中创建 mainMenu 时程序似乎崩溃了。我已经缩短了错误报告以减少 post 中使用的字符数。

错误:

Exception in Application start method
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
    at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication(LauncherImpl.java:182)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.WhosebugError
    at java.util.HashMap.hash(HashMap.java:339)
    at java.util.HashMap.get(HashMap.java:557)
    at sun.misc.JarIndex.get(JarIndex.java:175)

我已经尝试了一些我从该站点上的相关问题中看到的修复方法。我已将 src/res 文件夹设置为被 IntelliJ 视为资源文件夹。我已经尝试创建在我的 MainMenu class 中使用的按钮。我已经为我的 AnchorPane 设置了 fx:id 根目录。除其他事项外。

我的文件结构是:

主控制器

    package controllers;

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

import static javafx.fxml.FXMLLoader.load;

/**
 * The Main class handles the setup of the game and loads the JavaFX features of the program.
 * Main has the user choose the size of the board.
 * Main handles the main menu
 *
 * @author Devon X. Dalrymple
 * @version 2019.11.13-03
 */
public class MainController extends Application {


    private static Stage game;
    public MainMenu mainMenu;
    public ChooseSize chooseSize;



    /**
     * @param primaryStage stage used to run JavaFX program
     * @throws Exception thrown when the stage is not loaded correctly
     */
    @Override
    public void start(Stage primaryStage) throws Exception {

        game = primaryStage;


        mainMenu = new MainMenu();
        chooseSize = new ChooseSize();
        game.setTitle("Devon's Battleship");
        game.setScene(mainMenu.getScene());
        game.show();
    }

    /**
     * main method that launches javaFX and loads the program
     * @param args
     */
    public static void main(String[] args) {
        launch(args);
    }

    /**
     * Sets the primaryStage scene to the scene provided by the parameter
     * @param scene, Scene to change to
     */
    public void setScene(Scene scene)
    {
        game.setScene(scene);
    }
}

主菜单class:

package controllers;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;


import java.io.IOException;

/**
 * Handles the Main Menu and its buttons
 *
 * @author Devon X. Dalrymple
 * @version 2019.11.14-02
 */
public class MainMenu {

    private Parent menu;
    Scene scene;
    ActionEvent eventPlay;
    MainController mainController;
    @FXML Button playGame;
    @FXML AnchorPane root;
    @FXML Label menuLabel;
    @FXML Button rulesButton;
    @FXML Button quitButton;

    /**
     * Sets up the main menu and loads the related fxml file
     * @throws IOException
     */
    public MainMenu() throws IOException {
        playGame = new Button();
        root = new AnchorPane();
        menuLabel = new Label();
        rulesButton = new Button();
        quitButton = new Button();
        mainController = new MainController();
        menu = FXMLLoader.load(getClass().getResource("../res/MainMenu.fxml"));
        scene = new Scene(menu);
        eventPlay = new ActionEvent();
    }

    /**
     * Returns the main menu to load as the current scene
     * @return menu Main Menu of the game
     */
    public Scene getScene()
    {
        return scene;
    }

    /**
     * Connected using Scene Builder to change the scene whenever the play game button is clicked
     * @param eventPlay
     */
    public void usePlayGame(ActionEvent eventPlay)
    {
        mainController.setScene(mainController.chooseSize.getScene());
    }
}

MainMenu fxml

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane id="AnchorPane" fx:id="root" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="720.0" prefWidth="1280.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controllers.MainMenu">
  <children>
    <Label id="chooseSize" fx:id="menuLabel" layoutX="503.0" layoutY="101.0" text="Devon's Battleship" textAlignment="CENTER">
      <font>
        <Font name="System Bold" size="26.0" />
      </font>
    </Label>
    <Button id="makeTiny" fx:id="playGame" layoutX="558.0" layoutY="256.0" mnemonicParsing="false" onAction="#usePlayGame" prefWidth="166.0" text="Play Game">
      <font>
        <Font size="18.0" />
      </font>
    </Button>
    <Button id="makeTiny" fx:id="rulesButton" layoutX="558.0" layoutY="312.0" mnemonicParsing="false" prefWidth="166.0" text="How to Play">
         <font>
            <Font size="18.0" />
         </font></Button>
    <Button id="makeTiny" fx:id="quitButton" layoutX="558.0" layoutY="366.0" mnemonicParsing="false" prefWidth="166.0" text="Quit Game">
         <font>
            <Font size="18.0" />
         </font></Button>
  </children>
</AnchorPane>

选择尺寸class

package controllers;

import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;

import java.io.IOException;

/**
 * Handles the Main Menu and its buttons
 *
 * @author Devon X. Dalrymple
 * @version 2019.11.14-02
 */
public class ChooseSize {



    private Parent menu;
    Scene scene;

    /**
     * Creates the choose size scene to select board size by loading the appropriate fxml file
     * @throws IOException
     */
    public ChooseSize() throws IOException {
        menu = FXMLLoader.load(getClass().getResource("../res/ChooseSize.fxml"));
        scene = new Scene(menu);
    }

    /**
     * Returns the main menu to load as the current scene
     * @return menu Main Menu of the game
     */
    public Scene getScene() {
            return scene;
    }
}

我正在使用这个项目来教我 JavaFX,我不确定我是否犯了一些容易修复的错误,我们将不胜感激任何帮助。

public MainMenu() throws IOException { ... menu = FXMLLoader.load(getClass().getResource("../res/MainMenu.fxml")); ...} <... fx:controller="controllers.MainMenu">... This alone should result in an Whosebug even before you get the main menu loaded... – fabian

在看到 fabian 的评论并查看其他人如何编写他们的 JavaFX 程序后,我删除了 fxml 文件中对 MainMenu 的引用,并将我的程序设置更改为:

主控制器

/**
 * @param primaryStage stage used to run JavaFX program
 * @throws Exception thrown when the stage is not loaded correctly
 */
@Override
public void start(Stage primaryStage) throws Exception {

    game = primaryStage;

    MainMenu mainMenu = new MainMenu();
    ChooseSize chooseSize = new ChooseSize();

    theMainMenu = new Scene(mainMenu.getContent());
    chooseSizeMenu = new Scene(chooseSize.getContent());



    game.setTitle("Devon's Battleship");
    game.setScene(theMainMenu);
    game.show();
}

/**
 * main method that launches javaFX and loads the program
 * @param args
 */
public static void main(String[] args) throws IOException {

    launch(args);
}

/**
 * Sets the primaryStage scene to the scene provided by the parameter
 * @param sceneID, Scene to change to using its corresponding ID number
 */
public static void setScene(int sceneID)
{
    if (sceneID == 0)
    {
        game.setScene(theMainMenu);
    }
    if (sceneID == 1)
    {
        game.setScene(chooseSizeMenu);
    }

}

主菜单

/**
     * Sets up the main menu and loads the related fxml file
     * @throws IOException
     */
    public MainMenu() throws IOException {

        base = FXMLLoader.load(getClass().getResource("../res/MainMenuGUI.fxml"));

    }

    /**
     * Returns the main menu to load as the current scene
     * @return menu Main Menu of the game
     */
    public Parent getContent()
    {
        return base;
    }

    /**
     * Connected using Scene Builder to change the scene whenever the play game button is clicked
     * @param eventPlay
     */
    public void usePlayGame(ActionEvent eventPlay)
    {
        MainController.setScene(1);  //sceneID of chooseSizeMenu
    }