如果在JFrame代码中调用repaint(),则JPanel不会重新绘制
我有一个类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
初始状态,因为在调用jFrame.setVisible(true)
会调用paintComponent
。 然后while
执行循环时,但是CellularJPanel
没有重新绘制,则不会调用paintComponent
。 我不知道为什么,也许我应该以某种方式使用SwingUtilities.invokeLater(...)
或java.awt.EventQueue.invokeLater
,但我已经尝试过它们并没有用,我做错了。
有什么建议么?
PS我的目标是在同一个UI JFrame中显示CellularJPanel
,从中单击按钮。 但即使我将此面板添加到主UI JFrame,它也无法正常工作。
您的问题是在事件调度线程上有一段while(true)
,它将阻止与UI相关的任何事情,因为UI事件不再被处理。
事件调度线程(单个线程)在UI事件消息队列中运行,直到它处理运行while(true)
循环的那个。 然后它会阻止任何进一步的处理,因为它上面有一个无限循环。 从该循环调用SwingUtilities.invokeLater
将无济于事,因为它将事件发布到事件调度线程,该线程在while(true)
循环中被阻止。
因此,删除该循环,而不是使用javax.swing.Timer
来计时事件。 在计时器事件中,更改UI的状态并调用repaint
。 计时器事件将与UI线程同步,因此允许更改UI组件的状态。
有一个UI线程可以绘制东西 – 它也是处理按钮点击的线程。 在swing中,这称为事件派发线程 。 如果UI线程忙于运行while
循环,则无法绘制。
您可以通过使按钮单击处理程序仅运行循环的单次迭代(没有睡眠)来快速validation这一点: forest.update(); forestJpanel.repaint();
forest.update(); forestJpanel.repaint();
您可以从一个单独的线程(如Timer
)自动更新,该线程在循环中调用repaint / sleep。