Синхронизировать с Swing: ждать пользовательского интерфейса - PullRequest
2 голосов
/ 15 сентября 2010

Обычно ищут способ обновить пользовательский интерфейс, пока что-то в фоновом режиме все еще работает.Мой подход - использовать новую тему или просто использовать SwingUtilities.invokeLater.

Однако сейчас я нахожусь в совершенно противоположной ситуации.У меня есть кнопка, которая вызывает статический метод, который делает немного магии (здесь это не важно).Нажатие на кнопку также запускает анимацию в потоке пользовательского интерфейса (в настоящее время реализуется с помощью Swing Timer).Когда магический метод завершается, он сначала запускает событие в пользовательском интерфейсе, а затем продолжает делать что-то еще.Событие сообщает пользовательскому интерфейсу остановить анимацию - после некоторой задержки (фактически пользовательский интерфейс должен показывать другую анимацию в течение короткого времени).

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

Как правильно заставить фоновый процесс ожидать пользовательского интерфейса?

edit

Приведенный ниже код демонстрирует чрезвычайно упрощенное, что происходит.Пользовательский интерфейс является лишь одним из реальных слушателей (хотя и единственным блокирующим), поэтому я бы предпочел иметь некоторый блокирующий эффект на стороне пользовательского интерфейса при обработке событий.

public class Worker
{
    public static void magicMethod()
    {
        // do something
        // ...

        // fire event
        for ( ExampleEventListener listener : listeners )
            listener.onExampleEvent( new ExampleEvent() );

        // BLOCK until animation in UI completed
        nextStep();
    }

    public static void nextStep ()
    {
        // continue work
    }
}


public class MyWindow extends JFrame implements ExampleEventListener
{
    public void actionPerformed ( ActionEvent event )
    {
        // button clicked
        Worker.magicMethod();
    }

    public void onExampleEvent ( ExampleEvent event )
    {
        startAsynchronousAnimation();
    }

    private void completeAnimation ()
    {
        // animation completed
        animationPanel.setVisible( false );

        // UNLOCK
    }
}

Ответы [ 2 ]

1 голос
/ 15 сентября 2010

Не уверен, что это лучший способ, но вы можете использовать общее логическое значение, чтобы сигнализировать, готов ли фоновый процесс продолжить. Использование wait () заставит поток снять блокировку объекта в синхронизированном блоке. Что-то вроде:

while(! ready){
    try{
        mySynchonizedObject.wait(); 
    }catch(InterruptedException ex){
        System.exit(1);
    }
}

Где 'ready' - это общее логическое значение. Когда ваш пользовательский интерфейс будет готов, он установит для true значение true и вызовет notifyAll ().

0 голосов
/ 15 сентября 2010

Ваш фоновый процесс может выполняться в потоке диспетчеризации событий - в том же потоке, в котором выполняется Swing. Затем просто запустите ваш фоновый код после диалогового приглашения или чего-то еще, и, как только он вернется, ваш фоновый код будет выполнен, эффективно заставляя его ждать пользовательского интерфейса.

...