JavaFX MediaPlayer - обновляет метку для отображения «текущего времени» из потока / задачи - PullRequest
0 голосов
/ 09 января 2019

Я довольно новичок в программировании на Java и Generell.

У меня есть групповое упражнение, где мы должны запрограммировать медиаплеер, который должен иметь возможность проигрывать музыкальные файлы (не видео) и другие функции в JavaFX, и сейчас я работаю над «ползунком времени» и «общей продолжительностью». "и" текущее время "

Большинство из этих вещей работают. На самом деле моя проблема в текущем времени, потому что он работает в цикле while. Так что программа не зависает, я обнаружил, что я должен создать задачу / поток. Ползунок продолжительности работает нормально, и изменение ползунка работает довольно хорошо Таким образом, пользователь может видеть, как далеко находится его песня, и он может даже выбрать время, к которому он хочет перейти.

Основная проблема заключается в обновлении текущего времени.

Если я нажму «Play», то рассчитывается общая продолжительность этот код называется:

mp.currentTimeProperty().addListener(new InvalidationListener() {
            public void invalidated(Observable ov)
            {
                updatesValues();
            }
        });

сразу после этого вызывается этот метод.

String setCurrentTime = "0:00";
private void updatesValues(){

    Runnable r = new Runnable() {
        public void run() {
            while (isPlaying) {


                //System.out.println(mp.getCurrentTime().toMinutes());      // Debug

                String setCurrentTime = "0:00";
private void updatesValues(){

    Runnable r = new Runnable() {
        public void run() {
            while (isPlaying) {


                //System.out.println(mp.getCurrentTime().toMinutes());      // Debug

                String currentTime = "";
                int timeCurrentTime = (int) (100 * mp.getCurrentTime().toMinutes());

                int hourCurrentTime = timeCurrentTime / 3600;
                int minCurrentTime = timeCurrentTime / 100;
                int secCurrentTime = 60 * (timeCurrentTime % 100);

                if (hourCurrentTime == 0) {
                    if(secCurrentTime < (60 * (timeCurrentTime % 100))){
                        System.out.printf("%.2s:0%.1s \n", minCurrentTime, secCurrentTime);
                        setCurrentTime = currentTime.format("%.2s:0%.1s",minCurrentTime,secCurrentTime);
                    }else{
                        System.out.printf("%.2s:%.2s \n", minCurrentTime, secCurrentTime);
                        setCurrentTime = currentTime.format("%.2s:%.2s",minCurrentTime,secCurrentTime);
                    }
                } else {
                    if(secCurrentTime < (60 * (timeCurrentTime % 100))){
                        System.out.printf("%.2:%.2s:0%.1s \n", hourCurrentTime,minCurrentTime, secCurrentTime);
                        setCurrentTime = currentTime.format("%.2s%.2s:0%.1s",hourCurrentTime,minCurrentTime,secCurrentTime);
                    }else{
                        System.out.printf("%.2s:%.2s:%.2s \n", hourCurrentTime, minCurrentTime, secCurrentTime);
                        setCurrentTime = currentTime.format("%.2:%.2s:%.2s",hourCurrentTime,minCurrentTime,secCurrentTime);
                    }

                }


                durationSlider.setValue(mp.getCurrentTime().toMillis()/ mp.getTotalDuration().toMillis() * 100);

                try
                {
                    Thread.sleep(1000);
                }
                catch(InterruptedException ex)
                {
                    Thread.currentThread().interrupt();
                }
            }
        }
    };
    displayCurrentTime.setText(setCurrentTime);
    new Thread(r).start();


}

Systemout работает нормально. У меня просто есть проблемы с форматированием. Возможно также с расчетом / вычислительной частью. Спящая часть не работает, поэтому консоль получает спам (вероятно, из-за миллисекунд). Это выглядит как: 0:01 0:01 0:01 0:01 0:01 0:01 0:02 0:02 так далее.. Слайдер работает и обновляется, но без метки "displayCurrentTime"

Обходной путь должен был поместить "String setCurrentTime =" 0:00 ";" перед методом и "displayCurrentTime.setText (setCurrentTime);" в конце, но перед новым "Thread (r) .start ();"

По крайней мере, он работает сейчас, но выглядит не очень хорошо. Проблема только в том, что время иногда обновляется быстрее, чем в другое время. Пример: 1..2..3.4..5.6..7.8.9.0.10.11..12.13..14.15 (точки - это разрывы между каждым значением) (проб. Из-за миллисекунд)

Кто-нибудь знает, как я могу это исправить или, возможно, сделать возможным обновление ярлыка другим способом?

1 Ответ

0 голосов
/ 09 января 2019

В вашем коде есть несколько ошибок.

  1. Вы обновляете значение durationSlider из фонового потока. JavaFX является однопоточным, и доступ к GUI возможен только из Поток приложений JavaFX .
    • Вы можете использовать Platform.runLater здесь (но есть лучший вариант, см. Пункт # 4).
  2. Поле setCurrentTime не volatile, но вы пишете в него в фоновом потоке и читаете из него в Потоке приложений JavaFX . Это означает, что обновления одним потоком не гарантированы для просмотра другим.
    • Это может быть проблемой и для isPlaying, но вы не показываете его объявление.
  3. Каждый раз, когда вызывается updateValues(), вы запускаете новую тему !!
    • Поскольку свойство MediaPlayer.currentTime будет часто аннулироваться, у вас будет много потоков.
  4. Вы используете фоновый поток в первую очередь.
    • Не использование фонового потока отменяет предыдущие три пункта.
  5. Вы используете currentTime.format(...). Метод String.format является статическим, и было бы лучше вызвать его так: String.format(...).
    • Это делает ваш код более понятным. На самом деле, люди могут предположить, что format является методом экземпляра.

Относительно пункта № 4:

Нет необходимости использовать фоновый поток для обновления durationSlider или displayCurrentTime. Свойство currentTime MediaPlayer будет автоматически обновляться во время воспроизведения мультимедиа (и каждый раз уведомлять об этом любых слушателей). Эти обновления будут происходить в потоке приложений JavaFX . Все, что вам нужно сделать, это обновить пользовательский интерфейс внутри слушателя; поскольку вычисления не дороги, их можно делать в потоке приложений JavaFX .

mp.currentTimeProperty().addListener((observable, oldTime, newTime) -> {
  durationSlider.setValue(newTime.toMillis() / mp.getTotalDuration().toMillis() * 100);
  String formattedTime = ...; // your computations
  displayCurrentTime.setText(formattedTime);
});

В приведенном выше коде используется javafx.beans.value.ChangeListener вместо InvalidationListener. Он также использует лямбды; однако, если вы не хотите использовать лямбды (или пока не знаете о них), этот код эквивалентен:

mp.currentTimeProperty().addListener(new ChangeListener<>() {

  @Override
  public void changed(ObservableValue<? extends Duration> observable,
                      Duration oldTime, Duration newTime) {
    durationSlider.setValue(newTime.toMillis() / mp.getTotalDuration().toMillis() * 100);
    String formattedTime = ...; // your computations
    displayCurrentTime.setText(formattedTime);
  }

});
...