如果在JFrame代码

时间:2016-02-13 16:41:27

标签: java swing jpanel repaint

我有一个班级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的初始状态,因为paintComponent曾被调用jFrame.setVisible(true)叫做。然后正在执行 while循环,但CellularJPanel没有重新绘制,paintComponent未被调用。我不明白为什么,也许我应该以某种方式使用SwingUtilities.invokeLater(...)java.awt.EventQueue.invokeLater,但我已经尝试过它们并且它没有用,我做错了。< / p>

有什么建议吗?

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

2 个答案:

答案 0 :(得分:5)

您的问题是Event Dispatch Thread上的Map<String, Integer> keysToIndex = new HashMap<>(); Integer index = 0; for (String obj: hashMap.keySet()) { keysToIndex.put(obj, index); index += 1; } 会阻止与UI相关的任何内容,因为UI事件不再被处理。

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

因此请删除该循环,而是使用javax.swing.Timer为您的活动计时。在计时器事件中,更改UI的状态并调用while(true)。 timer事件将与UI线程同步,因此允许更改UI组件的状态。

答案 1 :(得分:4)

有一个UI线程可以绘制东西 - 它也是处理按钮点击的线程。在摇摆中,这被称为event dispatch thread。如果UI线程忙于运行while循环,则无法绘制。

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

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