addMouseMotionListener的问题得到错误的坐标

时间:2014-06-26 00:36:16

标签: java swing positioning jscrollpane

我借用下面的课程为项目制作选择区域工具。但是当我尝试在内容未在左上方对齐时进行选择时,它会出现问题,它会使我的鼠标坐标与ScrollPane相关,但会覆盖图像 - 请参阅此SS以便更好地理解: enter image description here

SSCCE

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.*;
import java.awt.image.*;

import javax.swing.*;

/** Getting a Rectangle of interest on the screen.
Requires the MotivatedEndUser API - sold separately. */
public class ScreenCaptureRectangle {

    Rectangle captureRect;

    ScreenCaptureRectangle(final BufferedImage screen) {
        final BufferedImage screenCopy = new BufferedImage(screen.getWidth(), screen.getHeight(), screen.getType());
        final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
        JScrollPane screenScroll = new JScrollPane(screenLabel);

        screenScroll.setPreferredSize(new Dimension((int)(screen.getWidth()*2), (int)(screen.getHeight()*2)));

        JPanel panel = new JPanel(new BorderLayout());
        panel.add(screenScroll, BorderLayout.CENTER);

        final JLabel selectionLabel = new JLabel("Drag a rectangle in the screen shot!");
        panel.add(selectionLabel, BorderLayout.SOUTH);

        repaint(screen, screenCopy);
        screenLabel.repaint();

        screenLabel.addMouseMotionListener(new MouseMotionAdapter() {

            Point start = new Point();

            @Override
            public void mouseMoved(MouseEvent me) {
                start = me.getPoint();
                repaint(screen, screenCopy);
                selectionLabel.setText("Start Point: " + start);
                screenLabel.repaint();
            }

            @Override
            public void mouseDragged(MouseEvent me) {
                Point end = me.getPoint();
                captureRect = new Rectangle(start, new Dimension(end.x-start.x, end.y-start.y));
                repaint(screen, screenCopy);
                screenLabel.repaint();
                selectionLabel.setText("Rectangle: " + captureRect);
            }
        });

        JOptionPane.showMessageDialog(null, panel);

        System.out.println("Rectangle of interest: " + captureRect);
    }

    public void repaint(BufferedImage orig, BufferedImage copy) {
        Graphics2D g = copy.createGraphics();
        g.drawImage(orig,0,0, null);
        if (captureRect!=null) {
            g.setColor(Color.RED);
            g.draw(captureRect);
            g.setColor(new Color(255,255,255,150));
            g.fill(captureRect);
        }
        g.dispose();
    }

    public static void main(String[] args) throws Exception {
        Robot robot = new Robot();
        final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

        final BufferedImage screen = robot.createScreenCapture(new Rectangle(300,0,300,300));

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new ScreenCaptureRectangle(screen);
            }
        });
    }
}

2 个答案:

答案 0 :(得分:3)

我认为您有问题,因为您试图将图像置于面板中心。

最简单的解决方案是确保从面板的顶部/左侧绘制图像:

    final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
    screenLabel.setHorizontalAlignment(JLabel.LEFT);
    screenLabel.setVerticalAlignment(JLabel.TOP);

答案 1 :(得分:2)

基本上,正在发生的事情是,你是直接绘制到图像表面(由JLabel持有),所以当你在屏幕上以2x2x36x36拖动时,然后在矩形上绘制RELATIVE到图像本身

因此即使图像在JLabel的上下文中居中,您仍然会渲染到图像的本地上下文(0x0),因此两者之间会断开连接。

根据您想要实现的目标,您可以改变绘画的工作方式并采取更直接的控制,例如......

Drag

import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class DrawimgExample {

    public static void main(String[] args) {
        try {
            Robot robot = new Robot();
            final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

            final BufferedImage screen = robot.createScreenCapture(new Rectangle(300, 0, 300, 300));
            new DrawimgExample(screen);
        } catch (AWTException exp) {
            exp.printStackTrace();
        }
    }

    public DrawimgExample(final BufferedImage screen) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new DrawingPane(screen));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class DrawingPane extends JPanel {

        private BufferedImage img;
        private Rectangle drawRect;

        public DrawingPane(BufferedImage img) {
            this.img = img;

            MouseAdapter mouseHandler = new MouseAdapter() {

                private Point startPoint;

                @Override
                public void mousePressed(MouseEvent e) {
                    startPoint = e.getPoint();
                }

                @Override
                public void mouseDragged(MouseEvent e) {
                    Point endPoint = e.getPoint();

                    int startX = Math.min(startPoint.x, endPoint.x);
                    int startY = Math.min(startPoint.y, endPoint.y);

                    int width = Math.max(startPoint.x, endPoint.x) - startX;
                    int height = Math.max(startPoint.y, endPoint.y) - startY;

                    drawRect = new Rectangle(
                            startX,
                            startY,
                            width,
                            height
                    );
                    repaint();
                }

            };

            addMouseListener(mouseHandler);
            addMouseMotionListener(mouseHandler);
        }

        @Override
        public Dimension getPreferredSize() {
            return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int x = (getWidth() - img.getWidth()) / 2;
            int y = (getHeight() - img.getHeight()) / 2;
            g2d.drawImage(img, x, y, this);
            if (drawRect != null) {
                g2d.setColor(Color.RED);
                g2d.draw(drawRect);
                g2d.setColor(new Color(255, 255, 255, 150));
                g2d.fill(drawRect);
            }
            g2d.dispose();
        }
    }

}

尽管如此,在可能的情况下,您应该避免直接绘制图像,因为JLabel已经做得很好,但有时候,如果它不能满足您的需求,您可能需要更直接地控制