0

I'm trying to do "memoryGame" in javaFX. What I'm now dealing with is changing the background of a button, using CSS, twice in one function, after this button was clicked.

In this game I create a GridPane and in each cell I put buttons with pictures, for every picture there are two buttons. On top of it I put another empty buttons. If I click on a button it became transparent, so I can see the picture. Then I clicked another button and the same happens. Now, if the pictures are the same I get one point and the transparency does not change, but if the pictures are different, program waits one second one change both buttons to their primary stage (not transparent).

The problem is that if I change style of a button, wait a second and change it another time, the button does not change its style during this function, but it will happens after the function will ends. So we cannot see the first style, only the last one.

The code I'm sending is simplified version, that 'works' only for one button.

public void changeTransparent(ActionEvent event) {
        butCver01.setStyle("-fx-background-color: transparent");

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {}

        butCver01.setStyle("-fx-background-color: green");

    }

Now when we clicked butCver01, after one second it will change to green.

Mikey566
  • 45
  • 5

1 Answers1

4

As I mentioned in my comment, the JavaFX Application Thread cannot schedule the next frame render (i.e. a "pulse") while it's still executing your method. This is compounded by the fact you use Thread.sleep which blocks the FX thread meaning it can't do anything, let alone schedule the next pulse. A blocked FX thread equals a frozen UI and your user won't be able to click on any more cards to try and get a match.

You should use the animation API to do actions "over time" on the FX thread. Animations are executed "asynchronously" (on the FX thread) which means other actions can be processed while an animation is running. The call to start an animation also returns immediately. Here's an example that will reveal a shape underneath a rectangle for one second; however, there's no logic to determine if two matching shapes are revealed, that only two shapes are revealed at a time, and so on.

import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        HBox box = new HBox(10, createCard(true), createCard(true), createCard(false));
        box.setPadding(new Insets(100));
        primaryStage.setScene(new Scene(box));
        primaryStage.show();
    }

    private StackPane createCard(boolean circle) {
        Shape shape;
        if (circle) {
            shape = new Circle(50, Color.FORESTGREEN);
        } else {
            // create triangle
            shape = new Polygon(0, 0, 50, 100, -50, 100);
            shape.setFill(Color.FIREBRICK);
        }

        Rectangle cover = new Rectangle(0, 0, 100, 150);
        cover.mouseTransparentProperty()
                .bind(cover.fillProperty().isEqualTo(Color.TRANSPARENT));
        cover.setOnMouseClicked(event -> {
            event.consume();

            cover.setFill(Color.TRANSPARENT);

            PauseTransition pt = new PauseTransition(Duration.seconds(1));
            pt.setOnFinished(e -> cover.setFill(Color.BLACK));
            pt.playFromStart();
        });
        return new StackPane(shape, cover);
    }

}
Slaw
  • 37,820
  • 8
  • 53
  • 80