Reputation: 51
I have got a set of nodes in my program, each have a specific x,y location. and each have a set of image icons.
I want to draw image animation for each nodes at its specific location.
Here is my code: (this only shows the last image which i know why!.)
public void showPicture() {
//nodes :
for(int i=0;i<thisGraph.getNode().size();i++){
if(thisGraph.getNode().get(i).getImageIcon()!=(null)){
for(int j=0;j<thisGraph.getNode().get(i).getImageIcon().size();j++){
if(j>0)
lables.get(lables.size()-1).setVisible(false);
JLabel jLabel1 = new JLabel();
lables.add(jLabel1);
jLabel1.setLayout(new GridBagLayout());
jLabel1.setIcon(thisGraph.getNode().get(i).getImageIcon().get(j));
jLabel1.setVisible(true);
jLabel1.setBounds((int)thisGraph.getNode().get(i).getX(),(int)thisGraph.getNode().get(i).getY(),195,163);
jPanel1.add(jLabel1);
}
}
}
}
This method showPicture() is called in a buttonActionListener. And I also have another button which I want it to stop the image animations for all labels.
What I have tried:
Thread.sleep()
-> it freezes the button and it only shows the last image
I figured I had to use timer, but through all the topics I went they only used it on one label, not multiple labels.
Edit -> i read those examples given in the comments . and here is what i have resolved but it still is freezes the button and doesn't works :
int j = 0;
public void showPicture(){
//nodes :
for(int i=0;i<thisGraph.getNode().size();i++){
if(thisGraph.getNode().get(i).getImageIcon()!=(null)){
j=0;
while( j<thisGraph.getNode().get(i).getImageIcon().size()){
if(j>0)
lables.get(lables.size()-1).setVisible(false);
JLabel jLabel1 = new JLabel();
lables.add(jLabel1);
jLabel1.setLayout(new GridBagLayout());
jLabel1.setIcon(thisGraph.getNode().get(i).getImageIcon().get(j));
jLabel1.setVisible(true);
jLabel1.setBounds((int)thisGraph.getNode().get(i).getX(),(int)thisGraph.getNode().get(i).getY(),195,163);
jPanel1.add(jLabel1);
//
ActionListener act;
act = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
jLabel1.setVisible(true);
j++;
}
};
Timer timer = new Timer(1000, act );
timer.start();
timer.stop();
//
}
}
}}
Upvotes: 0
Views: 225
Reputation: 347332
Swing is single threaded and not thread safe. This means that you shouldn't block the Event Dispatching Thread with long running or blocking operations, like Thread.sleep
. You should also, only ever update the UI (or anything it relies on) from within the context of the Event Dispatching Thread.
See Concurrency in Swing for more details.
Probably the simplest solution to your problem is to use a Swing Timer
.
The idea is a you use a single Timer
to act as the "main animation loop", changing the properties of ALL the objects you need updated within it.
The following is pretty basic example, it animates 100 JLabel
s, simply changing their background color with a randomly picked color
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class Test {
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();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<JLabel> nodes = new ArrayList<>(100);
private Random random = new Random();
private Color[] colors = new Color[] { Color.RED, Color.GREEN, Color.BLUE, Color.BLACK, Color.MAGENTA};
public TestPane() {
setLayout(new GridLayout(0, 10));
for (int index = 0; index < 100; index++) {
JLabel label = new JLabel();
label.setBorder(new EmptyBorder(5, 5, 5, 5));
label.setOpaque(true);
label.setBackground(pickColor());
nodes.add(label);
add(label);
}
Timer timer = new Timer(500, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (JLabel label : nodes) {
label.setBackground(pickColor());
}
}
});
timer.start();
}
protected Color pickColor() {
return colors[random.nextInt(colors.length)];
}
}
}
See How to Use Swing Timers for more details
Upvotes: 1