如果在JFrame代码中调用了repaint(),则JPanel不会重绘 [英] JPanel doesn't repaint if repaint() is called within JFrame code
问题描述
我有一个类Forest
和CellularJPanel
,该类扩展了JPanel
并显示Forest
.我写了一个原始代码来创建JFrame
,Forest
,CellularJPanel
并将CellularJPanel
添加到JFrame
.接下来是无限循环,该循环使Forest
更新和CellularJPanel
重新绘制.
I have a class Forest
and CellularJPanel
, which extends JPanel
and displays Forest
. I wrote a primitive code to create JFrame
, Forest
, CellularJPanel
and add CellularJPanel
to the JFrame
. Next is an infinite loop, which makes Forest
update and CellularJPanel
repaint.
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()
通常被调用.
If I use above code within main()
method, then everything works fine,
CellularJPanel
repaints, paintComponent()
is called normally.
如果我将相同的代码粘贴到UI JFrame按钮单击事件方法,则新的JFrame会显示甚至显示Forest
的初始状态,因为一旦调用jFrame.setVisible(true)
时就会调用paintComponent
.然后,将执行 while
循环,但是CellularJPanel
不会重新绘制,不会调用paintComponent
.我不知道为什么,也许我应该以某种方式使用SwingUtilities.invokeLater(...)
或java.awt.EventQueue.invokeLater
,但是我已经尝试了它们,但是它没有用,我做错了.
If I paste the same code to UI JFrame button click event method, then new JFrame shows and even displays initial state of the Forest
, because paintComponent
is once called, when jFrame.setVisible(true)
is called. Then while
loop is being executed, but CellularJPanel
doesn't repaint, paintComponent
is not called. I have no idea why, maybe I should use SwingUtilities.invokeLater(...)
or java.awt.EventQueue.invokeLater
somehow, but I've tried them and it didn't work, I'm doing something wrong.
有什么建议吗?
P.S.
我的目标是在单击该按钮的同一UI JFrame中显示CellularJPanel
.但是,即使我将此面板添加到主UI JFrame中,也无法正常工作.
P.S.
My target is to display CellularJPanel
within the same UI JFrame, from which button was clicked. But even if I add this panel to main UI JFrame, it doesn't work.
推荐答案
Your problem is having a while(true)
on the Event Dispatch Thread which will block anything related to UI because UI events aren't getting handled anymore.
事件分发线程(单个线程)处理UI事件消息的队列,直到处理while(true)
循环正在运行的线程为止.然后它会阻止任何进一步的处理,因为上面存在无限循环.从该循环中调用SwingUtilities.invokeLater
将无济于事,因为它会将事件发布到事件分配线程中,该事件在while(true)
循环中被阻止.
The event dispatch thread (a single thread) works down a queue of UI event messages, until it handles the one where your while(true)
loop is running. It then blocks any further processing because there's an infinite loop on it. Calling SwingUtilities.invokeLater
from that loop won't help because it posts an event to the event dispatch thread, which is blocked in the while(true)
loop.
因此,请删除该循环,而应使用 repaint
.计时器事件将与UI线程同步,因此允许更改UI组件的状态.
So remove that loop, instead use a javax.swing.Timer
to time your events. In the timer event, change the state of your UI and call for a repaint
. The timer event will be synchronized with the UI thread, so changing state of UI components is allowed.
这篇关于如果在JFrame代码中调用了repaint(),则JPanel不会重绘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!