2012-04-17 11 views
1

GUIでよく知られているMandelbrot Fractalを作成しています。イメージを作成するスピードを上げるために、Swing Workersを使用することにしました。 doInBackground()メソッドでは、すべてのピクセルの色を計算しており、すべての色を配列に入れています。メソッドdone()では、配列にアクセスして各ピクセルを適切な色で色付けしています。この方法では、EDTで色付けが行われている間に、重い計算が別のスレッドで実行されます。私はただ一つの問題しか持っていません。準備された画像は、BufferedImageに保存されていることを知っていても表示されません(ファイルをハードドライブに保存したり、BufferedImageに直接アクセスしたり、 BufferedImageの - この場合、私は適切な画像を見ることができます)。私はJavaにはまだまだ慣れていませんが、私のアプリケーションはできるだけ良いものにしたいと思っています。私のコードは以下とここにある:SwingWorkersによってBufferedImageが表示されない

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(...)画像の現在の内容を呼び出すhttp://pastebin.com/M2iw9rEYは、コンポーネントに描画されています。その時点で、SwingWorkersはdrawImageコールの直前にSwingWorkersを開始した時点で作業を完了していません。 paintComponentメソッドでSwingWorkersを起動しないでください。ペイント要求が受信された場合、描画処理を開始するには遅すぎます。

より良い解決策は、プログラムの起動時にBufferedImageを作成し、コンポーネントのサイズが変更されたときにそれを再作成することです。再描画が必要なときはいつでもSwingWorkersを起動し、描画が終了したらコンポーネントのrepaint()を呼び出す必要があります。

+0

SwingWorkersがdone()メソッドの実行を終了したかどうかを確認するにはどうすればよいですか?私は私のプログラムを始めるときにBufferedImageを作成することによって何を意味するのか分かりません。私はpaintComponent()メソッドを呼び出すことでこれをやっています。 "(...)コンポーネントのサイズが変更されたときに再作成します。" - 私は自分のコンポーネントのサイズを全く変更していません。ご協力ありがとうございました。 – Trishia

+0

あなたのプログラムは直接paintComponentメソッドを呼び出すべきではありません。スイングはそれを行います。あなたのプログラムは、どんなpaintComponent呼び出しにも迅速に応答できなければなりません。このため、paintComponentを開始する前にイメージを準備し描画する必要があります。イメージの内容が変更された場合は、panel.repaint()を呼び出してコンポーネントを再描画する必要があります。これにより、paintComponentを呼び出すSwingが発生します。 SwingWorkersが終了したかどうかを判断するには、done()の最後にブール値を設定してから、すべてのワーカーのリストを保持してブール値をチェックします。 –