0

I am creating a mini game which contains a set of labels that start out as black, but turn yellow once it's clicked. What I want to happen is for the previously clicked label to turn back to black when the currently clicked label is turned yellow.

The problem I'm having doing this is working out how to turn the previously clicked label back to black. I've tried creating a new GridPane every time a label is clicked and using different classes to do different things and none of it has worked. I've also tried creating a 2D array of labels while creating my GridPane but I can't manage to use it to reset previous labels.

Here is my code, where am I going wrong?

package application;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.InputEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        BorderPane borderpane = new BorderPane();
        GridPane grid = setGrid();

        borderpane.setTop(grid);
        Scene sc = new Scene(borderpane, 400, 400);
        sc.getStylesheets().add("application/application.css");
        primaryStage.setScene(sc);
        primaryStage.show();
    }

    public GridPane setGrid() {
        GridPane grid = new GridPane();

        for (int row = 0; row < 5; row++)
            for (int col = 0; col < 5; col++) {
                Label l = new Label();
                l.setPrefHeight(100);
                l.setPrefWidth(100);
                l.getStyleClass().add("box");

                l.setOnMouseClicked(new EventHandler<InputEvent>() {
                    @Override
                    public void handle(InputEvent arg0) {
                        l.getStyleClass().add("clicked");
                    }
                });

                grid.add(l, col, row);
        }
        return grid;
    }

    public static void main(String[] args) {
        Application.launch(args);
    }

}
Ouroborus
  • 16,237
  • 4
  • 39
  • 62

1 Answers1

0

What you're doing wrong? Obviously in your code you do not attempt to remove the style class anywhere. Of course nothing will turn back to the normal state, if everything you do is adding the style class over and over again.

To remove the style class from the previously clicked node, you need to store this information somewhere, e.g. in a EventHandler that you use for all labels. Note that instead of a style class repeatedly being removed/added, it's more suitable to use a pseudoclass, which allows you to easily add/remove the class without the need to prevent the class being added more than once. In the following code I therefore commented out the parts using a style class and replaced them with the use of a pseudoclass:

private static final PseudoClass CLICKED = PseudoClass.getPseudoClass("clicked");

public GridPane setGrid() {
    GridPane grid = new GridPane();


    EventHandler<MouseEvent> handler = new EventHandler<MouseEvent>() {

        private Label lastLabel;

        @Override
        public void handle(MouseEvent event) {
            Label currentLabel = (Label) event.getSource();

            // currentLabel.getStyleClass().add("clicked");

            if (lastLabel != null) {
                // lastLabel.getStyleClass().remove("clicked");
                lastLabel.pseudoClassStateChanged(CLICKED, false);
            }
            currentLabel.pseudoClassStateChanged(CLICKED, true);

            lastLabel = currentLabel;
        }

    };

    for (int row = 0; row < 5; row++) {
        for (int col = 0; col < 5; col++) {
            Label l = new Label();
            l.setPrefHeight(100);
            l.setPrefWidth(100);
            l.getStyleClass().add("box");

            l.setOnMouseClicked(handler);

            grid.add(l, col, row);
        }
    }
    return grid;
}

CSS

With style class

.box.clicked {
    -fx-background-color: yellow;
}
.box {
    -fx-background-color: black;
}

With pseudo class

.box:clicked {
    -fx-background-color: yellow;
}
.box {
    -fx-background-color: black;
}

Note that in this case since you do not use any text with the Labels, you could instead just use Region to achieve the same effect.

fabian
  • 80,457
  • 12
  • 86
  • 114