Search code examples
javaswingpaintrepaintthread-sleep

Scaling image through thread - JAVA


Let say I have an image. I put the image in a JPanel and add the JPanel inside a JFrame. The image moves from the bottom part of the frame to top of the frame while its size is also decreased using AffineTransform. The variable changes using thread.

So here's the following code:

public class SplashScreen extends JFrame{
    Image img1;
    int w=1,h=1;
    int x=0,y=0;
    Thread th = new Thread(new Runnable() {
    @Override
    public void run() {
        while(true){
            w-=0.05;
            h-=0.05;
            y-=2;
            x+=1;

            if(y==-100){
                new MainMenu_BlueJay().setVisible(true);
                dispose();
            }

            repaint();
            try {
                Thread.sleep(10);
            } catch (InterruptedException ex) {
                Logger.getLogger(SplashScreen.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
    }
});

JPanel p = new JPanel();

public SplashScreen(){
    setLayout(new BorderLayout());

    p.setPreferredSize(new Dimension(900,600));
    p.setBackground(Color.black);
    p.setLayout(new GridLayout());

    add(p);
    setTitle("BlueJay");
    setSize(900,600);

    getContentPane().setBackground(Color.black);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setLocationRelativeTo(null);
    setVisible(true);
    th.start();
    requestFocus();
    setFocusable(true);
}

@Override
public void paint(Graphics g) {
    super.paint(g);
    Graphics2D g2d = (Graphics2D) g;

    img1 = new ImageIcon("images/Intro/BJ Production 2013.png").getImage();
    AffineTransform at = new AffineTransform();
    at.scale(w,h);
    g2d.setTransform(at);
    g2d.drawImage(img1, x, y, p);
}

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

However what I get from code above is only black screen. What's the matter? Anyway, If I don't use the AffineTransform function (just move it from bottom to top), the image is shown and moves BUT the frame is flickered (blinking) rapidly.

Any idea to solve this problem so I could move the image while decrease its size and also solve the flickered/rapid blinking frame?


Solution

  • You should not override the paint method of the JFrame. If you want to paint anything, you should paint this in a class that extends JPanel, where you override the paintComponent method.

    You should NOT load the image in the painting method. This is horribly inefficient. You should load the image only ONCE, probably in a constructor.

    You should not call Graphics2D#setTransform(). Have a look at the JavaDoc at http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html#setTransform%28java.awt.geom.AffineTransform%29 , which explicitly states

    WARNING: This method should never be used to apply a new coordinate transform on top of an existing transform

    You should think about your w and h values. Should they be the size of the image that is painted, or used as scaling factors for the image? Setting them as the scaling factors of an AffineTransform will NOT have the effect of scaling an image to the desired size. At the moment, they are declared as int values, so something like w-=0.05 does not really make sense anyhow.

    You should have a clear idea of how you are going to describe the animation that the image should perform.

    One could possibly summarize this:

    You should not write code and assume it is "correct" only because there are no compilation errors ;-)

    However, the following snippet may be a first step towards your goal:

    package stackoverflow;
    
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Image;
    
    import javax.swing.ImageIcon;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class SplashScreen extends JFrame
    {
        public static void main(String[] args) 
        {
            SwingUtilities.invokeLater(new Runnable()
            {
                @Override
                public void run()
                {
                    new SplashScreen();
                }
            });
        }    
    
        private PaintPanel paintPanel;
    
        public SplashScreen()
        {
            setTitle("BlueJay");
            setDefaultCloseOperation(EXIT_ON_CLOSE);
    
            getContentPane().setBackground(Color.BLACK);
            getContentPane().setLayout(new BorderLayout());
    
            paintPanel = new PaintPanel();
            getContentPane().add(paintPanel, BorderLayout.CENTER);
    
            setSize(900,600);
            setLocationRelativeTo(null);
            setFocusable(true);
            requestFocus();
            setVisible(true);
    
            startAnimation();
        }
    
        void startAnimation()
        {
            Thread thread = new Thread(new Runnable()
            {
                int x = 100;
                int y = 100;
                int w = 0;
                int h = 0;
    
                @Override
                public void run()
                {
                    try
                    {
                        Thread.sleep(500);
                    }
                    catch (InterruptedException ex)
                    {
                        Thread.currentThread().interrupt();
                        return;
                    }
    
                    while (true)
                    {
                        if (y == 200)
                        {
                            // new MainMenu_BlueJay().setVisible(true);
                            dispose();
                        }
    
                        x += 2;
                        y += 1;
                        w += 1;
                        h += 1;
                        paintPanel.setImageCoordinates(x, y, w, h);
    
                        repaint();
                        try
                        {
                            Thread.sleep(10);
                        }
                        catch (InterruptedException ex)
                        {
                            Thread.currentThread().interrupt();
                            return;
                        }
    
                    }
                }
            });
            thread.start();
        }
    }
    
    
    class PaintPanel extends JPanel
    {
        private final Image image;
        private int imageX, imageY;
        private int imageW, imageH;
    
        PaintPanel()
        {
            image = new ImageIcon("Clipboard02.jpg").getImage();
            imageX = 0;
            imageY = 0;
            imageW = 0;
            imageH = 0;
        }
    
        void setImageCoordinates(int imageX, int imageY, int imageW, int imageH)
        {
            this.imageX = imageX;
            this.imageY = imageY;
            this.imageW = imageW;
            this.imageH = imageH;
            repaint();
        }
    
        @Override
        protected void paintComponent(Graphics gr)
        {
            super.paintComponent(gr);
            Graphics2D g = (Graphics2D) gr;
    
            float scalingX = (float) imageW / image.getWidth(null);
            float scalingY = (float) imageH / image.getHeight(null);
            g.scale(scalingX, scalingY);
    
            int ix = (int)(imageX / scalingX);
            int iy = (int)(imageY / scalingY);
            g.drawImage(image, ix, iy, null);
        }
    }