Invoke javax.swing.Timer#start() same time,
7u25 is not problem.
but 7u40 is big problem.
Too laggy invoke ActionListener#actionPerformed. (basically same time invoke u25)
Totally different move between u25 and u40. (I use Windows 8)
I bug report but still not add bug tracking system. Oracle crushing swing apps?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TimerProblem extends JComponent {
int red = 0;
TimerProblem(final long startMs) {
setPreferredSize(new Dimension(10, 10));
Timer t = new Timer(16, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
red = (int)(System.currentTimeMillis() - startMs) % 255;
repaint();
}
});
t.setInitialDelay(1000);
t.start();
}
#Override
protected void paintComponent(Graphics g) {
g.setColor(new Color(red, 255 - red, 0));
g.fillRect(0, 0, getWidth(), getHeight());
}
public static void main(String[] args) {
JFrame f = new JFrame();
Container c = f.getContentPane();
c.setLayout(new GridLayout(10, 10));
long startMs = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {
c.add(new TimerProblem(startMs));
}
f.pack();
f.setVisible(true);
}
}
Several issues arise in your example:
Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
All Swing Timer instances share a common thread, which is being saturated.
Depending on the goal, some alternatives are possible:
Use a single Timer instance, and select some fraction for update at a proportionally higher rate. The example below randomly selects N of the components and updates them every 100 ms.
Use TexturePaint, as shown here.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.swing.*;
/** #see https://stackoverflow.com/a/18936444/230513 */
public class BlinkenLights {
private static final int S = 24;
private static final int N = 10;
private static final Random r = new Random();
private static final List<MyComponent> list = new ArrayList<MyComponent>();
private static final class MyComponent extends JComponent {
public MyComponent() {
this.setOpaque(true);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(S, S);
}
#Override
protected void paintComponent(Graphics g) {
g.setColor(Color.getHSBColor(r.nextFloat() / 6, 1, 1));
g.fillRect(0, 0, getWidth(), getHeight());
}
}
private static JPanel createPanel() {
final JPanel p = new JPanel();
p.setLayout(new GridLayout(N, N));
for (int i = 0; i < N * N; i++) {
MyComponent c = new MyComponent();
p.add(c);
list.add(c);
}
Timer t = new Timer(1000 / N, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Collections.shuffle(list, r);
for (int i = 0; i < N; i++) {
list.get(i).repaint();
}
}
});
t.start();
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(createPanel());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
Finally I write DIY repaint management class .. :(
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
/**
* EffectTimer
*/
public class EffectTimer {
/**
* All of effect timers in instance of this class.
*/
static class GlobalTimer implements ActionListener {
List<EffectTimer> registeredEffects = new ArrayList<>();
Timer timer = new Timer(16, this);
public void start(final EffectTimer t) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
internalStart(t);
}
});
}
void internalStart(EffectTimer t) {
int initialDelay = Math.max(0, (int) (t.getEffectStartTime() - System.currentTimeMillis()));
if(timer.getInitialDelay() >= initialDelay) {
timer.setInitialDelay(initialDelay);
}
if(!registeredEffects.contains(t)) {
registeredEffects.add(t);
if(registeredEffects.size() == 1) {
timer.start();
}
}
}
void stop(final EffectTimer t) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
registeredEffects.remove(t);
checkStop();
}
});
}
#Override
public void actionPerformed(ActionEvent e) {
long now = e.getWhen();
Iterator<EffectTimer> iter = registeredEffects.iterator();
while(iter.hasNext()) {
EffectTimer t = iter.next();
long elapsedMs = now - t.getEffectStartTime();
if(elapsedMs > 0) {
float p = elapsedMs / (float)t.getEffectLengthMs();
if(p >= 1.0f) {
iter.remove();
t.stop();
} else {
if(t.isReversed()) {
p = 1.0f - p;
}
t.progressChanged(p);
}
}
}
checkStop();
}
void checkStop() {
if(registeredEffects.isEmpty()) {
timer.stop();
}
}
public int getRunningTimerCount() {
return registeredEffects.size();
}
public void stopAll() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
registeredEffects.clear();
checkStop();
}
});
}
}
static final GlobalTimer GTIMER = new GlobalTimer();
int effectLengthMs = -1;
long effectStartMs = -1;
float progress = 0.0f;
boolean reversed = true;
public long getEffectStartTime() {
return effectStartMs;
}
public int getEffectLengthMs() {
return effectLengthMs;
}
public void start(int lengthMs) {
start(lengthMs, System.currentTimeMillis());
}
public void start(int lengthMs, long startMs) {
effectLengthMs = lengthMs;
effectStartMs = startMs;
reversed = false;
progress = 0.0f;
GTIMER.start(this);
}
public boolean isReversed() {
return reversed;
}
public void reverse(final int lengthMs) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
internalReverse(lengthMs);
}
});
}
void internalReverse(int lengthMs) {
reversed = !reversed;
effectLengthMs = lengthMs;
int adjust = reversed ? (int)(lengthMs * (1.0f - progress)) : (int)(lengthMs * progress);
effectStartMs = System.currentTimeMillis() - adjust;
GTIMER.start(this);
}
final public void progressChanged(float p) {
progress = p;
run(p);
}
/**
* 0.0f to 1.0f effect progress.
* <code>Float.compare(progress, 1.0f) >= 0</code> to end progress.
*/
protected void run(float p) {}
public void stop() {
progress = reversed ? 0.0f : 1.0f;
GTIMER.stop(this);
}
public boolean isRunning() {
return 0.0f < progress && progress < 1.0f;
}
public float getProgress() {
return progress;
}
public static int getRunningTimerCount() {
return GTIMER.getRunningTimerCount();
}
public static void stopAll() {
GTIMER.stopAll();
}
}
Related
I wanted to make a Glass Panel that contain a JPanel with white background, border and the msg "please wait".
Here is the code example:
JLabel glassLabel = new JLabel("Please wait");
FadingPanel msg = new FadingPanel();
glassLabel.setFont(new Font("Dialog", Font.BOLD, 26));
msg.setLayout(new BorderLayout());
msg.add(glassLabel,BorderLayout.NORTH);
msg.setBackground(Color.white);
msg.setFont(UIManager.getFont("Table.font").deriveFont(24f));
msg.setBorder(new CompoundBorder(new TitledBorder(""),
new EmptyBorder(20,20,20,20)));
It will fade in and out while waiting for the query.
the problem is that I am getting a bad result.
need help
the other is that none of them show it with glass panel
Animating the opacity state of a glassPane is no different from animating the state of any Swing component, after all, the glassPane is just another component.
one is that the Timer system doesn't know if the start function started and it keeps the panel hanging on because it closing it before fading the panel and then before it shows it and then it dont try to close it again
This is more about your own internal state management. The panel shouldn't care, it should just be responding to the request to change opacity level, forward or backwards
What you should have, is some kind of "engine" which can provide events when certain states are achieved, at which time, you make decisions about what should be done, removing the functionality from the "panel" itself.
Theory TL;DR
Okay, first, some theory.
Animation...
Animation is the illusion of change over time. In your case, you're moving from 0 to 1 and back again over a specified period of time. This is commonly known as "linear progression/animation". Most naive animation implementations will simple add a constant delta to a value and keep doing so until a desired state is reached. This is naive because not all systems are equal. Some will be able to achieve the desired state faster than others, making the animation uneven and providing a poor user experience.
Instead, you should be focused on perform a operation over a fixed period of time, calculating the required value as fast as the system will allow. This allows the animation to "drop" frames as required based on the system's capabilities. This is commonly known as "duration based animation".
This approach is much more powerful, as it allows you to play around with the speed of the animation in a very simply way. It also allows you do some very advanced operations, like easement, which wouldn't be easily achievable through a linear progression.
Swing and animation...
Swing is SINGLE threaded. This means you can't perform blocking or long running operations within the context of the Event Dispatching Thread.
Swing is also NOT thread safe. This means you shouldn't update the UI (or any state the UI depends on) from outside the context of the EDT.
For animation, what you need is some way to post, fast, repetitive, events onto the EDT, which will allow you to make changes to the UI safely. For this, the most common tool is a Swing Timer...
The Framework
So based on that, what we need is some kind of "engine", which given a "range" and a "duration" can notify us of "ticks" on a regular bases from which we can calculate the progression that the animation has played, and calculate the value we should use based on our inputs ... simple ...
I, personally, prefer to use an animation library, but the simple framework presented in the examples basically abstracts all these concepts into a re-usable framework.
Make it so...
nb: I ran out of room, so the underlying framework is included in the main example
Okay, that's all nice and fluffy, but how does this actually help us. Essentially, the idea of the above is to abstract common functionality out and make it re-usable (and yes, I actually do use it, a lot)
What we now need, is a component which can actually use it, something like...
public interface FaderListener {
public void fadeDidComplete(FadePane pane);
}
public class FadePane extends JPanel {
private double alpha = 1;
private boolean fadingIn = true;
private DoubleAnimatable animatable;
private Duration duration = Duration.ofSeconds(5);
private List<FaderListener> listeners = new ArrayList<>(5);
public FadePane() {
setOpaque(false);
}
public void addFadeListener(FaderListener listener) {
listeners.add(listener);
}
public void removeFadeListener(FaderListener listener) {
listeners.remove(listener);
}
public boolean isFadingIn() {
return fadingIn;
}
public double getAlpha() {
return alpha;
}
#Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive((float)getAlpha()));
g2d.setColor(getBackground());
g2d.fillRect(0, 0, getWidth(), getHeight());
super.paint(g2d);
g2d.dispose();
}
protected void fadeTo(double to) {
double currentAlpha = getAlpha();
if (animatable != null) {
animatable.stop();
animatable = null;
}
if (currentAlpha == to) {
fadeDidComplete();
return;
}
DoubleRange animationRange = new DoubleRange(currentAlpha, to);
double maxFrom = to == 1 ? 1 : 0;
double maxTo = to == 1 ? 0 : 1;
DoubleRange maxRange = new DoubleRange(maxFrom, maxTo);
animatable = new DoubleAnimatable(animationRange, maxRange, duration, new AnimatableListener<Double>() {
#Override
public void animationChanged(Animatable<Double> animatable) {
alpha = animatable.getValue();
repaint();
}
}, new AnimatableLifeCycleListenerAdapter<Double>() {
#Override
public void animationCompleted(Animatable<Double> animatable) {
fadeDidComplete();
}
});
Animator.INSTANCE.add(animatable);
}
public void fadeIn() {
fadingIn = true;
fadeTo(1);
}
public void fadeOut() {
fadingIn = false;
fadeTo(0);
}
protected void fadeDidComplete() {
for (FaderListener listener : listeners) {
listener.fadeDidComplete(this);
}
}
}
Okay, this is a pretty simple concept. It's a JPanel which has a alpha property which changes the opacity level of the component - basically, this is all faked, as Swing only support opaque and transparent components, not translucent components. So we set the component to be transparent and manually paint the background ourselves.
The component exposes two methods, fadeIn and fadeOut and supports a FaderListener which can be used to notify interested parties that the fade operation has been completed
Runnable example...
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setBackground(Color.RED);
setLayout(new BorderLayout());
FadePane pane = new FadePane();
pane.setLayout(new GridBagLayout());
pane.add(new JLabel("Look ma, no hands"));
add(pane);
JButton btn = new JButton("Switch");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
btn.setEnabled(false);
if (pane.isFadingIn()) {
pane.fadeOut();
} else {
pane.fadeIn();
}
}
});
add(btn, BorderLayout.SOUTH);
pane.addFadeListener(new FaderListener() {
#Override
public void fadeDidComplete(FadePane pane) {
btn.setEnabled(true);
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public interface FaderListener {
public void fadeDidComplete(FadePane pane);
}
public class FadePane extends JPanel {
private double alpha = 1;
private boolean fadingIn = true;
private DoubleAnimatable animatable;
private Duration duration = Duration.ofSeconds(5);
private List<FaderListener> listeners = new ArrayList<>(5);
public FadePane() {
setOpaque(false);
}
public void addFadeListener(FaderListener listener) {
listeners.add(listener);
}
public void removeFadeListener(FaderListener listener) {
listeners.remove(listener);
}
public boolean isFadingIn() {
return fadingIn;
}
public double getAlpha() {
return alpha;
}
public void setFaddedOut() {
alpha = 0;
fadingIn = false;
}
public void setFaddedIn() {
alpha = 1;
fadingIn = true;
}
#Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive((float)getAlpha()));
g2d.setColor(getBackground());
g2d.fillRect(0, 0, getWidth(), getHeight());
super.paint(g2d);
g2d.dispose();
}
protected void fadeTo(double to) {
double currentAlpha = getAlpha();
if (animatable != null) {
animatable.stop();
animatable = null;
}
if (currentAlpha == to) {
fadeDidComplete();
return;
}
DoubleRange animationRange = new DoubleRange(currentAlpha, to);
double maxFrom = to == 1 ? 1 : 0;
double maxTo = to == 1 ? 0 : 1;
DoubleRange maxRange = new DoubleRange(maxFrom, maxTo);
animatable = new DoubleAnimatable(animationRange, maxRange, duration, new AnimatableListener<Double>() {
#Override
public void animationChanged(Animatable<Double> animatable) {
alpha = animatable.getValue();
repaint();
}
}, new AnimatableLifeCycleListenerAdapter<Double>() {
#Override
public void animationCompleted(Animatable<Double> animatable) {
fadeDidComplete();
}
});
Animator.INSTANCE.add(animatable);
}
public void fadeIn() {
fadingIn = true;
fadeTo(1);
}
public void fadeOut() {
fadingIn = false;
fadeTo(0);
}
protected void fadeDidComplete() {
for (FaderListener listener : listeners) {
listener.fadeDidComplete(this);
}
}
}
public class DoubleAnimatable extends AbstractAnimatable<Double> {
public DoubleAnimatable(DoubleRange animationRange, DoubleRange maxRange, Duration duration, AnimatableListener<Double> listener, AnimatableLifeCycleListener<Double> lifeCycleListener) {
super(animationRange, duration, listener, lifeCycleListener);
double maxDistance = maxRange.getDistance();
double aniDistance = animationRange.getDistance();
double progress = Math.min(100, Math.max(0, Math.abs(aniDistance / maxDistance)));
Duration remainingDuration = Duration.ofMillis((long) (duration.toMillis() * progress));
setDuration(remainingDuration);
}
}
public interface AnimatableListener<T> {
public void animationChanged(Animatable<T> animatable);
}
public interface AnimatableLifeCycleListener<T> {
public void animationStopped(Animatable<T> animatable);
public void animationCompleted(Animatable<T> animatable);
public void animationStarted(Animatable<T> animatable);
public void animationPaused(Animatable<T> animatable);
}
public class AnimatableLifeCycleListenerAdapter<T> implements AnimatableLifeCycleListener<T> {
#Override
public void animationStopped(Animatable<T> animatable) {
}
#Override
public void animationCompleted(Animatable<T> animatable) {
}
#Override
public void animationStarted(Animatable<T> animatable) {
}
#Override
public void animationPaused(Animatable<T> animatable) {
}
}
public abstract class AbstractAnimatable<T> implements Animatable<T> {
private Range<T> range;
private LocalDateTime startTime;
private Duration duration = Duration.ofSeconds(5);
private T value;
private AnimatableListener<T> animatableListener;
private AnimatableLifeCycleListener<T> lifeCycleListener;
// private Easement easement;
private double rawOffset;
public AbstractAnimatable(Range<T> range, Duration duration, AnimatableListener<T> listener) {
this.range = range;
this.value = range.getFrom();
this.animatableListener = listener;
}
public AbstractAnimatable(Range<T> range, Duration duration, AnimatableListener<T> listener, AnimatableLifeCycleListener<T> lifeCycleListener) {
this(range, duration, listener);
this.lifeCycleListener = lifeCycleListener;
}
// public AbstractAnimatable(Range<T> range, Duration duration, Easement easement, AnimatableListener<T> listener) {
// this(range, duration, listener);
// this.easement = easement;
// }
//
// public AbstractAnimatable(Range<T> range, Duration duration, Easement easement, AnimatableListener<T> listener, AnimatableLifeCycleListener<T> lifeCycleListener) {
// this(range, duration, easement, listener);
// this.lifeCycleListener = lifeCycleListener;
// }
//
// public void setEasement(Easement easement) {
// this.easement = easement;
// }
//
// #Override
// public Easement getEasement() {
// return easement;
// }
public Duration getDuration() {
return duration;
}
public Range<T> getRange() {
return range;
}
public void setRange(Range<T> range) {
this.range = range;
}
#Override
public T getValue() {
return value;
}
protected void setDuration(Duration duration) {
this.duration = duration;
}
public double getCurrentProgress(double rawProgress) {
double progress = Math.min(1.0, Math.max(0.0, getRawProgress()));
// Easement easement = getEasement();
// if (easement != null) {
// progress = easement.interpolate(progress);
// }
return Math.min(1.0, Math.max(0.0, progress));
}
public double getRawProgress() {
if (startTime == null) {
return 0.0;
}
Duration duration = getDuration();
Duration runningTime = Duration.between(startTime, LocalDateTime.now());
double progress = rawOffset + (runningTime.toMillis() / (double) duration.toMillis());
return Math.min(1.0, Math.max(0.0, progress));
}
#Override
public void tick() {
if (startTime == null) {
startTime = LocalDateTime.now();
fireAnimationStarted();
}
double rawProgress = getRawProgress();
double progress = getCurrentProgress(rawProgress);
if (rawProgress >= 1.0) {
progress = 1.0;
}
value = getRange().valueAt(progress);
fireAnimationChanged();
if (rawProgress >= 1.0) {
fireAnimationCompleted();
}
}
#Override
public void start() {
if (startTime != null) {
// Restart?
return;
}
Animator.INSTANCE.add(this);
}
#Override
public void stop() {
stopWithNotification(true);
}
#Override
public void pause() {
rawOffset += getRawProgress();
stopWithNotification(false);
double remainingProgress = 1.0 - rawOffset;
Duration remainingTime = getDuration().minusMillis((long) remainingProgress);
setDuration(remainingTime);
lifeCycleListener.animationStopped(this);
}
protected void fireAnimationChanged() {
if (animatableListener == null) {
return;
}
animatableListener.animationChanged(this);
}
protected void fireAnimationCompleted() {
stopWithNotification(false);
if (lifeCycleListener == null) {
return;
}
lifeCycleListener.animationCompleted(this);
}
protected void fireAnimationStarted() {
if (lifeCycleListener == null) {
return;
}
lifeCycleListener.animationStarted(this);
}
protected void fireAnimationPaused() {
if (lifeCycleListener == null) {
return;
}
lifeCycleListener.animationPaused(this);
}
protected void stopWithNotification(boolean notify) {
Animator.INSTANCE.remove(this);
startTime = null;
if (notify) {
if (lifeCycleListener == null) {
return;
}
lifeCycleListener.animationStopped(this);
}
}
}
public interface Animatable<T> {
public Range<T> getRange();
public T getValue();
public void tick();
public Duration getDuration();
//public Easement getEasement();
// Wondering if these should be part of a secondary interface
// Provide a "self managed" unit of work
public void start();
public void stop();
public void pause();
}
public abstract class Range<T> {
private T from;
private T to;
public Range(T from, T to) {
this.from = from;
this.to = to;
}
public T getFrom() {
return from;
}
public T getTo() {
return to;
}
#Override
public String toString() {
return "From " + getFrom() + " to " + getTo();
}
public abstract T valueAt(double progress);
}
public class DoubleRange extends Range<Double> {
public DoubleRange(Double from, Double to) {
super(from, to);
}
public Double getDistance() {
return getTo() - getFrom();
}
#Override
public Double valueAt(double progress) {
double distance = getDistance();
double value = distance * progress;
value += getFrom();
return value;
}
}
public enum Animator {
INSTANCE;
private Timer timer;
private List<Animatable> properies;
private Animator() {
properies = new ArrayList<>(5);
timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
List<Animatable> copy = new ArrayList<>(properies);
Iterator<Animatable> it = copy.iterator();
while (it.hasNext()) {
Animatable ap = it.next();
ap.tick();
}
if (properies.isEmpty()) {
timer.stop();
}
}
});
}
public void add(Animatable ap) {
properies.add(ap);
timer.start();
}
protected void removeAll(List<Animatable> completed) {
properies.removeAll(completed);
}
public void remove(Animatable ap) {
properies.remove(ap);
if (properies.isEmpty()) {
timer.stop();
}
}
}
}
But it's not a glassPane
... ok, as I said, a glassPane is just another component
This is a simple example which makes use of the frame's glassPane and will, when the panel is faded out, reset the glassPane to a default component
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
JButton btn = new JButton("Switch");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Window window = SwingUtilities.getWindowAncestor(TestPane.this);
if (!(window instanceof JFrame)) {
System.out.println("Not out frame");
return;
}
JFrame frame = (JFrame) window;
FadePane pane = new FadePane();
pane.setLayout(new BorderLayout());
pane.add(new JLabel("All your base are belong to us"));
pane.setFaddedOut();
pane.addFadeListener(new FaderListener() {
#Override
public void fadeDidComplete(FadePane pane) {
System.out.println("Completed");
if (pane.getAlpha() == 1) {
System.out.println("Fade out");
pane.fadeOut();
} else {
System.out.println("Remove glasspane");
frame.setGlassPane(new JPanel());
}
}
});
frame.setGlassPane(pane);
System.out.println("Fade in");
pane.setVisible(true);
pane.fadeIn();
}
});
add(btn);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
nb: The required classes are in the previous example
Consider using JDialog container. When it is undecorated, you can change its opacity:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.WindowConstants;
public class FadeDialog extends JDialog {
private float alfa = 1;
private JLabel label;
private boolean isFadeIn = true;
private JButton fadeIn, fadeOut;
FadeDialog() {
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setLocation(new Point(300, 300));
getContentPane().setLayout(new BorderLayout(5,0));
setUndecorated(true); //opacity supported for undecorated JDialogs
JButton close = new JButton("Close");
close.addActionListener(e -> dispose());
getContentPane().add(close, BorderLayout.PAGE_END);
getContentPane().add(new ContentPane(), BorderLayout.CENTER);
pack();
setVisible(true);
Timer timer = new Timer(2000, e -> fade());//endless fade-in-out loop
timer.setInitialDelay(100);
timer.start();
}
void fade() {
alfa = isFadeIn ? alfa + 0.1f : alfa -0.1f;
if(alfa <=0 ) {
alfa = 0; isFadeIn = true;
}else if(alfa >= 1) {
alfa = 1; isFadeIn = false;
}
fadeIn.setEnabled(! isFadeIn); fadeOut.setEnabled(isFadeIn);
label.setText("Alfa is " + alfa);
setOpacity(alfa); //set JDialog opacity
}
class ContentPane extends JPanel {
ContentPane() {
setPreferredSize(new Dimension(200, 100));
setLayout(new BorderLayout());
fadeIn = new JButton("Fade In");
fadeIn.addActionListener(e -> isFadeIn = true);
add(fadeIn, BorderLayout.PAGE_START);
label = new JLabel("Alfa is " + alfa);
add(label, BorderLayout.CENTER);
fadeOut = new JButton("Fade Out");
fadeOut.addActionListener(e -> isFadeIn = false);
add(fadeOut, BorderLayout.PAGE_END);
}
}
public static void main(String[] args) {
new FadeDialog();
}
}
I have form that button can auto re-size their size when mouse hover on button and default their size when mouse is exited. It work normally first time but after i try it more than one time their size is enlarged that i can not control normally.
ImageIcon ima=new ImageIcon("C:\\Users\\chen rina\\Pictures\\win.png");
ImageIcon icon;
Thread thr;
Runnable r=new Runnable() {
#Override
public void run() {
int i=40;
while(i!=80){
try{
Thread.sleep(20);
Image scale=ima.getImage().getScaledInstance(i,i,Image.SCALE_FAST);
icon=new ImageIcon(scale);
btn2.setIcon(icon);
i=i+5;
}
catch(Exception ex){}
}
}
};
private void btn2MouseEntered(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
thr=new Thread(r);
thr.start();
}
Runnable res=new Runnable() {
int i;
#Override
public void run() {
int i=80;
while(i!=40){
try{
Thread.sleep(20);
Image scale=ima.getImage().getScaledInstance(i,i,Image.SCALE_AREA_AVERAGING);
icon=new ImageIcon(scale);
btn2.setIcon(icon);
i=i-5;
}
catch(Exception ex){}
}
}
};
private void btn2MouseExited(java.awt.event.MouseEvent evt) {
thr=new Thread(res);
thr.start();
}
Your code violates Swing thread integrity rules by making Swing calls, here setIcon(...) from within a background state. Having said that, why not simplify all of this by:
Reading in and creating and storing your ImageIcons once and only once
Never ignore exceptions as you're doing. That's unsafe coding.
Most important, use a Swing Timer to simply swap icons every 20 msec, and have no fear about violating Swing threading rules.
Your grow Timer's ActionListener could be as simple as this:
// a private inner class
private class GrowListener implements ActionListener {
private int index = 0;
#Override
public void actionPerformed(ActionEvent e) {
// assuming the button is called button and the list iconList
button.setIcon(iconList.get(index));
index++;
if (index >= iconList.size()) {
((Timer) e.getSource()).stop();
}
}
}
The iconList would look something like:
private List<Icon> iconList = new ArrayList<>();
And you could fill it with code looking something like:
for (int i = startLength; i <= endLength; i += step) {
Image img = originalImg.getScaledInstance(i, i, Image.SCALE_FAST);
iconList.add(new ImageIcon(img));
}
And a more complete and runnable example:
import java.awt.Dimension;
import java.awt.Image;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class ResizeIconTest extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int START_LENGTH = 40;
private static final int END_LENGTH = 120;
private static final int STEP = 5;
private static final int TIMER_DELAY = 20;
private static final String URL_SPEC = "https://upload.wikimedia.org/wikipedia/commons/"
+ "thumb/2/2b/Oryx_gazella_-_Etosha_2014_square_crop.jpg/"
+ "600px-Oryx_gazella_-_Etosha_2014_square_crop.jpg";
private JButton button = new JButton();
private ResizeIcon resizeIcon;
public ResizeIconTest() throws IOException {
add(button);
URL imageUrl = new URL(URL_SPEC);
BufferedImage originalImg = ImageIO.read(imageUrl);
resizeIcon = new ResizeIcon(button, originalImg, START_LENGTH,
END_LENGTH, STEP, TIMER_DELAY);
button.setIcon(resizeIcon.getSmallestIcon());
button.addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
resizeIcon.grow();
}
#Override
public void mouseExited(MouseEvent e) {
resizeIcon.shrink();
}
});
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
ResizeIconTest mainPanel = null;
try {
mainPanel = new ResizeIconTest();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
JFrame frame = new JFrame("ResizeIconTest");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class ResizeIcon {
private List<Icon> iconList = new ArrayList<>();
private AbstractButton button;
private int delayTime;
private Timer growTimer;
private Timer shrinkTimer;
public ResizeIcon(AbstractButton button, BufferedImage originalImg,
int startLength, int endLength, int step, int delayTime) {
this.button = button;
this.delayTime = delayTime;
for (int i = startLength; i <= endLength; i += step) {
Image img = originalImg.getScaledInstance(i, i, Image.SCALE_FAST);
iconList.add(new ImageIcon(img));
}
}
public Icon getSmallestIcon() {
return iconList.get(0);
}
public void grow() {
if (growTimer != null && growTimer.isRunning()) {
return; // let's not run this multiple times
}
if (button.getIcon() == iconList.get(iconList.size() - 1)) {
return; // don't run if already at largest size
}
growTimer = new Timer(delayTime, new GrowListener());
growTimer.start();
}
public void shrink() {
if (shrinkTimer != null && shrinkTimer.isRunning()) {
return; // let's not run this multiple times
}
if (button.getIcon() == iconList.get(0)) {
return; // don't run if already at smallest size
}
shrinkTimer = new Timer(delayTime, new ShrinkListener());
shrinkTimer.start();
}
private class GrowListener implements ActionListener {
private int index = 0;
#Override
public void actionPerformed(ActionEvent e) {
button.setIcon(iconList.get(index));
index++;
if (index >= iconList.size()) {
((Timer) e.getSource()).stop();
}
}
}
private class ShrinkListener implements ActionListener {
private int index = iconList.size() - 1;
#Override
public void actionPerformed(ActionEvent e) {
button.setIcon(iconList.get(index));
index--;
if (index < 0) {
((Timer) e.getSource()).stop();
}
}
}
}
I work on jFrame project:
I have jlabel I want to move it in animation, and then move another jlabel
in other words, I want the first jlabel to move and then when it finished,the second jlabel
moves.
I've already tried and didn't succeed. I have a function to move one jlabel
and ifIi try to use it on both jlabels, both jlabels move at the same time, and I don't want this to happen.
Can you help me do it, thank you so much.
Here is the function that I have :
public void MoveForPlayer(JLabel PlayerCard)
{
int delay = q;
ActionListener taskPerformer = new ActionListener() {
int count=0;
#Override
public void actionPerformed(ActionEvent evt) {
if(count==20) {
((Timer)evt.getSource()).stop();
}
PlayerCard.setLocation((PlayerCard.getLocation().x-5), PlayerCard.getLocation().y+5);
count++;
}
};
new Timer(delay, taskPerformer).start();
}
You could take a look at something like this example which wraps animation layer around a GridBagLayout or someting like this which is based on the Universal Tween Engine
This is a modified version of the first example, which adds the ability to be notified when the animation for a particular layout sequence has finished.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.LayoutManager2;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.EventObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
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.LineBorder;
import javax.swing.event.EventListenerList;
public class TestAnimatedLayout {
public static void main(String[] args) {
new TestAnimatedLayout();
}
public TestAnimatedLayout() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestAnimatedLayoutPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestAnimatedLayoutPane extends JPanel {
private Card card1, card2;
public TestAnimatedLayoutPane() {
AnimatedLayout animatedLayout = new AnimatedLayout(new GridBagLayout());
animatedLayout.addLayoutAnimationListener(new LayoutAnimationListener() {
#Override
public void layoutAnimationStopped(LayoutAnimationEvent evt) {
System.out.println("Stoppped");
if (card2 == null) {
card2 = new Card("2");
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 4, 4, 4);
gbc.gridx = 1;
gbc.gridy = 0;
add(card2, gbc);
revalidate();
}
}
});
setLayout(animatedLayout);
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 4, 4, 4);
gbc.gridx = 0;
gbc.gridy = 0;
card1 = new Card("1");
add(card1, gbc);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class Card extends JLabel {
public Card(String text) {
super(text);
setHorizontalAlignment(CENTER);
setVerticalAlignment(CENTER);
setBorder(new LineBorder(Color.BLACK));
setOpaque(true);
setBackground(Color.WHITE);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(50, 100);
}
}
public class LayoutAnimationEvent extends EventObject {
private Container parent;
public LayoutAnimationEvent(AnimatedLayout source, Container parent) {
super(source);
this.parent = parent;
}
public Container getParent() {
return parent;
}
public AnimatedLayout getAnimationLayout() {
return (AnimatedLayout) getSource();
}
}
public interface LayoutAnimationListener extends EventListener {
public void layoutAnimationStopped(LayoutAnimationEvent evt);
}
public class AnimatedLayout implements LayoutManager2 {
private EventListenerList listenerList = new EventListenerList();
private LayoutManager2 proxy;
private Map<Component, Rectangle> mapStart;
private Map<Component, Rectangle> mapTarget;
private Map<Container, Timer> mapTrips;
private Map<Container, Animator> mapAnimators;
public AnimatedLayout(LayoutManager2 proxy) {
this.proxy = proxy;
mapTrips = new WeakHashMap<>(5);
mapAnimators = new WeakHashMap<>(5);
}
public void addLayoutAnimationListener(LayoutAnimationListener listener) {
listenerList.add(LayoutAnimationListener.class, listener);
}
public void removeLayoutAnimationListener(LayoutAnimationListener listener) {
listenerList.add(LayoutAnimationListener.class, listener);
}
protected void fireAnimationStopped(Container parent) {
LayoutAnimationListener[] listeners = listenerList.getListeners(LayoutAnimationListener.class);
if (listeners != null && listeners.length > 0) {
LayoutAnimationEvent evt = new LayoutAnimationEvent(this, parent);
for (LayoutAnimationListener listener : listeners) {
listener.layoutAnimationStopped(evt);
}
}
}
#Override
public void addLayoutComponent(String name, Component comp) {
proxy.addLayoutComponent(name, comp);
}
#Override
public void removeLayoutComponent(Component comp) {
proxy.removeLayoutComponent(comp);
}
#Override
public Dimension preferredLayoutSize(Container parent) {
return proxy.preferredLayoutSize(parent);
}
#Override
public Dimension minimumLayoutSize(Container parent) {
return proxy.minimumLayoutSize(parent);
}
#Override
public void layoutContainer(Container parent) {
Timer timer = mapTrips.get(parent);
if (timer == null) {
System.out.println("...create new trip");
timer = new Timer(125, new TripAction(parent));
timer.setRepeats(false);
timer.setCoalesce(false);
mapTrips.put(parent, timer);
}
System.out.println("trip...");
timer.restart();
}
protected void doLayout(Container parent) {
System.out.println("doLayout...");
mapStart = new HashMap<>(parent.getComponentCount());
for (Component comp : parent.getComponents()) {
mapStart.put(comp, (Rectangle) comp.getBounds().clone());
}
proxy.layoutContainer(parent);
LayoutConstraints constraints = new LayoutConstraints();
for (Component comp : parent.getComponents()) {
Rectangle bounds = comp.getBounds();
Rectangle startBounds = mapStart.get(comp);
if (!mapStart.get(comp).equals(bounds)) {
if (startBounds.x == 0 && startBounds.y == 0) {
startBounds.x = (parent.getWidth() - startBounds.width) / 2;
startBounds.y = (parent.getHeight() - startBounds.height) / 2;
}
comp.setBounds(startBounds);
constraints.add(comp, startBounds, bounds);
}
}
System.out.println("Items to layout " + constraints.size());
if (constraints.size() > 0) {
Animator animator = mapAnimators.get(parent);
if (animator == null) {
animator = new Animator(this, parent, constraints);
mapAnimators.put(parent, animator);
} else {
animator.setConstraints(constraints);
}
animator.restart();
} else {
if (mapAnimators.containsKey(parent)) {
Animator animator = mapAnimators.get(parent);
animator.stop();
mapAnimators.remove(parent);
}
}
}
#Override
public void addLayoutComponent(Component comp, Object constraints) {
proxy.addLayoutComponent(comp, constraints);
}
#Override
public Dimension maximumLayoutSize(Container target) {
return proxy.maximumLayoutSize(target);
}
#Override
public float getLayoutAlignmentX(Container target) {
return proxy.getLayoutAlignmentX(target);
}
#Override
public float getLayoutAlignmentY(Container target) {
return proxy.getLayoutAlignmentY(target);
}
#Override
public void invalidateLayout(Container target) {
proxy.invalidateLayout(target);
}
protected void animationDidStop(Container parent) {
fireAnimationStopped(parent);
}
protected class TripAction implements ActionListener {
private Container container;
public TripAction(Container container) {
this.container = container;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("...trip");
mapTrips.remove(container);
doLayout(container);
}
}
}
public class LayoutConstraints {
private List<AnimationBounds> animationBounds;
public LayoutConstraints() {
animationBounds = new ArrayList<AnimationBounds>(25);
}
public void add(Component comp, Rectangle startBounds, Rectangle targetBounds) {
add(new AnimationBounds(comp, startBounds, targetBounds));
}
public void add(AnimationBounds bounds) {
animationBounds.add(bounds);
}
public int size() {
return animationBounds.size();
}
public AnimationBounds[] getAnimationBounds() {
return animationBounds.toArray(new AnimationBounds[animationBounds.size()]);
}
}
public class AnimationBounds {
private Component component;
private Rectangle startBounds;
private Rectangle targetBounds;
public AnimationBounds(Component component, Rectangle startBounds, Rectangle targetBounds) {
this.component = component;
this.startBounds = startBounds;
this.targetBounds = targetBounds;
}
public Rectangle getStartBounds() {
return startBounds;
}
public Rectangle getTargetBounds() {
return targetBounds;
}
public Component getComponent() {
return component;
}
public Rectangle getBounds(float progress) {
return calculateProgress(getStartBounds(), getTargetBounds(), progress);
}
}
public static Rectangle calculateProgress(Rectangle startBounds, Rectangle targetBounds, float progress) {
Rectangle bounds = new Rectangle();
if (startBounds != null && targetBounds != null) {
bounds.setLocation(calculateProgress(startBounds.getLocation(), targetBounds.getLocation(), progress));
bounds.setSize(calculateProgress(startBounds.getSize(), targetBounds.getSize(), progress));
}
return bounds;
}
public static Point calculateProgress(Point startPoint, Point targetPoint, float progress) {
Point point = new Point();
if (startPoint != null && targetPoint != null) {
point.x = calculateProgress(startPoint.x, targetPoint.x, progress);
point.y = calculateProgress(startPoint.y, targetPoint.y, progress);
}
return point;
}
public static Dimension calculateProgress(Dimension startSize, Dimension targetSize, float progress) {
Dimension size = new Dimension();
if (startSize != null && targetSize != null) {
size.width = calculateProgress(startSize.width, targetSize.width, progress);
size.height = calculateProgress(startSize.height, targetSize.height, progress);
}
return size;
}
public static int calculateProgress(int startValue, int endValue, float fraction) {
int value = 0;
int distance = endValue - startValue;
value = (int) ((float) distance * fraction);
value += startValue;
return value;
}
public class Animator implements ActionListener {
private Timer timer;
private LayoutConstraints constraints;
private int tick;
private Container parent;
private AnimatedLayout layout;
public Animator(AnimatedLayout layout, Container parent, LayoutConstraints constraints) {
setConstraints(constraints);
timer = new Timer(16, this);
timer.setRepeats(true);
timer.setCoalesce(true);
this.parent = parent;
this.layout = layout;
}
private void setConstraints(LayoutConstraints constraints) {
this.constraints = constraints;
}
public void restart() {
tick = 0;
timer.restart();
}
protected void stop() {
timer.stop();
tick = 0;
}
#Override
public void actionPerformed(ActionEvent e) {
tick += 16;
float progress = (float) tick / (float) 1000;
if (progress >= 1f) {
progress = 1f;
timer.stop();
layout.animationDidStop(parent);
}
for (AnimationBounds ab : constraints.getAnimationBounds()) {
Rectangle bounds = ab.getBounds(progress);
Component comp = ab.getComponent();
comp.setBounds(bounds);
comp.invalidate();
comp.repaint();
}
parent.repaint();
}
}
}
Before you tell me "it's too complicated", understand that animation alone is a complex subject, but when trying to animated components who should be under the control of appropriate layout managers, it becomes even more complicated...
If I understand your question correctly, you want that one JLabel should be moved every second time the timer is run, and a different one should be moved every other time the timer is run. If this is the case, you can use the count variable you already have to decide which one to move.
For example:
public void MoveForPlayer(JLabel PlayerCard1, JLabel PlayerCard2)
{
and then...
if (count%2==0) { // It's even
PlayerCard1.setLocation((PlayerCard1.getLocation().x-5), PlayerCard1.getLocation().y+5);
} else {
PlayerCard2.setLocation((PlayerCard2.getLocation().x-5), PlayerCard2.getLocation().y+5);
}
I have a menu that has a variety of buttons on display, I'm able to make the buttons call their respective JPanels when clicked. The thing is I would like to make the Jpanel slide in when its called instead of instantaneously popping in. I tried using tween engine and as Java beginner, I find it really overwhelming, so I decided to use timed animation. I was able to make the Jpanel on top to slide to one side but for some reason the next panel doesn't want to display, im really tired, can someone help please! There code is below:
public class Listener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
new Timer(0, new ActionListener() {
public void actionPerformed(ActionEvent e) {
mainpane.setLocation(mainpane.getX() - 10, 0);
if (mainpane.getX() + mainpane.getWidth() == 0)
{
((Timer) e.getSource()).stop();
System.out.println("Timer stopped");
}
}
}).start();
}
}
Sliding panels can be tricky. Here is some starter code. Modify to fit
your needs. Add error checking and exception handling as necessary.
This example uses JButtons and a JTree as content but you can use just about any type of content.
Usage:
static public void main(final String[] args) throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
final JFrame jFrame = new JFrame() {
{
final PanelSlider42<JFrame> slider = new PanelSlider42<JFrame>(this);
final JPanel jPanel = slider.getBasePanel();
slider.addComponent(new JButton("1"));
slider.addComponent(new JButton("22"));
slider.addComponent(new JButton("333"));
slider.addComponent(new JButton("4444"));
getContentPane().add(jPanel);
setSize(300, 300);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setVisible(true);
}
};
}
});
}
The impl is lengthy ...
package com.java42.example.code;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.SwingUtilities;
public class PanelSlider42<ParentType extends Container> {
private static final int RIGHT = 0x01;
private static final int LEFT = 0x02;
private static final int TOP = 0x03;
private static final int BOTTOM = 0x04;
private final JPanel basePanel = new JPanel();
private final ParentType parent;
private final Object lock = new Object();
private final ArrayList<Component> jPanels = new ArrayList<Component>();
private final boolean useSlideButton = true;
private boolean isSlideInProgress = false;
private final JPanel glassPane;
{
glassPane = new JPanel();
glassPane.setOpaque(false);
glassPane.addMouseListener(new MouseAdapter() {
});
glassPane.addMouseMotionListener(new MouseMotionAdapter() {
});
glassPane.addKeyListener(new KeyAdapter() {
});
}
public PanelSlider42(final ParentType parent) {
if (parent == null) {
throw new RuntimeException("ProgramCheck: Parent can not be null.");
}
if ((parent instanceof JFrame) || (parent instanceof JDialog) || (parent instanceof JWindow) || (parent instanceof JPanel)) {
}
else {
throw new RuntimeException("ProgramCheck: Parent type not supported. " + parent.getClass().getSimpleName());
}
this.parent = parent;
attach();
basePanel.setSize(parent.getSize());
basePanel.setLayout(new BorderLayout());
if (useSlideButton) {
final JPanel statusPanel = new JPanel();
basePanel.add(statusPanel, BorderLayout.SOUTH);
statusPanel.add(new JButton("Slide Left") {
private static final long serialVersionUID = 9204819004142223529L;
{
setMargin(new Insets(0, 0, 0, 0));
}
{
addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
slideLeft();
}
});
}
});
statusPanel.add(new JButton("Slide Right") {
{
setMargin(new Insets(0, 0, 0, 0));
}
private static final long serialVersionUID = 9204819004142223529L;
{
addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
slideRight();
}
});
}
});
statusPanel.add(new JButton("Slide Up") {
{
setMargin(new Insets(0, 0, 0, 0));
}
private static final long serialVersionUID = 9204819004142223529L;
{
addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
slideTop();
}
});
}
});
statusPanel.add(new JButton("Slide Down") {
{
setMargin(new Insets(0, 0, 0, 0));
}
private static final long serialVersionUID = 9204819004142223529L;
{
addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
slideBottom();
}
});
}
});
}
}
public JPanel getBasePanel() {
return basePanel;
}
private void attach() {
final ParentType w = this.parent;
if (w instanceof JFrame) {
final JFrame j = (JFrame) w;
if (j.getContentPane().getComponents().length > 0) {
throw new RuntimeException("ProgramCheck: Parent already contains content.");
}
j.getContentPane().add(basePanel);
}
if (w instanceof JDialog) {
final JDialog j = (JDialog) w;
if (j.getContentPane().getComponents().length > 0) {
throw new RuntimeException("ProgramCheck: Parent already contains content.");
}
j.getContentPane().add(basePanel);
}
if (w instanceof JWindow) {
final JWindow j = (JWindow) w;
if (j.getContentPane().getComponents().length > 0) {
throw new RuntimeException("ProgramCheck: Parent already contains content.");
}
j.getContentPane().add(basePanel);
}
if (w instanceof JPanel) {
final JPanel j = (JPanel) w;
if (j.getComponents().length > 0) {
throw new RuntimeException("ProgramCheck: Parent already contains content.");
}
j.add(basePanel);
}
}
public void addComponent(final Component component) {
if (jPanels.contains(component)) {
}
else {
jPanels.add(component);
if (jPanels.size() == 1) {
basePanel.add(component);
}
component.setSize(basePanel.getSize());
component.setLocation(0, 0);
}
}
public void removeComponent(final Component component) {
if (jPanels.contains(component)) {
jPanels.remove(component);
}
}
public void slideLeft() {
slide(LEFT);
}
public void slideRight() {
slide(RIGHT);
}
public void slideTop() {
slide(TOP);
}
public void slideBottom() {
slide(BOTTOM);
}
private void enableUserInput(final ParentType w) {
if (w instanceof JFrame) {
((JFrame) w).getGlassPane().setVisible(false);
}
if (w instanceof JDialog) {
((JDialog) w).getGlassPane().setVisible(false);
}
if (w instanceof JWindow) {
((JWindow) w).getGlassPane().setVisible(false);
}
}
private void disableUserInput(final ParentType w) {
if (w instanceof JFrame) {
((JFrame) w).setGlassPane(glassPane);
}
if (w instanceof JDialog) {
((JDialog) w).setGlassPane(glassPane);
}
if (w instanceof JWindow) {
((JWindow) w).setGlassPane(glassPane);
}
glassPane.setVisible(true);
}
private void enableTransparentOverylay() {
if (parent instanceof JFrame) {
((JFrame) parent).getContentPane().setBackground(jPanels.get(0).getBackground());
parent.remove(basePanel);
parent.validate();
}
if (parent instanceof JDialog) {
((JDialog) parent).getContentPane().setBackground(jPanels.get(0).getBackground());
parent.remove(basePanel);
parent.validate();
}
if (parent instanceof JWindow) {
((JWindow) parent).getContentPane().setBackground(jPanels.get(0).getBackground());
parent.remove(basePanel);
parent.validate();
}
}
private void slide(final int slideType) {
if (!isSlideInProgress) {
isSlideInProgress = true;
final Thread t0 = new Thread(new Runnable() {
#Override
public void run() {
parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
disableUserInput(parent);
slide(true, slideType);
enableUserInput(parent);
parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
isSlideInProgress = false;
}
});
t0.setDaemon(true);
t0.start();
}
else {
Toolkit.getDefaultToolkit().beep();
}
}
private void slide(final boolean useLoop, final int slideType) {
if (jPanels.size() < 2) {
System.err.println("Not enough panels");
return;
}
synchronized (lock) {
Component componentOld = null;
Component componentNew = null;
if ((slideType == LEFT) || (slideType == TOP)) {
componentNew = jPanels.remove(jPanels.size() - 1);
componentOld = jPanels.get(0);
jPanels.add(0, componentNew);
}
if ((slideType == RIGHT) || (slideType == BOTTOM)) {
componentOld = jPanels.remove(0);
jPanels.add(componentOld);
componentNew = jPanels.get(0);
}
final int w = componentOld.getWidth();
final int h = componentOld.getHeight();
final Point p1 = componentOld.getLocation();
final Point p2 = new Point(0, 0);
if (slideType == LEFT) {
p2.x += w;
}
if (slideType == RIGHT) {
p2.x -= w;
}
if (slideType == TOP) {
p2.y += h;
}
if (slideType == BOTTOM) {
p2.y -= h;
}
componentNew.setLocation(p2);
int step = 0;
if ((slideType == LEFT) || (slideType == RIGHT)) {
step = (int) (((float) parent.getWidth() / (float) Toolkit.getDefaultToolkit().getScreenSize().width) * 40.f);
}
else {
step = (int) (((float) parent.getHeight() / (float) Toolkit.getDefaultToolkit().getScreenSize().height) * 20.f);
}
step = step < 5 ? 5 : step;
basePanel.add(componentNew);
basePanel.revalidate();
if (useLoop) {
final int max = (slideType == LEFT) || (slideType == RIGHT) ? w : h;
final long t0 = System.currentTimeMillis();
for (int i = 0; i != (max / step); i++) {
switch (slideType) {
case LEFT: {
p1.x -= step;
componentOld.setLocation(p1);
p2.x -= step;
componentNew.setLocation(p2);
break;
}
case RIGHT: {
p1.x += step;
componentOld.setLocation(p1);
p2.x += step;
componentNew.setLocation(p2);
break;
}
case TOP: {
p1.y -= step;
componentOld.setLocation(p1);
p2.y -= step;
componentNew.setLocation(p2);
break;
}
case BOTTOM: {
p1.y += step;
componentOld.setLocation(p1);
p2.y += step;
componentNew.setLocation(p2);
break;
}
default:
new RuntimeException("ProgramCheck").printStackTrace();
break;
}
try {
Thread.sleep(500 / (max / step));
} catch (final Exception e) {
e.printStackTrace();
}
}
final long t1 = System.currentTimeMillis();
}
componentOld.setLocation(-10000, -10000);
componentNew.setLocation(0, 0);
}
}
}
I have searched for that problem some time ago.I found this sample code somewhere - saved in my evernote for future reference. This is the shortest way to implement that when I googled that in the past
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class SlidingPanel {
JPanel panel;
public void makeUI() {
panel = new JPanel();
panel.setBackground(Color.RED);
panel.setBounds(0, 0, 400, 400);
JButton button = new JButton("Click");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
((JButton) e.getSource()).setEnabled(false);
new Timer(1, new ActionListener() {
public void actionPerformed(ActionEvent e) {
panel.setLocation(panel.getX() - 1, 0);
if (panel.getX() + panel.getWidth() == 0) {
((Timer) e.getSource()).stop();
System.out.println("Timer stopped");
}
}
}).start();
}
});
panel.add(button);
JFrame frame = new JFrame("Sliding Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setLayout(null);
frame.add(panel);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new SlidingPanel().makeUI();
}
});
}
}
My t.stop(); method is not working. I am going crazy trying to figure out why my stop method is not working.
I'm using the a timer in my code and I can't get it to stop. Can anyone take a look at it and tell me what's going on?:
/*Gilberto Rose*/
package homework2;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class MultipleBalls extends JFrame implements ActionListener
{
int dx = 2;
int dy = 2;
int x = 1;
int y = 1;
int i = 0;
public static void main(String[] args)
{
Runnable balls = new Ball2();
Thread thread1 = new Thread(balls);
thread1.run();
}
#Override
public void actionPerformed(ActionEvent arg0)
{
repaint();
System.out.println(i++);
}
}// End of Ball class
class Ball2 extends JPanel implements Runnable
{
MultipleBalls b = new MultipleBalls();
JButton g = new JButton("resume");
JButton f = new JButton("suspend");
JButton e = new JButton("-1");
JButton d = new JButton("+1");
List<Ball2> L = new ArrayList<Ball2>();
Timer t = new Timer(50, b);
public int x = 6;
public void loopstop()
{
t.stop();
}// end of loopstop method
Ball2()
{
controller4();
controller3();
controller2();
controller();
add(d);
add(e);
add(f);
add(g);
}// End of Ball2 constructor
public void run()
{
Ball2 c = new Ball2();
b.setSize(500, 500);
b.setVisible(true);
b.add(c);
t.start();
} // End of run method
public void controller()
{
d.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
L.add(new Ball2());
}
});
}// End of controller
public void controller2()
{
e.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.out.println("subtracter");
L.remove(L.size()-1);
}
});
}// End of controller2
public void controller3()
{
f.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
loopstop();
}
});
}// End of controller3
public void controller4()
{
g.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.out.println("Resume");
}
});
}// End of controller4
public void paintComponent(Graphics g)
{
if(L.size() > 0)
{
int i = 0;
do
{
g.fillOval(L.get(i).ballx(), L.get(i).bally(), 90, 90);
i++;
}while(i < L.size() && true ); // End of Do while loop
}// End of if statement
}// End of paintComponent
MultipleBalls bb = new MultipleBalls();
public int ballx()
{
if (bb.x == 0 || bb.x == 500)
{
bb.dx *= -1;
} // End of if statement
bb.x += bb.dx;
return bb.x;
}
public int bally()
{
if (bb.y == 0 || bb.y == 500 )
{
bb.dy *= -1;
}// end of if statement
bb.y += bb.dy;
return bb.y;
}// End of bally
}// End of Ball2 class
Your code is extremely convoluted, I believe that it's suffering from something called cyclomatic complexity, so much so, it is difficult for you or us to see what object is creating what other object, and what is running what. And this is your problem. You have at least two MultipleBall objects, two Ball2 objects, and you're starting the Timer for one of the Ball2 objects and stopping it for the other.
The solution: simplify this code greatly.
Create one MultipleBalls object, just one.
Don't have MultipleBalls implement ActionListener. Rather use an anonymous inner class for your ActionListener and create it on the spot where you need it.
Create just one Ball2 object, just one.
Also note that you almost never call run() on a Thread object but rather start(), but having said that, I'm not even sure that you should be using a Thread object where you're using it.
Edit
My main class would be simple, and would simply have a main method and supporting method that gets things started. Something like:
public class MultipleBalls {
private static void createAndShowGui() {
BallsPanel mainPanel = new BallsPanel();
JFrame frame = new JFrame("Multiple Balls");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Edit
For an example of a separation of concerns:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.*;
public class MultipleBallsZ {
private static void createAndShowGui() {
BallsPanelZ ballsPanel = new BallsPanelZ();
new Control(ballsPanel);
JFrame frame = new JFrame("Multiple Balls");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(ballsPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class BallsPanelZ extends JPanel {
private static final int TIMER_DELAY = 200;
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private Timer timer = new Timer(TIMER_DELAY, new TimerListener());
private int counter = 0;
private Control control = null;
public BallsPanelZ() {
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public Timer getTimer() {
return timer;
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
counter++;
System.out.printf("Count: %03d%n", counter);
}
}
public void setControl(Control control) {
this.control = control;
for (Action action : control) {
add(new JButton(action));
}
}
}
#SuppressWarnings("serial")
class Control implements Iterable<Action> {
private List<Action> actionList = new ArrayList<>();
private BallsPanelZ ballsPanel;
public Control(BallsPanelZ ballsPanel) {
actionList.add(new PauseAction());
actionList.add(new ResumeAction());
this.ballsPanel = ballsPanel;
ballsPanel.setControl(this);
}
private class PauseAction extends AbstractAction {
public PauseAction() {
super ("Timer Pause");
putValue(MNEMONIC_KEY, KeyEvent.VK_P);
}
#Override
public void actionPerformed(ActionEvent e) {
ballsPanel.getTimer().stop();
}
}
private class ResumeAction extends AbstractAction {
public ResumeAction() {
super("Timer Resume");
putValue(MNEMONIC_KEY, KeyEvent.VK_R);
putValue(DISPLAYED_MNEMONIC_INDEX_KEY, 6);
}
#Override
public void actionPerformed(ActionEvent e) {
ballsPanel.getTimer().restart();
}
}
#Override
public Iterator<Action> iterator() {
return actionList.iterator();
}
}