如何在JPanel中为Rectangle设置动画?

时间:2014-05-22 19:20:39

标签: java swing user-interface jframe jpanel

我想为我的项目学习一些关于JAVA的技巧。

我想设置我的Rectangle leftoright和righttoleft的动画,但我不能为球动画应用相同的功能。

此外,如何使用y坐标的边框在不同的x方向上开始我的球?

非常感谢您的建议和帮助。

enter image description here

我的代码:

import javax.swing.Timer;
import java.util.ArrayList;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class MultipleBall extends JApplet {
public MultipleBall() {
    add(new BallControl());
}

class BallControl extends JPanel {
    private BallPanel ballPanel = new BallPanel();
    private JButton Suspend = new JButton("Suspend");
    private JButton Resume = new JButton("Resume");
    private JButton Add = new JButton("+1");
    private JButton Subtract = new JButton("-1");
    private JScrollBar Delay = new JScrollBar();

    public BallControl() {
        // Group buttons in a panel
        JPanel panel = new JPanel();
        panel.add(Suspend);
        panel.add(Resume);
        panel.add(Add);
        panel.add(Subtract);

        // Add ball and buttons to the panel
        ballPanel.setBorder(new javax.swing.border.LineBorder(Color.red));
        Delay.setOrientation(JScrollBar.HORIZONTAL);
        ballPanel.setDelay(Delay.getMaximum());
        setLayout(new BorderLayout());
        add(Delay, BorderLayout.NORTH);
        add(ballPanel, BorderLayout.CENTER);
        add(panel, BorderLayout.SOUTH);

        // Register listeners
        Suspend.addActionListener(new Listener());
        Resume.addActionListener(new Listener());
        Add.addActionListener(new Listener());
        Subtract.addActionListener(new Listener());
        Delay.addAdjustmentListener(new AdjustmentListener() {

            public void adjustmentValueChanged(AdjustmentEvent e) {
                ballPanel.setDelay(Delay.getMaximum() - e.getValue());
            }
        });
    }

    class Listener implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == Suspend)
                ballPanel.suspend();
            else if (e.getSource() == Resume)
                ballPanel.resume();
            else if (e.getSource() == Add)
                ballPanel.add();
            else if (e.getSource() == Subtract)
                ballPanel.subtract();
        }
    }
}

class BallPanel extends JPanel {
    private int delay = 30;
    private ArrayList<Ball> list = new ArrayList<Ball>();

    // Create a timer with the initial delay
    protected Timer timer = new Timer(delay, new ActionListener() {
        /** Handle the action event */
        public void actionPerformed(ActionEvent e) {
            repaint();
        }
    });

    public BallPanel() {
        timer.start();
    }

    public void add() {
        list.add(new Ball());
    }

    public void subtract() {
        if (list.size() > 0)
            list.remove(list.size() - 1); // Remove the last ball
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawRect(185, 279, 50, 15);
        g.setColor(Color.RED);
        g.fillRect(185, 279, 50, 15);

        for (int i = 0; i < list.size(); i++) {
            Ball ball = (Ball) list.get(i); // Get a ball
            g.setColor(ball.color); // Set ball color

            // Check boundaries
            if (ball.x < 0 || ball.x > getWidth())
                ball.dx = -ball.dx;

            if (ball.y < 0 || ball.y > getHeight())
                ball.dy = -ball.dy;

            // Adjust ball position
            ball.x += ball.dx;
            // ball.y += ball.dy;
            g.fillOval(ball.x - ball.radius, ball.y - ball.radius,
                    ball.radius * 2, ball.radius * 2);
        }
    }

    public void suspend() {
        timer.stop();
    }

    public void resume() {
        timer.start();
    }

    public void setDelay(int delay) {
        this.delay = delay;
        timer.setDelay(delay);
    }
}

class Ball {
    int x = 20;
    int y = 20; // Current ball position
    int dx = 2; // Increment on ball's x-coordinate
    int dy = 2; // Increment on ball's y-coordinate
    int radius = 15; // Ball radius
    Color color = new Color((int) (Math.random() * 256),
            (int) (Math.random() * 256), (int) (Math.random() * 256));
}

/** Main method */
public static void main(String[] args) {
    JFrame frame = new JFrame();
    JApplet applet = new MultipleBallApp();
    frame.add(applet);
    frame.setTitle("MultipleBallApp");
    frame.setLocationRelativeTo(null); // Center the frame
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(400, 400);
    frame.setLocationRelativeTo(null); // Center the frame
    frame.setVisible(true);
}
}

2 个答案:

答案 0 :(得分:4)

  

无法对球类动画应用相同的功能

这可能是你的第一个错误。事实上,这正是你应该尝试做的事情。这个想法是,你应该尝试通过绘制/动画是抽象的方法来设计一种方法,这样你想要绘制的形状无关紧要,你可以将它应用到sam基本动画过程...

例如,您可以从某种interface开始,它描述了动画实体的基本属性...

public interface AnimatedShape {
    public void update(Rectangle bounds);
    public void paint(JComponent parent, Graphics2D g2d);
}

这表示动画实体可以更新(移动)和绘制。按照惯例(因为我很懒),我喜欢创建一个实现最常见方面的abstract实现...

public abstract class AbstractAnimatedShape implements AnimatedShape {

    private Rectangle bounds;
    private int dx, dy;

    public AbstractAnimatedShape() {
    }

    public void setBounds(Rectangle bounds) {
        this.bounds = bounds;
    }

    public Rectangle getBounds() {
        return bounds;
    }

    public int getDx() {
        return dx;
    }

    public int getDy() {
        return dy;
    }

    public void setDx(int dx) {
        this.dx = dx;
    }

    public void setDy(int dy) {
        this.dy = dy;
    }

    @Override
    public void update(Rectangle parentBounds) {
        Rectangle bounds = getBounds();
        int dx = getDx();
        int dy = getDy();
        bounds.x += dx;
        bounds.y += dy;
        if (bounds.x  < parentBounds.x) {
            bounds.x = parentBounds.x;
            setDx(dx *= -1);
        } else if (bounds.x + bounds.width > parentBounds.x + parentBounds.width) {
            bounds.x = parentBounds.x + (parentBounds.width - bounds.width);
            setDx(dx *= -1);
        }
        if (bounds.y < parentBounds.y) {
            bounds.y = parentBounds.y;
            setDy(dy *= -1);
        } else if (bounds.y + bounds.height > parentBounds.y + parentBounds.height) {
            bounds.y = parentBounds.y + (parentBounds.height - bounds.height);
            setDy(dy *= -1);
        }
    }
}

然后开始创建实现......

public class AnimatedBall extends AbstractAnimatedShape {

    private Color color;

    public AnimatedBall(int x, int y, int radius, Color color) {
        setBounds(new Rectangle(x, y, radius * 2, radius * 2));
        this.color = color;
        setDx(Math.random() > 0.5 ? 2 : -2);
        setDy(Math.random() > 0.5 ? 2 : -2);
    }

    public Color getColor() {
        return color;
    }

    @Override
    public void paint(JComponent parent, Graphics2D g2d) {
        Rectangle bounds = getBounds();
        g2d.setColor(getColor());
        g2d.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);
    }
}

通过这种方式,您可以自定义实体的动画和绘制方式,但实体的每个实例的基本逻辑都是相同的......

但这有什么意义呢......

基本上,它允许我们做的是生成所有动画对象的“虚拟”概念并简化管理,例如......

我们可以使用松散的情侣List而不是使用“紧密”耦合的List ......

private ArrayList<AnimatedShape> list = new ArrayList<AnimatedShape>();

然后,当我们想要更新实体时,我们只需要迭代List并要求实体更新......

protected Timer timer = new Timer(delay, new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        for (AnimatedShape ball : list) {
            ball.update(getBounds());
        }
        repaint();
    }
});

当他们需要画画时......

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    Graphics2D g2d = (Graphics2D) g;
    for (AnimatedShape ball : list) {
        ball.paint(this, g2d);
    }
}

因为BallPane并不关心它实际上是什么类型的实体,而只是因为它是AnimatedShape的类型......让生活变得更轻松......

现在,我AnimatedBall的实现已经随机化了球的每个实例的方向,但是你也可以在使用类似的东西添加球时随机化起始位置。

public void add() {
    int radius = 15;
    // Randomised position
    int x = (int)(Math.random() * (getWidth() - (radius * 2))) + radius;
    int y = (int)(Math.random() * (getHeight() - (radius * 2))) + radius;
    Color color = new Color((int) (Math.random() * 256),
                    (int) (Math.random() * 256), (int) (Math.random() * 256));

    AnimatedBall ball = new AnimatedBall(x, y, radius, color);

    list.add(ball);
}

但是这对于添加矩形有什么帮助呢?

您现在需要创建一个AnimatedRectangle,其范围从AbstractAnimatedShape开始,并实现了所需的方法,并将此实例添加到List AnimatedShape的{​​{1}}中BallPane 1}}。

如果您不希望在同一列表中管理矩形,您可以创建另一个列表并单独管理它(它创建了两个额外的方法,update(List<AnimatedShape>)paint(List<AnimatedShape>, Graphics2D)传递每个个体列表,以减少重复的代码,但那是我... ...

您可以通过覆盖setDy方法并忽略任何更改来限制矩形垂直移动,例如

Example

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.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class MultipleBall {

    public MultipleBall() {
        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("MultipleBallApp");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new BallControl());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class BallControl extends JPanel {

        private BallPanel ballPanel = new BallPanel();
        private JButton Suspend = new JButton("Suspend");
        private JButton Resume = new JButton("Resume");
        private JButton Add = new JButton("+1");
        private JButton Subtract = new JButton("-1");
        private JScrollBar Delay = new JScrollBar();

        public BallControl() {
            // Group buttons in a panel
            JPanel panel = new JPanel();
            panel.add(Suspend);
            panel.add(Resume);
            panel.add(Add);
            panel.add(Subtract);

            // Add ball and buttons to the panel
            ballPanel.setBorder(new javax.swing.border.LineBorder(Color.red));
            Delay.setOrientation(JScrollBar.HORIZONTAL);
            ballPanel.setDelay(Delay.getMaximum());
            setLayout(new BorderLayout());
            add(Delay, BorderLayout.NORTH);
            add(ballPanel, BorderLayout.CENTER);
            add(panel, BorderLayout.SOUTH);

            // Register listeners
            Suspend.addActionListener(new Listener());
            Resume.addActionListener(new Listener());
            Add.addActionListener(new Listener());
            Subtract.addActionListener(new Listener());
            Delay.addAdjustmentListener(new AdjustmentListener() {

                public void adjustmentValueChanged(AdjustmentEvent e) {
                    ballPanel.setDelay(Delay.getMaximum() - e.getValue());
                }
            });
        }

        class Listener implements ActionListener {

            public void actionPerformed(ActionEvent e) {
                if (e.getSource() == Suspend) {
                    ballPanel.suspend();
                } else if (e.getSource() == Resume) {
                    ballPanel.resume();
                } else if (e.getSource() == Add) {
                    ballPanel.add();
                } else if (e.getSource() == Subtract) {
                    ballPanel.subtract();
                }
            }
        }
    }

    class BallPanel extends JPanel {

        private int delay = 30;
        private ArrayList<AnimatedShape> list = new ArrayList<AnimatedShape>();
        private AnimatedRectange rectangle;

        public BallPanel() {
            this.rectangle = new AnimatedRectange(-25, 200, 50, 25, Color.RED);

            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }

        // Create a timer with the initial delay
        protected Timer timer = new Timer(delay, new ActionListener() {
            /**
             * Handle the action event
             */
            @Override
            public void actionPerformed(ActionEvent e) {
                for (AnimatedShape ball : list) {
                    ball.update(getBounds());
                }
                rectangle.update(getBounds());
                repaint();
            }
        });

        public void add() {
            int radius = 15;
            // Randomised position
            int x = (int) (Math.random() * (getWidth() - (radius * 2))) + radius;
            int y = (int) (Math.random() * (getHeight() - (radius * 2))) + radius;
            Color color = new Color((int) (Math.random() * 256),
                            (int) (Math.random() * 256), (int) (Math.random() * 256));

            AnimatedBall ball = new AnimatedBall(x, y, radius, color);

            list.add(ball);
        }

        public void subtract() {
            if (list.size() > 0) {
                list.remove(list.size() - 1); // Remove the last ball
            }
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g;
            for (AnimatedShape ball : list) {
                ball.paint(this, g2d);
            }
            rectangle.paint(this, g2d);
        }

        public void suspend() {
            timer.stop();
        }

        public void resume() {
            timer.start();
        }

        public void setDelay(int delay) {
            this.delay = delay;
            timer.setDelay(delay);
        }
    }

    public interface AnimatedShape {

        public void update(Rectangle bounds);

        public void paint(JComponent parent, Graphics2D g2d);
    }

    public abstract class AbstractAnimatedShape implements AnimatedShape {

        private Rectangle bounds;
        private int dx, dy;

        public AbstractAnimatedShape() {
        }

        public void setBounds(Rectangle bounds) {
            this.bounds = bounds;
        }

        public Rectangle getBounds() {
            return bounds;
        }

        public int getDx() {
            return dx;
        }

        public int getDy() {
            return dy;
        }

        public void setDx(int dx) {
            this.dx = dx;
        }

        public void setDy(int dy) {
            this.dy = dy;
        }

        @Override
        public void update(Rectangle parentBounds) {
            Rectangle bounds = getBounds();
            int dx = getDx();
            int dy = getDy();
            bounds.x += dx;
            bounds.y += dy;
            if (bounds.x  < parentBounds.x) {
                bounds.x = parentBounds.x;
                setDx(dx *= -1);
            } else if (bounds.x + bounds.width > parentBounds.x + parentBounds.width) {
                bounds.x = parentBounds.x + (parentBounds.width - bounds.width);
                setDx(dx *= -1);
            }
            if (bounds.y < parentBounds.y) {
                bounds.y = parentBounds.y;
                setDy(dy *= -1);
            } else if (bounds.y + bounds.height > parentBounds.y + parentBounds.height) {
                bounds.y = parentBounds.y + (parentBounds.height - bounds.height);
                setDy(dy *= -1);
            }
        }
    }

    public class AnimatedBall extends AbstractAnimatedShape {

        private Color color;

        public AnimatedBall(int x, int y, int radius, Color color) {
            setBounds(new Rectangle(x, y, radius * 2, radius * 2));
            this.color = color;
            setDx(Math.random() > 0.5 ? 2 : -2);
            setDy(Math.random() > 0.5 ? 2 : -2);
        }

        public Color getColor() {
            return color;
        }

        @Override
        public void paint(JComponent parent, Graphics2D g2d) {
            Rectangle bounds = getBounds();
            g2d.setColor(getColor());
            g2d.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);
        }
    }

    public class AnimatedRectange extends AbstractAnimatedShape {

        private Color color;

        public AnimatedRectange(int x, int y, int width, int height, Color color) {
            setBounds(new Rectangle(x, y, width, height));
            this.color = color;
            setDx(2);
        }

        // Don't want to adjust the vertical speed
        @Override
        public void setDy(int dy) {
        }

        @Override
        public void paint(JComponent parent, Graphics2D g2d) {
            Rectangle bounds = getBounds();
            g2d.setColor(color);
            g2d.fill(bounds);
        }

    }

    /**
     * Main method
     */
    public static void main(String[] args) {
        new MultipleBall();
    }
}

<强>修订

  • 你真的应该避免将JApplet添加到JFrame,applet有一个你忽略的规定的生命周期和管理过程。最好只关注使用BallControl面板作为核心UI元素,然后将其添加到您想要的顶级容器中
  • 您可能会发现JSlider更多的是海盗,而不是JScrollBar,更不用说,它会在不同平台上看起来更好,大多数用户都会了解滑块的用途......

答案 1 :(得分:0)

添加一个像ballCount这样的静态变量,并在每次制球时为其添加1。在Ball类中,将y的定义更改为y = 20 + ballcount*(radius*2+distanceInBalls)

public class RandomTests extends JApplet {


    public RandomTests() {
        add(new BallControl());
    }

    static int ballCount = 0;

    class BallControl extends JPanel {
        private BallPanel ballPanel = new BallPanel();
        private JButton Suspend = new JButton("Suspend");
        private JButton Resume = new JButton("Resume");
        private JButton Add = new JButton("+1");
        private JButton Subtract = new JButton("-1");
        private JScrollBar Delay = new JScrollBar();

        public BallControl() {
            // Group buttons in a panel
            JPanel panel = new JPanel();
            panel.add(Suspend);
            panel.add(Resume);
            panel.add(Add);
            panel.add(Subtract);

            // Add ball and buttons to the panel
            ballPanel.setBorder(new javax.swing.border.LineBorder(Color.red));
            Delay.setOrientation(JScrollBar.HORIZONTAL);
            ballPanel.setDelay(Delay.getMaximum());
            setLayout(new BorderLayout());
            add(Delay, BorderLayout.NORTH);
            add(ballPanel, BorderLayout.CENTER);
            add(panel, BorderLayout.SOUTH);

            // Register listeners
            Suspend.addActionListener(new Listener());
            Resume.addActionListener(new Listener());
            Add.addActionListener(new Listener());
            Subtract.addActionListener(new Listener());
            Delay.addAdjustmentListener(new AdjustmentListener() {

                public void adjustmentValueChanged(AdjustmentEvent e) {
                    ballPanel.setDelay(Delay.getMaximum() - e.getValue());
                }
            });
        }

        class Listener implements ActionListener {

            public void actionPerformed(ActionEvent e) {
                if (e.getSource() == Suspend) ballPanel.suspend();
                else if (e.getSource() == Resume) ballPanel.resume();
                else if (e.getSource() == Add) ballPanel.add();
                else if (e.getSource() == Subtract) ballPanel.subtract();
            }
        }
    }

    class BallPanel extends JPanel {
        private int delay = 30;
        private ArrayList<Ball> list = new ArrayList<Ball>();

        // Create a timer with the initial delay
        protected Timer timer = new Timer(delay, new ActionListener() {
            /** Handle the action event */
            public void actionPerformed(ActionEvent e) {
                repaint();
            }
        });

        public BallPanel() {
            timer.start();
        }

        public void add() {
            list.add(new Ball());
            ballCount++;
        }

        public void subtract() {
            if (list.size() > 0) list.remove(list.size() - 1); // Remove the last ball
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawRect(185, 279, 50, 15);
            g.setColor(Color.RED);
            g.fillRect(185, 279, 50, 15);

            for (int i = 0; i < list.size(); i++) {
                Ball ball = (Ball) list.get(i); // Get a ball
                g.setColor(ball.color); // Set ball color

                // Check boundaries
                if (ball.x < 0 || ball.x > getWidth()) ball.dx = -ball.dx;

                if (ball.y < 0 || ball.y > getHeight()) ball.dy = -ball.dy;

                // Adjust ball position
                ball.x += ball.dx;
                // ball.y += ball.dy;
                g.fillOval(ball.x - ball.radius, ball.y - ball.radius, ball.radius * 2, ball.radius * 2);
            }
        }

        public void suspend() {
            timer.stop();
        }

        public void resume() {
            timer.start();
        }

        public void setDelay(int delay) {
            this.delay = delay;
            timer.setDelay(delay);
        }
    }

    class Ball {
        int radius = 15; // Ball radius
        int x = radius;
        int y = 20 + (radius * ballCount * 2 + 15); // Current ball position
        int dx = 2; // Increment on ball's x-coordinate
        int dy = 2; // Increment on ball's y-coordinate
        Color color = new Color((int) (Math.random() * 256), (int) (Math.random() * 256), (int) (Math.random() * 256));
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        JApplet applet = new RandomTests();
        frame.add(applet);
        frame.setTitle("MultipleBallApp");
        frame.setLocationRelativeTo(null); // Center the frame
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 400);
        frame.setLocationRelativeTo(null); // Center the frame
        frame.setVisible(true);
    }
}