2

My problem is that I don't understand how the swingworker works because what I'm trying to do is to make fa=worker.get() because I have a long method which compute a lot of points running in background because I don't want to freeze my interface and I want to get her results to paint the component image. But I don't understand where it goes when I do fa=worker.get() because my console prints "titi" and I put a lot of other printing to see the next part of program reached but no one is printed. Please help me to know where the compilation goes after get() or while it execute it and if you have an idea of how to implements what I need every block of code is welcome.

public void paintComponent(final Graphics g1){
            // TODO Auto-generated method stub
            final int width=getWidth();
            final int height=getHeight();
            image= new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
            //On transforme le rectangle de base en un rectangle qui a le meme ratio que le cadre contenant l'ancien
            //(Il yaura dessus la meme fractale mais avec plus de fond noir) afin que l'on puisse zoomer sans deformer la fractale
            frame = frame.expandToAspectRatio((double)getWidth()/getHeight());
            FlameAccumulator fa=null;
            worker= new SwingWorker<FlameAccumulator,FlameAccumulator>(){

                @Override
                protected FlameAccumulator doInBackground() throws Exception {
                    // TODO Auto-generated method stub
                    System.out.println("exception");
                    return builder.build().compute(frame,width,height,density);
                }
            };
            try {
                System.out.println("titi");
                fa=worker.get();
            } catch (InterruptedException | ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Graphics g0=(Graphics2D)g1;
            if(fa==null){
                System.out.println("toto");
                for (int i = 0; i <height; i++) {
                    for (int j = 0; j < width; j++) {
                        image.setRGB(j,i,0);
                    }
                }
            }
            else{
                System.out.println("tata");
                for (int i = 0; i <height; i++) {
                    for (int j = 0; j < width; j++) {
                        image.setRGB(j,i,fa.color(palette, background, j, height-1-i).asPackedRGB());
                    }
                }
            }
            g0.drawImage(image,0,0,null);
        }
mKorbel
  • 109,525
  • 20
  • 134
  • 319
The Answer
  • 279
  • 1
  • 4
  • 11
  • `paintComponent` is not a place to put your logic. `paintComponent` is only meant for "painting the component" (ie, draw images, draw shapes, fill shapes, etc...). Your logic must absolutely be put and invoked somewhere else. This is mandatory because you don't (and you can't) control how many times and when `paintComponent` will be invoked. – Guillaume Polet Jun 02 '13 at 07:59
  • @Guillaume Polet this could be an nice answer, – mKorbel Jun 02 '13 at 08:50

2 Answers2

8

Instead of blocking on get(), you should publish() intermediate results and process() them on the EDT, for example.

Addendum: It looks like you're trying to simulate flame using a fractal approach. Because this may be computationally expensive, it may be useful to construct the image as a TexturePaint, which can be used to fill any Shape in a Graphics context. In the example, a SwingWorker<TexturePaint, TexturePaint> publishes a simple sequence of frames at an artificial rate of ~25Hz. Because process() executes on the EDT, it's safe to reference each new paint in updating the TexturePanel.

image

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;

/**
 * @see https://stackoverflow.com/a/16880714/230513
 */
public class HeatTest {

    private static final int N = 256;
    private TexturePanel p = new TexturePanel();

    private void display() {
        JFrame f = new JFrame("HeatTest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(p);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        new HeatWorker().execute();
    }

    private class TexturePanel extends JPanel {

        private TexturePaint paint;

        public void setTexture(TexturePaint tp) {
            this.paint = tp;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setPaint(paint);
            g2d.fillRect(0, 0, getWidth(), getHeight());
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(N, N);
        }
    }

    private class HeatWorker extends SwingWorker<TexturePaint, TexturePaint> {

        private final Random random = new Random();

        @Override
        protected TexturePaint doInBackground() throws Exception {
            BufferedImage image = new BufferedImage(N, N, BufferedImage.TYPE_INT_ARGB);
            TexturePaint paint = new TexturePaint(image, new Rectangle(N, N));
            int[] iArray = {0, 0, 0, 255};
            while (true) {
                WritableRaster raster = image.getRaster();
                for (int row = 0; row < N; row++) {
                    for (int col = 0; col < N; col++) {
                        iArray[0] = 255;
                        iArray[1] = (int) (128 + 32 * random.nextGaussian());
                        iArray[2] = 0;
                        raster.setPixel(col, row, iArray);
                    }
                }
                publish(paint);
                Thread.sleep(40); // ~25 Hz
            }
        }

        @Override
        protected void process(List<TexturePaint> list) {
            for (TexturePaint paint : list) {
                p.setTexture(paint);
                p.repaint();
            }
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new HeatTest().display();
            }
        });
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • How can i do this that's exactly what i need to do but i learnt java doc of swing worker to understand how to do but i still have no idea. Can you explain me ? Because publish doesn't return anything and what i need to do is to get the accumulator from the thread in background and then draw it. – The Answer Jun 02 '13 at 07:29
  • 1
    put all Objects/Items to array, fill array inside SwingWorker, if ended invoke repaint and inside paitComponent to loop in prepared array (filled in SwingWorker), don't to invoke whatever (not prepared as local variable) inside paintCompoent, rest is in Oracle tutorials, forum – mKorbel Jun 02 '13 at 07:33
  • @mKorbel Sorry but I didn't understand anything to what you said – The Answer Jun 02 '13 at 07:38
  • Do your set/draw in `process()`. You'll want to [profile](http://stackoverflow.com/q/2064427/230513) to be sure, but `clearRect()` is likely faster than looping through pixels. – trashgod Jun 02 '13 at 07:41
  • @trashgod Should i override process and do everything in it? Can you explain me well because i'm not good at using swingWorker i really not understand a lot how it works – The Answer Jun 02 '13 at 09:16
  • The `doInBackground ` function didn't return anything? – qed Sep 03 '15 at 19:49
3

You should not call get() in the paintComponent() method. This will block and wait until the worker has finished its computation. get() should only be called in the done() method of your worker, when you're sure the worker has finished doing its computation, as shown in the example contained in the documentation.

Howard
  • 38,639
  • 9
  • 64
  • 83
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255