按下我的JComponent时触发MouseListener,即使它被AffineTransform转换

时间:2013-02-17 17:12:55

标签: java swing jcomponent mouselistener affinetransform

我正在尝试将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();
            }
        }
    }
}

2 个答案:

答案 0 :(得分:0)

两点:

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

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

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

答案 1 :(得分:0)

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

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()...");
}
}