Swing Worker : function get()

放肆的年华 提交于 2019-11-26 16:41:48
trashgod

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.

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();
            }
        });
    }
}
JB Nizet

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!