提问者:小点点

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


我有一个类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);
    }
}

如果我在< code>main()方法中使用上面的代码,那么一切正常,< code>CellularJPanel重新绘制,< code>paintComponent()被正常调用。

如果我将相同的代码粘贴到UI JFrame按钮click事件方法,那么new JFrame会显示甚至显示< code>Forest的初始状态,因为在调用< code > JFrame . set visible(true)时,会调用< code>paintComponent。然后执行< code>while循环,但< code>CellularJPanel不重新绘制,不调用< code>paintComponent。我不知道为什么,也许我应该使用< code > swing utilities . invokelater(...)或者< code > Java . awt . event queue . invoke later ,但是我试过了,没有用,我做错了。

有什么建议吗?

P.S. 我的目标是在同一个UI JFrame中显示CellularJPanel,从中单击按钮。但是即使我将此面板添加到主UI JFrame,它也无法正常工作。


共2个答案

匿名用户

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

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

因此,请删除该循环,而是使用javax. swing.Timer来为您的事件计时。在计时器事件中,更改UI的状态并调用重新绘制。计时器事件将与UI线程同步,因此允许更改UI组件的状态。

匿名用户

有一个绘制东西的UI线程,它也是处理按钮点击的线程。在swing中,这被称为事件调度线程。如果UI线程忙于运行< code>while循环,它就不能进行绘制。

你可以通过让你的按钮点击处理程序只运行循环的一次迭代(没有睡眠)来快速验证这一点:forest.update();forestJpanel.repair()

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