在 MouseEvent 上绘制可见的 JComponents

Drawing visible JComponents on MouseEvent

我正在尝试编写一个主要用于演示的简单 java 应用程序,但由于某种原因它无法运行。它的主要功能是基本跟踪鼠标的移动,鼠标到哪里就画一个方框。我已经在研究一些代码,这就是我所拥有的。我做错了什么吗?

这是主要的class

package peter;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.MouseInfo;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Frame extends JPanel implements MouseMotionListener {

    private final static JFrame window = new JFrame();

    public Frame(){
        addMouseMotionListener(this);
        setPreferredSize(new Dimension(450, 450));
        setBackground(Color.GREEN);   
    }

    private static int mouseX;
    private static int mouseY;
    public static void main(String[] args){
        //Create and set up the window.
        JFrame frame = new JFrame("MouseMotionEventDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        JComponent newContentPane = new Frame();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }
    @Override
    public void mouseDragged(MouseEvent e)
    {
        ;
    }
    @Override
    public void mouseMoved(MouseEvent e)
    {
        JComponent P = new Paintings();
        window.add(P);
        System.out.println("Mouse moved");
    }

    public static int getMouseY()
    {
        return MouseInfo.getPointerInfo().getLocation().y;
    }
    public static int getMouseX()
    {
        return MouseInfo.getPointerInfo().getLocation().x;
    }

    public static Rectangle rectOnMouse()
    {
        Rectangle rect = new Rectangle(getMouseX(), getMouseY(), 10,10);    
        return rect;
    }
}

这就是画作class

package peter;

import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;

public class Paintings extends JComponent{

    public void paintComponent(Graphics g)
    {
        Graphics2D g2d = (Graphics2D) g;
        g2d.draw(Frame.rectOnMouse());
    }
}

我的猜测是,您还需要在每次更新后对正在绘制的任何组件调用 repaint() 方法。另外,你只需要添加一次绘画方法。你想要做的只是从鼠标侦听器中调用它。 在主函数中创建 P 并将其添加到 window。
调用 P.repaint();来自鼠标监听器。 阅读有关 paintComponent() 和 MouseListeners 的 oracle 文档。

您不想继续在 MouseMotionListener 中添加组件。只需更改矩形的位置并绘制它。另外,您想将 MouseListener 或 MouseMotionListener 添加到绘图组件,否则您的鼠标点可能会关闭。例如:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;

@SuppressWarnings("serial")
public class SimpleDraw extends JPanel {
    private static final int PREF_W = 450;
    private static final int PREF_H = PREF_W;
    private static final Dimension RECT_DIM = new Dimension(10, 10);
    private Rectangle rect = null;

    public SimpleDraw() {
        addMouseMotionListener(new MyMouse());
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        if (rect != null) {
            g2.draw(rect);
        }
    }

    // so this JPanel's is sized correctly 
    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }

    private class MyMouse extends MouseAdapter {

        @Override
        public void mouseMoved(MouseEvent e) {
            // simply change the Rectangle
            rect = new Rectangle(e.getPoint(), RECT_DIM);
            repaint();  // and have the JVM re-paint this JPanel
        }
    }

    private static void createAndShowGui() {
        SimpleDraw mainPanel = new SimpleDraw();

        JFrame frame = new JFrame("SimpleDraw");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        // initialize our GUI on the Swing event thread
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui();
            }
        });
    }
}

有关 Swing 绘图的更多信息:

您的代码的其他问题:

  • 您将希望避免让您的视图 classes,例如 Frame,实现您的侦听器接口,因为这可能会变得混乱并且无法很好地扩展。
  • 您过度依赖静态方法,这样做会失去 OOP 的优势,主要是 OOP 有助于降低复杂性的能力。
  • 您的 mouseMoved 方法再次创建新的 Paintings 组件并将它们连续添加到 JFrame。这不仅是不必要的,而且是有害的,因为新组件会占用大量资源和内存,并且会覆盖之前 JFrame contentPane 上的所有内容,包括具有您的 MouseMotionListener 的 Frame 实例。您想添加一个组件,即绘图组件到顶层 window,并且只添加一次,在我的代码中,它是我的 SimpleDraw class 的一个实例。 mouseMoved方法应该是移动一个逻辑实体,在我的代码中叫rect,然后调用repaint().