Обновление компонентов swing правильно?

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

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

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

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

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

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

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 ответов


есть ряд важных понятий, которые вы, кажется, не хватает.

  1. Swing-это среда, управляемая событиями. Это означает, что нет средств (или, по крайней мере, очень мало), которые вы можете "ждать" ввода пользователя, как правило, вам просто нужно реагировать на их взаимодействие.
  2. Swing управляется одним потоком, известным как поток диспетчеризации событий (он же EDT). Ответственность за отправку/обработку событий, поступающих в приложение, лежит на этом потоке к соответствующим частям приложения, чтобы они могли принять меры.
  3. менеджер перекраски отправляет свои запросы на обновление в 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();
        }
    }

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


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