#javafx #fxml #actionevent
#javafx #fxml #actionevent
Вопрос:
Я свел вопрос только к проблеме, поэтому я создаю пользовательский интерфейс для игры в сапер, в контроллере ниже, в методе startGame, все хорошо (согласно моей проверке с использованием debug), пока строка
game.open(x, y)
, то есть мне удается создать доску и добавить кнопки (которые будут выступать в качестве слотов) в панель сетки, но моя проблема в том, что я не могу открыть и показать правильное значение в слоте. (класс logics of Mines работает нормально — тот, который не содержит части JavaFX).
package MS;
import java.io.IOException;
import java.util.Random;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBase;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class NewGameCONTROLLER {
Mines game;
int rows, columns, mines;
Button b;
@FXML
private TextField NumRows;
@FXML
private TextField NumCols;
@FXML
private TextField NumM;
@FXML
private Button StartGame;
@FXML
private Button BackMainMenu;
@FXML
private Button RandomGame;
@FXML
void BackMainMenu(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader(); // Create loading object
loader.setLocation(getClass().getResource("MainMenuFXML.fxml")); // fxml location
VBox root = loader.load(); // Load layout
root.setStyle("-fx-background-image: url("file:///C:/EclipseProjects/MineSweeper/src/MS/menu.jpg")");
Scene scene = new Scene(root); // Create scene with chosen layout
Stage primaryStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
primaryStage.setTitle("..."); // Set stage's title
primaryStage.setMinWidth(400); // Won't be allowed to make width/height smaller
primaryStage.setMinHeight(350);
primaryStage.setMaxWidth(600);
primaryStage.setMaxHeight(450);
primaryStage.setScene(scene); // Set scene to stage
primaryStage.show(); // Show stage
}
@FXML
void RandomGame(ActionEvent event) {
Random rand = new Random();
int low = 3, high = 15;
int minesLow = 1, minesHigh;
rows = rand.nextInt(high - low) low;
columns = rand.nextInt(high - low) low;
minesHigh = rows * columns - 1;
mines = rand.nextInt(minesHigh - minesLow) minesLow;
game = new Mines(rows, columns, mines);
}
@FXML
void StartGame(ActionEvent event) throws IOException {
rows = Integer.parseInt(NumRows.getText());
columns = Integer.parseInt(NumCols.getText());
mines = Integer.parseInt(NumM.getText());
game = new Mines(rows, columns, mines);
FXMLLoader loader = new FXMLLoader(); // Create loading object
loader.setLocation(getClass().getResource("BoardFXML.fxml")); // fxml location
AnchorPane root = loader.load(); // Load layout
root.setStyle("-fx-background-image: url("file:///C:/EclipseProjects/MineSweeper/src/MS/Pic.jpg")");
Scene scene = new Scene(root); // Create scene with chosen layout
Stage gameStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
gameStage.setTitle("..."); // Set stage's title
gameStage.setMinWidth(1000); // Won't be allowed to make width/height smaller
gameStage.setMinHeight(500);
gameStage.setMaxWidth(1200);
gameStage.setMaxHeight(800);
gameStage.setScene(scene); // Set scene to stage
BoardCONTROLLER bCont = loader.getController(); // Prepare board in BoardCONTROLLER
for (int i = 0; i < columns; i )
for (int j = 0; j < rows; j ) {
b = new Button(" ");
b.setMinSize(40, 40);
b.setMaxSize(40, 40);
bCont.TheBoard.add(b, i, j);
}
for (int i = 0; i < bCont.TheBoard.getChildren().size(); i ) {
((ButtonBase) bCont.TheBoard.getChildren().get(i)).setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
int x, y;
event.getSource();
x = (int) ((Button) event.getSource()).getProperties().get("gridpane-column");
y = (int) ((Button) event.getSource()).getProperties().get("gridpane-row");
game.open(x, y);
for (int i=0;i<game.getCol();i )
for (int j=0;i<game.getRow();j ) {
if (game.board[i][j].charAt(1)=='T')
((Button) bCont.TheBoard.getChildren().get(i)).setText(game.get(x, y));
}
/* while ()
for (int i = 0; i < bCont.TheBoard.getChildren().size(); i ) {
if (game.board[x][y].charAt(2) == 'B') {
((Button) bCont.TheBoard.getChildren().get(i)).setText(game.get(x, y));
}
}*/
}
});
}
gameStage.show(); // Show stage
}
}
Спасибо.
Комментарии:
1. @matt готово, надеюсь, теперь это более понятно
2. Круто, это намного лучше. Похоже, вы нажимаете кнопку, и вам нужно проверить, есть ли у этой кнопки бомба, и «открыть» ее, если ее нет. Возвращаются ли правильные значения для x и y?
3. @matt да, значения x и y возвращаются правильно (убедился и проверил это в отладчике), переменная «game» (объект Mines) открывает правильный слот (после «game.open (x, y)»), метод «open» в основном добавляет символ «T», поэтому код открывает этот слот («T» — это индикатор открываемого слота). И теперь, что касается проблемы, я, похоже, не могу найти способ ее открыть, я пытался, как показано в цикле, но это неправильно, поскольку этот слот уже содержит «T», поэтому он открывает много других слотов (которые не следует открывать), мне нужно открыть только правильный слот (содержащий «T»).
4. Почему вы просматриваете все слоты? Разве у вас еще нет слота, который вы хотите изменить?
(Button)evt.getSource()
это кнопка, которую вы хотите изменить?5. пожалуйста, соглашения об именовании Java
Ответ №1:
Когда я смотрю на этот цикл.
for (int i=0;i<game.getCol();i )
for (int j=0;i<game.getRow();j ) {
if (game.board[i][j].charAt(1)=='T')
((Button) bCont.TheBoard.getChildren().get(i)).setText(game.get(x, y));
}
}
Переменная i
не соответствует координате строки, она соответствует n-му дочернему элементу в таблице. Так что, на самом деле, вы просто перебираете все дочерние элементы в первой строке (или первом столбце).
Я вижу, как это исправить;
for( Node child: bCont.TheBoard.getChildren() ){
int i = (int) ((Button) child).getProperties().get("gridpane-column");
int j = (int) ((Button) child).getProperties().get("gridpane-row");
if (game.board[i][j].charAt(1)=='T'){
((Button) child).setText(game.get(x, y));
}
}
Таким образом, вы просматриваете всех дочерних элементов и проверяете их статус на доске.
Я не знаю, соответствует ли порядок дочерних узлов в GridPane порядку компоновки, распространенному методу упаковки 2D-массива в 1D-массив,
bCont.TheBoard.getChildren().get(i j*game.getCol());
Помните, что у вас всего кнопок в строке x.
Комментарии:
1. Я просто изменил строку if на game.get(i, j) вместо (x, y), и это отлично сработало (я предполагаю, что это потому, что если в слоте просто есть «T», он должен быть открыт)! Спасибо! Также ваше последнее замечание, я знаю это, но никогда не пытался реализовать его таким образом, очень полезно, спасибо!