简体   繁体   中英

How to add event handling for Button object made in For Loop(JavaFX / Scenebuilder)

The project:
I am creating a tic-tac-toe game in which the user decides the size of the board.

I've figured out how to change the size of the board; fantastic. I've figured out how to fill the board with button objects; awesome.

What I still need to figure out is how do I attach a function/event to each button. I want a button to change its text to either an "X" or "O" when the user clicks on a button. Looking at tutorials, they only show how to do it when you have a specific name fxid for your button and/or when you have already made the button in SceneBuilder and attaching an event to a specific object.

What I'm using:
SceneBuilder / IntelliJ

Below I've listed controller class, main class, and FXML.

The method that decides the size of the board and generates buttons (In Controller Class):

gameBoard is Gridpane used for tic-tac-toe board.

public void changeGameBoard(ActionEvent event){
    if (boardNumber > 3){
        sizeLabel.setText("Set at :" + boardNumber);
        //Generating Columns and Rows
        for(int i = 0; i < (boardNumber - 3); i++){
            ColumnConstraints column = new ColumnConstraints();
            column.setMinWidth(100);
            gameBoard.getColumnConstraints().add(column);

            RowConstraints row = new RowConstraints();
            row.setMinHeight(100);
            gameBoard.getRowConstraints().add(row);

        }
        //Generating Buttons
        for(int j = 0; j < boardNumber; j++){
            for(int i = 0; i < boardNumber; i++){
                Button boardButton = new Button();
                boardButton.setMinWidth(100);
                boardButton.setMinHeight(100);
                boardButton.setText("Blank");
                gameBoard.addRow(j,boardButton);


            /*for(int j = 0; j <= boardNumber; j++){
                gameBoard.add(boardButton, j,i);
            }*/
            }
        }
    }
}

Entire Controller Class:

package com.sosgame;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.RowConstraints;
import javafx.scene.text.Text;

public class SosController {

    @FXML
    private GridPane gameBoard;
    @FXML
    private RadioButton sButton, gButton, blueSButton, blueOButton, redSButton, redOButton;

    @FXML
    private TextField boardSizeInput;

    @FXML
    private Button startButton;
    private Button moveButton;

    @FXML
    private Label sizeLabel;

    private int boardNumber = 10;
    private String gameMode = new String(" ");
    private String bluePlayerMove = " ";
    private String redPlayerMove = " ";

    private GridPane newGameBoard = new GridPane();


    public void setBoardSize(ActionEvent event){
        boardNumber = Integer.parseInt(boardSizeInput.getText());
        sizeLabel.setText("Set at : " + boardNumber);

    }

    public int getBoardNumber(){
        return boardNumber;
    }



    public void setGameType(ActionEvent event) {
        if (sButton.isSelected()) {
            gameMode = sButton.getText();
        }
        else if (gButton.isSelected()){
                gameMode = gButton.getText();
            }
        }

    public String getGameMode() {
        return gameMode;
    }
    public void textAppear(ActionEvent event){
        Text lily = new Text();


    }
    public void changeGameBoard(ActionEvent event){
        if (boardNumber > 3){
            sizeLabel.setText("Set at :" + boardNumber);
            //Generating Columns and Rows
            for(int i = 0; i < (boardNumber - 3); i++){
                ColumnConstraints column = new ColumnConstraints();
                column.setMinWidth(100);
                gameBoard.getColumnConstraints().add(column);

                RowConstraints row = new RowConstraints();
                row.setMinHeight(100);
                gameBoard.getRowConstraints().add(row);

            }
            //Generating Buttons
            for(int j = 0; j < boardNumber; j++){
                for(int i = 0; i < boardNumber; i++){
                    Button boardButton = new Button();
                    boardButton.setMinWidth(100);
                    boardButton.setMinHeight(100);
                    boardButton.setText("Blank");
                    
                    gameBoard.addRow(j,boardButton);


                /*for(int j = 0; j <= boardNumber; j++){
                    gameBoard.add(boardButton, j,i);
                }*/
                }
            }
        }
    }

    public void ButtonChange (ActionEvent event){

    }
    public void setBluePlayerMoveType(ActionEvent event){
        if (blueSButton.isSelected()){
            bluePlayerMove = "S";
        } else if (blueOButton.isSelected()) {
            bluePlayerMove = "O";
        }
    }

    public void setRedPlayerMoveType(ActionEvent event){
        if (redSButton.isSelected()){
            redPlayerMove = "S";
        } else if (redOButton.isSelected()) {
            redPlayerMove = "O";
        }
    }

}

Entire Main Class:

package com.sosgame;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;
import javafx.scene.layout.GridPane;


import java.io.IOException;

public class SosApplication extends Application {
    @Override
    public void start(Stage stage) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(SosApplication.class.getResource("sos-gui.fxml"));
        Scene scene = new Scene(fxmlLoader.load(), 600, 400);
        stage.setTitle("Jacob's SOS Game");

        stage.setScene(scene);
        stage.show();

    }

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

Entire FXML:

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onInputMethodTextChanged="#setBoardSize" prefHeight="600.0" prefWidth="606.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sosgame.SosController">
   <children>
      <RadioButton fx:id="sButton" layoutX="53.0" layoutY="14.0" mnemonicParsing="false" onAction="#setGameType" prefHeight="32.0" prefWidth="104.0" text="Simple Game">
         <toggleGroup>
            <ToggleGroup fx:id="gameTypeSelected" />
         </toggleGroup>
         <font>
            <Font size="13.0" />
         </font>
      </RadioButton>
      <RadioButton fx:id="gButton" layoutX="209.0" layoutY="14.0" mnemonicParsing="false" onAction="#setGameType" prefHeight="32.0" prefWidth="110.0" text="General Game" toggleGroup="$gameTypeSelected">
         <font>
            <Font size="13.0" />
         </font>
      </RadioButton>
      <Label layoutX="389.0" layoutY="18.0" prefHeight="25.0" prefWidth="73.0" text="Board Size">
         <font>
            <Font size="14.0" />
         </font>
      </Label>
      <Label layoutX="34.0" layoutY="130.0" prefHeight="65.0" prefWidth="110.0" text="Blue Player">
         <font>
            <Font size="20.0" />
         </font>
      </Label>
      <RadioButton fx:id="blueSButton" layoutX="43.0" layoutY="179.0" mnemonicParsing="false" onAction="#setBluePlayerMoveType" prefHeight="32.0" prefWidth="47.0" selected="true" text="S">
         <font>
            <Font size="18.0" />
         </font>
         <toggleGroup>
            <ToggleGroup fx:id="bluePlayerMoveType" />
         </toggleGroup>
      </RadioButton>
      <RadioButton fx:id="blueOButton" layoutX="43.0" layoutY="220.0" mnemonicParsing="false" onAction="#setBluePlayerMoveType" prefHeight="32.0" prefWidth="47.0" text="O" toggleGroup="$bluePlayerMoveType">
         <font>
            <Font size="18.0" />
         </font>
      </RadioButton>
      <Label layoutX="461.0" layoutY="126.0" prefHeight="65.0" prefWidth="110.0" text="Red Player">
         <font>
            <Font size="20.0" />
         </font>
      </Label>
      <RadioButton fx:id="redSButton" layoutX="469.0" layoutY="175.0" mnemonicParsing="false" onAction="#setRedPlayerMoveType" prefHeight="32.0" prefWidth="47.0" selected="true" text="S">
         <font>
            <Font size="18.0" />
         </font>
         <toggleGroup>
            <ToggleGroup fx:id="redPlayerMoveType" />
         </toggleGroup>
      </RadioButton>
      <RadioButton fx:id="redOButton" layoutX="469.0" layoutY="216.0" mnemonicParsing="false" onAction="#setRedPlayerMoveType" prefHeight="32.0" prefWidth="47.0" text="O" toggleGroup="$redPlayerMoveType">
         <font>
            <Font size="18.0" />
         </font>
      </RadioButton>
      <GridPane fx:id="gameBoard" gridLinesVisible="true" layoutX="153.0" layoutY="260.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="195.0" prefWidth="194.0">
        <columnConstraints>
            <ColumnConstraints hgrow="ALWAYS" minWidth="100.0" prefWidth="100.0" />
          <ColumnConstraints hgrow="ALWAYS" minWidth="100.0" prefWidth="100.0" />
          <ColumnConstraints hgrow="ALWAYS" minWidth="100.0" prefWidth="100.0" />
        </columnConstraints>
        <rowConstraints>
          <RowConstraints minHeight="100.0" prefHeight="30.0" vgrow="ALWAYS" />
          <RowConstraints minHeight="100.0" prefHeight="30.0" vgrow="ALWAYS" />
          <RowConstraints minHeight="100.0" prefHeight="30.0" vgrow="ALWAYS" />
        </rowConstraints>
      </GridPane>
      <Label alignment="CENTER" layoutX="78.0" layoutY="110.0" prefHeight="32.0" prefWidth="445.0" text="Current Player: Blue">
         <font>
            <Font size="17.0" />
         </font>
      </Label>
      <Button fx:id="startButton" layoutX="212.0" layoutY="85.0" mnemonicParsing="false" onAction="#changeGameBoard" prefHeight="25.0" prefWidth="182.0" text="Start Game" />
      <TextField fx:id="boardSizeInput" layoutX="487.0" layoutY="18.0" onAction="#setBoardSize" onInputMethodTextChanged="#setBoardSize" prefHeight="25.0" prefWidth="29.0" />
      <Label fx:id="sizeLabel" layoutX="391.0" layoutY="46.0" prefHeight="17.0" prefWidth="94.0" text="Size Label" />
   </children>
</AnchorPane>

You set an action event handler using java code on a button like this:

Button button = new Button(); 
button.setOnAction(e -> myAction()); 

where myAction is whatever action you want to take when the button is actioned.

A basic hello, world app demonstrates this.

To do this in a loop, just place the above code in the loop.


To set an action handler from a button defined in FXML, see:

If the button is defined in FXML, the action handlers are not attached in a loop. If you want to attach action handlers in a loop, you should create the associated buttons in a loop as outlined previously rather than in FXML.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM