如何正确地为我的 Jcomponent 实现 mouselistener?

How do I properly implement a mouselistener to my Jcomponent?

我有一个项目,我需要在 Java 中创建一个 GUI,它在鼠标单击时创建一个圆圈,并在鼠标拖过框架时继续制作尾随圆圈。我在这里提到了多个线程,但 none 似乎帮助我完成了我需要做的事情。到目前为止,我已经将一个静态圆圈添加到我的 JFrame 中,但我想让多个圆圈显示在该框架的 JPanel 上。在尝试了许多不同的角度后,我被卡住了。截至目前,我只需要能够单击一次并创建一个圆圈。

public class Theremin extends JFrame implements ActionListener, MouseListener{
    private JPanel windowArea;
    private int x, y;
private static final long serialVersionUID = 1L;

public Theremin() {
    
}

public static void main(String[] args) {
    Theremin Frame = new Theremin();
    Frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    MyPanel panel = new MyPanel();
    panel.setLayout(null);
    Frame.add(panel);
    Frame.pack();
    Frame.setLocationRelativeTo(null);
    Frame.setVisible(true);
}

private static class MyPanel extends JPanel {

    public void paint(Graphics g) {
        Graphics2D gObj = (Graphics2D)g;
        Shape disk = new Ellipse2D.Double(10, 10, 100, 100);
        gObj.setColor(new Color(255, 0, 0, 120));
        gObj.fill(disk);
    }

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

@Override
public void actionPerformed(ActionEvent e) {
    // TODO Auto-generated method stub
    
}

@Override
public void mouseClicked(MouseEvent e) {
    x = e.getX();
    y = e.getY();

    repaint();
}

@Override
public void mousePressed(MouseEvent e) {
    // TODO Auto-generated method stub
    
}

@Override
public void mouseReleased(MouseEvent e) {
    // TODO Auto-generated method stub
    
}

@Override
public void mouseEntered(MouseEvent e) {
    // TODO Auto-generated method stub
    
}

@Override
public void mouseExited(MouseEvent e) {
    // TODO Auto-generated method stub
    
}

}

这里的想法是:

  • 占领点
  • 将其添加到列表
  • 重绘组件

这是我的做法,这是一个示例代码。

package com.company;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        Theremin frame = new Theremin();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        MyPanel panel = new MyPanel();
        panel.initListeners();
        panel.setLayout(null);
        frame.add(panel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        frame.addWindowListener(new WindowListener() {
            @Override
            public void windowOpened(WindowEvent e) {

            }

            @Override
            public void windowClosing(WindowEvent e) {
                panel.releaseListener();
            }

            @Override
            public void windowClosed(WindowEvent e) {

            }

            @Override
            public void windowIconified(WindowEvent e) {

            }

            @Override
            public void windowDeiconified(WindowEvent e) {

            }

            @Override
            public void windowActivated(WindowEvent e) {

            }

            @Override
            public void windowDeactivated(WindowEvent e) {

            }
        });
    }
}

class MyPanel extends JPanel implements MouseListener, MouseMotionListener {

    private Graphics graphics;
    private List<CircleData> shapeList = new ArrayList<>();
    private Graphics2D gObj;

    public MyPanel() {
    }

    @Override
    public void paint(Graphics g) {
        this.graphics = g;
        gObj = (Graphics2D) g;
        System.out.println("called paint with times: " + times++);
        for (CircleData circleData : shapeList) {
            Rectangle rectangle = circleData.rectangle;
            Color color = circleData.color;
            Shape disk = new Ellipse2D.Double(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
            gObj.setColor(color);
            gObj.fill(disk);
        }
    }


    Color randomColor() {
        int red = (int) (Math.random() * 256);
        int green = (int) (Math.random() * 256);
        int blue = (int) (Math.random() * 256);
        return new Color(red, green, blue);
    }

    static int times = 0;


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

    public void initListeners() {
        System.out.println("added default listeners");
        addMouseListener(this);
        addMouseMotionListener(this);
    }

    public void releaseListener() {
        System.out.println("removed default listeners");
        removeMouseListener(this);
        removeMouseMotionListener(this);
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        float x = e.getX();
        float y = e.getY();
        String cordinates = String.format("(%f, %f)", x, y);
        System.out.println("Mouse Clicked @ " + cordinates);
        shapeList.add(new CircleData(new Rectangle((int) x, (int) y, 50, 50), randomColor()));
        repaint();
    }

    @Override
    public void mousePressed(MouseEvent e) {

    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }

    @Override
    public void mouseDragged(MouseEvent e) {
        float x = e.getX();
        float y = e.getY();
        String cordinates = String.format("(%f, %f)", x, y);
        System.out.println("Mouse Dragged @ " + cordinates);
        System.out.println("Mouse Dragged @ " + shapeList.size());
        shapeList.add(new CircleData(new Rectangle((int) x, (int) y, 50, 50), randomColor()));
        repaint();
    }

    @Override
    public void mouseMoved(MouseEvent e) {

    }
}

class CircleData {
    Rectangle rectangle;
    Color color;

    public CircleData(Rectangle rectangle, Color color) {
        this.rectangle = rectangle;
        this.color = color;
    }
}

class Theremin extends JFrame {
    private static final long serialVersionUID = 1L;

    public Theremin() {

    }

}

这是我整理的 GUI。

每次鼠标点击创建一个圆圈。

当我创建 Swing GUI 或任何 Java 应用程序时,我使用 model / view / controller (MVC) 模式。这种模式使我能够将我的关注点分开并一次专注于应用程序的一部分。

对于 Swing GUI,MVC 模式意味着:

  1. 视图从模型中读取。
  2. 视图不更新模型。
  3. 控制器更新模型并重新绘制/重新验证视图。

该模型由两个 class 组成,CirclesCircleCircle class 定义了一个圆,圆心为 Point,半径为 int,颜色为 Color。因为 Circle 是一个 class,我可以定义任意数量的实例(圆圈)。

Circles class 拥有 ListCircle 个实例。

视图由 JFrame 和绘图 JPanel 组成。绘图 JPanelpaintComponent 方法绘制圆圈。时期。我们在控制器 class.

中创建圆圈

控制器 class CirclesListener 创建圆圈并重新绘制绘图 JPanel。每次重新绘制绘图 JPanel 时,都会重新绘制所有圆圈。

JFrame class 和应用程序模型 class 的一个实例被传递给控制器​​ CirclesListener class。这允许 class 创建一个新圆并重新绘制绘图 JPanel

这是完整的可运行代码。

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class MouseClickCircleGUI implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new MouseClickCircleGUI());
    }
    
    private Circles circles;
    
    private DrawingPanel drawingPanel;
    
    public MouseClickCircleGUI() {
        this.circles = new Circles();
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Circles");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        drawingPanel = new DrawingPanel(this, circles);
        frame.add(drawingPanel, BorderLayout.CENTER);

        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
    
    public void repaint() {
        drawingPanel.repaint();
    }
    
    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;

        private final Circles circles;

        public DrawingPanel(MouseClickCircleGUI frame, Circles circles) {
            this.circles = circles;
            setBackground(Color.WHITE);
            setPreferredSize(new Dimension(500, 500));
            addMouseListener(new CirclesListener(frame, circles));
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            g2.setStroke(new BasicStroke(3f));

            for (Circle circle : circles.getCircles()) {
                Point p = circle.getCenter();
                int radius = circle.getRadius();
                g2.setColor(circle.getColor());
                g2.drawOval(p.x - radius, p.y - radius,
                        2 * radius, 2 * radius);
            }
        }

    }
    
    public class CirclesListener extends MouseAdapter {
        
        private final Circles circles;
        
        private final MouseClickCircleGUI frame;
        
        public CirclesListener(MouseClickCircleGUI frame, Circles circles) {
            this.frame = frame;
            this.circles = circles;
        }

        @Override
        public void mouseReleased(MouseEvent event) {
            circles.addCircle(new Circle(event.getPoint(), 30, Color.BLACK));
            frame.repaint();
        }

    }
    
    public class Circles {
        
        private final List<Circle> circles;
        
        public Circles() {
            this.circles = new ArrayList<>();
        }
        
        public void addCircle(Circle circle) {
            this.circles.add(circle);
        }

        public List<Circle> getCircles() {
            return circles;
        }
        
    }
    
    public class Circle {
        
        private final int radius;
        
        private final Color color;
        
        private final Point center;

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

        public int getRadius() {
            return radius;
        }

        public Point getCenter() {
            return center;
        }

        public Color getColor() {
            return color;
        }
        
    }

}