Question

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?

Was it helpful?

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);
    }
}

OTHER TIPS

  1. Don't paint on top-level containers like JFrame. Instead use a JPanel and override its paintComponent method and call super.paintComponent
  2. No need to call Thread.sleep(). Instead Use a javax.swing.Timer.
  3. Run your program from the EDT
  4. Don't create a new ImageIcon in the paint method. It will create new ImageIcon object every time repaint() is called. Instead, instantiate it in the constructor.

Here's a refactor of the code.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SplashScreen extends JFrame {

    Image img1;
    int w = 900, h = 600;
    int x = 0, y = 0;

    public SplashScreen() {

        setLayout(new BorderLayout());

        add(new MyPanel());
        setTitle("BlueJay");
        setSize(900, 600);

        getContentPane().setBackground(Color.black);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setVisible(true);

        requestFocus();
        setFocusable(true);

    }

    private class MyPanel extends JPanel {

        public MyPanel() {
            img1 = new ImageIcon(SplashScreen.class.getResource("/resources/stackoverflow5.png")).getImage();
            setBackground(Color.black);
            setLayout(new GridLayout());
            Timer timer = new Timer(20, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    w -= 5;
                    h -= 5;
                    y -= 2;
                    x += 1;

                    if (y == -250) {
                        new MainMenu_BlueJay().setVisible(true);
                        dispose();
                    }
                    repaint();
                }
            });
            timer.start();
        }

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

            //AffineTransform at = new AffineTransform();
            // at.scale(w, h);
            // g2d.setTransform(at);
            g2d.drawImage(img1, x, y, w, h, this);
        }

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

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new SplashScreen();
            }
        });

    }
}

I'm not too familiar with Graphics2D so I commented out the AffirmTransformation stuff, but fixed your other problems.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top