Как вызвать немедленное обновление графического интерфейса Java?(конфликт с Thread.sleep ()) - PullRequest
7 голосов
/ 28 сентября 2011

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

Проблема, с которой я столкнулся, заключается в методе repaint(), который не перерисовывается немедленно.

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

Конечно, если я repaint() переверну карты, поверну их правой стороной вверх, подожду секунду, а затем repaint() снова, основываясь на их значениях, полезная маленькая Java перекрасит только один раз (я скучаю по C!).

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

Поскольку я знаю, что полезные люди в StackOverflow любят читать код, вот часть программы, о которой я говорю ниже. Класс HitArea является объектом Card, а массив cards[] содержит количество HitArea (я не переименовал класс HitArea). activeCard1 и activeCard2 являются экземплярами HitArea, которые я использую для отслеживания двух выборов пользователя, а пустой конструктор является зарезервированным «невидимым» HitArea, хотя позже я изменю его на ноль. Наконец, cards.flip() инвертирует логическое значение toggle, которое определяет, является ли карта правой стороной вверх.

public void respond(HitArea choice)
{
    if(choice.inGame)
    {
        if(activeCard1.value == 0 && activeCard1.value == 0)
            activeCard1 = choice;
        else if((!(activeCard1.value == 0) && activeCard2.value == 0) && (activeCard1.id != choice.id))
        {
            activeCard2 = choice;
            check();
        }

    }
}
public void check()
{
    update();
    pause(250);
    if(activeCard2.value == activeCard1.value)
    {
        score += 2;
        activeCard1.inGame = false;
        activeCard2.inGame = false;
    }
    activeCard1.flip();
    activeCard2.flip();
    activeCard1 = new HitArea();
    activeCard2 = new HitArea();
}
public void pause(int milliseconds)
{
    try{
      Thread.currentThread().sleep(milliseconds);
    }
    catch(InterruptedException e){
        System.out.println("Exception: " + e);
    }
}

public void mousePressed(MouseEvent e)
{
    int x = e.getX();
    int y = e.getY();

    for (int i = 0; i < cardNum; i++)
        if(cards[i].boundsCheck( x, y ) )
        {
            repaint();
            cards[i].flip();
            respond(cards[i]);
        }
}

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

1 Ответ

14 голосов
/ 28 сентября 2011

Не вызывайте Thread.sleep (...) в главном потоке Swing, EDT. Всегда .Вместо этого используйте Swing Timer.

Подумайте об использовании JLabels для отображения ваших изображений, и тогда вы сможете «перевернуть» свои карты, просто заменив ImageIcons.Когда вторая карта перевернута, если совпадения нет, запустите неповторяющийся таймер Swing с задержкой на xxxx мс, и в методе ActionCistener Timer ActionList он вернет оба JLabel обратно в ImageIcon по умолчанию.

Учебное пособие по javax.swing.Timer можно найти здесь: Как использовать таймеры Swing

Редактировать:
Что касается вашего комментария об использовании g.drawString:теперь это еще проще, поскольку все, что вам нужно сделать, это поменять текст вашего JLabel.Но позже, если вы решите обновить программу для отображения изображений, у вас все готово для этого.

Редактировать 2:
По поводу вашего вопроса о создании нового ActionListenerкласс: я бы использовал для этого анонимный внутренний класс.Например:

  int delayTime = 2 * 1000;
  javax.swing.Timer myTimer = new Timer(delayTime, new ActionListener() {

     @Override
     public void actionPerformed(ActionEvent e) {
        // TODO: put in the code you want called in xxx mSecs.
     }
  });
  myTimer.setRepeats(false);
  myTimer.start();
...