我有一个班级Forest
和CellularJPanel
,它会扩展JPanel
并显示Forest
。我写了一个原始代码来创建JFrame
,Forest
,CellularJPanel
并将CellularJPanel
添加到JFrame
。接下来是一个无限循环,使Forest
更新和CellularJPanel
重绘。
JFrame jFrame = new JFrame();
Forest forest = new Forest();
CellularJPanel forestJPanel = new CellularJPanel(forest);
jFrame.add(forestJPanel);
jFrame.pack();
//jFrame.setResizable(false);
jFrame.setLocationRelativeTo(null);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setVisible(true);
while (true)
{
try
{
forestJPanel.repaint();
forest.update();
forest.sleep(); // calls Thread.sleep(...)
}
catch (InterruptedException e)
{
}
}
以下是CellularJPanel
类的代码:
public class CellularJPanel extends JPanel
{
private CellularAutomata cellularAutomata;
public CellularJPanel(CellularAutomata cellularAutomata)
{
super();
this.cellularAutomata = cellularAutomata;
setPreferredSize(this.cellularAutomata.getDimension());
}
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D graphics2D = (Graphics2D)g;
cellularAutomata.draw(graphics2D);
}
}
如果我在main()
方法中使用上面的代码,那么一切正常,
CellularJPanel
重绘,paintComponent()
被正常调用。
如果我将相同的代码粘贴到UI JFrame按钮点击事件方法,那么新的JFrame会显示甚至显示Forest
的初始状态,因为paintComponent
曾被调用jFrame.setVisible(true)
叫做。然后正在执行 while
循环,但CellularJPanel
没有重新绘制,paintComponent
未被调用。我不明白为什么,也许我应该以某种方式使用SwingUtilities.invokeLater(...)
或java.awt.EventQueue.invokeLater
,但我已经尝试过它们并且它没有用,我做错了。< / p>
有什么建议吗?
P.S。
我的目标是在同一个UI JFrame中显示CellularJPanel
,点击该按钮。但即使我将此面板添加到主UI JFrame,它也无法正常工作。
答案 0 :(得分:5)
您的问题是Event Dispatch Thread上的Map<String, Integer> keysToIndex = new HashMap<>();
Integer index = 0;
for (String obj: hashMap.keySet()) {
keysToIndex.put(obj, index);
index += 1;
}
会阻止与UI相关的任何内容,因为UI事件不再被处理。
事件调度线程(单个线程)处理UI事件消息队列,直到它处理运行while(true)
循环的事件。然后它会阻止任何进一步的处理,因为它上面有一个无限循环。从该循环调用while(true)
不会有帮助,因为它会向事件调度线程发布一个事件,该线程在SwingUtilities.invokeLater
循环中被阻止。
因此请删除该循环,而是使用javax.swing.Timer
为您的活动计时。在计时器事件中,更改UI的状态并调用while(true)
。 timer事件将与UI线程同步,因此允许更改UI组件的状态。
答案 1 :(得分:4)
有一个UI线程可以绘制东西 - 它也是处理按钮点击的线程。在摇摆中,这被称为event dispatch thread。如果UI线程忙于运行while
循环,则无法绘制。
您可以通过使按钮单击处理程序仅运行循环的单次迭代(无睡眠)来快速验证这一点:forest.update(); forestJpanel.repaint();
您可以从一个循环调用repaint / sleep的单独线程(如Timer
)自动更新。