我试图在FlowPane中显示扑克牌。我有一个主要布局和嵌套布局。出于某种原因,当我调试IntelliJ报告时,在两个控制器上使用@FXML注释的所有字段都为空。
这是我迄今所获得的缩短版本。 Full Code on GitHub:
<BorderPane fx:controller="controller.MainWindowController">
<center>
<fx:include fx:id="tableScene" source="TableScene.fxml"/>
</center>
</BorderPane>
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
}
}
<AnchorPane fx:controller="controller.TableSceneController">
<children>
<FlowPane fx:id="dealerHandFlowPane"></FlowPane>
<FlowPane fx:id="playerHandFlowPane"></FlowPane>
</children>
</AnchorPane>
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
}
}
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();
}
}
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);
}
}
}
我在TableSceneController中的displayIntitialHand上得到一个NullPointerException。这是简短的堆栈跟踪:
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)
对于我的生活,我无法想象这一个。我哪里出错了?我已经仔细检查过,我已经在* .fxml文件的fx:controller
属性中设置了控制器的名称。我还仔细检查了组件中fx:id
属性是否正确,以及它们是否也正确匹配控制器中的@FXML
注释。
我对JavaFX过程的理解是:
load()
应该加载* .fxml文件fx:controller
属性指定)initialize
我的嵌套fxml
文件有问题吗?如果是这种情况,我认为MainWindowController.java
中的@FXML字段也不会是null
。我正在努力解决这个问题。我可以使用另一组眼睛和比我更聪明的人。
提前致谢。
答案 0 :(得分:1)
花了一段时间才弄明白,但是当您为场景创建控制器时,在initializeGame()
内你会做:
var tableSceneController = new TableSceneController();
var mainWindowController = new MainWindowController();
这意味着您要创建控制器的新实例,而不是在initializeMainWindow
内加载FXML文件时创建的实例。
为了解决这个问题,我建议创建一个类变量来保存每个控制器,然后在加载FXML文件时分配它们。
因此,在BlackJackMain.java
中,声明类变量
private TableSceneController tableSceneController;
private MainWindowController mainWindowController;
然后当你加载它们时,我可以看到你在initializeMainWindow
加载主窗口,所以添加
mainWindowController = loader.getController();
到try块后面,就在loader.load
行之后。
这解决了这个场景的空指针,但我无法弄清楚你在何处或是否加载了表场景FXML,因此你没有控制器的实例传递给你的方法。如果您确实加载了该文件,请对其应用相同的逻辑以获取该控制器的实例。