2016-02-13 30 views
4

我有一个类ForestCellularJPanel,它扩展了JPanel并显示Forest。我写了一个原始代码来创建JFrame,Forest,CellularJPanel并将CellularJPanel添加到JFrame。接下来是一个无限循环,它使Forest更新和CellularJPanel重绘。如果在JFrame代码中调用repaint(),则JPanel不会重新绘制

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.S. 我的目标是在单击按钮的同一个UI JFrame中显示CellularJPanel。但即使我将此面板添加到主UI JFrame,它也不起作用。

+0

顺便说一句,欢迎来到StackOverflow! – Krease

+0

谢谢:) StackOverflow是令人难以置信的有用! – Darko

回答

5

您的问题是Event Dispatch Thread上有while(true)这将阻止任何与UI相关的任何事情,因为UI事件不再受到处理。

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

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

4

有一个UI线程绘制的东西 - 它也是一个处理按钮点击。在挥杆中,这叫做event dispatch thread。如果UI线程忙于运行while循环,则无法绘制。

,可以快速使你的按钮单击处理程序只运行你的循环的单次迭代(不睡觉)验证这一点:forest.update(); forestJpanel.repaint();

你可以从一个单独的线程自动更新(如Timer)调用重绘/睡在一个循环。

+0

您的回答也可以接受,但TT已经提前2分钟回复:) – Darko

+0

从技术上讲,时间戳显示我的时间是第一个2分钟,但是很好 – Krease

相关问题