如果在JFrame代码中调用repaint(),则JPanel不会重新绘制

Dar*_*rko 4 java swing jpanel repaint

我有一个类ForestCellularJPanel,延伸JPanel和显示Forest.我写了一个原始的代码来创建JFrame,Forest,CellularJPanel并添加CellularJPanelJFrame.接下来是一个无限循环,它进行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)
        {

        }
    }
Run Code Online (Sandbox Code Playgroud)

这是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);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我在main()方法中使用上面的代码,那么一切正常, CellularJPanel重绘,paintComponent()正常调用.

如果我将相同的代码粘贴到UI JFrame按钮单击事件方法,那么新的JFrame会显示甚至显示的初始状态Forest,因为paintComponent一旦被调用,jFrame.setVisible(true)就会被调用.然后while循环正在执行,但CellularJPanel没有重新绘制,paintComponent也没有被调用.我不知道为什么,也许我应该使用SwingUtilities.invokeLater(...)java.awt.EventQueue.invokeLater以某种方式,但我已经尝试过它们并没有用,我做错了什么.

有什么建议?

PS我的目标是CellularJPanel在同一个UI JFrame中显示,从中单击按钮.但即使我将此面板添加到主UI JFrame,它也不起作用.

TT.*_*TT. 5

您的问题是while(true)事件调度线程上有一个阻止与UI相关的任何内容,因为UI事件不再被处理.

事件调度线程(单个线程)在UI事件消息队列中while(true)运行,直到它处理循环运行的那个.然后它会阻止任何进一步的处理,因为它上面有一个无限循环.SwingUtilities.invokeLater从该循环调用将无济于事,因为它将事件发布到事件调度线程,该事件在while(true)循环中被阻塞.

所以删除该循环,而不是使用a javax.swing.Timer来计时事件.在计时器事件中,更改UI的状态并调用repaint.计时器事件将与UI线程同步,因此允许更改UI组件的状态.