Reputation: 11
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
Reputation: 13066
Many mistakes that you have done in your code...
paint
method instead of paintComponent
to draw Image.Thread
for drawing and removing image on Swing
component (JPanel
). You should use javax.swing.Timer instead.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.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
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
Thread
s 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 Timer
s
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