Вопрос по swing, timer, java, concurrency, event-dispatching – Правильно ли обновлять компоненты свинга?

6

Я новичок на качелях, любая помощь приветствуется.

В этом фрагменте кода я переворачиваю карту лицевой стороной вверх, если выясняется, что они не совпадают, я хочу, чтобы они снова повернули лицевой стороной вниз.

В момент, когда происходит: 1. при нажатии первая карта переворачивается 2. при нажатии второй карты происходит одно из двух: (а) если они одинаковые, они оба остаются, что я хочу (б), если они не совпадают, я никогда не вижу 2-ую карту вообще, так как она немедленно повторно отображает оборотную сторону карты (и оборотную сторону предыдущей карты также, как определено в моем методе).

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

Я попытался использовать contentPane.revalidate (); & contentPane.repaint (); но это ничего не меняет.

Я вставил в некоторые выводы консоли:

Console output:
Card: 0 set
Card: 6 set
Sleeping now
Card: 6 unset
Card: 0 unset

Выше приведен результирующий вывод консоли при нажатии двух карт, которые не совпадают

@Override
public void actionPerformed(ActionEvent e) 
{
    String buttonPressed = e.getActionCommand();
    int pos = Integer.valueOf(buttonPressed);
    action = Control.model.ReceiveCardsTurned(pos);

    keypadArray[pos].setIcon(myIcons[pos]);     
    System.out.println("Card: "+pos+" set");
    currentTime.setText("" + Control.model.time);
    currentScore.setText("" + Control.model.score);

    //contentPane.revalidate();
    //contentPane.repaint();        

    if(Control.model.twoCardsTurned == false)
    {
        if (action == "unturn") 
        {
            System.out.println("Sleeping now");

            try 
            {
                Thread.sleep(1000);
            }

            catch (InterruptedException e1) 
            {
                e1.printStackTrace();
            }

            keypadArray[pos].setIcon(back);
            keypadArray[Control.model.lastCard].setIcon(back);
            System.out.println("Card: "+pos+" unset");
            System.out.println("Card: "+Control.model.lastCard+" unset");
        }
    }
}

Ваш Ответ

2   ответа
7

потому что ваш графический интерфейс будет зависать. Вы должны использоватьТаймер качания, Что касается фоновых задач, о которых вам, вероятно, придется беспокоиться в будущем, взгляните наSwingWorker.

@HovercraftFullOfEels Я улучшил ответ, спасибо за вашу заметку. Behnil
Я согласен с ховеркрафтом, думаюSwingWorker покончено с этой простой проблемой MadProgrammer
Спасибо за помощь, приятель Ron
в конечном итоге использовать SwingWorker ... в конце концов, это было необходимо позже, как вы и предсказывали Behnill .. спасибо Ron
6

Swing - это управляемая событиями среда. Это означает, что нет средств (или, по крайней мере, очень немногих), которые вы могли бы «ждать» ввода пользователя, обычно вам просто нужно реагировать на их взаимодействие.Swing управляется одним потоком, известным как поток диспетчеризации событий (AKA EDT). Этот поток отвечает за отправку / обработку событий, поступающих в приложение, в соответствующие части приложения, чтобы они могли предпринять действия.Менеджер перерисовки публикует свои запросы на обновление в EDT.

ЛЮБОЕ действие, которое вы предпринимаете, чтобы остановить EDT от выполнения этой работы, заставит ваше приложение выглядеть как зависшее.

Вы НИКОГДА не должны выполнять какие-либо трудоемкие операции (такие как ввод / вывод, циклы илиThread#sleep например) на EDT, это сделает ваше приложение "паузой", которая никогда не бывает красивой.

ПрочитайтеПараллелизм в Swing для дополнительной информации.

Теперь у вас есть несколько вариантов. Вы могли бы использоватьThread «ждать» в фоновом режиме и повернуть карты обратно, или вы могли бы использоватьSwingWorker илиjavax.swing.Timer.

Другая проблема, которую вы имеете, состоит в том, что вы НИКОГДА не должны обновлять какие-либо компоненты пользовательского интерфейса из любогоThread кроме EDT. Это означает, что если бы вы использовалиThread, вы станете ответственным за повторную синхронизацию этого потока с EDT. Хотя это и не сложно, это просто становится грязным.

SwingWorker а такжеjavax.swing.Timer есть функциональность, которая делает это намного проще.

Темы иSwingWorker отлично подходят для выполнения фоновой обработки и будут просто излишними для этой проблемы. Вместо этогоjavax.swing.Timer идеально подошло бы здесь.

if (!Control.model.twoCardsTurned)
    {
        if ("unturn".equals(action)) 
        {
            new Timer(1000, new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    keypadArray[pos].setIcon(back);
                    keypadArray[Control.model.lastCard].setIcon(back);
                    System.out.println("Card: "+pos+" unset");
                    System.out.println("Card: "+Control.model.lastCard+" unset");
                }
            }).start();
        }
    }

Это действительно простой пример. Возможно, вы захотите добавить некоторые элементы управления, которые не позволят пользователю нажимать что-либо, пока не сработает таймер, например;)

Еще раз спасибо, очень полезный и очень информативный ответ. Я должен буду еще немного почитать об основных понятиях свинга Ron

Похожие вопросы