Jerba
Jerba

Reputation: 11

Why won't this draw the image?

What I'm trying to do is make it so when I run my application, it starts the thread and the image is shown for 3 seconds (3000ms), then the thread stops running.

The path for the image is correct, the image file exists, and the thread itself runs; however, the image doesn't seem to show. What could be wrong? Here is my code:

package org.main;

import java.awt.Graphics;
import java.awt.Image;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class Splasher extends JPanel implements Runnable {
    private static final long serialVersionUID = 1L;
    Image image;
    ImageIcon splash = new ImageIcon("res/splash.png");
    public static Thread DrawSplash = new Thread(new Splasher());

    public Splasher() {
        setFocusable(true);
        image = splash.getImage();  
        repaint();
    }
    boolean hasRan = false;
    public void run() {
        try {
            System.out.println("Drawing Splash Screen");
            repaint();
            Thread.sleep(3000);
            System.out.println("Repainted");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void paint(Graphics g) {
        g.drawImage(image, 0, 0, null);
    }

    public Image getImage() {
        return image;
    }
}

Upvotes: 0

Views: 565

Answers (2)

Vishal K
Vishal K

Reputation: 13066

Many mistakes that you have done in your code...

  1. You have overriden paint method instead of paintComponent to draw Image.
  2. You have used Thread for drawing and removing image on Swing component (JPanel). You should use javax.swing.Timer instead.
  3. Although you should use javax.swing.Timer , but still the basic mistake that you did is that You have created a static Thread and within that passed a new object of Splasher instead of current object.
  4. Each Time you want to make changes in the Graphics of a Component You should call repaint explicitly. For example, If you want to make the image to disappear after 3 seconds you should call repaint method after 3 seconds laps , and should have the proper logic written inside paintComponent method to remove that image.

Here is the modified version of your code , which is doing exactly what you are looking for.Have a look on it.:

import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentAdapter;

import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.SwingUtilities;

public class Splasher extends JPanel {

    private static final long serialVersionUID = 1L;
    Image image;
    ImageIcon splash = new ImageIcon("apple.png");
    MyComponentListener componentListener ;
    Timer timer ;

    public Splasher() 
    {
        componentListener = new MyComponentListener();
        setFocusable(true);
        image = splash.getImage();  
        timer = new Timer(3000, new LoadAction());
        addComponentListener(componentListener);
     }
    boolean hasRan = false;

    @Override
    public void paintComponent(Graphics g) 
    {
        super.paintComponent(g);
        if (image == null && timer !=null )
        {
            g.clearRect(0, 0, getWidth(), getHeight()) ;
            timer.stop();
            removeComponentListener(componentListener);
        }
        else
        {
            g.drawImage(image, 0, 0, null);
        }
    }
    public Image getImage() 
    {
        return image;
    }
    private class MyComponentListener extends ComponentAdapter
    {
        @Override
        public void componentResized(ComponentEvent evt)
        {
            System.out.println("Resized..");
            timer.start();
        }
    }
    private class LoadAction implements ActionListener 
    {
        public void actionPerformed(ActionEvent evt)
        {
            System.out.println("Drawing Splash Screen");
            repaint();
            image = null;
            repaint();
            System.out.println("Repainted");
        }

    }
    public static void main(String st[])
    {
        SwingUtilities.invokeLater ( new Runnable()
        {
            @Override
            public void run()
            {
                JFrame frame = new JFrame("Splash:");
                frame.getContentPane().add(new Splasher());
                frame.setSize(300,500);
                frame.setVisible(true);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            }
        });
    }
}

Also Watch the following tutorial for Paint mechanism in java. http://docs.oracle.com/javase/tutorial/uiswing/painting/closer.html

Upvotes: 1

MadProgrammer
MadProgrammer

Reputation: 347194

There's not enough to go from you question.

You don't show how you use the splash screen, if it's attached to anything or how you start/use the Thread.

So the problem could be anything...

In addition to everything else VishalK has already pointed out, I would add public static Thread DrawSplash = new Thread(new Splasher()) is a bad idea. You shouldn't use static Threads are threads are non-reentrant, that is, you can run the same thread twice.

This is a little example demonstrating a "fading" splash screen, using a number of Swing Timers

This assumes you're using Java 7, there is away to make it work for Java 6, I've not posted that code.

public class TestSplashScreen01 {

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

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

                SplashScreen splash = new SplashScreen();
                splash.start();

            }
        });
    }

    public class SplashScreen extends JWindow {

        private SplashPane splash;

        public SplashScreen() {
            setBackground(new Color(0, 0, 0, 0));
            splash = new SplashPane();
            add(splash);
            pack();
            setLocationRelativeTo(null);
        }

        public void start() {
            splash.start();
        }

        public class SplashPane extends JPanel {

            private BufferedImage splash;
            private Timer timer;
            private float alpha = 0f;
            private int duration = 1000;
            private long startTime = -1;

            public SplashPane() {
                try {
                    splash = ImageIO.read(getClass().getResource("/res/SokahsScreen.png"));
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                timer = new Timer(3000, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        fadeOut();
                    }
                });
                timer.setRepeats(false);
            }

            protected void fadeOut() {
                Timer fadeInTimer = new Timer(40, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        long now = System.currentTimeMillis();
                        long runTime = now - startTime;
                        alpha = 1f - ((float) runTime / (float) duration);
                        if (alpha <= 0.01f) {
                            alpha = 0f;
                            ((Timer) (e.getSource())).stop();
                            SwingUtilities.invokeLater(new Runnable() {
                                @Override
                                public void run() {
                                    dispose();
                                }
                            });
                        }
                        repaint();
                    }
                });
                startTime = System.currentTimeMillis();
                fadeInTimer.setRepeats(true);
                fadeInTimer.setCoalesce(true);
                fadeInTimer.start();
            }

            protected void fadeIn() {
                Timer fadeInTimer = new Timer(40, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        long now = System.currentTimeMillis();
                        long runTime = now - startTime;
                        alpha = (float) runTime / (float) duration;
                        if (alpha >= 1f) {
                            alpha = 1f;
                            ((Timer) (e.getSource())).stop();
                            timer.start();
                        }
                        repaint();
                    }
                });
                startTime = System.currentTimeMillis();
                fadeInTimer.setRepeats(true);
                fadeInTimer.setCoalesce(true);
                fadeInTimer.start();
            }

            public void start() {
                if (!SplashScreen.this.isVisible()) {
                    alpha = 0f;
                    SplashScreen.this.setVisible(true);
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            fadeIn();
                        }
                    });
                }
            }

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

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

NB:

The problem with this example is once you call start, the program will continue to execute, this will require some kind of listener to tell interested parties when the splash screen has completed.

Alternatively, you could use a undecorated modal JDialog

Upvotes: 2

Related Questions