How can I draw an image part by part?

134 Views Asked by At
class DrawIma extends JPanel{
    protected void paintComponent(Graphics g) {

        super.paintComponent(g);
        for (int i=0;i<20;i++){
            for (int j=0;j<20;j++) {    
                g.drawImage(BuArr[i*20+j], 20*i, 20*j, 20, 20, null);
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

In this part, BuArr are the 400 blocks divided from a BufferedImage, now i want them to be draw one by one, but the method can not draw the blocks separately, how can i do this?

1

There are 1 best solutions below

0
On

Swing is single thread and not thread safe.

This means that you should not perform any long running or blocking (Thread.sleep) operations within the IU thread (the Event Dispatching Thread). It also means that you can not update, modify or create UI elements outside of the EDT context.

Instead, use a Swing Timer to generate a repeated callback at a specified interval and render the portions of the image to something like a BufferedImage, which you can the paint to the component via its paintComponent method...

See Concurrency in Swing and How to use Swing Timers for more details

Because it was a good time waster

This generates a List of Rectangles which represent the individual blocks I want to paint, I then randomise the List and run the Timer, picking the top most Rectangle off the List and using BufferedImage#getSubImage to draw it from the master to the buffer, which gets painted to the screen...

Raining Pixels

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestImage {

    public static void main(String[] args) {
        new TestImage();
    }

    public TestImage() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private BufferedImage master;
        private BufferedImage copy;

        private List<Rectangle> blocks;

        public TestPane() {
            setBackground(Color.BLACK);
            try {
                master = ImageIO.read(new File("..."));
                copy = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
                Graphics2D g2d = copy.createGraphics();
                AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f);
                g2d.setComposite(composite);
                g2d.setColor(new Color(0, 0, 0, 0));
                g2d.fillRect(0, 0, master.getWidth(), master.getHeight());
                g2d.dispose();

                int blockSize = 40;

                int width = master.getWidth();
                int height = master.getHeight();

                float aspect = Math.min(width, height) / (float) Math.max(width, height);

                int blockHeight = blockSize;
                blocks = new ArrayList<>(blockSize * 2);
                for (int y = 0; y < master.getHeight(); y += blockHeight) {
                    if (y + blockHeight > master.getHeight()) {
                        blockHeight = master.getHeight() - y;
                    }
                    int blockWidth = blockSize;
                    for (int x = 0; x < master.getWidth(); x += blockWidth) {
                        if (x + blockWidth > master.getWidth()) {
                            blockWidth = master.getWidth() - x;
                        }
                        Rectangle block = new Rectangle(x, y, blockWidth, blockHeight);
                        blocks.add(block);
                    }
                }
                Collections.shuffle(blocks);
                Timer timer = new Timer(40, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        if (blocks.isEmpty()) {
                            ((Timer) e.getSource()).stop();
                        } else {
                            Graphics2D g2d = copy.createGraphics();
                            Rectangle block = blocks.remove(0);
                            g2d.drawImage(master.getSubimage(block.x, block.y, block.width, block.height), block.x, block.y, TestPane.this);
                            g2d.dispose();
                            repaint();
                        }
                    }
                });

                timer.start();

            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return master == null ? new Dimension(200, 200) : new Dimension(master.getWidth(), master.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            if (copy != null) {
                int x = (getWidth() - copy.getWidth()) / 2;
                int y = (getHeight() - copy.getHeight()) / 2;
                g2d.drawImage(copy, x, y, this);
            }
            g2d.dispose();
        }

    }

}