Java – use timer to animate JPanel (slide)
I'm trying to make JPanel slides from the side using this class I made:
public class AnimationClass { private int i; private int y; private JPanel panel; private int xTo; private Timer timer; private int xFrom; synchronized void slidePanelInFromRight(JPanel panelInput,int xFromInput,int xToInput,int yInput,int width,int height) { this.panel = panelInput; this.xFrom = xFromInput; this.xTo = xToInput; this.y = yInput; panel.setSize(width,height); timer = new Timer(0,new ActionListener() { public void actionPerformed(ActionEvent ae) { for (int i = xFrom; i > xTo; i--) { panel.setLocation(i,y); panel.repaint(); i--; timer.stop(); timer.setDelay(100); if (i >= xTo) { timer.stop(); } } timer.stop(); } }); timer.start(); } }
Well, I don't know what the problem is I've tried many different things, but I can't seem to make it work
Solution
The timer should change the position of each tick until it is in place, not at each tick. You are running a for next loop, which prevents EDT from updating the UI until the end of the loop
Update with examples
For example
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.Action; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class TestAnimatedPane { public static void main(String[] args) { new TestAnimatedPane(); } public TestAnimatedPane() { EventQueue.invokelater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | illegalaccessexception | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Test"); 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 JPanel panel; public TestPane() { setLayout(null); panel = new JPanel(); panel.setBackground(Color.RED); add(panel); Dimension size = getPreferredSize(); Rectangle from = new Rectangle(size.width,(size.height - 50) / 2,50,50); Rectangle to = new Rectangle((size.width - 50) / 2,50); Animate animate = new Animate(panel,from,to); animate.start(); } @Override public Dimension getPreferredSize() { return new Dimension(200,200); } } public static class Animate { public static final int RUN_TIME = 2000; private JPanel panel; private Rectangle from; private Rectangle to; private long startTime; public Animate(JPanel panel,Rectangle from,Rectangle to) { this.panel = panel; this.from = from; this.to = to; } public void start() { Timer timer = new Timer(40,new ActionListener() { @Override public void actionPerformed(ActionEvent e) { long duration = System.currentTimeMillis() - startTime; double progress = (double)duration / (double)RUN_TIME; if (progress > 1f) { progress = 1f; ((Timer)e.getSource()).stop(); } Rectangle target = calculateProgress(from,to,progress); panel.setBounds(target); } }); timer.setRepeats(true); timer.setCoalesce(true); timer.setInitialDelay(0); startTime = System.currentTimeMillis(); timer.start(); } } public static Rectangle calculateProgress(Rectangle startBounds,Rectangle targetBounds,double 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,double 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 int calculateProgress(int startValue,int endValue,double fraction) { int value = 0; int distance = endValue - startValue; value = (int)Math.round((double)distance * fraction); value += startValue; return value; } public static Dimension calculateProgress(Dimension startSize,Dimension targetSize,double 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; } }
to update
I should have added this last night (1 year without going to bed, 2 parents, no more...)
Animation is a complex topic, especially when you start looking at the transmission (the example is static)
You should seriously consider taking a look at... Rather than reinventing the wheel
>Timing framework – this is the basic animation framework and makes no assumptions about how you use it. > Trident – similar to the timing framework, but also supports swing based component (through reflection) building > Universal tween engine