如果在 JFrame 代码中调用 repaint(),JPanel 不会重新绘制
Posted
技术标签:
【中文标题】如果在 JFrame 代码中调用 repaint(),JPanel 不会重新绘制【英文标题】:JPanel doesn't repaint if repaint() is called within JFrame code 【发布时间】:2016-02-13 16:41:27 【问题描述】:我有一个类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
,但我已经尝试过了,但它不起作用,我做错了什么。
有什么建议吗?
附:
我的目标是在同一个 UI JFrame 中显示CellularJPanel
,点击该按钮。但即使我将此面板添加到主 UI JFrame,它也不起作用。
【问题讨论】:
对了,欢迎来到 ***! 谢谢 :) *** 非常有用! 【参考方案1】:您的问题是在Event Dispatch Thread 上有一个while(true)
,这将阻止与 UI 相关的任何内容,因为不再处理 UI 事件。
事件调度线程(单个线程)在 UI 事件消息队列中工作,直到它处理您的 while(true)
循环正在运行的那个。然后它会阻止任何进一步的处理,因为它上面有一个无限循环。从该循环调用 SwingUtilities.invokeLater
将无济于事,因为它会将事件发布到事件调度线程,该线程在 while(true)
循环中被阻塞。
所以删除那个循环,而是使用javax.swing.Timer
来为您的事件计时。在计时器事件中,更改 UI 的状态并调用 repaint
。定时器事件将与 UI 线程同步,因此允许更改 UI 组件的状态。
【讨论】:
【参考方案2】:有一个单独的 UI 线程来绘制事物 - 它也是处理按钮点击的线程。在摇摆中,这称为event dispatch thread。如果 UI 线程忙于运行 while
循环,则无法绘制。
您可以通过让您的按钮单击处理程序只运行循环的一次迭代(没有睡眠)来快速验证这一点:forest.update(); forestJpanel.repaint();
您可以从一个单独的线程(如 Timer
)自动更新,该线程在循环中调用 repaint/sleep。
【讨论】:
你的回答也可以接受,但TT早2分钟就回答了:) 从技术上讲,时间戳显示我的是第一个 2 分钟,但是哦,好吧以上是关于如果在 JFrame 代码中调用 repaint(),JPanel 不会重新绘制的主要内容,如果未能解决你的问题,请参考以下文章