Как дождаться завершения перехода в javafx 2.1?

Моя сцена состоит только из ImageView, отображающего изображение. Я хотел бы сделать изображение черным (назначенный цвет сцены), а затем через некоторое время снова перейти от черного к изображению. Я нашел FadeTransition очень подходящим для этой цели. Это фрагмент моего кода:

    // fade to black transition
    FadeTransition ft1 = new FadeTransition(Duration.millis(2000), myImageView);
    ft1.setFromValue(1.0);
    ft1.setToValue(0.0);
    ft1.play();

    // fade from black transition
    FadeTransition ft2 = new FadeTransition(Duration.millis(2000), myImageView);
    ft2.setFromValue(0.0);
    ft2.setToValue(1.0);
    ft2.play();

Моя проблема в том, что ft1.play() является асинхронным, поэтому приведенный ниже код начнет выполняться до выхода из ft1.play(). В результате я вижу только второй переход. Как мне дождаться завершения первого перехода, а затем запустить второй переход? Я не могу усыпить поток между ними, потому что это основной поток javafx (пробовал и не работал).

Я пробовал использовать метод onFinishedProperty () с комбинацией занятого ожидания на флаге, но навсегда застрял в цикле while. Вот мой код для этого:

    boolean isTransitionPlaying;
    FadeTransition ft = new FadeTransition(Duration.millis(2000), iv);
    ft.setFromValue(1.0);
    ft.setToValue(0.0);
    ft.onFinishedProperty().set(new EventHandler<ActionEvent>() {
        @Override 
        public void handle(ActionEvent actionEvent) {
            transitionPlaying = false;
        }
    });
    transitionPlaying = true;
    ft.play();

    while (transitionPlaying == true)
    {
        // busy wait
        System.out.println("still waiting...");
    }

    FadeTransition ft2 = new FadeTransition(Duration.millis(2000), iv);
    ft2.setFromValue(0.0);
    ft2.setToValue(1.0);
    ft2.play();

Как правильно выполняется ожидание? Спасибо


person dadox    schedule 25.06.2012    source источник


Ответы (3)


Занятое ожидание (или даже Thread.sleep) в потоке приложения JavaFX всегда является плохой идеей - вы связываете поток, который обрабатывает обработку пользовательского интерфейса, чтобы ваши переходы, а также остальная часть вашего пользовательского интерфейса никогда не обновлялись - эффективно замораживая ваш пользовательский интерфейс приложения на время ожидания. Для отзывчивого пользовательского интерфейса вам необходимо как можно быстрее запустить логику в потоке приложения FX, а затем отпустить поток, чтобы остальная часть системы JavaFX могла продолжить его обработку. Вот почему у переходов есть асинхронные обратные вызовы, которые, как только вы к ним привыкнете, станут очень естественным способом разработки.

В дополнение к решениям Улука (которые великолепны) вы также можете посмотреть SequentialTransition для обработки помощи при последовательном выполнении переходов. Обратите внимание, что если вы хотите выполнить действие после завершения SequentialTransition, вы все равно захотите добавить обработчик onFinished в SequentialTransition, чтобы выполнить действие в это время.

person jewelsea    schedule 25.06.2012
comment
Думаю, я думал, что, поскольку переходы play () асинхронны, они происходят в другом потоке, а не в потоке приложения JavaFX. Вот почему я подумал, что могу заставить основной поток дождаться завершения переходов, а затем возобновить работу. Теперь я вижу, что если поток приложения спит, переходы тоже не могут быть обработаны, верно? Поэтому я думаю, что SequentialTransition - самое ясное решение для моего случая. Спасибо вам и Укуку. - person dadox; 26.06.2012

Хорошо, если ваша ft2 является отражающей анимацией ft1, тогда сделайте

ft1.setAutoReverse(true);
ft1.setCycleCount(1);
// Or
// ft1.setCycleCount(Timeline.INDEFINITE);
// to loop infinitely (blinking effect) until stop()

а вы не ft2. Если вам все еще нужно ft2, чтобы играть после ft1, тогда

ft1.setOnFinished(new EventHandler<ActionEvent>() {

    @Override
    public void handle(ActionEvent event) {
        ft2.play();
    }
});
person Uluk Biy    schedule 25.06.2012
comment
Хорошо, знаете ли вы о другом способе выполнения данного фрагмента кода после завершения play (), кроме setOnFinished ()? Я хотел бы иметь возможность организовывать переходы по моему коду, а не организовывать логику вокруг переходов ... - person dadox; 25.06.2012
comment
К сожалению, как вы упомянули, перевести основной поток в режим ожидания / ожидания непросто. Такая же трудность возникает при отображении модального (подтверждающего) диалогового окна. Но там метод showAndWait (v2.2) предоставит решение, которое применимо только к модальным этапам. - person Uluk Biy; 25.06.2012

У меня была проблема, когда другой код выполнял некоторые вычисления, и я хотел запустить анимацию в приложении JavaFX, но мне нужно было заставить другой код ждать завершения анимации. Я не смог сообщить этот другой код, когда анимация завершилась, поэтому я создал метод для воспроизведения анимации и затем ждал его завершения:

    private synchronized void playAnimationAndWaitForFinish(final Animation animation) {
    if (Platform.isFxApplicationThread()) {
        throw new IllegalThreadStateException("Cannot be executed on main JavaFX thread");
    }
    final Thread currentThread = Thread.currentThread();
    final EventHandler<ActionEvent> originalOnFinished = animation.getOnFinished();
    animation.setOnFinished(new EventHandler<ActionEvent>() {

        @Override
        public void handle(ActionEvent event) {
            if (originalOnFinished != null) {
                originalOnFinished.handle(event);
            }
            synchronized (currentThread) {
                currentThread.notify();
            }
        }
    });
    Platform.runLater(new Runnable() {

        @Override
        public void run() {
            animation.play();
        }
    });
    synchronized (currentThread) {
        try {
            currentThread.wait();
        } catch (InterruptedException ex) {
            //somebody interrupted me, OK
        }
    }
}

Требуется, чтобы этот метод не вызывался в основном потоке JavaFX, в противном случае он работает для меня.

person user3727126    schedule 10.06.2014