Есть ли способ рисовать на JPanel из асинхронного метода? - PullRequest
1 голос
/ 29 мая 2019

Я пишу Java-игру с использованием Swing и Firebase. Я сохраняю всех своих игроков в списке, и когда любой из них перемещает обратный вызов onChildChanged(...) (см. Ниже), запускается. Поскольку это асинхронный режим, я, очевидно, не могу установить переменные, выходящие за рамки функции. Это было все нормально, пока мне не нужно было нарисовать этот плеер на экране.

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

Я попытался «экспортировать» объект Graphics g в глобальную переменную, а затем использовать эту переменную в асинхронной функции, но это не дало никаких результатов. Может быть, потому что это на самом деле не рисование на холсте JPanel?

Итак, у меня есть что-то вроде этого:

class Screen extends JPanel {

@Override
public void paintComponent(Graphics g) {
    // All my painting stuff goes here
}

ref.addChildEventListener(new ChildEventListener() {

            // This is the callback
            @Override
            public void onChildChanged(DataSnapshot snapshot, String previousChildName) {
                      // Draw the player
                }
            }
        });

}

РЕДАКТИРОВАТЬ: забыл упомянуть, что я также звоню repaint() на каждом игровом тике (60 раз в секунду). Я не знаю, если это что-то меняет, но на всякий случай:)

Итак, я хочу, чтобы я мог рисовать игрока внутри колбэка или рисовать его методом paintComponent(), и мне интересно, как это можно сделать.

Спасибо!

1 Ответ

2 голосов
/ 29 мая 2019

Вы не должны рисовать нигде, кроме как внутри метода paintComponent. Итак, решение:

  • Обновите поля модели, которые используются, чтобы указать GUI, что рисовать.
  • Если это обновление будет напрямую влиять на GUI любым другим способом, таким как текстовые поля обновления, метки, JTables и т. Д., То это изменение данных следует выполнить в EDT, поместив его в очередь событий в Runnable, переданном в SwingUtilities.invokeLater(...)
  • Тогда звоните repaint()
  • Затем графический интерфейс будет использовать эти поля и рисовать все в потоке событий Swing.

Обратите внимание, что repaint() - это один из немногих методов Swing, который можно вызвать off из EDT.


Меня немного смущает, что вы подразумеваете под обновлением полей модели, хотя, ха-ха, не могли бы вы уточнить это?

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

Например, если у вас есть игра с анимацией, модель будет отображать местоположение игроков, состояние игроков (здоровье, оружие, инвентарь), их поведение, .... в то время как представление будет рисовать все это основано на состоянии модели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...