Шаблон проектирования для потоковой передачи аудио в свинг-приложении: как сообщить, что midi executor выключен для изменения состояния графического интерфейса? - PullRequest
1 голос
/ 12 марта 2012

Мое приложение отображает различные изменения состояния графического интерфейса пользователя, а также позволяет пользователю вводить данные, основываясь на том, что файлы Midi успешно завершили воспроизведение.Какой лучший способ подождать в цикле while, который меняет состояние графического интерфейса, воспроизводит midi на ExecutorService, обновляет модель и ждет, пока midifile завершит воспроизведение, прежде чем повторить через некоторое время?В настоящее время мой код выглядит примерно так:

public void startTraining() {
    int i = 0;
    while( i != Model.getTestIteration() + 1) {

        //create GUI state changes and schedule on EDT
        myButton.setButtonSelected( true);
        Timer t = new Timer( DELAY_TIME, new ActionListener() {
            public void actionPerformed( ActionEvent avt) {
                 myButton.setButtonSelected( false);
                                 }
                });)
        t.setRepeats( false);
        t.start();

        //MidiplaybackController uses ScheduluedExecutorService
        //to start and stop playback with its own ScheduluedFuture<?> for stopping
        //at a fixed interval
        _midiPlaybackController.playQueue( (int)aCue));

        //TODO: pause somehow relative to midiplayback finishing

        Model.updateTestIteration();
        myButton.setSelected( true);
        i++;
    }
}

Какой здесь лучший шаблон.Я хочу, чтобы изменения состояния происходили в EDT, midistuff в его собственном потоке с расписанием, а затем ожидал в midi внесение изменений в другие серии или состояния GUI.Должен ли я создать SwingWorker и затем запустить Midiplayback ExecutorServices в SwingWorker?Или я должен создать что-то вроде CountDownLatch в Todo, которое ожидает завершения работы Midi Executor и Timer t до конца?

Дополнительный вопрос: стоит ли устанавливать и значок, и выбранный значок?, а затем просто переключаться между вызовами setSelected (boolean b), чтобы отразить состояние кнопки?

Ответы [ 2 ]

1 голос
/ 13 марта 2012

Я не уверен, что вам действительно нужен цикл while в GUI.Можете ли вы настроить графический интерфейс для получения сообщений?Например, когда MIDI-файл заканчивается, если это важная информация, попросите прослушиватель MIDI-файла отправить любое желаемое сообщение на панель GUI, возможно, вместе с update или repaint ().

Для SourceDataLineвоспроизведения, есть LineListener, который может быть активирован в конце воспроизведения.Я почти уверен, что есть что-то подобное и для воспроизведения MIDI.

[Редактировать: осматривать учебник, http://docs.oracle.com/javase/tutorial/sound/MIDI-seq-adv.html, есть раздел «Указание прослушивателей специальных событий», который может быть полезен.]

Если я хочу приостановить поток, мой первый выбор - Thread.sleep ().Можно отправить прерывание команде сна, если вам нужно выйти из него раньше, чем вы выбрали.Точность команды сна ограничена прерыванием системных часов, а в некоторых ОС Microsoft может быть отключено до 15 мсек - это единственный недостаток.Настройка «пробуждения по вызову» от таймера имеет такое же ограничение точности синхронизации.

Если вы включаете активность, чтобы убить время, вы, вероятно, потребляете циклы ЦП без необходимости, потенциально замедляя остальную часть вашей программы.

Не могу сказать, что полностью понимаю вашу настройку после попытки прочитать ваш вопрос, и я надеюсь, что это, по крайней мере, несколько полезно!

0 голосов
/ 13 марта 2012

Я думаю, вы могли бы ладить с чем-то вроде этого:

_midiPlaybackController.playQueue((int)aCue, new MyMidiPlaybackListener());

, где MyMidiPlaybackListener - это класс вашего собственного создания, который выглядит примерно так

public class MyMidiPlaybackListener implements MidiPlaybackListener
{
    public void onPlaybackComplete()
    {
        // Since onPlaybackComplete is likely called by a worker thread
        // And we don't want to update the GUI from a worker thread
        // (because that would violate Swing's threading policy)
        // we update the GUI via a SwingUtilities.invokeLater Runnable
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                myButton.setSelected(true);
            }
        });
    }
}

Класс реализует интерфейс MidiPlaybackListener, который также является вашим собственным созданием:

public interface MidiPlaybackListener 
{
    public void onPlaybackComplete();
}

Измените метод playQueue для MidiPlaybackController, чтобы он поддерживал принятие аргумента слушателя (как показано).MidiPlaybackController также необходимо изменить, чтобы сохранить слушателя и вызвать его в соответствующее время (предположительно, в конце воспроизведения).

...