java - JFrame调整大小后如何计算圆形的X-Y坐标和半径?

标签 java swing awt

我正在使用 JComponent (AWT/SWING) 在 JFrame 上绘制圆圈,我想确保当用户调整框架大小时,会进行某些计算并在屏幕上动态绘制圆圈(无论是更大还是更小) ,向左或向右移动等)。我实现了 ComponentAdapter 事件和 componentResized 方法,但是我正在努力想出一些动态的东西。这是我的代码:

CircleViewer 类

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

public class CircleViewer
{
    public static void main(String[] args)
    {
        final JFrame frame = new JFrame("Circle Shapes");
        final CirclePanel panel = new CirclePanel();

        // Class for Mouse Listener which implements the necessary interfaces
        class MousePressListener implements MouseListener, MouseMotionListener
        {
            public void mouseClicked(MouseEvent event) { }
            public void mouseEntered(MouseEvent event) { }
            public void mouseExited(MouseEvent event) { }
            public void mouseWheelMoved(MouseWheelEvent event) { }
            public void mouseMoved(MouseEvent event) { }
            public void mousePressed(MouseEvent event) { }

            @Override
            public void mouseDragged(MouseEvent event)
            {
                var x = event.getX();
                var y = event.getY();
                panel.moveTo(x, y);
            }

            @Override
            public void mouseReleased(MouseEvent event)
            {
                panel.finalMove();
            }
        }

        panel.addComponentListener(new ComponentAdapter() {
            public void componentResized(ComponentEvent event)
            {
                panel.frameResizeCalculation(frame.getWidth(), frame.getHeight());
            }
        });

        MousePressListener listener = new MousePressListener();
        panel.addMouseListener(listener);
        panel.addMouseMotionListener(listener);

        frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(panel);
        frame.setVisible(true); 
    }
    public static final int FRAME_WIDTH = 700;
    public static final int FRAME_HEIGHT = 500;
}

CirclePanel类

import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
import java.util.ArrayList;
import java.awt.Color;
import java.lang.Math;
import java.awt.BasicStroke;
import java.awt.Stroke;

public class CirclePanel extends JComponent
{
    private int mouseX;
    private int mouseY;
    private ArrayList<Circle> circleList;
    private final BasicStroke dashLine = new BasicStroke(1, 
            BasicStroke.CAP_BUTT, 
            BasicStroke.JOIN_BEVEL, 
            0, new float[]{6}, 0);
    private Circle newCircle;
    private final Color newCircleColor = Color.RED;
    private final Color finalCircleColor = Color.BLUE;

    public CirclePanel()
    {
        this.circleList = new ArrayList<Circle>();
        this.mouseX = 0;
        this.mouseY = 0;
    }

    public void moveTo(int x, int y)
    {
        mouseX = x;
        mouseY = y;
        if (newCircle == null)
        {
            newCircle = new Circle(x,y,0);
        }
        else
        {
            int dX = newCircle.get(0) - mouseX;
            int dY = newCircle.get(1) - mouseY;
            newCircle.set(2, (int)Math.sqrt(dX*dX + dY*dY));
        }
        repaint();
    }

    public void finalMove()
    {
        if (newCircle != null)
        {
            circleList.add(newCircle);
            newCircle = null;
            repaint();
        }
    }
    // Do something here and change X-Y coordinates and radius of the circles and finally call repaint() method of Graphics2D
    public void frameResizeCalculation(int width, int height)
    {
        var dX = CircleViewer.FRAME_WIDTH - width;
        var dY = CircleViewer.FRAME_HEIGHT - height;
    }

    public void paintComponent(Graphics g)
    {

        g.setColor(finalCircleColor);
        for (Circle circle : circleList) 
        {

            drawCircle(g, circle);
        }

        Circle c = newCircle;
        if (c != null)
        {
            g.setColor(newCircleColor);
            drawCircle(g, c);

            Graphics2D g2 = (Graphics2D)g.create();
            g2.setStroke(dashLine);
            g2.drawLine(c.get(0), c.get(1), mouseX, mouseY);
            g2.dispose();
        }
    }

    public void drawCircle(Graphics g, Circle c)
    {
        g.drawOval(c.get(0) - c.get(2), c.get(1) - c.get(2), c.get(2) * 2, c.get(2) * 2);
    }
}

最后是圆圈

public class Circle
{
    private int x;
    private int y;
    private int radius;

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

    public int get(int option)
    {
        switch (option)
        {
            case 0:
                return this.x;
            case 1:
                return this.y;
            case 2:
                return this.radius;
        }
        return 0;
    }

    public void set(int option, int value)
    {
        switch (option)
        {
            case 0: //set x
                this.x = value;
                break;
            case 1:
                this.y = value;
                break;
            case 2:
                this.radius = value;
                break;
        }
    }
}

最佳答案

that certain calculations are made and circles are drawn on screen dynamically (whether if it's bigger, smaller, moved to left or right etc.).

那么,您需要定义调整框架大小时想要发生的情况。我们无法告诉您该怎么做。

但是,在您担心之前,您需要重组您的类以使动态绘画成为可能。

我发现基本代码存在以下问题:

  1. 忘记框架大小。该尺寸与将在 CirclePanel 中完成的自定义绘画无关。也就是说,CirclePanel 的大小与框架的大小不同,因为框架大小包括框架边框和标题栏。您的逻辑应该基于面板的大小,而不是框架。

  2. 在进行自定义绘制时,组件还有责任重写 getPreferredSize() 方法以返回组件的首选大小。然后在代码中将面板添加到框架中,然后调用框架上的 pack() 方法。

  3. 您调用类 CirclePanel,但扩展 JComponent。为什么?给你的类(class)一个合适的名字。如果您想扩展 JComponent,请调用您的 CircleComponent 类。如果您想调用您的 CirclePanel 类,请扩展 JPanel。但您还需要了解扩展 JComponent 和 JPanel 之间的区别。所有 Swing 组件都有责任在进行任何绘制之前清除组件的背景。 JPanel 会自动为您完成此操作,您只需在开始时调用 super.paintComponent(...) 即可。 JComponent 不会清除背景,因此您必须通过设置 Graphics 对象的颜色来清除它,然后调用 fillRect(0, 0, getWidth(), getHeight()) 来绘制背景。

  4. Circle 对象应包含绘制自身所需的所有信息。您已经有了 x、y、半径值。我建议您还需要一个 Color 属性,以便每个 Circle 可以是不同的颜色。

  5. Circle 对象应该知道如何使用其属性来绘制自身。因此,您的 Circle 类应该有一个方法,例如 draw(Graphics grapics)。然后,您可以使用该类的属性来绘制椭圆形。因此,这意味着paintComponent() 方法将调用Circle 类的draw(...) 方法,并且您将删除当前拥有的drawOval(...) 方法。

  6. “getter”方法不带参数。如果您觉得其他类需要知道 x、y、radius 属性,则创建 getX()、getY() 和 getRadiout() 方法。我建议您不需要 get()/set() 方法。

我建议您首先需要实现上述建议,然后才能使绘画变得动态。

接下来,您不需要将 ComponentListener 添加到面板。相反,您需要将逻辑添加到 CirclePanel 类的 paintComponent(...) 方法中。每次面板大小发生变化时,paintComponent()方法都会被自动调用。基本逻辑是确定绘制每个圆时要使用的“乘数”。

因此,您可以使用 getPreferredSize() 方法来获取首选宽度,并且可以使用面板的 getWidth() 方法来获取当前大小。所以你的乘数是:

double multiplierX = getWidth() / getPreferredSize().x;

现在需要将此信息传递给 Circle 对象的 draw(...) 方法,因此方法签名将变为 draw(Graphics g, double multiplierX)。当您调用 drawOval(...) 方法时,您将乘数应用于“x”参数。当调整框架大小时,这应该会导致圆圈在水平方向上移动。

然后,您可以对乘数 Y 重复上述步骤,以使圆沿垂直方向移动。

然后您需要决定如何影响半径?

关于java - JFrame调整大小后如何计算圆形的X-Y坐标和半径?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58600469/

相关文章:

java - Java 中 BufferedImage 的 3/3/2 RGB 样本字节数组

java - 如何在 Eclipse 上安装 Cucumber-JVM

java - Axis2 不返回自己的对象

java - 在 IntelliJ GUI Builder 中打开现有源代码

java - 在关闭未完成编辑的 JFrame 时保存 JTable 的内容

java - 在 Java AWT 中单击时更改椭圆形的颜色

java - 更改 JLabel 字体大小

java - 在 Java 中动态转换为原语

java - 使用 Exception Missing Envelope 标签的 Spring Web 服务模板

java - 我怎样才能阻止程序第二次跳过我的检查?