JavaFX。单击按钮中的线程

问题描述 投票:0回答:1

单击 myButton 后,运行 2 个线程。首先更改按钮图像,第二个 - 循环。我希望我的程序首先更改图像并在运行循环之后。但这不行,一瞬间就完蛋了。

myButton.setOnMouseClicked(event -> {
            if (event.getButton() == MouseButton.PRIMARY) {
                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        ImageView imageView = new ImageView(image);
                        imageView.setFitHeight(my_button_height - 16);
                        imageView.setFitWidth(my_button_width - 16);
                        myButton.setStyle("-fx-background-color: #ffffff00; ");
                        myButton.setGraphic(imageView);
                    }
                });
                thread.run();
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                Thread thread1 = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        for (int i = 0; i < 15; i++){
                            System.out.println(i);
                            try {
                                Thread.sleep(500);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                        }
                    }
                });
                thread1.run();
            }
        });
    }

我尝试添加.join。没有帮助

multithreading button javafx imageview
1个回答
0
投票

您不需要使用线程来实现您的需求。

游戏,在哪里找到与图像相同的卡片。卡片是带有图像的按钮。当玩家打开两张牌时,我的程序会检查它们,如果它们相同,则一切都很好,以另一种方式关闭。但是当玩家打开第二张牌时我遇到了一个问题,他看不到它

问题在于,在某些情况下,玩家行动后没有暂停,因此玩家在翻回之前无法看到他们翻过的牌。

这可以使用

PauseTransition
来修复。这个答案解释了用法:

示例

这里是一些记忆游戏的示例代码。例子:

  • 在用户翻转两张卡片后应用暂停过渡。
  • 暂停期间,UI 输入被禁用。
  • 暂停完成后,用户界面将更新(如果卡片不匹配,则将其翻转回来;如果匹配,则将其从板上删除)。

这只是一个演示应用程序,它没有经过彻底的测试,并且可能存在一些错误,但希望它说明了一种使用 PauseTransition 概念来解决与您遇到的问题类似的问题的方法。

MemoryGame.java

import javafx.animation.PauseTransition;
import javafx.beans.Observable;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.collections.*;
import javafx.collections.transformation.FilteredList;
import javafx.geometry.Insets;
import javafx.scene.control.Labeled;
import javafx.scene.layout.Pane;
import javafx.scene.layout.TilePane;
import javafx.util.Duration;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class MemoryGame {
    private static final Duration FLIP_PAUSE_DURATION = Duration.seconds(
            1
    );

    private final TilePane board;
    private final ReadOnlyBooleanWrapper solved = new ReadOnlyBooleanWrapper(
            false
    );

    public MemoryGame(String tileText) {
        ObservableList<Tile> tiles = createTiles(tileText);
        FilteredList<Tile> visibleTiles = tiles.filtered(Tile::isShowing);

        board = createBoard(tiles);

        PauseTransition pauseForCompletion = new PauseTransition(
                FLIP_PAUSE_DURATION
        );
        pauseForCompletion.setOnFinished(e ->
                completeMove(tiles, visibleTiles, board)
        );

        visibleTiles.addListener((ListChangeListener<Tile>) c ->
                respondToMove(visibleTiles, board, pauseForCompletion)
        );
    }

    private static void respondToMove(
            FilteredList<Tile> visibleTiles,
            TilePane board,
            PauseTransition pauseForCompletion
    ) {
        if (visibleTiles.size() == 2) {
            board.setDisable(true);
            pauseForCompletion.playFromStart();
        }
    }

    private void completeMove(
            ObservableList<Tile> tiles,
            FilteredList<Tile> visibleTiles,
            TilePane board
    ) {
        long nShowing = visibleTiles.stream()
                .map(Labeled::getText)
                .distinct()
                .count();

        if (nShowing == 1) { // all visible tiles match
            // replace all matching tiles with a blank pane.
            for (Tile tile : visibleTiles) {
                int tileIdx = board.getChildren().indexOf(tile);
                board.getChildren().set(tileIdx, new Pane());
            }
            for (int i = visibleTiles.size() - 1; i >= 0; i--) {
                tiles.remove(visibleTiles.get(i));
            }

            if (tiles.isEmpty()) {
                solved.set(true);
            }
        } else {
            // tiles don't match, so hide them until they are turned again.
            for (int i = visibleTiles.size() - 1; i >= 0; i--) {
                visibleTiles.get(i).setShowing(false);
            }
        }

        board.setDisable(false);
    }

    private static TilePane createBoard(ObservableList<Tile> tiles) {
        TilePane board = new TilePane(
                10, 10
        );

        board.getStyleClass().add("board");

        board.getChildren().addAll(tiles);
        board.setPrefColumns((int) Math.sqrt(tiles.size()));
        board.setPadding(new Insets(10));

        return board;
    }

    private static ObservableList<Tile> createTiles(String tileText) {
        List<String> gameText =
                (tileText + tileText)
                        .chars()
                        .mapToObj(Character::toString)
                        .collect(Collectors.toCollection(ArrayList::new));
        Collections.shuffle(gameText);

        ObservableList<Tile> tiles = FXCollections.observableArrayList(
                tile -> new Observable[] { tile.showingProperty() }
        );
        gameText.stream()
                .map(Tile::new)
                .forEachOrdered(tiles::add);
        return tiles;
    }

    public TilePane getBoard() {
        return board;
    }

    public boolean isSolved() {
        return solved.get();
    }

    public ReadOnlyBooleanProperty solvedProperty() {
        return solved.getReadOnlyProperty();
    }
}

Tile.java

import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.Button;

class Tile extends Button {
    private static final String BLANK = " ";

    private final BooleanProperty showing = new SimpleBooleanProperty(
            false
    );

    public Tile(String tileText) {
        getStyleClass().add("tile");

        textProperty().bind(
                Bindings
                        .when(showing)
                        .then(tileText)
                        .otherwise(BLANK)
        );

        setOnAction(e -> setShowing(true));
    }

    public boolean isShowing() {
        return showing.get();
    }

    public BooleanProperty showingProperty() {
        return showing;
    }

    public void setShowing(boolean showing) {
        this.showing.set(showing);
    }
}

import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.Button;

class Tile extends Button {
    private static final String BLANK = " ";

    private final BooleanProperty showing = new SimpleBooleanProperty(
            false
    );

    public Tile(String tileText) {
        getStyleClass().add("tile");

        textProperty().bind(
                Bindings
                        .when(showing)
                        .then(tileText)
                        .otherwise(BLANK)
        );

        setOnAction(e -> setShowing(true));
    }

    public boolean isShowing() {
        return showing.get();
    }

    public BooleanProperty showingProperty() {
        return showing;
    }

    public void setShowing(boolean showing) {
        this.showing.set(showing);
    }
}

MemoryGameApp.java

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class MemoryGameApp extends Application {
    private static final String TILE_TEXT = "Qn39Pzr#";
    private static final String CSS =
            """
            data:text/css,
            .board .button:disabled {
                -fx-opacity: 1;
            }
            .tile {
                -fx-font-family: monospace; -fx-font-size: 40px;
            }
            """;

    private MemoryGame memoryGame;
    private Scene scene;

    @Override
    public void start(Stage stage) {
        memoryGame = new MemoryGame(TILE_TEXT);

        scene = new Scene(memoryGame.getBoard());
        scene.getStylesheets().add(CSS);
        stage.setScene(scene);
        stage.show();

        memoryGame.solvedProperty().addListener(new EndGameListener());
    }

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

    class EndGameListener implements ChangeListener<Boolean> {
        @Override
        public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
            if (memoryGame.isSolved()) {
                memoryGame.solvedProperty().removeListener(this);
                memoryGame = new MemoryGame(TILE_TEXT);
                memoryGame.solvedProperty().addListener(this);
                scene.setRoot(memoryGame.getBoard());
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.