JFrame flash image for 1/100 second - java

I have JFrame and need to flash an Image for 10 milliseconds (or the minimum the monitor can support).
Currently, this is what I have done:
I have a JFrame with a JPanel with overwritten paintComponent() method. When I need to flash that image, I call the repaint() method to draw the image on the JFrame, then schedule a next to call repaint() again to remove the image after 10 milliseconds. However it makes a long flash, that is very visible to bare eye.
Here is my code:
public static boolean show = true;
public static void main(String[] args) {
final JFrame f = new JFrame("Test");
f.setUndecorated(true);
f.setAlwaysOnTop(true);
f.setFocusable(false);
JPanel c = new JPanel() {
#Override
public void paintComponent(Graphics g) {
if (show) {
try {
// I was too lazy to save the image as a variable ;)
g.drawImage(ImageIO.read(ClassLoader.getSystemResource("Puppy.png")), 1, 1, null);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
super.paintComponent(g);
}
};
c.setOpaque(false);
c.setPreferredSize(new Dimension(1920, 1080));
f.getContentPane().add(c);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
com.sun.awt.AWTUtilities.setWindowOpaque(f, false);
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
long time = System.nanoTime();
show = true;
f.repaint();
timer.schedule(new TimerTask() {
#Override
public void run() {
show = false;
f.repaint();
System.out.println(System.nanoTime() - time + Boolean.toString(show));
}
}, 10);
}
}, 1000, 1000);
}
Question: Why is the frame flashing for so long, and not for 10 milliseconds?

There are so many things that might be occuring...
The time between calling setVisible and the time that the frame is actually visible to the user...
The time to setup the Event Dispatching Thread...
The time to setup the Timer and schedule the TimerTask
The time between making a request for the frame to be repainted and when the repaint actually occurs
The fact that you are requesting the frame to be repainted and not the component which is actually displaying the image
Some other activity on the system, both within the Java API and/or the OS...
You need to try and mitigate some of these issues...
So, instead of scheduling the TimerTask straight after calling setVisible, may be use a WindowListener so you can be notified when the window is opened and start the timer then...
Instead of building everything within the thread that calls main, make sure you are creating and updating the UI from within the context of the Event Dispatching Thread
Instead of calling repaint on the frame, try repainting the actual component you want repainted...
Instead of using java.util.Timer, use a javax.swing.Timer, it's safer when making modifications to the state of the UI
The following example simply uses a JLabel to render the image and removes it after the javax.swing.Timer ticks...
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
/**
*
* #author shane
*/
public class Test {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
try {
BufferedImage img = ImageIO.read(new File("C:\\hold\\thumbnails\\_MTCGAC__Pulling_Cords_by_Dispozition.png"));
JLabel label = new JLabel(new ImageIcon(img));
JFrame frame = new JFrame("Testing");
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowOpened(WindowEvent e) {
Timer timer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
frame.remove(label);
frame.revalidate();
frame.repaint();
}
});
timer.setRepeats(false);
timer.start();
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException exp) {
exp.printStackTrace();
}
}
});
}
}

Related

Thread.sleep() delaying entire program instead of only what's after it

Pretty much title. The code is supposed to draw one box, wait 1 second, then draw a new one at a different location and repaint. Instead, it will wait for 1 second then paint both boxes. Thanks for the help and sorry if I messed up on formatting.
import javax.swing.*;
import java.awt.*;
public class GameRunner extends JPanel{
#Override
public void paintComponent (Graphics g){
int x = 0;
boolean directionRight = true;
g.setColor(Color.blue);
g.fillRect(300,400,100,100);
repaint();
try{
Thread.sleep(1000);
}
catch (Exception ex){}
g.fillRect(600,400,100,100);
repaint();
}
public static void main (String[] args){
JFrame frame = new JFrame("Submarine");
GameRunner gameRunner = new GameRunner();
frame.add(gameRunner);
frame.setSize(1200,700);
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
Thread.sleep(1000); will block the current running thread
paintComponent is called from within the context of the Event Dispatching Thread.
Swing won't update the state of the UI until it's finished processing the current (in this case "paint") event, meaning that while it's blocked at Thread.sleep, nothing will be updated on the UI and no new events will be processed.
Swing is a single threaded framework. You should never perform any blocking or long running operations from within the context of the Event Dispatching Thread.
Have a look at Concurrency in Swing for more details and How to use Swing Timers for a possible solution.
As a side note, you should NEVER modify the state if the UI or any variable the UI relies on from within any paint method. Painting should only paint the current state of the component, never modify it, this includes calling repaint directly or indirectly
For example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class GameRunner extends JPanel {
private int xPos = 300;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.blue);
g.fillRect(xPos, 400, 100, 100);
repaint();
}
public GameRunner() {
Timer timer = new Timer(1000, new ActionListener() {
private boolean state = false;
#Override
public void actionPerformed(ActionEvent e) {
if (state) {
xPos = 300;
} else {
xPos = 600;
}
state = !state;
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(700, 500);
}
public static void main(String[] args) {
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 GameRunner());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}

Can't understand Java Swing Timers. How do I make a 1 time delay?

I need a one-time pause in this program for what I'm trying to do. I display some text in a Java Swing JFrame, repaint shows it, I wait 1.5 sec, then I change the text.
Basically, I started with this:
statusLabel.setText(s);
appFrame.repaint();
Thread.sleep(1500);
statusLabel.setText(y);
appFrame.repaint();
But this wasn't working. Thread.sleep() would invoke before repaint had finished, meaning s would never be shown. I read a lot of places that you're not supposed to use Thread.sleep() in swing applications because it pauses all threads, even the threads trying to repaint, and that to pause something triggered by actionPerformed() you need to use a Java Swing Timer.
Which is all well and fine, except I can't find a single place that offers a decent explanation on how they work. Since, as far as I can tell, timers are specifically used for repeating events on a timer. I just want a 1.5 second delay between 2 repaints.
I tried doing this...
statusLabel.setText(s);
appFrame.repaint();
Timer timer = new Timer(1500, new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
}
});
timer.setInitialDelay(1500);
timer.setRepeats(false);
timer.start();
statusLabel.setText(y);
appFrame.repaint();
...adding a timer with a 1.5 sec initial delay, no repeating, and no body to its actionPerformed event, so that it literally does nothing but wait that 1.5 sec, but it didn't work.
As coded in your example, it looks like the timer would "work", it just doesn't do anything because the actionPerformed method is empty. You might be thinking that timer.start() blocks and waits for the timer to trigger, but it fact it returns immediately. The way timers work is that the timer's actionPerformed method will be invoked from the UI thread when it is supposed to be. Placing code inside the actionPerformed method of a timer is a good way to update the UI state periodically.
Have you tried placing statusLabel.setText(y); inside the actionPerformed method of your ActionListener?
statusLabel.setText(s);
Timer timer = new Timer(1500, new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
statusLabel.setText(y);
}
});
timer.setRepeats(false);
timer.start();
If that's still not working, then consider providing a runnable example which demonstrates your problem. This will result in less confusion and better responses
Updated
What you "seem" to be wanting to do, is set up a series of events which get trigger at different times...Rather then using separate Timers, you should be using a single Timer like a loop, each time it ticks, you check it's state and make some decisions about what should be done, for example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Flashy {
public static void main(String[] args) {
new Flashy();
}
public Flashy() {
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 static class TestPane extends JPanel {
private JLabel flash;
private JButton makeFlash;
protected static final Color[] FLASH_COLORS = new Color[]{Color.BLUE, Color.RED, Color.GREEN, Color.YELLOW};
protected static final int[] FLASH_DELAY = new int[]{1000, 2000, 3000, 4000};
private int flashPoint;
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
flash = new JLabel("Flash");
flash.setOpaque(true);
makeFlash = new JButton("Make Flash");
add(flash, gbc);
add(makeFlash, gbc);
makeFlash.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
flashPoint = -1;
Timer timer = new Timer(0, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Timer timer = ((Timer)e.getSource());
flashPoint++;
if (flashPoint < FLASH_COLORS.length) {
flash.setBackground(FLASH_COLORS[flashPoint]);
System.out.println(FLASH_DELAY[flashPoint]);
timer.setDelay(FLASH_DELAY[flashPoint]);
} else {
flash.setBackground(null);
timer.stop();
makeFlash.setEnabled(true);
}
}
});
timer.setInitialDelay(0);
timer.start();
makeFlash.setEnabled(false);
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
Now, if you wanted to do something really fancy, you could devise a series of key frames over a given period of time.
This means that you could change the duration of the animation, without needing to change any other piece of code, for example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Flashy {
public static void main(String[] args) {
new Flashy();
}
public Flashy() {
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 static class TestPane extends JPanel {
private JLabel flash;
private JButton makeFlash;
protected static final Color[] FLASH_COLORS = new Color[]{Color.BLUE, Color.RED, Color.GREEN, Color.YELLOW};
protected static final double[] FLASH_DELAY = new double[]{0, 0.2, 0.4, 0.6};
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
flash = new JLabel("Flash");
flash.setOpaque(true);
makeFlash = new JButton("Make Flash");
add(flash, gbc);
add(makeFlash, gbc);
makeFlash.addActionListener(new ActionListener() {
private int playTime = 10000;
private long startTime;
private int currentFrame = -1;
#Override
public void actionPerformed(ActionEvent e) {
startTime = System.currentTimeMillis();
Timer timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Timer timer = ((Timer) e.getSource());
long now = System.currentTimeMillis();
long duration = now - startTime;
double progress = (double) duration / (double) playTime;
int keyFrame = 0;
for (keyFrame = 0; keyFrame < FLASH_DELAY.length; keyFrame++) {
double current = FLASH_DELAY[keyFrame];
double next = 1d;
if (keyFrame + 1 < FLASH_DELAY.length) {
next = FLASH_DELAY[keyFrame + 1];
}
if (progress >= current && progress < next) {
break;
}
}
if (keyFrame < FLASH_COLORS.length) {
flash.setBackground(FLASH_COLORS[keyFrame]);
}
if (duration >= playTime) {
timer.stop();
makeFlash.setEnabled(true);
flash.setBackground(null);
}
}
});
timer.setInitialDelay(0);
timer.start();
makeFlash.setEnabled(false);
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
A much more advanced concept, which is demonstrated in this answer

Counter on JFrame

I am trying to make a JFrame and see the progress of the counter.
int i = 1;
while (i < 100000){
textField.setText(String.valueOf(i));
System.out.println(i);
i++;
}
When I start it I can see the progress at the console but the value of the textField does not change. It changes to 100000 when the loop ends.
How can I make it show the progress like in console?
There are a number of important differences between and other GUI toolkits like C#.
Firstly, Swing components SHARE a common native peer. In many other GUI frameworks, components have their own native peer, this affects the context in which how you can access these components.
Secondly, because Swing components share a common native peer, there are inherently un-thread safe (they all share the same message queue for example), this means you should never modify a UI component out side of the context of the Event Dispatching Thread.
Thirdly, you should never block the Event Dispatching Thread, this will prevent it from process new events, including paint requests.
In this context, you should should probably use s a javax.swing.Timer, which will allow you to schedule a callback (which will occur within the context of the EDT) at a regular interval, making it safe to use within the context of the Swing framework, for example...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Counter {
public static void main(String[] args) {
new Counter();
}
public Counter() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel label;
private Timer timer;
private int count;
public TestPane() {
label = new JLabel("...");
setLayout(new GridBagLayout());
add(label);
timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
count++;
if (count < 100000) {
label.setText(Integer.toString(count));
} else {
((Timer)(e.getSource())).stop();
}
}
});
timer.setInitialDelay(0);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
Take a look at Concurreny in Swing and How to Use Swing Timers for more details...

Why does viewport changelistener get called multiple times

I've got a viewport, and I've attached a change listener to it. Whenever I scroll through my viewport, my change listener gets called about four times. I'm not sure how to avoid this; I only want the call to happen once?
There's no way around this, JViewport will fire several stateChanged events because it's providing notification about changes to a number of properties...
From the JavaDocs...
Adds a ChangeListener to the list that is notified each
time the view's size, position, or the viewport's extent size has
changed.
At this point, it's kind of hard to know what to suggest as we don't know what it is you are trying to achieve, however, if you have to use a ChangeListener, you could set up a coalescing mechanism. That is, rather then responding to each event, you basically wait until a long enough delay has occurred between events before responding to it...
For example...
public class DelayedChangeHandler implements ChangeListener {
private Timer timer;
private ChangeEvent last;
public DelayedChangeHandler() {
timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
stableStateChanged();
}
});
timer.setRepeats(false);
}
#Override
public void stateChanged(ChangeEvent e) {
last = e;
timer.restart();
}
protected void stableStateChanged() {
System.out.println("Finally...");
}
}
Basically, this is a ChangeListener implementation that uses a non-repeating javax.swing.Timer with a short delay. Each time stateChanged is called, the timer is restart. Finally, when the timer is allowed to "tick", it calls stableStateChanged indicating that enough time has passed since the last event was raised.
This assumes that you don't so much care about what caused the event, only that the event occured...
A runnable example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TestViewport {
public static void main(String[] args) {
new TestViewport();
}
public TestViewport() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JPanel pane = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(1000, 1000);
}
};
JScrollPane sp = new JScrollPane(pane);
sp.getViewport().addChangeListener(new DelayedChangeHandler());
sp.getViewport().addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
System.out.println(evt.getPropertyName());
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(sp);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DelayedChangeHandler implements ChangeListener {
private Timer timer;
private ChangeEvent last;
public DelayedChangeHandler() {
timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
stableStateChanged();
}
});
timer.setRepeats(false);
}
#Override
public void stateChanged(ChangeEvent e) {
last = e;
timer.restart();
}
protected void stableStateChanged() {
System.out.println("Finally...");
}
}
}
You can try to use AdjustmentListener for gettign scroll event once, try next:
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.io.UnsupportedEncodingException;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Example {
public static void main(String[] args) throws UnsupportedEncodingException {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JScrollPane pane = new JScrollPane(new JTextArea());
pane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
if(e.getValueIsAdjusting()){
return;
}
System.out.println("vertical scrolled");
System.out.println("bar value = " + e.getValue());
}
});
frame.setContentPane(pane);
frame.setSize(300, 200);
frame.setVisible(true);
}
}
Here is another example.

Refreshing JPanel after loading next Image into it

I have created ImagePanel which is able to display images from the specified directory -> it sleeps 1 second and loads next image from the java project's directory.
It actually loads next image but it is not displayed(it does not refresh the panel), when it is done with all the files from the directory it shows only the last image from the directory. I would like to make it refresh after loading every image.
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
public class Okno extends JFrame {
JPanel jp;
ImagePanel ImagePanel;
JButton buttonExit;
JButton buttonWyjscie;
public Okno() {
}
public void createGUI() {
setSize(400, 400);
setLayout(new GridLayout());
buttonExit = new JButton("Exit");
buttonWyjscie = new JButton("Wyjscie");
// Sluchacz sluchacz = new Sluchacz();
// buttonExit.addActionListener(sluchacz);
buttonExit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
jp = new JPanel();
jp.setBorder(new LineBorder(new Color(40, 120, 80), 4));
ImagePanel = new ImagePanel();
ImagePanel.setBorder(new LineBorder(Color.blue, 4));
jp.add(buttonExit);
add(jp);
add(ImagePanel);
setVisible(true);
slajd();
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void slajd() {
try {
File f = new File(".");
File[] tablicaPlikow = f.listFiles();
for (File el : tablicaPlikow) {
String rozszerzenie = el.getName().substring(
el.getName().length() - 3);
if (rozszerzenie.equals("jpg") || rozszerzenie.equals("peg")) {
System.out.println(rozszerzenie);
ImagePanel.setImage(el);
}
repaint();
}
setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Okno().createGUI();
}
});
}
}
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class ImagePanel extends JPanel {
private BufferedImage image;
public ImagePanel() {
}
public ImagePanel(String sciezka) {
setImage(new File(sciezka));
}
public void setImage(File plik) {
try {
image = ImageIO.read(plik);
System.out.println("tutaj");
repaint();
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
public void paint(Graphics g) {
if (image != null) {
Image b = image.getScaledInstance(getWidth(), getHeight(),
Image.SCALE_FAST);
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
}
}
}
Sleeping in the EDT prevents swing from doing the painting, so you see only the last image. Instead of sleeping in the event dispatch thread, use a swing Timer to do repeated tasks:
private final ActionListener timerTask = new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
// Whatever you need to to that
showNextImage();
}
};
Timer timer = new Timer(1000, timerTask);
timer.start();
If loading the images is taking long time, consider using a background task for preloading the next one in memory, without blocking the EDT.
The short answer could be: in method slajd, after call to repaint();, add
Thread.sleep(1000);
However, this is completely contrary to the event-based nature of Swing, and in this particular case doesn't even work because, for efficiency reasons, Swing does not execute repaint() calls immediately. It "collects" and executes them only once after all event processing has concluded. If you include an sleep period (or any other long-running operation) in an event handler (directly or indirectly), repainting will be delayed and the application be extremely unresponsive to the point, as in this case, of not really be working.
What you need to do is in createGUI instantiate a Swing Timer (javax.swing.Timer; do not confuse it with java.util.Timer, or Timer classes in a few other packages) that fires every 1 second instead of calling slajd(). First firing should be immediate, or you could include code to display the first file. The associated listener, which would replace slajd() should keep track of the next file to display. You will most probably want to make this listener a full-fledged class with fields to support this tracking, a pointer to the ImagePanel where to display files, etc.
For more information, read Java's Tutorial on How to Use Swing Timers

Categories

Resources