如何为单个JavaFX按钮创建按顺序触发的多个onAction监听器?
JavaFX黑杰克游戏分步输入交互解决方案
不需要创建新场景,通过追踪当前交互步骤,在同一个按钮监听器里分阶段处理输入即可解决问题。核心是用一个变量记录当前处于哪个流程节点,每次点击按钮时根据节点执行对应逻辑,完成后切换到下一个节点。
修改后的完整代码
package blackjack; import javafx.application.Application; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.ContentDisplay; import javafx.scene.control.Label; import javafx.scene.control.TextArea; import javafx.scene.control.TextField; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class BlackJack extends Application { //"topPane" will reveal the area to be maniplated by player public GridPane getTopPane(){ GridPane topPane = new GridPane(); // 步骤追踪变量:0=输入姓名,1=输入存款金额,2=输入下注金额,3=回合开始 int[] currentStep = {0}; //first section TextArea gameplayTA = new TextArea("Welcome to the table.\nWhat is your name?"); gameplayTA.setEditable(false); gameplayTA.setPrefRowCount(3); gameplayTA.setPrefColumnCount(3); HBox userEntryHB = new HBox(); TextField userEntryTF = new TextField(""); Button userEntryBtn = new Button("ENTER"); userEntryBtn.disableProperty().bind(userEntryTF.textProperty().isEmpty()); userEntryHB.getChildren().addAll(userEntryTF, userEntryBtn); HBox.setMargin(userEntryTF, new Insets(10, 5, 10, 0)); HBox.setMargin(userEntryBtn, new Insets(10, 5, 10, 0)); VBox gameplayVB = new VBox(); gameplayVB.getChildren().addAll(gameplayTA, userEntryHB); VBox.setMargin(gameplayTA, new Insets(10, 5, 5, 10)); VBox.setMargin(userEntryHB, new Insets(0, 0, 0, 10)); topPane.getChildren().add(gameplayVB); GridPane.setConstraints(gameplayVB, 0, 0); //second section - scores/bank/bet TextField playerBankTF = new TextField(""); playerBankTF.setEditable(false); TextField compBankTF = new TextField(""); compBankTF.setEditable(false); TextField betAmountTF = new TextField(""); betAmountTF.setEditable(false); TextField playerScoreTF = new TextField(""); playerScoreTF.setEditable(false); TextField compScoreTF = new TextField(""); compScoreTF.setEditable(false); playerBankTF.setPrefWidth(80); compBankTF.setPrefWidth(80); betAmountTF.setPrefWidth(80); playerScoreTF.setPrefWidth(40); compScoreTF.setPrefWidth(40); Label playerBankLbl = new Label("Player Bank: ", playerBankTF); Label compBankLbl = new Label("Computer Bank: ", compBankTF); Label betAmountLbl = new Label("Bet Amount: ", betAmountTF); Label playerScoreLbl = new Label("Player Score: ", playerScoreTF); Label compScoreLbl = new Label("Computer Score: ", compScoreTF); playerBankLbl.setContentDisplay(ContentDisplay.RIGHT); compBankLbl.setContentDisplay(ContentDisplay.RIGHT); betAmountLbl.setContentDisplay(ContentDisplay.RIGHT); playerScoreLbl.setContentDisplay(ContentDisplay.RIGHT); compScoreLbl.setContentDisplay(ContentDisplay.RIGHT); HBox hbOne = new HBox(); hbOne.getChildren().addAll(playerBankLbl, compBankLbl); HBox.setMargin(playerBankLbl, new Insets(20, 10, 10, 10)); HBox.setMargin(compBankLbl, new Insets(20, 10, 10, 10)); HBox hbTwo = new HBox(); hbTwo.getChildren().add(betAmountLbl); HBox.setMargin(betAmountLbl, new Insets(0, 0, 10, 70)); HBox hbThree = new HBox(); hbThree.getChildren().addAll(playerScoreLbl, compScoreLbl); HBox.setMargin(playerScoreLbl, new Insets(0, 10, 10, 30)); HBox.setMargin(compScoreLbl, new Insets(0, 10, 10, 10)); VBox statsVB = new VBox(); statsVB.getChildren().addAll(hbOne, hbTwo, hbThree); topPane.getChildren().add(statsVB); GridPane.setConstraints(statsVB, 2, 0); //create new player Player player = new Player(); //create new computer player Computer computer = new Computer(); // 统一按钮监听器,根据步骤处理逻辑 userEntryBtn.setOnAction(e -> { String input = userEntryTF.getText().trim(); userEntryTF.clear(); switch(currentStep[0]){ case 0: // 处理姓名输入 player.setName(input); gameplayTA.setText("Hello, " + player.getName() + ".\nLet's add money" + " to your account.\nEnter $$ amount."); currentStep[0] = 1; // 切换到存款步骤 break; case 1: // 处理存款金额输入 try { double deposit = Double.parseDouble(input); player.setBank(deposit); playerBankTF.setText(String.format("%.2f", deposit)); gameplayTA.setText("Your bank now has $" + String.format("%.2f", deposit) + "\nEnter your bet amount for this round."); currentStep[0] = 2; // 切换到下注步骤 } catch(NumberFormatException ex){ gameplayTA.setText("Invalid amount. Please enter a valid number.\nEnter $$ amount."); } break; case 2: // 处理下注金额输入 try { double bet = Double.parseDouble(input); if(bet > 0 && bet <= player.getBank()){ player.setBet(bet); betAmountTF.setText(String.format("%.2f", bet)); gameplayTA.setText("Bet placed: $" + String.format("%.2f", bet) + "\nPress ENTER to start the round!"); currentStep[0] = 3; // 切换到回合开始步骤 } else { gameplayTA.setText("Invalid bet amount. Must be positive and within your bank.\nEnter your bet amount."); } } catch(NumberFormatException ex){ gameplayTA.setText("Invalid amount. Please enter a valid number.\nEnter your bet amount."); } break; case 3: // 这里接入你的业务逻辑,比如发牌、计算分数等 gameplayTA.setText("Round started!\nYour cards: ..."); // 可继续扩展后续步骤,比如Hit/Stand选择 currentStep[0] = 4; break; } }); return topPane; } @Override public void start(Stage primaryStage) { Scene scene1 = new Scene(getTopPane(), 600, 600); primaryStage.setTitle("BLACKJACK"); primaryStage.setScene(scene1); primaryStage.show(); } public static void main(String[] args) { launch(args); } }
关键修改说明
- 使用
int[] currentStep作为步骤追踪变量(用数组是因为Lambda表达式中需访问effectively final变量) - 将所有交互逻辑整合到同一个按钮
onAction监听器中,通过switch分支处理不同步骤的输入 - 每完成一个步骤后,更新
currentStep的值,同时清空输入框、更新TextArea提示,引导用户进入下一个环节 - 加入输入合法性校验(金额格式、下注金额范围),避免无效输入影响流程
这种方式无需切换场景,所有交互在同一界面完成,逻辑清晰且易于扩展后续游戏步骤。
内容的提问来源于stack exchange,提问作者torireb
相关产品推荐
相关产品推荐

