2016-02-13 82 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

相關問題