(multiple image ) animation Java - java

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

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 JLabels, 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

Related

Toggle the visibility of Jlabel and JPanel

I am trying to toggle the visibility of JLable and JPanel. Both are in initial case in visible state. After pressing a Button, they should be invisible for two seconds. After this time they are going to be visible again. In adddition, there are two checkBoxes on the JPanel, which are grouped by ButtonGroup. The selection should be cleared after pressing the Button.
For solving I wrote the following code:
package Aufgaben;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.border.EmptyBorder;
public class Aufgabe1 extends JFrame {
private JPanel contentPane;
private JPanel checkPanel;
private JPanel pointPanel;
private JRadioButton rdbtnJa;
private JRadioButton rdbtnNein;
private ButtonGroup btnGroup;
private JButton btnStart;
private JLabel lblX;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Aufgabe1 frame = new Aufgabe1();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Aufgabe1() {setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 700, 300);
contentPane = new JPanel();
setContentPane(contentPane);
contentPane.setLayout(null);
btnStart = new JButton("Start");
btnStart.setBounds(0, 0, 684, 23);
contentPane.add(btnStart);
checkPanel = new JPanel();
checkPanel.setBounds(0, 229, 684, 33);
contentPane.add(checkPanel);
btnGroup = new ButtonGroup();
rdbtnJa = new JRadioButton("Ja");
checkPanel.add(rdbtnJa);
btnGroup.add(rdbtnJa);
rdbtnNein = new JRadioButton("Nein");
checkPanel.add(rdbtnNein);
btnGroup.add(rdbtnNein);
pointPanel = new JPanel(new BorderLayout());
pointPanel.setBackground(Color.BLACK);
pointPanel.setBounds(0, 23, 684, 209);
contentPane.add(pointPanel);
lblX = new JLabel("X");
lblX.setForeground(Color.WHITE);
lblX.setVerticalAlignment(JLabel.CENTER);
lblX.setHorizontalAlignment(JLabel.CENTER);
pointPanel.add(lblX, BorderLayout.CENTER);
run();
}
public void run() {
System.out.println("----------");
System.out.println("Method run()");
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("btn actionPerformed()");
createLightPoint();
}
});
}
private void createLightPoint() {
System.out.println("----------");
System.out.println("Method createLightPoint()");
btnGroup.clearSelection();
lblX.setVisible(false);
// lblX.repaint();
// pointPanel.repaint();
checkPanel.setVisible(false);
// checkPanel.repaint();
System.out.println("Bevor Sleep");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("After Sleep");
lblX.setVisible(true);
// lblX.repaint();
checkPanel.setVisible(true);
// checkPanel.repaint();
}
}
As you can see I tried to solve the problems (what I described above) over the function .setVisibility() as well .repaint(). I tried the functions .show() and .hide althought they are deprecatet as well.But in any case, it doesn't work.
I already read the following posts:
Show/Hide JLabel with button?
https://softwareengineering.stackexchange.com/questions/233068/is-better-show-hide-or-setvisiblebool-visible
But none of them could help the solve my problem.
I hope you can Help me.
Don't use sleep() on Event Dispatch Thread - it will prevent the thread from processing painting and other UI related events and the UI will become frozen. See The Event Dispatch Thread tutorial for more details.
You can use Swing timer instead, see How to Use Swing Timers tutorial for examples.

How can the mouse listener activate after a certain time when the mouse is already over the button?

I'm trying to have a border appear over the react button after the timer has ended. I can't seem to have that happen unless I move the mouse away from the trigger button and then back onto it. Is there a way to activate the mouse listener without moving the mouse off and then back on the trigger button after the timer? And please dont't say: set border when timer ends, because that's not what I'm looking for.
Also, feel free to point out other mistakes or bad habits with my code as well. I'm new to Java coding.
import java.util.Timer;
import java.util.TimerTask;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import java.awt.event.MouseListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class ButtonTester{
public static final Border PANEL_BORDER = new LineBorder(Color.red, 12);
public static JPanel panel;
public static JButton trigger;
public static JButton react;
public static JLabel msg;
public static void main(String [] args){
JFrame frame = new JFrame();
frame.setSize(new Dimension(500,200));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel();
panel.setBorder(PANEL_BORDER);
frame.getContentPane().add(panel);
JButton trigger = new JButton("Trigger");
JButton react = new JButton("React");
JLabel msg = new JLabel();
react.setPreferredSize(new Dimension(200, 60));
trigger.setPreferredSize(new Dimension(200, 60));
panel.add(trigger);
panel.add(react);
panel.add(msg);
panel.setVisible(true);
frame.setVisible(true);
MouseListener mL = new MouseAdapter(){
#Override public void mouseEntered(MouseEvent evt) {
react.setBorder(PANEL_BORDER);
}
#Override public void mouseExited(MouseEvent evt) {
react.setBorder(javax.swing.BorderFactory.createEmptyBorder());
}
};
countDown(msg, trigger, mL);
}
public static void countDown(JLabel msg, JButton trigger, MouseListener mL){
Timer timer = new Timer();
TimerTask task = new TimerTask(){
short seconds = 4;
public void run(){
if(seconds == 0){
timer.cancel();
trigger.addMouseListener(mL);
return;
}
seconds--;
msg.setText("Attempting to add listener in : "+seconds);
}
};
timer.scheduleAtFixedRate(task, 1000, 1000);
}
}
Okay, this example sets up two state variables, one to determine if the mouse has entered or exited the button and one which determines if the timer has completed or not.
If these two conditions are true, then the border is set.
This means that the border of the react button WON'T be changed if the mouse is NOT over the trigger button when the timer runs out, but if the user moves back into the button, it will be changed. It will also be changed in the mouse is over the trigger button AND the timer runs out
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
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 static class TestPane extends JPanel {
public static final Border PANEL_BORDER = new LineBorder(Color.red, 12);
private boolean mouseInTheHouse = false;
private boolean timedOut = false;
private JButton react;
private JButton trigger;
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.ipadx = 200;
gbc.ipady = 60;
gbc.gridwidth = GridBagConstraints.REMAINDER;
react = new JButton("React");
trigger = new JButton("Trigger");
add(react, gbc);
add(trigger, gbc);
trigger.addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
mouseInTheHouse = true;
stateChanged();
}
#Override
public void mouseExited(MouseEvent e) {
mouseInTheHouse = false;
}
});
Timer timer = new Timer(4000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
timedOut = true;
System.out.println("!!");
stateChanged();
}
});
timer.start();
}
protected void stateChanged() {
if (mouseInTheHouse && timedOut) {
react.setBorder(PANEL_BORDER);
}
}
}
}
Note, that I've not setup a condition for what should happen when the mouse leaves the trigger button, but I assume you'd reset the border.
I see. I have an additional question. What if I had 10 trigger buttons (top of the panel) and 10 react button (bottom of the panel)? The condition is: If I have my mouse over one of the trigger button, then the corresponding react button of the same position plus the react button to the right side of that react button will have borders. How do I detect that without looping through my button List and detecting mouseInHouse?
Basically, distill the idea down to it's most common level. You have two buttons, a Timer, MouseListener and two state variables. Wrap these up into a common class which you can then reuse.
public class ButtonStateManager {
private boolean mouseInTheHouse = false;
private boolean timedOut = false;
private JButton trigger;
private JButton react;
private Timer timer;
public ButtonStateManager(JButton trigger, JButton react, int timeOut) {
this.trigger = trigger;
this.react = react;
trigger.addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
mouseInTheHouse = true;
stateChanged();
}
#Override
public void mouseExited(MouseEvent e) {
mouseInTheHouse = false;
}
});
Timer timer = new Timer(timeOut, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
timedOut = true;
stateChanged();
}
});
}
protected void stateChanged() {
if (mouseInTheHouse && timedOut) {
react.setBorder(TestPane.PANEL_BORDER);
}
}
}
Now, this assumes there's a relationship between the two buttons.
If your mouse is on the trigger button, and then MouseListener is added to the button, it cannot capture the previously happened event of entering the trigger button's area.
If you insist on showing the border when your mouse is on the trigger button without getting off and on it again, you should call the mouseEnter method manually after you add the mouseListener to it:
(before that you should pass the final JFrame frame to your countDown method)
if(seconds == 0){
timer.cancel();
trigger.addMouseListener(mL);
Point mousePosition = MouseInfo.getPointerInfo().getLocation();
Rectangle triggerRect = trigger.getBounds();
Rectangle frameRect = frame.getBounds();
Rectangle newRect = new Rectangle(triggerRect.x + frameRect.x, triggerRect.y + frameRect.y, triggerRect.width, triggerRect.height);
if(newRect.contains(mousePosition)) {
mL.mouseEntered(new MouseEvent(trigger, 0, System.currentTimeMillis(), 1, 0, 0, 0, false));
}
return;
}
But as MadProgrammer mentioned your question is not clear by saying "I'm trying to have the react button appear with a border after the timer has ended".
Hope this helps!

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...

Java GUI: Image will be overwritten, Path the same -> show it in the frame (image still the same)

I want to show a changing image on my frame. The imagepath is always the same, but the image will be getting overwritten every 10 seconds from another program.
The problem is that the image is not changing when I overwrite it with another image with the same name. So in my understanding: Compiler looks every look in the path and gets the image -> when the image changed it will be changed on the frame!
I hope you understand my problem and somebody could help me.
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.io.File;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class GUI extends JFrame{
public ImageIcon imageBar;
public JLabel labelimage1;
private JLabel labelimage2;
private JLabel bar1 = new JLabel();
private JLabel bar2 = new JLabel();
private JLabel bar3 = new JLabel();
private JLabel bar4 = new JLabel();
private JLabel bar5 = new JLabel();
private JButton buttonBar1 = new JButton("1");
private JButton buttonBar2 = new JButton("2");
private JButton buttonBar3 = new JButton("3");
private JButton buttonBar4 = new JButton("4");
private JButton buttonBar5 = new JButton("5");
private JPanel panel1 = new JPanel();
private JPanel panel2 = new JPanel();
private JPanel panel3 = new JPanel();
private JFrame window = new JFrame("Interface");
public GUI(){
//set the layouts
panel1.setLayout(new GridLayout(1, 2));
panel2.setLayout(new GridLayout(2, 1));
panel3.setLayout(new GridLayout(2, 5));
//place Panel2 and Panel3 in the window
panel1.add(panel2);
panel1.add(panel3);
//----Panel2
//refreshImage();
//----Panel3
panel3.add(buttonBar1); //add the bars 1-5 on panel3
panel3.add(buttonBar2);
panel3.add(buttonBar3);
panel3.add(buttonBar4);
panel3.add(buttonBar5);
//configure the frame
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
window.setSize(800, 400);
window.getContentPane().add(panel1);
}
public void refreshImage() {
panel2.removeAll(); //delete the old panel
//panel2.repaint();
//panel2.revalidate()
DrawImage pan = new DrawImage();
panel2.add(pan);
panel2.add(labelimage2);
}
}
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class DrawImage extends JPanel implements ActionListener{
private ImageIcon image;
public DrawImage(){
image = new ImageIcon("C:\\Users\\usuario\\Desktop\\image.png");
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
image.paintIcon(this, g, 50, 50);
repaint();
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}
import java.io.File;
public class Main {
public static void main(String[] args) {
GUI Interface = new GUI();
while(true)
{
Interface.refreshImage();
try {
Thread.sleep(5000); //wait for 5000ms
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Thank you very much!
The likely cause is Java is caching the image in memory, associated with the source name. So rather then trying to reload the image again, Java simply returns the cached version.
You could use ImageIcon#getImage#flush to force Java to reconstruct the image
Problems
You are calling refreshImage from a Thread other then the Event Dispatching Thread, this could cause issues with the updating of the components and cause rendering artifacts
You are forcefully removing the DrawImage pane and adding a new instance, rather the trying to reload the image
You're calling repaint within the paintComponent method, don't do this...
You should consider using a Swing Timer, which will allow you to schedule a regular update and be notified within the context of the Event Dispatching Thread.
You could provide a simple refresh method which flushes the current ImageIcon and schedule a repaint of the panel...or you could just use a JLabel and save your self the time
An example of Image#flush
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SlideShow {
public ImageIcon imageBar;
public static void main(String[] args) {
new SlideShow();
}
public SlideShow() {
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 DrawImage());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DrawImage extends JPanel {
private ImageIcon image;
public DrawImage() {
image = new ImageIcon("D:\\thumbs\\image.png");
Timer timer = new Timer(5000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
refresh();
}
});
timer.start();
}
public void refresh() {
image.getImage().flush();
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image.getImage(), 0, 0, this);
}
}
}
The problem with this, is because the image data is loaded in a background thread, it won't may no be available when the component is first repainted, which could make the component appear to flicker.
A better approach would be to use ImageIO.read, which will ensure that the image is fully loaded before the method returns, the draw back here is that could cause the application to "pause" momentary as the image is loaded, personally, I'd use the refresh method to stop the the Timer (or set the Timer to non-repeating), start a background Thread to load the image (using ImageIO.read) call repaint (which is thread safe) and restart the Timer...
Your while (true) loop risks typing up the Swing event thread locking your program. If it doesn't do that, then you risk unpredictable threading issues by making Swing calls off of the event Thread. These problems can be solved easily by your using a Swing Timer not a while true loop to do your swapping.
Rather than removing and adding components, why not simply display images as ImageIcons within a single non-swapped JLabel.
To swap images here, simply call setIcon(...) on the JLabel.
For an example of using a Swing Timer to swap images, please check out my answer to a similar question here.
For example:
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class TimerImageSwapper {
public static final String[] IMAGE_URLS = {
"http://imaging.nikon.com/lineup/dslr/d7000/img/sample/img_01.png",
"http://imaging.nikon.com/lineup/dslr/d7000/img/sample/img_02.png",
"http://imaging.nikon.com/lineup/dslr/d7000/img/sample/img_04.png",
"http://imaging.nikon.com/lineup/dslr/d3200/img/sample/img_08.png",
"http://imaging.nikon.com/lineup/dslr/d3200/img/sample/img_05.png",
"http://imaging.nikon.com/lineup/dslr/d3200/img/sample/img_01.png",
"http://imaging.nikon.com/lineup/dslr/d3200/img/sample/img_06.png" };
private ImageIcon[] icons = new ImageIcon[IMAGE_URLS.length];
private JLabel mainLabel = new JLabel();
private int iconIndex = 0;;
public TimerImageSwapper(int timerDelay) throws IOException {
for (int i = 0; i < icons.length; i++) {
URL imgUrl = new URL(IMAGE_URLS[i]);
BufferedImage image = ImageIO.read(imgUrl);
icons[i] = new ImageIcon(image);
}
mainLabel.setIcon(icons[iconIndex]);
new Timer(timerDelay, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
iconIndex++;
iconIndex %= IMAGE_URLS.length;
mainLabel.setIcon(icons[iconIndex]);
}
}).start();
}
public Component getMainComponent() {
return mainLabel;
}
private static void createAndShowGui() {
TimerImageSwapper timerImageSwapper;
try {
timerImageSwapper = new TimerImageSwapper(5 * 1000);
JFrame frame = new JFrame("Timer Image Swapper");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(timerImageSwapper.getMainComponent());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Categories

Resources