繁体   English   中英

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

[英]JPanel doesn't repaint if repaint() is called within JFrame code

我有一个类ForestCellularJPanel ,它扩展了JPanel并显示了Forest 我写了一个原始代码来创建JFrameForestCellularJPanel并将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循环,则无法绘制。

您可以通过使按钮单击处理程序仅运行循环的单次迭代(不使用睡眠)来快速验证这一点: forest.update(); forestJpanel.repaint(); forest.update(); forestJpanel.repaint();

您可以从一个单独的线程(如Timer )自动更新,该线程在循环中调用repaint / sleep。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM