2012-04-17 17 views
1

我在GUI中創建了一個着名的Mandelbrot分形,並加快創建我的圖像我決定使用Swing Workers。在doInBackground()方法中,我正在計算每個像素的顏色,並將所有顏色放入數組中。在done()方法中,我訪問數組並使用適當的顏色爲每個像素着色。這種方式在EDT中着色時在不同的線程中進行繁重的計算。我只有一個問題 - 即使我知道它們存儲在BufferedImage中(我可以將文件保存到硬盤,直接訪問BufferedImage,或者 - 在縮放時 - 我正在創建一個深層副本的BufferedImage - 在這種情況下,我可以看到正確的圖像)。我對Java很新,但我希望我的應用程序儘可能好。我的代碼如下,在這裏:http://pastebin.com/M2iw9rEYBufferedImage在SwingWorkers製作後不顯示

public abstract class UniversalJPanel extends JPanel{ 

    protected BufferedImage image; 
    protected Graphics2D g2d; 

    protected int iterations = 100; // max number of iterations 
    protected double realMin = -2.0; // default min real 
    protected double realMax = 2.0;// default max real 
    protected double imaginaryMin = -1.6; // default min imaginary 
    protected double imaginaryMax = 1.6;// default max imaginary 
    protected int panelHeight; 
    protected int panelWidth; 
    protected Point pressed, released; // points pressed and released - used to calculate drawn rectangle 
    protected boolean dragged; // if is dragged - draw rectangle 
    protected int recWidth, recHeight,xStart, yStart; // variables to calculate rectangle 
    protected FractalWorker[] arrayOfWorkers; // array of Swing workers 



    public abstract int calculateIterations(Complex c); 
    public abstract double getDistance(Complex a, Complex b); 

    public void paintComponent(Graphics g){ 
     super.paintComponent(g); 
     panelHeight = getHeight(); 
     panelWidth = getWidth(); 
     image =new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); // creating new Bufered image 
     g2d= (Graphics2D) image.getGraphics(); 



     arrayOfWorkers= new FractalWorker[getHeight()]; // create new worker for each row and execute them 
     for(int q = 0; q < getHeight(); q++){ 
       arrayOfWorkers[q] = new FractalWorker(q); 
       arrayOfWorkers[q].execute(); 
     } 

     g.drawImage(image, 0, 0, null); // draw an image 

    } 

// *** getters, setters, different code// 

private class FractalWorker extends SwingWorker<Object, Object>{ 
    private int y; // row on which worker should work now 
    private Color[] arrayOfColors; // array of colors produced by workers 
    public FractalWorker(int z){ 
     y = z;  
    } 
    protected Object doInBackground() throws Exception { 

     arrayOfColors = new Color[getWidth()]; 

     for(int q=0; q<getWidth(); q++){ // calculate and insert into array proper color for given pixel 
      int iter = calculateIterations(setComplexNumber(new Point(q,y))); 
      if(iter == iterations){ 
       arrayOfColors[q] = Color.black; 
      }else{ 
       arrayOfColors[q] = Color.getHSBColor((float)((iter/ 20.0)), 1.0f, 1.0f); 
      } 
     }   
     return null; 
    } 
    protected void done(){ // take color from the array and draw pixel 
     for(int i = 0; i<arrayOfColors.length; i++){    
      g2d.setColor(arrayOfColors[i]); 
      g2d.drawLine(i, y, i, y); 
     } 
    } 

} 

回答

0

當你調用g.drawImage(...)圖像的當前內容都被吸收到組件。那時SwingWorkers還沒有完成他們的工作,因爲你在drawImage調用之前馬上啓動它們。你不應該在paintComponent方法中啓動SwingWorkers,如果已經收到繪畫請求,那麼啓動一個長的繪圖過程已經太晚了。

更好的解決方案可能是在程序啓動時創建BufferedImage,然後在組件大小發生更改時重新創建BufferedImage。您應該在需要重繪時啓動SwingWorkers,並在完成繪圖時調用組件的repaint()。

+0

如何檢查SwingWorkers是否已完成執行done()方法中的內容?我不確定在開始我的程序時創建BufferedImage是什麼意思 - 我想通過調用paintComponent()方法來實現。 「(...),然後在組件大小改變時重新創建它。」 - 我沒有改變我的組件的大小。感謝您的幫助。 – Trishia 2012-04-17 18:27:56

+0

你的程序不應該直接調用paintComponent方法 - Swing會這樣做。您的程序必須能夠快速響應任何paintComponent調用。這就是爲什麼在paintComponent啓動之前你必須準備好並繪製圖像。如果圖像內容發生變化,則需要通過調用panel.repaint()重新繪製組件,這將導致Swing調用paintComponent。 要確定您的SwingWorkers是否已完成,您可以在done()的末尾設置布爾值,然後保留所有工作人員的列表,並在檢查布爾值時對其進行迭代。 – 2012-04-18 08:33:18