【发布时间】:2018-05-20 04:47:07
【问题描述】:
我正在尝试在 FlowPane 中显示扑克牌。我有一个主布局和一个嵌套布局。出于某种原因,当我调试 IntelliJ 报告时,两个控制器上的所有字段都用 @FXML 注释为空。
这是我目前所掌握的内容的简化版本。 Full Code on 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);
}
}
}
我在 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 文件 - 实例化控制器(由 .fxml 文件中的
fx:controller属性指定) - 在控制器上调用无参数构造函数
- 设置@FXML 值(通过注入)
- 注册任何事件处理程序
- 在每个控制器上调用
initialize
我的嵌套 fxml 文件有问题吗?如果是这种情况,我会认为MainWindowController.java 中的@FXML 字段也不会是null。我正在努力解决这个问题。我可以用另一双眼睛和比我更聪明的人。
提前致谢。
【问题讨论】:
-
如果存在注入字段的控制器实例并不意味着该字段被注入到每个控制器实例。您不会期望
new ArrayList()创建的列表包含元素,因为您将元素添加到某些ArrayList...
标签: java javafx-8 fxml playing-cards