0

我正在尝试将 MouseListener 添加到我的自定义 JComponent。我只想在按下圆的边界时触发 MouseListener(JComponent 的绘画方法绘制一个圆)。我已经尝试使用下面的代码,但我无法让它工作(特别是在mousePressed方法中)。我该如何解决这个问题?

SSCCE:

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;

public class AffineTransformTest {

    private static TransformingCanvas canvas;

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        canvas = new AffineTransformTest.TransformingCanvas();
        TranslateHandler translater = new TranslateHandler();
        canvas.addMouseListener(translater);
        canvas.addMouseMotionListener(translater);
        canvas.addMouseWheelListener(new ScaleHandler());
        frame.setLayout(new BorderLayout());
        frame.getContentPane().add(canvas, BorderLayout.CENTER);
        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setVisible(true);
    }

    private static class TransformingCanvas extends JComponent {

        private double translateX;
        private double translateY;
        private double scale;

        TransformingCanvas() {
            translateX = 0;
            translateY = 0;
            scale = 1;
            setOpaque(true);
            setDoubleBuffered(true);
        }

        @Override
        public void paint(Graphics g) {

            AffineTransform tx = new AffineTransform();
            tx.translate(translateX, translateY);
            tx.scale(scale, scale);
            Graphics2D ourGraphics = (Graphics2D) g;
            ourGraphics.setColor(Color.WHITE);
            ourGraphics.fillRect(0, 0, getWidth(), getHeight());
            ourGraphics.setTransform(tx);
            ourGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            ourGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                    RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            ourGraphics.setColor(Color.BLACK);
            ourGraphics.fillOval(50, 50, 50, 50);
        }
    }

    private static class TranslateHandler implements MouseListener,
            MouseMotionListener {

        private int lastOffsetX;
        private int lastOffsetY;

        public void mousePressed(MouseEvent e) {
            lastOffsetX = e.getX();
            lastOffsetY = e.getY();

            double width = canvas.scale * 50;
            double height = canvas.scale * 50;
            double x = (AffineTransformTest.canvas.getWidth() - width) / 2;
            double y = (AffineTransformTest.canvas.getHeight() - height) / 2;
            Rectangle2D.Double bounds = new Rectangle2D.Double(x, y, width, height);
            System.out.println(bounds + " " + e.getPoint());
            if (bounds.contains(e.getPoint())) {
                System.out.println("Click!");
            }
        }

        public void mouseDragged(MouseEvent e) {
            int newX = e.getX() - lastOffsetX;
            int newY = e.getY() - lastOffsetY;

            lastOffsetX += newX;
            lastOffsetY += newY;

            canvas.translateX += newX;
            canvas.translateY += newY;

            canvas.repaint();
        }

        public void mouseClicked(MouseEvent e) {
        }

        public void mouseEntered(MouseEvent e) {
        }

        public void mouseExited(MouseEvent e) {
        }

        public void mouseMoved(MouseEvent e) {
        }

        public void mouseReleased(MouseEvent e) {
        }
    }

    private static class ScaleHandler implements MouseWheelListener {

        public void mouseWheelMoved(MouseWheelEvent e) {
            if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
                canvas.scale += (.1 * e.getWheelRotation());
                canvas.scale = Math.max(0.00001, canvas.scale);
                canvas.repaint();
            }
        }
    }
}
4

2 回答 2

1

这是代码。一些快速说明,代码中仍有一些调试,并将对 LOGGER 对象的调用替换为 System.out.println()。

import java.awt.Color;
import java.awt.Container;
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.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Point2D;
import java.util.logging.Logger;

import javax.swing.JComponent;
import javax.swing.event.MouseInputListener;


public abstract class LCARSComponent extends JComponent implements MouseInputListener {

/**
 * A reference to the global Logger object.
 */
protected final static Logger LOGGER = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);

protected int x;
protected int y;
protected int w;
protected int h;

protected double scaleFactor = 1.0;

protected Area area;
protected Area scaledArea;
protected int style;

protected Color color;

protected AffineTransform renderingTransform;

protected ActionListener actionListener;

public LCARSComponent(Container parent, int x, int y, int w, int h, int style) {

    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;

    this.style = style;

    setBounds(x,y,w,h);

    addMouseListener(this);

}


@Override
protected void paintComponent(Graphics g) {

    /**
     * First, paint the background if the component is opaque. Required when 
     * JComponent is extended, and the paintCompnent() method is overridden.
     */
    if(isOpaque()) {
        g.setColor(getBackground());
        g.fillRect(0, 0, getWidth(), getHeight());
    }

    /**
     * Create a Graphics2D object so we can use Java 2D features.
     */
    Graphics2D g2d = (Graphics2D) g.create();

    /**
     * Set the anti aliasing rendering hint and the color to draw with.
     */
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setColor(color);


    scaleComponent();       

    /**
     * Draw the Area object of the LCARS component, and fill it.
     */
    g2d.draw(scaledArea);
    g2d.fill(scaledArea);

    g2d.drawRect(scaledArea.getBounds().x, scaledArea.getBounds().y, scaledArea.getBounds().width, scaledArea.getBounds().height);

    /**
     * Clean up when the method has completed by disposing the Graphics2D object that was created.
     */
    g2d.dispose();

}


protected void scaleComponent() {
    double sw = (double)getParent().getWidth() / (double)getParent().getPreferredSize().width;
    double sh = (double)getParent().getHeight() / (double)getParent().getPreferredSize().height;

    LOGGER.info("scaledWidth = " + sw);
    LOGGER.info("scaledHeight = " + sh);

    double scaleFactor;

    if(sh < sw) {
        scaleFactor = sh;
    }
    else {
        scaleFactor = sw;
    }

    LOGGER.info("scaleFactor = " + scaleFactor);

    if(scaleFactor != this.scaleFactor) {
        this.scaleFactor = scaleFactor;

        scaledArea = new Area(area);
        renderingTransform = new AffineTransform();
        renderingTransform.scale(scaleFactor, scaleFactor);
        scaledArea.transform(renderingTransform);           
    }

    setBounds((int)(this.x*scaleFactor), (int)(this.y*scaleFactor), this.getWidth(), this.getHeight());
}


public Point screenToComponent(Point pt) {

    if(renderingTransform == null) {
        Graphics2D g2d = (Graphics2D)(this.getParent().getGraphics());
        renderingTransform = g2d.getTransform();            
    }


    Point2D pt2d = renderingTransform.transform(pt,null);

    LOGGER.info("mouse click: " + pt.getX() + ", " + pt.getY() + "  --  " + pt2d.getX() + ", " + pt2d.getY());
    return new Point((int)Math.round(pt2d.getX()), (int)Math.round(pt2d.getY()));
}


public void setActionListener(ActionListener actionListener) {
    this.actionListener = actionListener;
}


@Override
public void mouseClicked(MouseEvent e) {

    Point pt = e.getPoint();
    LOGGER.info("mouseClicked: " + this.getName() + " - " + pt.getX() + ", " + pt.getY());

    if(area.contains(e.getPoint())) {

        if(actionListener != null) {
            actionListener.actionPerformed(new ActionEvent(e.getSource(), e.getID(), e.paramString()));
        }

        if(color.equals(Color.black))
            color = Color.blue;
        else
            color = Color.black;
        this.repaint();
    }
}

@Override
public void mousePressed(MouseEvent e) {
    // TODO Auto-generated method stub
    if(area.contains(e.getLocationOnScreen()))
        System.out.println("mousePressed()...");
}

@Override
public void mouseReleased(MouseEvent e) {
    // TODO Auto-generated method stub
    if(area.contains(e.getLocationOnScreen()))
        System.out.println("mouseReleased()...");
}

@Override
public void mouseEntered(MouseEvent e) {
    Point pt = e.getPoint();
    // TODO Auto-generated method stub
     System.out.println("mouseEntered()...");
    LOGGER.info("mouseEntered: " + this.getName() + " - " + pt.getX() + ", " + pt.getY());

}

@Override
public void mouseExited(MouseEvent e) {
    // TODO Auto-generated method stub
    Point pt = e.getPoint();
    System.out.println("mouseExited()...");
    LOGGER.info("mouseExited: " + pt.getX() + ", " + pt.getY());
}

@Override
public void mouseDragged(MouseEvent e) {
    // TODO Auto-generated method stub
    System.out.println("mouseDragged()...");
}

@Override
public void mouseMoved(MouseEvent e) {
    // TODO Auto-generated method stub
    System.out.println("mouseMoved()...");
}
}
于 2013-12-14T17:41:37.503 回答
0

两点:

首先,我将使用 Shape 或 Area 对象并使用其 .contains() 方法。Bounds 始终是围绕整个形状的 Rectangle。此外,当您可以简单地使用 JComponent 的 setBounds() 方法时,不确定为什么要创建边界矩形。

其次,可以转换 JComponent 的边界,但我还没有找到任何内置的东西来缩放它们。不过,您可以动态更改大小。我正在研究一个相同的问题。现在,我正在考虑在 JComponent 缩放时动态更改边界。我试图了解屏幕坐标和 JComponent 坐标之间的相关性。鼠标坐标似乎总是在未缩放的帧/屏幕坐标中(可能是我正在使用的全屏模式的产物。我见过的解决方案在 JPanel 中绘制所有内容并且不使用离散的 JComponents 来解决缩放问题。代码有点难以理解,而且不是特别模块化,但它确实有效。

无论如何,我相信它最终可以完成。这只是让数学正确的问题。完成后,我将发布可扩展 JComponent 扩展的代码并且它工作可靠。希望这有所帮助。

于 2013-12-11T15:28:43.283 回答