【问题标题】:How to generate multiple circle shapes and animate those shapes going down the frame如何生成多个圆形并为这些形状设置动画
【发布时间】:2016-06-20 15:35:18
【问题描述】:

单击框架面板时,我无法生成多个椭圆形。我想要的是它会生成许多椭圆形并且这些形状会向下移动。要求之一是使用两个多线程。但是在我的情况下,我创建的程序是,它只会生成一个椭圆形,并且位置是随机变化的。谁能帮我一个这个。

package ovalrandomcolors;

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.List;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class OvalRandomColors extends JPanel{

    private int ovalX = 50;
    private int ovalY =50;
    private int ovalPositionX = 250;
    private int ovalPositionY = 250;
    private Color color = Color.YELLOW;

    public OvalRandomColors(){
        setBackground(Color.DARK_GRAY);
    }
    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);


        g.setColor(color);
        g.fillOval(ovalPositionX, ovalPositionY, ovalX, ovalY);

        g.setColor(color);
        g.fillOval(ovalPositionX, ovalPositionY, ovalX, ovalY);

    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable(){

            @Override
            public void run() {
               JFrame frame = new JFrame();
               final OvalRandomColors oval = new OvalRandomColors();
               oval.addMouseListener(new MouseAdapter(){
                   @Override
                   public void mouseClicked(MouseEvent e){
                       OvalWithThreading firstThread = new OvalWithThreading(oval);
                       OvalWithThreading secondThread = new OvalWithThreading(oval);

                       Thread first = new Thread(firstThread);
                       Thread second = new Thread(secondThread);
                       second.start();
                       first.start();
                   }
               });

               frame.add(oval);
               frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
               frame.setSize(500,700);
               frame.setVisible(true);
            }  
        });      
    }


    public void updateOval(){

        int r = (int)(Math.random() * 255);
        int g = (int) (Math.random() * 255);
        int b = (int)(Math.random() * 255);

        color = new Color(r,g,b);

        ovalPositionX = (int)(Math.random() * 78);
        ovalPositionY = (int) (Math.random() * 245);

        animateOval();
        repaint();
    }
    public void animateOval(){
           // ovalPositionX += 30;
            ovalPositionY += 30;
    }

    public static class OvalWithThreading implements Runnable{

        private final OvalRandomColors ovalShape;
        public OvalWithThreading(OvalRandomColors oS){
            this.ovalShape = oS;
        }
        @Override
        public void run() {
            for(;;){
                    ovalShape.updateOval();
                try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                Logger.getLogger(OvalRandomColors.class.getName()).log(Level.SEVERE, null, ex);
                }
            }           
        }       
    }   
}

【问题讨论】:

  • 您需要某种List,您可以在其中添加新的矩形并从中移动和绘制。一般来说,Swing Timer 比使用 Thread 更好,因为 Swing 不是线程安全的
  • @MadProgrammer 我也读过。但是,要求之一是现在使用线程。能否请您举例说明如何实现列表?

标签: java multithreading swing awt


【解决方案1】:

让我们开始吧,Swing 不是Thread 安全的,所以有另一个Thread 来更新UI 依赖渲染的对象的状态需要一些认真的考虑。通常,我建议使用 Swing TimerSwingWorker 来完成此操作,但这不是“要求”

为了渲染多个对象,您需要某种方式来存储它们,这样您就可以更新它们的状态并渲染它们。最简单的解决方案是List,您可以查看Collections Trail 了解更多详情。

现在,如果您还需要管理颜色,您可以看看我是如何管理每个形状的增量的,并且应该会给您一个想法

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

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

    public class TestPane extends JPanel {

        private ReentrantLock shapesLock = new ReentrantLock();
        private List<Ellipse2D> shapes;

        public TestPane() {
            shapes = new ArrayList<>(25);
            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    shapesLock.lock();
                    try {
                        shapes.add(new Ellipse2D.Double(e.getX() - 5, e.getY() - 5, 10, 10));
                    } finally {
                        shapesLock.unlock();
                    }
                }
            });

            Thread t = new Thread(new Runnable() {
                private Map<Shape, Double> deltas = new HashMap<>();

                @Override
                public void run() {
                    while (true) {
                        try {
                            shapesLock.lock();
                            try {
                                Rectangle containerBounds = getBounds();
                                containerBounds.setLocation(0, 0);
                                Iterator<Ellipse2D> it = shapes.iterator();
                                while (it.hasNext()) {
                                    Ellipse2D shape = it.next();
                                    Rectangle2D bounds = shape.getBounds2D();
                                    double y = bounds.getY();
                                    Double delta = deltas.get(shape);
                                    if (delta == null) {
                                        delta = 0d;
                                    }
                                    y += delta;
                                    shape.setFrame(bounds.getX(), y, bounds.getWidth(), bounds.getHeight());
                                    if (containerBounds.contains(shape.getBounds())) {
                                        delta = Math.min(delta + 0.25, 6d);
                                        deltas.put(shape, delta);
                                    } else {
                                        it.remove();
                                    }
                                }
                            } finally {
                                shapesLock.unlock();
                            }
                            repaint();
                            Thread.sleep(40);
                        }   catch (InterruptedException ex) {
                        }
                    }
                }
            });
            t.setDaemon(false);
            t.start();
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            shapesLock.lock();
            try {
                for (Ellipse2D shape : shapes) {
                    g2d.fill(shape);
                }
            } finally {
                shapesLock.unlock();
            }
            g2d.dispose();
        }

    }

}

【讨论】:

  • @MadProgrammer 再次感谢您。你太棒了,我正在学习新东西,这有助于我提高我的 Java 技能
  • @MadProgrammer 很抱歉打扰您,但我忽略的要求之一是使用两个线程。示例程序使用列表创建另一个椭圆形。我只需要实例化新线程并使用 start() 方法吗?
  • @JayGorio 你想要第二个线程来生成点而不是鼠标点击?
  • @MadProgrammer 没有形状的创建仍然会在单击鼠标时出现我想要的是在为椭圆形设置动画时创建两个线程。顺便说一句,要求发生了变化。第一个球将通过使用无限循环在框架边界上弹跳来制作动画。因此,当球击中框架的外部底部边界时,它将继续向上移动,依此类推。当击中框架的最顶部时,它也会下降。接下来当再次点击面板时,将会有第二个球动画,将跟随第一个球并且会有延迟。
  • @JayGorio 一个线程不仅适合,还是推荐,增加线程并不总是意味着运行得更快,事实上,它可以让运行更慢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多