【问题标题】:how can i draw a circle again if it goes too far on a JPanel如果在 JPanel 上画得太远,我怎么能再次画一个圆圈
【发布时间】:2013-12-26 01:27:41
【问题描述】:

我正在尝试制作一个以 JPanel 顶部的 7 个圆圈开头的程序。所有的圆圈都有随机的大小和颜色。圆圈从屏幕顶部开始,一旦到达 JPanel 的底部就会向下移动,它们应该会重新出现在 JPanel 的顶部并再次向下移动。我已经可以让圆圈向下移动,但我不确定如何将它们再次拉回到顶部。我创建了一个名为 replaceCircle 的方法,用于在 JPanel 顶部绘制圆圈,但它不起作用。

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;
import java.util.Random;
import javax.swing.JPanel;
import javax.swing.Timer;

public class keyExample extends JPanel implements ActionListener, KeyListener {

    private Circle[] circles = new Circle[7];

    Timer t = new Timer(5, this);
//current x and y
    double x = 150, y = 200;
    double changeX = 0, changeY = 0;
    private Circle c1, c2, c3, c4, c5, c6, c7, circleone;
    private int circlex = 10, circley = 0; // makes initial starting point of circles 0
    private int newCirclex = 0, newCircley = 0;
    private javax.swing.Timer timer2;
    private Random num = new Random();
    private int s = num.nextInt(8);

    public keyExample() {

        t.start();
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
        Random num = new Random();
        Random colors = new Random();

        Color color1 = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
        Color color2 = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
        Color color3 = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
        Color color4 = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
        Color color5 = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
        Color color6 = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
        Color color7 = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));

        int radius1 = num.nextInt(40);
        int radius2 = num.nextInt(20);
        int radius3 = num.nextInt(25);
        int radius4 = num.nextInt(45);
        int radius5 = num.nextInt(15);
        int radius6 = num.nextInt(40);
        int radius7 = num.nextInt(50);

        if (radius1 < 5) {
            radius1 = 10;
        } else if (radius2 < 5) {
            radius2 = 10;
        } else if (radius3 < 5) {
            radius3 = 10;
        } else if (radius4 < 5) {
            radius4 = 10;
        } else if (radius5 < 5) {
            radius5 = 10;
        } else if (radius6 < 5) {
            radius6 = 10;
        } else if (radius7 < 5) {
            radius7 = 10;
        } else {
        }
        c1 = new Circle(circlex, circley, radius1, color1);
        c2 = new Circle(circlex + 70, circley, radius2, color2);
        c3 = new Circle(circlex + 150, circley, radius3, color3);
        c4 = new Circle(circlex + 220, circley, radius4, color4);
        c5 = new Circle(circlex + 270, circley, radius5, color5);
        c6 = new Circle(circlex + 340, circley, radius6, color6);
        c7 = new Circle(circley + 410, circley, radius7, color7);

        circles[0] = c1;
        circles[1] = c2;
        circles[2] = c3;
        circles[3] = c4;
        circles[4] = c5;
        circles[5] = c6;
        circles[6] = c7;

        timer2 = new javax.swing.Timer(33, new MoveListener());
        timer2.start();

    }

    public void NewCircle() {
        for (int i = 0; i < circles.length; i++) {
            Random num = new Random();
            Random colors = new Random();
            Color color = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
            int radius = num.nextInt(40);
            if (radius < 5) {
                radius = radius + 10;
            } else {
            }
            circles[i] = new Circle(circlex, circley, radius, color);

        }

    }

    public void replaceCircle() {
        int height = getHeight();
        newCircley = newCircley + s;
        circley = newCircley;
        Random num = new Random();
        int radius = num.nextInt(34);
        Random colors = new Random();
        Color color = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
        if (circley > height) {
            c1 = new Circle(10, 0, radius, color);
        } else {
        }

    }

    public void createCircle() {

    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setColor(Color.BLUE);
        g2.fill(new Rectangle2D.Double(x, y, 40, 40));
        for (int i = 0; i < circles.length; i++) {
            circles[i].fill(g);
        }

    }

    public void actionPerformed(ActionEvent e) {
        repaint();
        x += changeX;
        y += changeY;
        changeX = 0;
        changeY = 0;

    }

    public void up() {
        if (y != 0) {
            changeY = -3.5;
            changeX = 0;
        }
    }

    public void down() {
        if (y <= 350) {
            changeY = 3.5;
            changeX = 0;

        }
    }

    public void left() {
        if (x >= 0) {
            changeX = -3.5;
            changeY = 0;
        }
    }

    public void right() {
        if (x <= 550) {
            changeX = 3.5;
            changeY = 0;
        }
    }

    private class MoveListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {

            Random speed = new Random();

            int s2 = speed.nextInt(12);
            int s3 = speed.nextInt(4);
            int s4 = speed.nextInt(20);
            int s5 = speed.nextInt(7);
            int s6 = speed.nextInt(5);
            int s7 = speed.nextInt(8);

            c1.move(0, s);
            c2.move(0, s2);
            c3.move(0, s3);
            c4.move(0, s4);
            c5.move(0, s5);
            c6.move(0, s6);
            c7.move(0, s7);

            repaint();

        }
    }

    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        if (code == KeyEvent.VK_UP) {
            up();
        }
        if (code == KeyEvent.VK_DOWN) {
            down();
        }
        if (code == KeyEvent.VK_RIGHT) {
            right();
        }
        if (code == KeyEvent.VK_LEFT) {
            left();

        }
    }

    public void keyTyped(KeyEvent e) {
    }

    public void keyReleased(KeyEvent e) {
    }

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

圈类

import java.awt.*;

公共类圈子{

    private int centerX, centerY, radius, coord;
    private Color color;

    public Circle(int x, int y, int r, Color c) {
        centerX = x;
        centerY = y;
        radius = r;
        color = c;

    }

    public void draw(Graphics g) {
        Color oldColor = g.getColor();
        g.setColor(color);
        g.drawOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
        g.setColor(oldColor);

    }

    public void fill(Graphics g) {
        Color oldColor = g.getColor();
        g.setColor(color);
        g.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
        g.setColor(oldColor);
    }

    public boolean containsPoint(int x, int y) {
        int xSquared = (x - centerX) * (x - centerX);
        int ySquared = (y - centerY) * (y - centerY);
        int RadiusSquared = radius * radius;
        return xSquared + ySquared - RadiusSquared <= 0;
    }

    public void move(int xAmount, int yAmount) {
        centerX = centerX + xAmount;
        centerY = centerY + yAmount;
    }

}

【问题讨论】:

  • Circle 类中公开setCenter(int x, int y) 方法以将圆圈放回开始的位置是否有问题?
  • 想一想。你有一个 move 方法,它只知道对象应该移动多远。它对它所在的容器一无所知。你有一个Circle 通行证,它没有提供关于它在哪里或有多大的信息。所以没有人能真正确定给定的Circle 是否已经超出了可用容器空间...
  • 我明白你在说什么,这是我无法解决的问题之一。我不确定如何将两者联系起来。

标签: java swing jpanel paintcomponent


【解决方案1】:

更好的解决方案是为Circle 提供一些方法来确定当它越界时应该做什么,但是,代码太复杂了,我改用了它...

首先将getBounds 方法添加到您的Circle 类...

public Rectangle getBounds() {
    int x = centerX - radius;
    int y = centerY - radius;
    return new Rectangle(x, y, radius * 2, radius * 2);
}

这将提供有关圆圈大小和位置的信息...

接下来,在您的 MoveListener 中,添加一个 checkBounds 方法...

public void checkBounds(Circle circle) {
    int height = getHeight();
    Rectangle bounds = circle.getBounds();

    if (bounds.y + bounds.height > height) {
        circle.move(0, -(height) + bounds.height);
    }
}

这将用于确定给定的Circle 是否已超出可视区域的范围...

接下来,在您的MoveListeneractionPerformed 方法中,检查每个圆圈...

c1.move(0, s);
checkBounds(c1);

等等……

更新了快速示例

所以,这是我正在努力实现的快速而快速的示例......

这使用ArrayList 作为Circles 的主容器,但更改它以使用数组并不需要太多(事实上,某些部分会变得更容易)......

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.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class DropCircles {

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

    public DropCircles() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class TestPane extends JPanel {

        protected static final int MAX_CIRCLES = 7;
        private List<Circle> circles;
        private Random rnd = new Random();

        public TestPane() {
            circles = new ArrayList<>(MAX_CIRCLES);
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    while (circles.size() < MAX_CIRCLES) {
                        circles.add(createCircle());
                    }

                    List<Circle> purge = new ArrayList<>(MAX_CIRCLES);
                    for (Circle circle : circles) {
                        Point p = circle.getLocation();
                        p.y += circle.getYDelta();
                        if (p.y > getHeight()) {
                            purge.add(circle);
                        } else {
                            circle.setLocation(p);
                        }
                    }
                    circles.removeAll(purge);

                    repaint();
                }
            });
            timer.start();
        }

        protected Circle createCircle() {

            int x = rnd.nextInt(getWidth());
            int radius = 5 + rnd.nextInt(45);
            int speed = 1 + rnd.nextInt(8);

            if (x + radius > getWidth()) {
                x = getWidth() - radius;
            }

            Circle circle = new Circle(radius, new Color(rnd.nextInt(255), rnd.nextInt(255), rnd.nextInt(255)));
            circle.setLocation(x, 0);
            circle.setYDelta(speed);

            return circle;

        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            for (Circle circle : circles) {
                circle.paint(g);
            }
            g2d.dispose();
        }
    }

    public static class Circle {

        private final int radius;
        private final Color color;
        private int x;
        private int y;

        private int yDelta;

        public Circle(int radius, Color color) {
            this.radius = radius;
            this.color = color;
        }

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

        public void setLocation(Point p) {
            setLocation(p.x, p.y);
        }

        public Point getLocation() {
            return new Point(x, y);            
        }

        public void setYDelta(int yDelta) {
            this.yDelta = yDelta;
        }

        public int getYDelta() {
            return yDelta;
        }

        public void paint(Graphics g) {
            g.setColor(color);
            g.fillOval(x, y, radius, radius);
        }

    }

}

基本上发生的情况是,当Circle 离开可视区域时,它会从“列表”中删除,并且在下一个刻度(Timer)上,会创建一个新的Circle,以确保存在总是在屏幕上(或大约)七个圆圈。

如果您要使用数组。您可以简单地在当前Circle 的索引位置在移动循环中创建一个新的Circle,有效地替换它...

【讨论】:

  • 感谢帮助,如果我找到一个移动圆的 Y 值,并在 Y 值高于 JPanel 的高度时在顶部出现一个新的圆,它是否也有效。跨度>
  • 概念是一样的,但是你知道的问题是,你不知道你在处理哪个圈子……所以如何在数组中替换它,但你似乎已经放弃了数组,所以你有双重麻烦......
  • 我找不到我制作的第一个圆圈的 Y 值,称为 c1,所以当它走得太远时,我只需要制作一个新的。我尝试使用该数组,但是当我必须找到任何随机圆的 Y 值时,它变得有点太复杂了,因为我希望一个新的随机圆出现在旧圆所在的顶部。因此,如果一个圆圈从屏幕中间开始,当它下降到远处时,一个新的圆圈将出现在相同的 x 值上
  • 如果两个或多个圈子具有相同的y 位置会怎样?我个人的方法是使用某种Stack,这样当一个对象移动到容器边界之外时,您只需将pop 它从堆栈中取出。然后,您将拥有一些机制来检查堆栈的大小并用新的圆圈将其填充到所需的限制
  • 我明白你的意思,但我认为如果我为每个圈子制作不同的变量,我的想法可能会奏效。它们都将设置为零,但它们的调用方式不同,所以如果我检查圆 c1 的 Y 值,我可以寻找 Yone。我认为这样做可以让我检查变量 Yone 并查看它是否走得太远,如果它走得太远,那么我会做一个新的圈子。我唯一的问题是知道如何使变量保持每个圆的变化的 Y 值
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-04
相关资源
最近更新 更多