JavaFX在Button字段中覆盖和显示Button文本

时间:2016-11-14 11:48:05

标签: java button javafx minesweeper

好的,所以在初始化Minesweeper的游戏板时,我的代码会遍历窗格中创建的所有按钮,并将文本设置为X for bomb或数字(表示有多少炸弹是邻居)。如果它既不会做任何事情。但现在我想知道如何在初始化游戏时隐藏该文本,以便可以通过单击鼠标来揭开它并稍后恢复?

enter image description here

这里是迭代逻辑:

//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或类似的......

2 个答案:

答案 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));

输出:

enter image description here

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