Как добавить обработку событий для объекта Button, созданного в For Loop (JavaFX/Scenebuilder)

Проект: Я создаю игру в крестики-нолики, в которой пользователь определяет размер доски.

Я понял, как изменить размер доски; фантастический. Я понял, как заполнить доску объектами-кнопками; классно.

Что мне еще нужно выяснить, так это то, как привязать функцию/событие к каждой кнопке. Я хочу, чтобы кнопка меняла свой текст на «X» или «O», когда пользователь нажимает кнопку. Глядя на учебники, они показывают, как это сделать только тогда, когда у вас есть конкретное имя fxid для вашей кнопки и/или когда вы уже сделали кнопку в SceneBuilder и привязали событие к определенному объекту.

Что я использую: Построитель сцен / IntelliJ

Ниже я перечислил класс контроллера, основной класс и FXML.

Метод, который определяет размер доски и генерирует кнопки (в классе контроллера):

GameBoard — это Gridpane, используемая для игры в крестики-нолики.

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);
            }*/
            }
        }
    }
}

Весь класс контроллера:

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";
        }
    }

}

Весь основной класс:

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();
    }
}

Весь 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>
минимальный воспроизводимый пример пожалуйста (обратите внимание на М! никто не хочет пробираться через тонны несвязанного кода :) Тем не менее: если вы добавляете кнопки вручную (то есть не вводите их через fxml), то вам нужно прикреплять действия/обработчики также вручную - каждый учебник начального уровня покажет вам, как это сделать (ваша попытка не является допустимым синтаксисом Java, поэтому не компилируется, не так ли;) Не имеет отношения: придерживайтесь соглашений об именах Java, пожалуйста
kleopatra 20.11.2022 18:17

Отредактировал мою попытку добавить событие кнопки в код и спасибо за напоминание M! Не могли бы вы объяснить, как прикрепить обработчик действия события к объекту, который не создается вручную?

user120265 20.11.2022 21:10

Вы устанавливаете действие для кнопки следующим образом: Button button = new Button(); button.setOnAction(e -> myAction()); где myAction — это любое действие, которое вы хотите выполнить, когда кнопка нажата. Простое приложение hello, world демонстрирует это.

jewelsea 21.11.2022 08:50

@ SedJ601 заголовок спрашивает о кнопках, созданных в цикле for, поэтому параметры, определяющие кнопки в fxml, в этом случае не применяются. Это сбивает с толку, потому что большая часть кода в вопросе не имеет отношения к вопросу.

jewelsea 22.11.2022 12:47

@jewelsea, спасибо! Я определенно пропустил часть for loop.

SedJ601 22.11.2022 14:43

@jewelsea Спасибо, похоже, это работает!

user120265 22.11.2022 18:58
LeetCode запись решения 2536. Увеличение подматриц на единицу
LeetCode запись решения 2536. Увеличение подматриц на единицу
Увеличение подматриц на единицу - LeetCode
Версия Java на основе версии загрузки
Версия Java на основе версии загрузки
Если вы зайдете на официальный сайт Spring Boot , там представлен start.spring.io , который упрощает создание проектов Spring Boot, как показано ниже.
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Как включить TLS в gRPC-клиенте и сервере : 2
Как включить TLS в gRPC-клиенте и сервере : 2
Здравствуйте! 🙏🏻 Надеюсь, у вас все хорошо и добро пожаловать в мой блог.
Сортировка hashmap по значениям
Сортировка hashmap по значениям
На Leetcode я решал задачу с хэшмапой и подумал, что мне нужно отсортировать хэшмапу по значениям.
1
6
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы устанавливаете обработчик события действия, используя код Java для кнопки следующим образом:

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

Где myAction — любое действие, которое вы хотите предпринять, когда нажимается кнопка.

Простое приложение hello, world демонстрирует это.

Чтобы сделать это в цикле, просто поместите приведенный выше код в цикл.


Чтобы установить обработчик действия для кнопки, определенной в FXML, см.:

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

Другие вопросы по теме