有没有一种方法可以从异步方法绘制到JPanel上?

时间:2019-05-29 00:01:25

标签: java swing firebase awt

我正在使用Swing和Firebase编写基于Java的游戏。我将所有播放器都存储在一个列表中,当其中任何一个移动时,都会触发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
                }
            }
        });

}

编辑:忘记提及我在每个游戏滴答声(每秒60次)时也呼叫repaint()。我不知道这是否会改变,只是以防万一:)

所以我希望能够在回调中绘制播放器或在paintComponent()方法中绘制播放器,而我想知道如何做到这一点。

谢谢!

1 个答案:

答案 0 :(得分:2)

除了paintComponent方法内,您不应该在任何地方绘制。因此解决方案是:

  • 更新用于告知GUI绘画内容的模型字段。
  • 如果此更新将以任何其他方式直接影响GUI,例如更新文本字段,标签,JTables等,则应在EDT上执行此数据更改,方法是将其放入传递给Runnable的事件队列中。 SwingUtilities.invokeLater(...)
  • 然后致电repaint()
  • 然后,GUI将使用这些字段并在Swing事件线程上进行所有绘制。

请注意,repaint()是少数几种可以在EDT中称为 off 的Swing方法之一。


  

我对您通过哈哈更新模型字段的含义感到困惑,您能否澄清一下?

如果要创建任何复杂的GUI,则可能会使用模型-视图类型的结构(例如用于模型视图控制器的MVC),在该结构中,程序逻辑,模型部分与GUI分开,视图。该视图描述了模型的状态并允许用户交互,因此我在谈论状态字段。

例如,如果您有一个带有动画的游戏,则该模型将表示玩家的位置,玩家的状态(健康状况,武器,存货),他们的行为等,而视图将绘制所有基于模型的状态。