JavaFX - простая флип-карта (смена изображения на 2 с задержкой 2 се c) - PullRequest
0 голосов
/ 11 апреля 2020

Я создаю простую игру памяти с изображением карт: пользователь пытается найти две карты с одинаковым изображением. Для начала создаю кнопку с изображением закрытой карты. Когда пользователь нажимает на кнопку, программа меняет изображение картинки на открытую карту, ждет 2 секунды и снова меняет картинку. И я застрял на этом.

Когда пользователь нажимает на кнопку, я запускаю три других потока в действии. Слушатель кнопки: кулак изменяет закрытое изображение на открытом изображении, второй ждет 2 секунды, третий меняет изображение назад. Но вместо этого изменения в пользовательском интерфейсе происходят только тогда, когда все потоки выходят

Список кодов действий

btn.setOnAction(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent event) {
        Runnable r1 = ()->{
            synchronized (btn) {
                System.out.println("test");
                Image image2 = new Image(getClass().getResourceAsStream("img/open.jpg"));
                ImageView iv = new ImageView(image2);
                iv.setFitWidth(100);
                iv.setFitHeight(100);
                Platform.runLater(()->btn.setGraphic(iv));
            }

        };

        Runnable r2 = ()->{

            synchronized (btn) {
                System.out.println("test2");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("test2 end");
            }
        };
        Runnable r3=()->{
            synchronized (btn) {
                System.out.println("test3");
                Image image2 = new Image(getClass().getResourceAsStream("img/unnamed.jpg"));
                ImageView iv = new ImageView(image2);
                iv.setFitWidth(100);
                iv.setFitHeight(100);
                btn.setGraphic(iv);
            }
        };

        Platform.runLater(r1);
        Platform.runLater(r2);
        Platform.runLater(r3);

    }
});

1 Ответ

1 голос
/ 11 апреля 2020

Как указано в комментариях, вы вообще не создаете никаких потоков; все, что вы делаете, - это планирование трех фрагментов кода, которые будут выполняться в потоке приложений FX (поток, в котором вы находитесь) в какой-то момент в будущем, один за другим. Один из этих фрагментов кода приостанавливает поток приложения FX на две секунды, что не позволяет ему делать то, что он должен был делать (отображать пользовательский интерфейс и обрабатывать пользовательские события) в течение этого времени. Следовательно, вы на самом деле не видите результатов кода в r1, потому что пользовательский интерфейс не отображается во время паузы, созданной r2, а затем r3 немедленно выполняется.

Все вы Здесь необходимо выполнить код в r1, а затем выполнить код в r3 через две секунды. Самый простой способ выполнить sh это с помощью PauseTransition:

btn.setOnAction(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent event) {
        Image image2 = new Image(getClass().getResourceAsStream("img/open.jpg"));
        ImageView iv = new ImageView(image2);
        iv.setFitWidth(100);
        iv.setFitHeight(100);
        btn.setGraphic(iv);

        PauseTransition pause = new PauseTransition(Duration.seconds(2));
        pause.setOnFinished(e -> {
            Image image2 = new Image(getClass().getResourceAsStream("img/unnamed.jpg"));
            ImageView iv = new ImageView(image2);
            iv.setFitWidth(100);
            iv.setFitHeight(100);
            btn.setGraphic(iv);
        });
        pause.play();
    }
});

Нет реальной причины для создания двух ImageView с; Вы можете просто обновить изображение, и нет необходимости перезагружать изображения при каждом нажатии кнопки (при необходимости вы можете использовать одно и то же изображение в нескольких режимах просмотра изображений). И если вы используете лямбда-выражения для вашего обработчика событий, ваш код упрощается до

// you can scope these as widely as you need: you should only load them once
Image openImage = new Image(getClass().getResourceAsStream("img/open.jpg"));
Image unnamedImage = new Image(getClass().getResourceAsStream("img/unnamed.jpg"));

// this needs to be specific to this button:
ImageView iv = new ImageView();
iv.setFitWidth(100);
iv.setFitHeight(100);

btn.setOnAction(event -> {
    iv.setImage(openImage);
    btn.setGraphic(iv);

    PauseTransition pause = new PauseTransition(Duration.seconds(2));
    pause.setOnFinished(e -> iv.setImage(unnamedImage));
    pause.play();

});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...