Все мои ссылки @FXML являются нулевыми - PullRequest
0 голосов
/ 20 мая 2018

Я пытаюсь отобразить игральные карты в FlowPane.У меня есть основной макет и вложенный макет.По какой-то причине, когда я отлаживаю, IntelliJ сообщает, что все поля на обоих контроллерах, помеченные @FXML, равны нулю.

Вот сокращенная версия того, что я получил до сих пор. Полный код на GitHub :

MainWindow.fxml

<BorderPane fx:controller="controller.MainWindowController">
    <center>
        <fx:include fx:id="tableScene" source="TableScene.fxml"/>
    </center>
</BorderPane>

MainWindowController.java

public class MainWindowController implements Initializable {
    @FXML
    MenuBar menuBar;

    @FXML
    Menu fileMenu;

    [...] more fields

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // nothing here in my code
    }

}

TableScene.fxml

<AnchorPane fx:controller="controller.TableSceneController">
    <children>
        <FlowPane fx:id="dealerHandFlowPane"></FlowPane>
        <FlowPane fx:id="playerHandFlowPane"></FlowPane>
    </children>
</AnchorPane>

TableSceneController

public class TableSceneController implements Initializable {

    @FXML
    private FlowPane dealerHandFlowPane;

    @FXML
    private FlowPane playerHandFlowPane;

    public void displayInitialHand(Player player) {
        var cards = new ArrayList<>(player.getHand().getCards());
        for (BlackjackCard card : cards) {
            if(player.getName().equals("Dealer")) {
                dealerHandFlowPane.getChildren().add(new ImageView(getCardFace(card)));
            } else {
                playerHandFlowPane.getChildren().add(new ImageView(getCardFace(card)));
            }
        }
    }

    public void displayHand(Player player) {
      var cards = new ArrayList<>(player.getHand().getCards());
    }

    public Image getCardFace(BlackjackCard card) {
        return new Image("/images/cards/" + card.getRank().getLetter()
            + card.getSuit().getLetter() + ".png");
    }

    public Image getCardBack() {
        String color[] = {"blue","red"};
        String design = "123";
        return new Image("/images/backs/" + color[0] + design.charAt(2));
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // nothing here in my code either
    }

}

BlackjackMain

public class BlackjackMain extends Application {

    private final String MAIN_WINDOW_PATH = "/fxml/MainWindow.fxml";
    private final String ICON_PATH = "/images/blackjack_icon.png";
    private final String MAIN_STYLE_PATH = "/css/MainWindow.css";
    private final String TABLE_STYLE_PATH = "/css/TableScene.css";
    private final Image MAIN_ICON = new Image(getClass().getResourceAsStream(ICON_PATH));

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("Blackjack");
        // close the app gracefully when the 'X' is clicked
        primaryStage.setOnCloseRequest(e -> Platform.exit());
        primaryStage.centerOnScreen();
        primaryStage.setResizable(false);
        initializeMainWindow(primaryStage);
        primaryStage.getIcons().add(MAIN_ICON);
        primaryStage.show();
        primaryStage.toFront();
        initializeGame();
    }

    public void initializeMainWindow(Stage primaryStage) {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource(MAIN_WINDOW_PATH));
        try {
          Parent mainWindow = loader.load();
          Scene scene = new Scene(mainWindow,600,600);
          scene.getStylesheets().add(TABLE_STYLE_PATH);
          primaryStage.setScene(scene);
        } catch (IOException e) {
          System.err.println("There was a problem loading /fxml/MainWindow.fxml");
          e.printStackTrace();
        }
    }

    public void initializeGame() {
        var tableSceneController = new TableSceneController();
        var mainWindowController = new MainWindowController();
        Dealer dealer = new Dealer();
        List<Player> allPlayers = new ArrayList<>();
        var playerName = tableSceneController.getPlayerName();
        allPlayers.add(new BlackjackPlayer(playerName));
        BlackjackGame game = new BlackjackGame(dealer, allPlayers,
            mainWindowController, tableSceneController);
        game.playGame();
    }
}

BlackjackGame.java

public class BlackjackGame implements BlackjackGameRules {

    private List<Player> playerList;
    private Deck deck;
    private Shoe shoe;
    private final TableSceneController tableSceneController;
    private final MainWindowController mainWindowController;

    public BlackjackGame(Dealer dealer, List<Player> players,
        final MainWindowController mainWindowController,
        final TableSceneController tableSceneController) {
        Objects.requireNonNull(dealer,
            "You must provide a dealer to begin the game.");
        Objects.requireNonNull(players,
            "You must provide a list of players to begin the game.");

        playerList = new ArrayList<>();

        this.tableSceneController = tableSceneController;
        this.mainWindowController = mainWindowController;

        // add dealer first for easier future access
        playerList.add(dealer);
        playerList.addAll(players);

        deck = new Deck(BlackjackGameRules.NUMBER_OF_DECKS);

        // place the shuffled deck in the shoe
        shoe = new Shoe(deck.getDeck());
    }

    public void dealInitialCards() {
        for (Player player : playerList) {
            player.getHand().addCard(shoe.dealCard());
            player.getHand().addCard(shoe.dealCard());
        }
    }

    public boolean hasValidNumberOfPlayers() {
        // this number includes the dealer
        var numPlayers = playerList.size();
        return numPlayers >= BlackjackGameRules.MIN_PLAYERS &&
            numPlayers <= BlackjackGameRules.MAX_PLAYERS;
    }

    public List<Player> getPlayers() {
        return new ArrayList<>(playerList);
    }

    public Shoe getShoe() {
        return shoe;
    }

    public void playGame() {
        dealInitialCards();

        for(Player player: playerList) {
            tableSceneController.displayInitialHand(player);
        }

    }

}

Я получаю исключение NullPointerException на displayIntitialHand в TableSceneController.Вот краткая трассировка стека:

Caused by: java.lang.NullPointerException
    at blackjack.controller.TableSceneController.displayInitialHand(TableSceneController.java:35)
    at blackjack.model.BlackjackGame.playGame(BlackjackGame.java:139)
    at blackjack.controller.BlackjackMain.initializeGame(BlackjackMain.java:70)
    at blackjack.controller.BlackjackMain.start(BlackjackMain.java:44)

За свою жизнь я не могу понять это.Где я ошибся?Я дважды проверил, что я установил имена контроллеров в атрибутах fx:controller в файлах * .fxml.Я также дважды проверил правильность атрибутов fx:id в компонентах и ​​то, что они также правильно соответствуют аннотациям @FXML в контроллере.

Мое понимание процесса JavaFX:

  1. что load() должен загрузить файл * .fxml
  2. создать экземпляр контроллера (заданный атрибутом fx:controller в файле .fxml)
  3. Вызываетконструктор без аргументов на контроллере
  4. Устанавливает значения @FXML (путем внедрения)
  5. Регистрирует любые обработчики событий
  6. Вызовы initialize на каждом контроллере

Проблема с моими вложенными fxml файлами?Если бы это было так, я бы подумал, что поля @FXML в MainWindowController.java также не будут null.Я изо всех сил пытаюсь понять это.Я мог бы использовать другой набор глаз и кого-то умнее меня.

Заранее спасибо.

1 Ответ

0 голосов
/ 20 мая 2018

Потребовалось время, чтобы понять, но когда вы создаете контроллеры для своих сцен, в пределах initializeGame() вы делаете:

    var tableSceneController = new TableSceneController();
    var mainWindowController = new MainWindowController();

Что это означает, что вы создаете новый экземпляр контроллера,а не экземпляр, который создается при загрузке файлов FXML в initializeMainWindow.

. Чтобы исправить это, я бы предложил создать переменную класса для хранения каждого из ваших контроллеров, а затем назначить их при загрузкеФайлы FXML.

Итак, в BlackJackMain.java объявите переменные класса

private TableSceneController tableSceneController;
private MainWindowController mainWindowController;

, а затем, когда вы их загружаете, я вижу, что вы загружаете главное окно в initializeMainWindow, поэтому добавьте

mainWindowController = loader.getController();

в блок try, сразу после строки loader.load.

Это разрешает ваши нулевые указатели для этой сцены, но я не могу понять, где или если вы загружаете табличную сцену FXMLи, таким образом, у вас нет экземпляра контроллера для передачи в ваш метод.Если вы загрузите файл, примените ту же логику к нему, чтобы получить экземпляр этого контроллера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...