简体   繁体   English

如何正确地为我的 Jcomponent 实现鼠标侦听器?

[英]How do I properly implement a mouselistener to my Jcomponent?

I have a project where I need to create a GUI in Java that creates a circle on mouse-click and and continues to make trailing circles as the mouse is dragged through the frame.我有一个项目,我需要在 Java 中创建一个 GUI,在鼠标单击时创建一个圆圈,并在鼠标拖过框架时继续制作尾随圆圈。 I've been given reference to multiple threads on here but none have seemed to help me do what I need to do.我在这里得到了多个线程的参考,但似乎没有一个可以帮助我做我需要做的事情。 So far I've got a static circle added to my JFrame, but I want to make the multiple circles show on a JPanel in that frame.到目前为止,我已经在 JFrame 中添加了一个 static 圆圈,但我想让多个圆圈显示在该框架中的 JPanel 上。 I'm stuck after trying many different angles.在尝试了许多不同的角度后,我被卡住了。 As of now I just need to be able to click once and create a circle.到目前为止,我只需要能够单击一次并创建一个圆圈。

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
    
}

} }

Here's a GUI that I put together.这是我放在一起的 GUI。

圆圈图形用户界面

Each mouse click creates a circle.每次鼠标单击都会创建一个圆圈。

When I create a Swing GUI, or any Java application, I use the model / view / controller (MVC) pattern. When I create a Swing GUI, or any Java application, I use the model / view / controller (MVC) pattern. This pattern allows me to separate my concerns and focus on one part of the application at a time.这种模式使我能够分离我的关注点并一次专注于应用程序的一个部分。

For a Swing GUI, the MVC pattern means:对于 Swing GUI,MVC 模式意味着:

  1. The view reads from the model.该视图从 model 读取。
  2. The view does not update the model.该视图不会更新 model。
  3. The controller updates the model and repaints / revalidates the view. controller 更新 model 并重新绘制/重新验证视图。

The model consists of two classes, Circles and Circle . model 包含两个类, CirclesCircle The Circle class defines a circle with a Point center, int radius, and a Color color. Circle class 定义了一个具有Point中心、 int半径和Color颜色的圆。 Because Circle is a class, I can define as many instances (circles) as I want.因为Circle是 class,所以我可以定义任意数量的实例(圆)。

The Circles class holds a List of Circle instances. Circles class 包含一个Circle实例List

The view consists of a JFrame and a drawing JPanel .该视图由JFrame和绘图JPanel组成。 The paintComponent method of the drawing JPanel paints circles.绘图JPanelpaintComponent方法绘制圆圈。 Period.时期。 We create the circles in the controller class.我们在 controller class 中创建圆圈。

The controller class CirclesListener creates the circles and repaints the drawing JPanel . controller class CirclesListener创建圆圈并重新绘制绘图JPanel All of the circles are redrawn each and every time the drawing JPanel is repainted.每次重新绘制绘图JPanel时,都会重新绘制所有圆圈。

An instance of the JFrame class and the application model class is passed to the controller CirclesListener class. An instance of the JFrame class and the application model class is passed to the controller CirclesListener class. This allows the class to create a new circle and repaint the drawing JPanel .这允许 class 创建一个新圆圈并重新绘制绘图JPanel

Here's the complete runnable code.这是完整的可运行代码。

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;
        }
        
    }

}

The idea here is to:这里的想法是:

  • capture point捕获点
  • add it to list将其添加到列表中
  • repaint component重绘组件

Here is how I have done it, this is a sample code.这是我的做法,这是一个示例代码。

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() {

    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM