好的,所以在初始化Minesweeper的游戏板时,我的代码会遍历窗格中创建的所有按钮,并将文本设置为X for bomb或数字(表示有多少炸弹是邻居)。如果它既不会做任何事情。但现在我想知道如何在初始化游戏时隐藏该文本,以便可以通过单击鼠标来揭开它并稍后恢复?
这里是迭代逻辑:
//iterate through rows and columns to fill board with random bombs
for (int y = 0; y < model.Y_FIELDS; y++) {
for (int x = 0; x < model.X_FIELDS; x++) {
Field field = new Field(x, y, Math.random() < 0.2, model);
model.array[x][y] = field;
root.getChildren().add(field);
}
}
for (int y = 0; y < model.Y_FIELDS; y++) {
for (int x = 0; x < model.X_FIELDS; x++) {
Field field = model.array[x][y];
if (field.isBomb())
continue;
long number = field.getSurrounding().stream().filter(f -> f.isBomb()).count();
if (number > 0)
field.board.setText(String.valueOf(number));
}
}
我希望他们一开始就是空白。我在哪里放setText("")
?在鼠标左键单击事件中,我想要揭开它们。这看起来像if(leftmouseclick)
然后set.Visible
或类似的......
答案 0 :(得分:1)
您可以使用PseudoClass
API来更改Button
之间的{CSS}状态,并显示&#34;显示&#34;并且&#34;未公开&#34;。
您需要定义一个CSS伪类,如:
.button:unrevealed { -fx-text-fill: transparent; }
代表未按下按钮的按钮,使Button
的文字不可见。
你必须定义JavaFX PseudoClass
,如:
PseudoClass unrevealedPseudo = PseudoClass.getPseudoClass("unrevealed");
然后使用它:
Button button = new Button("X");
button.pseudoClassStateChanged(unrevealedPseudo, true);
button.setOnAction(e -> button.pseudoClassStateChanged(unrevealedPseudo, false));
在代码段中,Button
设置为&#34;未显示&#34;当它被创建时,然后按下该状态,因此-fx-text-fill
属性将被更改回默认属性。
如果为所有按钮应用相同的创建逻辑,则它们的初始文本无关紧要,因为它在未显示之前被隐藏(通过按下按钮或以编程方式更改它)。
注1:您可以使用相同的API来定义更多伪类,如果您想要设置一个&#34;标记&#34;在右键单击按钮上,因为您可以简单地使用这些CSS类来定义按钮在不同状态下的外观。
注2:如果您有后端,则会在创建单独的Button
时在前端存储每个字段的状态(显示,标记,未显示),例如使用属性对于域模型的每个元素,您只需检查模型中元素的state属性的更新,您只需将Button
放入正确的伪类中即可。它更优雅然后改变它,例如按钮单击。
注释2中的方法示例:
型号:
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
public class MineSweeperField {
public enum State {
UNREVEALED, REVEALED, FLAGGED
};
private ObjectProperty<State> state = new SimpleObjectProperty<State>(State.UNREVEALED);
public ObjectProperty<State> stateProperty() {
return state;
}
public State getState() {
return stateProperty().get();
}
public void setState(State state) {
stateProperty().set(state);
}
}
按钮:
import application.MineSweeperField.State;
import javafx.css.PseudoClass;
import javafx.scene.control.Button;
public class MineSweepButton extends Button {
static PseudoClass unrevealedPseudo = PseudoClass.getPseudoClass("unrevealed");
static PseudoClass revealedPseudo = PseudoClass.getPseudoClass("revealed");
static PseudoClass flaggedPseudo = PseudoClass.getPseudoClass("flagged");
public MineSweepButton(MineSweeperField field) {
this.getStyleClass().add("minesweep-button");
this.pseudoClassStateChanged(unrevealedPseudo, true);
field.stateProperty().addListener((obs, oldVal, newVal) -> changePseudoClass(newVal));
changePseudoClass(field.getState());
}
private void changePseudoClass(State state) {
this.pseudoClassStateChanged(unrevealedPseudo, false);
this.pseudoClassStateChanged(revealedPseudo, false);
this.pseudoClassStateChanged(flaggedPseudo, false);
switch (state) {
case FLAGGED:
this.pseudoClassStateChanged(flaggedPseudo, true);
break;
case REVEALED:
this.pseudoClassStateChanged(revealedPseudo, true);
break;
case UNREVEALED:
this.pseudoClassStateChanged(unrevealedPseudo, true);
break;
}
}
}
CSS:
.minesweep-button:unrevealed { -fx-text-fill: transparent; }
.minesweep-button:revealed { -fx-text-fill: black; }
.minesweep-button:flagged { -fx-text-fill: orange; }
用法:的
BorderPane root = new BorderPane();
MineSweeperField field = new MineSweeperField();
MineSweepButton msButton = new MineSweepButton(field);
msButton.setText("5");
Button reveal = new Button("Reveal");
Button unreveal = new Button("Unreveal");
Button flag = new Button("Flag");
root.setTop(new VBox(msButton, new HBox(reveal, unreveal, flag)));
reveal.setOnAction(e -> field.setState(State.REVEALED));
unreveal.setOnAction(e -> field.setState(State.UNREVEALED));
flag.setOnAction(e -> field.setState(State.FLAGGED));
输出:
答案 1 :(得分:1)
只需在单击按钮之前不设置文本。如果将Button
存储在GridPane
中,则行和列索引仍会存储在Button
中。地雷可以简单地存储在boolean[][]
数组中,并根据索引查找。顺便说一句:我建议使用ToggleButton
,因为它们已经提供了一个选定状态和一个未选择状态,可用于表示已经发现的节点。
private static boolean checkMine(boolean[][] mines, int row, int column) {
return row >= 0 && column >= 0 && row < mines.length && column < mines[row].length && mines[row][column];
}
@Override
public void start(Stage primaryStage) {
GridPane field = new GridPane();
boolean[][] mines = new boolean[][]{
new boolean[]{false, false, false},
new boolean[]{false, true, false},
new boolean[]{false, false, false}
};
EventHandler<ActionEvent> handler = event -> {
ToggleButton source = (ToggleButton) event.getSource();
// find column/row indices in GridPane
Integer row = GridPane.getRowIndex(source);
Integer column = GridPane.getColumnIndex(source);
int r = row == null ? 0 : row;
int c = column == null ? 0 : column;
boolean mine = mines[r][c];
if (mine) {
source.setText("X");
System.out.println("you loose");
// TODO: Represent lost state in GUI
} else {
int mineCount = 0;
// count surrounding mines
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
if (checkMine(mines, r + i, c + j)) {
mineCount++;
}
}
}
if (mineCount > 0) {
source.setText(Integer.toString(mineCount));
}
}
source.setDisable(true);
// keep activated look
source.setOpacity(1);
};
for (int i = 0; i < mines.length; i++) {
boolean[] row = mines[i];
for (int j = 0; j < row.length; j++) {
ToggleButton toggleButton = new ToggleButton();
toggleButton.setPrefSize(30, 30);
toggleButton.setOnAction(handler);
field.add(toggleButton, j, i);
}
}
Scene scene = new Scene(field);
primaryStage.setScene(scene);
primaryStage.show();
}