有没有办法从异步方法绘制到 JPanel 上?
Is there a way to paint onto a JPanel from an async method?
我正在使用 Swing 和 Firebase 编写一个基于 Java 的游戏。我将我所有的玩家存储在一个列表中,当他们中的任何一个移动时, onChildChanged(...)
回调(见下文)被触发。由于这是异步的,我显然不能设置任何超出函数范围的变量。这一切都很好,直到我需要将这个播放器实际绘制到屏幕上。
因为我扩展了 JPanel
并覆盖它 paintComponent(Graphics g)
我必须在这个方法中完成我的所有绘图(或者至少这是我被告知的)。问题是我需要从回调中绘制这个玩家,这是我不知道该怎么做的。
我曾尝试将 "export" 对象 Graphics g
设置为全局变量,然后在异步函数中使用该变量,但这没有产生任何结果。可能是因为它实际上并没有绘制到 JPanel 的 canvas?
所以我有一个 class 像这样的东西:
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()
方法中绘制它,我想知道如何做到这一点。
谢谢!
除了在 paintComponent 方法内,你不应该在任何地方绘画。所以解决方案是:
- 更新用于告诉 GUI 要绘制什么的模型字段。
- 如果此更新将以任何其他方式直接影响 GUI,例如更新文本字段、标签、JTable 等,则应通过将 EDT 放入 Runnable 内的事件队列来对 EDT 执行此数据更改传入
SwingUtilities.invokeLater(...)
- 然后调用
repaint()
- 然后 GUI 将使用这些字段并在 Swing 事件线程上进行所有绘制。
请注意,repaint()
是为数不多的可以调用 EDT off 的 Swing 方法之一。
I am little confused as to what you mean by updating the model's fields though haha, could you maybe clarify that?
如果您正在创建任何复杂的 GUI,您可能会使用模型 - 视图类型的结构(例如 M-V-C 用于 model-view-controller),您可以在其中分离程序逻辑、模型部分, 从 GUI 来看。视图描述了模型的状态并允许用户交互,所以我说的是状态字段。
例如,如果您有一个带有动画的游戏,模型将代表玩家的位置、玩家的状态(生命值、武器、库存)、他们的行为……而视图将根据模型的状态绘制所有这些。
我正在使用 Swing 和 Firebase 编写一个基于 Java 的游戏。我将我所有的玩家存储在一个列表中,当他们中的任何一个移动时, onChildChanged(...)
回调(见下文)被触发。由于这是异步的,我显然不能设置任何超出函数范围的变量。这一切都很好,直到我需要将这个播放器实际绘制到屏幕上。
因为我扩展了 JPanel
并覆盖它 paintComponent(Graphics g)
我必须在这个方法中完成我的所有绘图(或者至少这是我被告知的)。问题是我需要从回调中绘制这个玩家,这是我不知道该怎么做的。
我曾尝试将 "export" 对象 Graphics g
设置为全局变量,然后在异步函数中使用该变量,但这没有产生任何结果。可能是因为它实际上并没有绘制到 JPanel 的 canvas?
所以我有一个 class 像这样的东西:
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()
方法中绘制它,我想知道如何做到这一点。
谢谢!
除了在 paintComponent 方法内,你不应该在任何地方绘画。所以解决方案是:
- 更新用于告诉 GUI 要绘制什么的模型字段。
- 如果此更新将以任何其他方式直接影响 GUI,例如更新文本字段、标签、JTable 等,则应通过将 EDT 放入 Runnable 内的事件队列来对 EDT 执行此数据更改传入
SwingUtilities.invokeLater(...)
- 然后调用
repaint()
- 然后 GUI 将使用这些字段并在 Swing 事件线程上进行所有绘制。
请注意,repaint()
是为数不多的可以调用 EDT off 的 Swing 方法之一。
I am little confused as to what you mean by updating the model's fields though haha, could you maybe clarify that?
如果您正在创建任何复杂的 GUI,您可能会使用模型 - 视图类型的结构(例如 M-V-C 用于 model-view-controller),您可以在其中分离程序逻辑、模型部分, 从 GUI 来看。视图描述了模型的状态并允许用户交互,所以我说的是状态字段。
例如,如果您有一个带有动画的游戏,模型将代表玩家的位置、玩家的状态(生命值、武器、库存)、他们的行为……而视图将根据模型的状态绘制所有这些。