Проект: Я создаю игру в крестики-нолики, в которой пользователь определяет размер доски.
Я понял, как изменить размер доски; фантастический. Я понял, как заполнить доску объектами-кнопками; классно.
Что мне еще нужно выяснить, так это то, как привязать функцию/событие к каждой кнопке. Я хочу, чтобы кнопка меняла свой текст на «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>
Отредактировал мою попытку добавить событие кнопки в код и спасибо за напоминание M! Не могли бы вы объяснить, как прикрепить обработчик действия события к объекту, который не создается вручную?
Вы устанавливаете действие для кнопки следующим образом: Button button = new Button(); button.setOnAction(e -> myAction()); где myAction — это любое действие, которое вы хотите выполнить, когда кнопка нажата. Простое приложение hello, world демонстрирует это.
@ SedJ601 заголовок спрашивает о кнопках, созданных в цикле for, поэтому параметры, определяющие кнопки в fxml, в этом случае не применяются. Это сбивает с толку, потому что большая часть кода в вопросе не имеет отношения к вопросу.
@jewelsea, спасибо! Я определенно пропустил часть for loop.
@jewelsea Спасибо, похоже, это работает!
Вы устанавливаете обработчик события действия, используя код Java для кнопки следующим образом:
Button button = new Button();
button.setOnAction(e -> myAction());
Где myAction — любое действие, которое вы хотите предпринять, когда нажимается кнопка.
Простое приложение hello, world демонстрирует это.
Чтобы сделать это в цикле, просто поместите приведенный выше код в цикл.
Чтобы установить обработчик действия для кнопки, определенной в FXML, см.:
Если кнопка определена в FXML, обработчики действий не прикрепляются в цикле. Если вы хотите присоединить обработчики действий в цикле, вам следует создать связанные кнопки в цикле, как описано ранее, а не в FXML.