2012-10-24 38 views
3

我正在寫一個使用swing的java應用程序,其中我需要在正方形上方繪製網格。爲此,我使用Graphics類提供的drawLine(...)方法。Java Swing:drawLine非常慢

一切工作正常,但它需要大量的時間繪製每一行(超過20秒50行...)。我甚至可以看到實時繪製的線條。奇怪的是,水平線的繪製方式比垂直線快(幾乎立即)。

我可能會做錯事。這是網格的代碼。

public void drawGrid(Graphics g){ 
    g.setColor(new Color(255, 255, 255, 20)); 
    int width = getWidth(); 
    int height = (int) (width * Utils.PLATE_RATIO); 
    int step = pixelSize*gridSpacing; 
    Color bright = new Color(255, 255, 255, 100); 
    Color transparent = new Color(255, 255, 255, 20); 
    for(int ix = insets.left + step;       
      ix < width; ix += step){ 
     if(((ix - insets.left)/step) % 10 == 0){ 
      g.setColor(bright); 
     } 
     else{ 
      g.setColor(transparent); 
     } 
     g.drawLine(ix, insets.top, ix, height+insets.top); 
    } 
    for(int iy = insets.top+step; 
      iy < (insets.top + height); iy += step){ 
     if(((iy - insets.top)/step) % 10 == 0){ 
      g.setColor(bright); 
     } 
     else{ 
      g.setColor(transparent); 
     } 
     g.drawLine(insets.left, iy, width + insets.left, iy); 
    } 
} 
+5

這是因爲你沒有使用雙緩衝。見http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html –

+0

當然,我怎麼會這麼愚蠢。謝謝 ! – Nicolas

+3

@SureshKumar擺動組件默認是雙緩衝...... – kleopatra

回答

4

您發佈的代碼很好,沒有問題。
下面是使用的方法(有點簡化)的部件的一個工作示例:

public static class MyGrid extends JComponent 
{ 
    private int step = 10; 

    public MyGrid() 
    { 
     super(); 
    } 

    public Dimension getPreferredSize() 
    { 
     return new Dimension (500, 500); 
    } 

    protected void paintComponent (Graphics g) 
    { 
     super.paintComponent (g); 
     drawGrid (g); 
    } 

    public void drawGrid (Graphics g) 
    { 
     int width = getWidth(); 
     int height = getHeight(); 
     Color bright = new Color (255, 255, 255, 200); 
     Color transparent = new Color (255, 255, 255, 100); 

     for (int ix = step; ix < width; ix += step) 
     { 
      if ((ix/step) % 10 == 0) 
      { 
       g.setColor (bright); 
      } 
      else 
      { 
       g.setColor (transparent); 
      } 
      g.drawLine (ix, 0, ix, height); 
     } 

     for (int iy = step; iy < height; iy += step) 
     { 
      if ((iy/step) % 10 == 0) 
      { 
       g.setColor (bright); 
      } 
      else 
      { 
       g.setColor (transparent); 
      } 
      g.drawLine (0, iy, width, iy); 
     } 
    } 
} 

我想有那一段代碼之外的一些問題。

P.S.有點偏移,但...

我建議你計算繪畫區域的可見部分(使用JComponent的getVisibleRect()方法或圖形g.getClip().getBounds()方法),並限制你的繪畫只有該區域。

如果組件面積很大(例如10000x10000像素組件的面積),那麼這個小的優化可能會加快組件的繪製速度。

+1

getVisibleRect()+1 – mKorbel

+0

我不認爲在代碼之外有任何問題,我做的或多或少與你相同。我現在用'getVisibleRect()。getSize()'替換'getWidth()'。請參閱下面的解決方案 – Nicolas

-1

這是我如何使用雙緩衝來解決問題,正如@sureshKumar所建議的那樣。我只是畫一幅離屏圖像,並在繪圖結束時簡單地調用drawImage()。這似乎有伎倆。

編輯:這似乎只是如果你想打電話給你的繪畫方法(在我的情況drawGrid())從paintComponent(...)方法之外是有用的。

下面是代碼:

private Graphics bufferGraphics; 
private Image offScreen; 
private Dimension dim; 
//other attributes not shown... 

public CentralPanel(){ 
    //Some initialization... (not shown) 

    //I added this listener so that the size of my rectangle 
    //and of my grid changes with the frame size 
    this.addComponentListener(new ComponentListener() { 

     @Override 
     public void componentResized(ComponentEvent e) { 
      dim = getVisibleRect().getSize(); 
      offScreen = createImage(dim.width, dim.height); 
      bufferGraphics = offScreen.getGraphics(); 
      repaint(); 
      revalidate(); 
     } 
     //other methods of ComponentListener not shown 
    }); 
} 

@Override 
protected void paintComponent(Graphics g) { 
    super.paintComponent(g); 
    g.drawImage(offScreen, 0, 0, null); 
} 

public void drawGrid(){ 
    int width = dim.width - insets.left - insets.right; 
    width -= (width % plateSize.getXSize()); 
    int height = (int) (width*Utils.PLATE_RATIO); 
    height -= (height % plateSize.getYSize()); 
    int step = pixelSize*gridSpacing; 
    Color bright = new Color(255, 255, 255, 100); 
    Color transparent = new Color(255, 255, 255, 20); 
    for(int ix = insets.left + step;       
      ix < (width+insets.left); ix += step){ 
     if(((ix - insets.left)/step) % 10 == 0){ 
      bufferGraphics.setColor(bright); 
     } 
     else{ 
      bufferGraphics.setColor(transparent); 
     } 
     //I am now drawing on bufferGraphics instead 
     //of the component Graphics 
     bufferGraphics.drawLine(ix, insets.top, ix, height+insets.top); 
    } 
    step *= Utils.PLATE_RATIO; 
    for(int iy = insets.top+step; 
      iy < (insets.top + height); iy += step){ 
     if(((iy - insets.top)/step) % 10 == 0){ 
      bufferGraphics.setColor(bright); 
     } 
     else{ 
      bufferGraphics.setColor(transparent); 
     } 
     bufferGraphics.drawLine(insets.left, iy, width + insets.left, iy); 
    } 
} 

P.S:如果這應該作爲一個編輯我的問題,請告訴我,我會做到這一點。

+0

耶穌,爲什麼不擴展一個已經有雙緩衝策略的JComponent(實際上每個Swing組件都有它並默認使用它)?這將節省大量時間,並且不需要發明輪子......擴展JComponent時所需的一切就是擴展paintComponent方法,並且......是的,繪製!就這樣。甚至不需要爲雙緩衝而煩惱。 –

+0

還有一件事 - 當我提到使用'getVisibleRect()'方法來避免無意義的繪畫時,你沒有得到我說的話。我在談論排除組件上不可見的線條(以及線條的那些部分)。例如,如果您的組件包含在活動卷軸內 - 您一次只能看到其中的一部分。在可能的情況下,您應該避免在可見部分外繪畫。在你的情況下,你可以很容易地排除不可見的線條。 –

+0

@MikleGarin我明白現在是什麼問題。我實際上是從另一個函數調用'drawGrid(Graphics g)',但我相信只有'painComponent(Graphics g)'自動被雙緩衝,而不是所有用JComponent的Graphics繪製。無論如何,如果我可以從'paintComponent(...)'之外調用'drawGrid(...)'方法,它會使它更容易,所以我會繼續執行。感謝您對getVisibleRect()的評論,我現在明白了你的意思。 – Nicolas