【问题标题】:Ball Animation in SwingSwing 中的球动画
【发布时间】:2012-04-05 18:09:05
【问题描述】:

问题是当我调整 JFrame 的大小时,动画会继续使用它为 JComponent 预先提供的尺寸。有没有办法可以在调整JFrame 的大小时更新我的​​widthheight 变量,以便动画可以与新坐标一起运行。

简单来说,假设JComponent 具有初始width = 300height = 300,因此BALL 在这些指定的Co-ordinates 内移动。现在,如果我调整JFrame 的大小,JComponent 的大小仍然保持不变,即width = 300height = 300,但我希望的是一种用当前窗口大小修改这些变量的方法.如果我无法解释我的问题,请告诉我。

这是我正在使用的代码:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class BallAnimation
{
    private int x;
    private int y;
    private int count;
    private int width;
    private int height;
    private int speedValue;
    private boolean flag;
    /*
     * These variables are used to keep track of 
     * the ball, either it is going LEFT or RIGHT
     * depending on that, we will set the 
     * Co-ordinates.
     */
    private boolean toLeft, toRight;

    private boolean fromTop, fromBottom;

    private Timer timer;

    private JButton button;

    private ActionListener actionTimer; 
    private ActionListener buttonAction;

    public BallAnimation()
    {
        x = y = count = 0;
        flag = toLeft = false;
        toRight = true;
        fromTop = true;
        fromBottom = false;
        speedValue = 5;
    }

    public static void main(String args[])
    {
        Runnable runnable = new Runnable()
        {
            public void run()
            {
                BallAnimation animation = new BallAnimation();
                animation.go();
            }
        };      
        SwingUtilities.invokeLater(runnable);
    }

    public void go()
    {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //JPanel contentPane = new JPanel();

        /*
         * Class Name : 
         * Java Naming Convention says that class names 
         * should be in Pascal Case, i.e. the first
         * letter of the class name should be capitalized
         * and every new word must start with a capitalized 
         * Alphabet.
         * For Example : 
         * public class ClassName{...}
         * ----------------------------------------------------------
         * Variable Name : 
         * Java Naming Convention says that the variable name
         * should be in Camel Case, i.e. the first letter of 
         * the variable name should be small case or _ (underscore)
         * and every new word must start with a capitalized
         * Alphabet.
         * ---------------------------------------------------------
         */
        final MyDraw drawPanel = new MyDraw(0, 0);
        x = drawPanel.getXValue();
        y = drawPanel.getYValue();
        //contentPane.add(drawPanel);

        actionTimer = new ActionListener()
        {
            public void actionPerformed(ActionEvent ae)
            {               
                if (fromTop && !fromBottom && x < width && y < height 
                            && toRight && !toLeft)
                {
                    x += speedValue;
                    y += speedValue;
                }
                else if (fromTop && !fromBottom && x < width && y >= height
                                 && toRight && !toLeft)
                {
                    /*
                     * Since the ball coming from the TOP LEFT Side
                     * touched the BOTTOM of the JPanel.
                     */
                    y -= speedValue;
                    x += speedValue;
                    fromTop = false;
                    fromBottom = true;
                }
                else if (!fromTop && fromBottom && x < width && y <= 0
                                  && toRight && !toLeft)
                {
                    /*
                     * Since the ball coming from BOTTOM LEFT Side
                     * touched the TOP of the JPanel. 
                     */
                    fromTop = true;
                    fromBottom = false;
                    x += speedValue;
                    y += speedValue;
                }
                else if (!fromTop && fromBottom && x < width && y < height
                                  && toRight && !toLeft)
                {
                    x += speedValue;
                    y -= speedValue;
                }
                else if (!fromTop && fromBottom && x >= width && y < height
                                  && toRight && !toLeft)
                {
                    /*
                     * Since the ball coming from the BOTTOM LEFT Side
                     * touched the RIGHT Side of the JPanel.
                     */
                    toRight = false;
                    toLeft = true;
                    x -= speedValue;
                    y -= speedValue;
                }                
                else if (!fromTop && fromBottom && x < width && y <= 0
                                  && !toRight && toLeft)
                {
                    /*
                     * Since the ball coming from the BOTTOM RIGHT Side
                     * touched the Top Side of the JPanel.
                     */
                    fromTop = true;
                    fromBottom = false;
                    x -= speedValue;
                    y += speedValue;
                }
                else if (fromTop && !fromBottom && x <= 0 && y < height
                                 && !toRight && toLeft)
                {
                    /*
                     * Since the ball coming from the TOP RIGHT Side
                     * touched the LEFT Side of the JPanel.
                     */
                    toRight = true;
                    toLeft = false;
                    x += speedValue;
                    y += speedValue;
                }
                else if (fromTop && !fromBottom && x >= width && y < height
                                  && toRight && !toLeft)
                {
                    /*
                     * Since the ball coming from the TOP LEFT Side
                     * touched the RIGHT Side of the JPanel
                     */
                    toRight = false;
                    toLeft = true;
                    x -= speedValue;
                    y += speedValue;
                }
                else if (fromTop && !fromBottom && x < width && y < height
                                  && !toRight && toLeft)
                {
                    x -= speedValue;
                    y += speedValue;
                }
                else if (!fromTop && fromBottom && x <= 0 && y < height
                                  && !toRight && toLeft)
                {
                    /*
                     * Since the ball coming from the BOTTOM RIGHT Side
                     * touched the LEFT Side of the JPanel.
                     */
                    toRight = true;
                    toLeft = false;
                    x += speedValue;
                    y -= speedValue;
                }
                else if (!fromTop && fromBottom && x < width && y < height
                                  && !toRight && toLeft)
                {
                    x -= speedValue;
                    y -= speedValue;
                }
                else if (fromTop && !fromBottom && x < width && y >= height
                                  && !toRight && toLeft)
                {
                    /*
                     * Since the ball coming from the TOP RIGHT Side
                     * touched the BOTTOM Side of the JPanel.
                     */
                    fromTop = false;
                    fromBottom = true;
                    x -= speedValue;
                    y -= speedValue;
                }
                System.out.println("X : " + x);
                System.out.println("Y : " + y);
                System.out.println("Direction is LEFT : " + toLeft);
                System.out.println("Direction is RIGHT : " + toRight);
                System.out.println("Coming from TOP : " + fromTop);
                System.out.println("Coming from BOTTOM : " + fromBottom);
                drawPanel.setXYValues(x, y);
            }
        };

        buttonAction = new ActionListener()
        {
            public void actionPerformed(ActionEvent ae)
            {
                if (!flag)
                {
                    timer.start();
                    button.setText("STOP ANIMATION");
                    flag = true;
                }
                else if (flag)
                {
                    timer.stop();
                    button.setText("START ANIMATION");
                    flag = false;
                }
            }
        };

        button = new JButton("START ANIMATION");
        button.addActionListener(buttonAction);

        frame.getContentPane().add(drawPanel, BorderLayout.CENTER);
        frame.getContentPane().add(button, BorderLayout.PAGE_END);
        frame.setSize(300, 300);
        //frame.pack();
        frame.setVisible(true);        

        timer = new Timer(40, actionTimer);
        width = drawPanel.getWidth() - 30;
        System.out.println("WIDTH : " + width);
        height = drawPanel.getHeight() - 30;    
        System.out.println("HEIGHT : " + height);
    }
    class MyDraw extends JComponent
    {
        private int x;
        private int y;
        private Timer timer;

        public MyDraw(int x, int y)
        {
            this.x = x;
            this.y = y;
        }

        public int getXValue()
        {
            return x;
        }

        public int getYValue()
        {
            return y;
        }

        public void setXYValues(int x, int y)
        {
            this.x = x;
            this.y = y;
            repaint();
        }

        public Dimension getPreferredSize()
        {
            return (new Dimension(300, 300));
        }

        public void paintComponent(Graphics g)
        {
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, getWidth(), getHeight());
            g.setColor(Color.BLUE);
            g.fillOval(x, y, 40, 40);
        }
    }
}

【问题讨论】:

  • 您知道您的大量 if 逻辑可以压缩到 1/4 的大小,而且代码要少得多,对吧?让它使用 x 和 y 速度(可能是负数)将消除布尔标志,将所有运动代码转换为x+=xVel;y+=yVel;,然后你只剩下出界检查,这会推动球回到界限内,并反转相关速度。
  • @zebediah49 :请您在回答中向我详细说明逻辑问题:-)
  • 这段代码大约有 7 年的历史了,因此图形处理相当不受欢迎。尽管如此,控制和墙壁逻辑是标准的。之所以如此,是因为它同时具有固体(反弹)和周期性(!反弹)边界条件。 pastebin.com/UT8fyAaB
  • 在调整父级大小期间,必须是 Swing Timer 不活动,或保持最后已知的 Dimension +1
  • 您可能还喜欢这个KineticModel,它使用ComponentListener

标签: java swing resize paintcomponent jcomponent


【解决方案1】:

只需要addHierarchyBoundsListener(...),到您的MyDraw 对象,即drawPanel,如下所述:

private HierarchyBoundsListener boundsListener = 
                                new HierarchyBoundsListener()
{
    public void ancestorMoved(HierarchyEvent he)
    {
    }

    public void ancestorResized(HierarchyEvent he)
    {
        JComponent component = (JComponent) he.getComponent();
        width = component.getWidth() - 30;
        height = component.getHeight() - 30;
    }
};

并将其添加到您的 drawPanel 对象中,您正在做的事情:

drawPanel.addHierarchyBoundsListener(boundsListener);

【讨论】:

  • 这确实让我很开心,添加了HierarchyBoundsListener。谢谢你的帮助:-)
【解决方案2】:

现在这是一大堆代码帮助!试试这个变体(破坏一两件事,但解决了主要问题)。解决方法是将宽度/高度基于组件的当前大小。

package test;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class BallAnimation
{
    private int x;
    private int y;
    private int count;
    //private int drawPanel.getWidth();
    //private int drawPanel.getHeight();
    private int speedValue;
    private boolean flag;
    /*
     * These variables are used to keep track of 
     * the ball, either it is going LEFT or RIGHT
     * depending on that, we will set the 
     * Co-ordinates.
     */
    private boolean toLeft, toRight;

    private boolean fromTop, fromBottom;

    private Timer timer;

    private JButton button;

    private ActionListener actionTimer; 
    private ActionListener buttonAction;

    MyDraw drawPanel;

    public BallAnimation()
    {
        x = y = count = 0;
        flag = toLeft = false;
        toRight = true;
        fromTop = true;
        fromBottom = false;
        speedValue = 5;
    }

    public static void main(String args[])
    {
        Runnable runnable = new Runnable()
        {
            public void run()
            {
                BallAnimation animation = new BallAnimation();
                animation.go();
            }
        };      
        SwingUtilities.invokeLater(runnable);
    }

    public void go()
    {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //JPanel contentPane = new JPanel();

        /*
         * Class Name : 
         * Java Naming Convention says that class names 
         * should be in Pascal Case, i.e. the first
         * letter of the class name should be capitalized
         * and every new word must start with a capitalized 
         * Alphabet.
         * For Example : 
         * public class ClassName{...}
         * ----------------------------------------------------------
         * Variable Name : 
         * Java Naming Convention says that the variable name
         * should be in Camel Case, i.e. the first letter of 
         * the variable name should be small case or _ (underscore)
         * and every new word must start with a capitalized
         * Alphabet.
         * ---------------------------------------------------------
         */
        drawPanel = new MyDraw(0, 0);
        x = drawPanel.getXValue();
        y = drawPanel.getYValue();
        //contentPane.add(drawPanel);

        actionTimer = new ActionListener()
        {
            public void actionPerformed(ActionEvent ae)
            {               
                if (fromTop && !fromBottom && x < drawPanel.getWidth() && y < drawPanel.getHeight() 
                            && toRight && !toLeft)
                {
                    x += speedValue;
                    y += speedValue;
                }
                else if (fromTop && !fromBottom && x < drawPanel.getWidth() && y >= drawPanel.getHeight()
                                 && toRight && !toLeft)
                {
                    /*
                     * Since the ball coming from the TOP LEFT Side
                     * touched the BOTTOM of the JPanel.
                     */
                    y -= speedValue;
                    x += speedValue;
                    fromTop = false;
                    fromBottom = true;
                }
                else if (!fromTop && fromBottom && x < drawPanel.getWidth() && y <= 0
                                  && toRight && !toLeft)
                {
                    /*
                     * Since the ball coming from BOTTOM LEFT Side
                     * touched the TOP of the JPanel. 
                     */
                    fromTop = true;
                    fromBottom = false;
                    x += speedValue;
                    y += speedValue;
                }
                else if (!fromTop && fromBottom && x < drawPanel.getWidth() && y < drawPanel.getHeight()
                                  && toRight && !toLeft)
                {
                    x += speedValue;
                    y -= speedValue;
                }
                else if (!fromTop && fromBottom && x >= drawPanel.getWidth() && y < drawPanel.getHeight()
                                  && toRight && !toLeft)
                {
                    /*
                     * Since the ball coming from the BOTTOM LEFT Side
                     * touched the RIGHT Side of the JPanel.
                     */
                    toRight = false;
                    toLeft = true;
                    x -= speedValue;
                    y -= speedValue;
                }                
                else if (!fromTop && fromBottom && x < drawPanel.getWidth() && y <= 0
                                  && !toRight && toLeft)
                {
                    /*
                     * Since the ball coming from the BOTTOM RIGHT Side
                     * touched the Top Side of the JPanel.
                     */
                    fromTop = true;
                    fromBottom = false;
                    x -= speedValue;
                    y += speedValue;
                }
                else if (fromTop && !fromBottom && x <= 0 && y < drawPanel.getHeight()
                                 && !toRight && toLeft)
                {
                    /*
                     * Since the ball coming from the TOP RIGHT Side
                     * touched the LEFT Side of the JPanel.
                     */
                    toRight = true;
                    toLeft = false;
                    x += speedValue;
                    y += speedValue;
                }
                else if (fromTop && !fromBottom && x >= drawPanel.getWidth() && y < drawPanel.getHeight()
                                  && toRight && !toLeft)
                {
                    /*
                     * Since the ball coming from the TOP LEFT Side
                     * touched the RIGHT Side of the JPanel
                     */
                    toRight = false;
                    toLeft = true;
                    x -= speedValue;
                    y += speedValue;
                }
                else if (fromTop && !fromBottom && x < drawPanel.getWidth() && y < drawPanel.getHeight()
                                  && !toRight && toLeft)
                {
                    x -= speedValue;
                    y += speedValue;
                }
                else if (!fromTop && fromBottom && x <= 0 && y < drawPanel.getHeight()
                                  && !toRight && toLeft)
                {
                    /*
                     * Since the ball coming from the BOTTOM RIGHT Side
                     * touched the LEFT Side of the JPanel.
                     */
                    toRight = true;
                    toLeft = false;
                    x += speedValue;
                    y -= speedValue;
                }
                else if (!fromTop && fromBottom && x < drawPanel.getWidth() && y < drawPanel.getHeight()
                                  && !toRight && toLeft)
                {
                    x -= speedValue;
                    y -= speedValue;
                }
                else if (fromTop && !fromBottom && x < drawPanel.getWidth() && y >= drawPanel.getHeight()
                                  && !toRight && toLeft)
                {
                    /*
                     * Since the ball coming from the TOP RIGHT Side
                     * touched the BOTTOM Side of the JPanel.
                     */
                    fromTop = false;
                    fromBottom = true;
                    x -= speedValue;
                    y -= speedValue;
                }
                System.out.println("X : " + x);
                System.out.println("Y : " + y);
                System.out.println("Direction is LEFT : " + toLeft);
                System.out.println("Direction is RIGHT : " + toRight);
                System.out.println("Coming from TOP : " + fromTop);
                System.out.println("Coming from BOTTOM : " + fromBottom);
                drawPanel.setXYValues(x, y);
            }
        };

        buttonAction = new ActionListener()
        {
            public void actionPerformed(ActionEvent ae)
            {
                if (!flag)
                {
                    timer.start();
                    button.setText("STOP ANIMATION");
                    flag = true;
                }
                else if (flag)
                {
                    timer.stop();
                    button.setText("START ANIMATION");
                    flag = false;
                }
            }
        };

        button = new JButton("START ANIMATION");
        button.addActionListener(buttonAction);

        frame.getContentPane().add(drawPanel, BorderLayout.CENTER);
        frame.getContentPane().add(button, BorderLayout.PAGE_END);
        frame.setSize(300, 300);
        //frame.pack();
        frame.setVisible(true);        

        timer = new Timer(40, actionTimer);
        System.out.println("WIDTH : " + drawPanel.getWidth());
        System.out.println("HEIGHT : " + drawPanel.getHeight());
    }
    class MyDraw extends JComponent
    {
        private int x;
        private int y;
        private Timer timer;

        public MyDraw(int x, int y)
        {
            this.x = x;
            this.y = y;
        }

        public int getXValue()
        {
            return x;
        }

        public int getYValue()
        {
            return y;
        }

        public void setXYValues(int x, int y)
        {
            this.x = x;
            this.y = y;
            repaint();
        }

        public Dimension getPreferredSize()
        {
            return (new Dimension(300, 300));
        }

        public void paintComponent(Graphics g)
        {
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, getWidth(), getHeight());
            g.setColor(Color.BLUE);
            g.fillOval(x, y, 40, 40);
        }
    }
}

【讨论】:

  • 抱歉,回复晚了,虽然我喜欢这个答案(+1),让事情对我有用,但正如@zebediah49 所指出的,我的代码是废话,就逻辑而言担心,所以似乎向它添加函数调用会使情况变得更糟,以及条件检查。谢谢你对这个问题的帮助:-)
  • 今天,我更改了程序的逻辑部分,看起来就像您在回答中所说的那样,效果太好了,不需要Listener 之类的东西。以前我做的是同时检查 x 和 y,这导致了太多的条件检查。我将两者分开,结果只进行了几行检查,并且您的建议完美无缺:-)谢谢你:-)
  • “改变了我程序的逻辑部分” 太好了!很高兴看到您采纳了 zebediah49 的建议(重构逻辑)。 :)
  • 是的,我从任何地方都学到了 :-),专注于 zebediah49 的逻辑部分,@trashgod 提供的有关球的更多信息,显然,你的建议也是如此,最后都产生了奇迹我的小应用程序:-)
  • “我到处都学到了” 到处都很棒。我会经常快速搜索一下 Google,然后在 SO 上找到 3 个单独的线程,从每个线程中获取花絮。 ;)
【解决方案3】:

我希望您只需要将各种侦听器 (WindowEventListener?) 绑定到 JFrame,以便在窗口尺寸发生变化时更新 widthheight

【讨论】:

  • 不,最好将宽度/高度基于组件的当前大小,如我的变体所示。
  • 我不一定不同意,但我很好奇为什么每次使用时都获取它更好? (另外,为什么不把它分配给一个局部变量,而不是每次都调用它呢?)
  • 调用当前大小是最小的费用,并且正如 OP 所指出的,当前版本在调整大小时不起作用。可以使用监听器来实现大小的更新,但与在需要时查询大小相比,这似乎是一种笨拙的技巧。
  • @zebediah49 :谢谢你指出我的代码是垃圾,+1 :-) ,这只是我的第一幅画,所以除了手头的任务外,从来没有这么费心过这是绘画:-)。感谢您对此提供的帮助。
猜你喜欢
  • 1970-01-01
  • 2012-08-10
  • 1970-01-01
  • 2012-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-04
  • 1970-01-01
相关资源
最近更新 更多