2014-06-19 55 views
0

我已經完成了一個程序,它可以數字化地求解一組描述「任意」疾病如何在一個孤立且恆定的人羣中移動的微分方程組,這是一個我剛剛學過的課程的編程任務。我所做的擴展它的方法是添加一些可以暫停,重置和「播放」仿真的圖形組件,以及一些允許我改變方程中常數的組件。圖形組件

所有這些都是編程練習,因爲我發現它很有趣,令人興奮,想要變得更好。

但是,目前我卡住了,現在我想要做的是製作一個非常簡單的動畫形式。我想將我得到的數據以網格中受感染,敏感和抵抗物的數量可視化爲點。我設法創建了網格並瞭解如何放置點。

我遇到的問題是如何在程序運行時畫點,我可以在網格中繪製一個點,但只能在網格創建時,就是這樣。我需要能夠在網格中的特定位置創建一個點,直到點數達到有限數字(例如30)爲止。在這一點上,我想要移除第一個點,左邊一個點,所有的點向左移動,並將新點放在網格的最右側,然後重複整個事情。

我想我可以找出一些關於paintComponent()方法的幫助/提示,​​以及我是否需要使用repaint()方法,但出於某種原因,我無法理解這些問題。我已閱讀了關於Java的課程文獻,但儘管有大量的章節介紹了大多數不同的圖形組件,但他並沒有多說這些方法,只是你不需要使用paintComponent()方法,它已經完成了自動。

如果有什麼不清楚的東西讓我知道,我會盡力澄清它。

在此先感謝。

// 狐狸穆德

回答

1

我想我將能夠提供有關paintComponent()方法和是否我需要使用repaint()方法都有些幫助/提示,​​算起來,我不能讓由於某種原因,我的頭圍繞着這些。

基本上,假設您通過擴展JPanel來創建自定義組件。當你@Override,paintComponent()方法,它隱含地被稱爲你,所以你永遠不必調用它。所以你在這個方法裏面畫什麼,都會被繪製在你的表面上。例如

public class DrawingPanel extends JPanel { 
    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     g.fillOval(x, y, 10, 10); 
    } 
} 

當你調用repaint()你基本上是導致paintComponent方法隱式調用。所以要回答你的問題,是的如果你想動畫,你將需要調用它,因爲你需要更新paintComponent()方法中的某種變量(如x和y),以查看任何更改圖紙。

你可以看到更多在Performing Custom Painting

不處理實際的動畫,你需要使用一個javax.swing.Timer。你可以在How to use Swing Timers看到更多。這裏是基本的結構

Timer (int delayInMillis, ActionListener listener) 

其中delayInMillis是蜱之間的延遲時間(在這種情況下,動畫)和ActionListener監聽「滴答」。調用每個勾號ActionListeneractionPerformed。在那裏,您可以將代碼更新用於動畫的任何變量。

因此,例如,在更新X和Y,在actionPerformed,然後調用repaint()

public class DrawingPanel extends JPanel { 

    int x = 50; 
    int y = 50; 

    public DrawingPanel() { 
     Timer timer = new Timer(40, new ActionListener(){ 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       x += 5; 
       y += 5; 
       repaint(); 
      } 
     }); 
     timer.start(); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     g.fillOval(x, y, 10, 10); 
    } 
} 

現在,這只是一個簡單的例子。但在你的情況下,你想要動畫一個散點圖。所以你可以做的是有一個列表Point s和在actionPerformed你可以添加列表中的拉點並將它們推入另一個要繪製的列表中。所以說你有這個

List<Point> originalPoints; 
List<Point> pointsToDraw; 
... 
@Override 
protected void paintComponent(Grapchics g) { 
    super.paintComponent(g); 
    for (Point point : pointsToDraw) { 
     g.fillOval(point.x - 5, point.y - 5, 10, 10); 
    } 
} 

基本上所有的點在pointsToDraw列表將被繪製。最初它將是空的。在計時器中,您可以添加到列表中,直到originalPoints列表已用盡。例如。

List<Point> originalPoints; 
List<point> pointsToDraw; 

private int currentIndex = 0; 

public DrawingPanel(List<Point> originalPoints) { 
    this.originalPoints = originalPoints; 
    pointsToDraw = new ArrayList<>(); 

    Timer timer = new Timer(40, new ActionListener(){ 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      if (currentIndex == originalPoints.size() - 1) { 
       ((Timer)e.getSource()).stop(); 
      } else { 
       pointsToDraw.add(originalPoints.get(currentIndex)); 
       currentIndex++; 
      } 
      repaint(); 
     } 
    }); 
    timer.start(); 
} 

因此,基本上你只是保持當前的指數。當索引達到原始列表的大小時,您停止定時器。否則,您只需從originalPoints彈出並推送至pointsToDraw。對於添加pointsToDraw的每個點,調用一個repaint(),並且paintComponent會有另一個點繪製圓。

結束


UDPATE

我只是重讀你的問題,我想我已經誤解了它。如果你想要繪製所有的點,那麼基本上只有一個列表。並且最初畫出所有要點。每次打勾時,只需刪除第一個索引,將所有其餘索引加到索引上,並在結尾添加一個新索引。雖然這是執行LinkedList,所以你可能只想使用