首页 > 解决方案 > Java Swing:通过鼠标点击 JPanel 制作一个不断增长的圆圈

问题描述

我是 Java 的初学者,这次我试图通过查找代码示例并编辑它们来了解更多信息,例如从这个网站。我有一个 JFrame,每次单击它(或更准确地说是其中的 JPanel)时,都会绘制一个圆圈,该圆圈会像水波纹一样向外增长/扩展。每个圆都以一定的半径开始,当达到更大的半径时将被删除或重新绘制(我选择半径“r”从 10 到 200)。我有两个程序几乎可以工作,但缺少一些东西。如果我是正确的,我可能也知道他们的问题是什么,但我不知道如何解决它们:

一个会生成不断增长的圆圈,但无论何时生成,它们都具有相同的大小,因为我不知道如何将半径分配给单个圆圈。代码改编自这里

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Ripples extends JPanel implements ActionListener{

    public int r = 10;
    private ArrayList<Point> p;
    
    public Ripples() {
        p = new ArrayList<>();
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                p.add(new Point(e.getX(), e.getY()));
            }
        });
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(Color.CYAN);
        for (Point pt : p) {
            g2.drawOval(pt.x-r, pt.y-r, 2*r, 2*r);
        }
    }
    
        
    @Override
    public void actionPerformed(ActionEvent evt) {
        if(r<200){
            r++;
        } else {
            r = 10;
        }
        repaint();
    }
    
    public static void Gui() {
        JFrame f = new JFrame();
        Ripples p = new Ripples();
        p.setBackground(Color.WHITE);
        f.setContentPane(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(500,300);
        f.setVisible(true);
        Timer t = new Timer(20,p);
        t.start();
    }

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

}

另一个程序(我忘记了我从哪里得到它)具有不同半径的圆圈,具体取决于它们的生成时间,但是圆圈“闪烁”,因为-据我所知-它们都是同时处理的,因为代码不包含一个数组来单独存储和更新每个圆圈,就像上面的那样:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Ripples extends JPanel { 
    int x,y;
    int r = 10;
    
    public Ripples(int x, int y) {
        this.x = x;
        this.y = y; 
        Timer t = new Timer(20, new ActionListener() { 
            @Override
            public void actionPerformed(ActionEvent e) { 
                if (r<200) { 
                    r++;
                } else {
                    r=10;
                }
                revalidate();
                repaint();
            }
        }); 
        t.start(); 
    }

    @Override
    public void paintComponent(Graphics g) { 
        super.paintComponent(g);
        g.setColor(Color.CYAN);
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.drawOval(x-r,y-r,2*r,2*r);
    }
    
    public static void Gui() {
        JFrame f = new JFrame("Water Ripples");
        JPanel p0 = new JPanel();
        p0.setBackground(Color.WHITE);
        f.add(p0);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setBounds(100,100,600,500);
        f.setVisible(true);
        f.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) { 
                Ripples rG = new Ripples(e.getX(), e.getY());
                rG.setBackground(Color.WHITE);
                f.add(rG); 
            }
         });
    }

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

那么我该如何解决这个问题,以便让圈子彼此独立成长呢?我更喜欢上面代码的解决方案/改进/提示,因为我认为它的结构比第二个更好。此外,对于没有将代码拆分为更多类以及可能不遵守命名约定,我深表歉意。感谢您的帮助,非常感谢!

标签: javaswingarraylistgraphicsmouselistener

解决方案


我更喜欢上面代码的解决方案/改进/提示

第二个代码更好,因为它使用:

  1. 一个自定义类,包含有关要绘制的对象的信息
  2. 一个 ArrayList 包含要绘制的对象
  3. 动画的计时器。

因为我认为它的结构比第二个更好。

不是很好的理由。使用提供所需功能的代码。

自己重构代码。这是学习经历的一部分。

第二个代码的问题:

  1. 它不编译。为什么要发布无法编译的代码?这意味着你甚至没有测试过它。
  2. 创建对象时分配初始半径Position
  3. 当 Timer 触发时,您需要遍历 ArrayList 以更新每个Position对象的半径。
  4. Position绘制代码中使用了对象的半径。

作为一个额外的变化,也许调用Positionclass RippleColor然后,您可以为波纹添加另一个自定义属性。然后,当您将 ArrayList 添加Ripple到 ArrayList 时,您会随机生成一个 Color。然后在绘画方法中使用Ripple类的 Color 属性。这就是您如何使对象和绘画更加灵活和动态的方式。


推荐阅读