Java: Moving jLabel twice using Timer

2019-01-12 11:46发布

问题:

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

回答1:

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



回答2:

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